@ai-hero/sandcastle 0.6.5 → 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 +137 -62
- package/dist/{MountConfig.d.ts → MountConfig-CmXclHA5.d.ts} +3 -2
- package/dist/{SandboxProvider.d.ts → SandboxProvider-EkSMuBp8.d.ts} +25 -39
- package/dist/chunk-52CIJF45.js +25569 -0
- package/dist/chunk-52CIJF45.js.map +1 -0
- package/dist/chunk-5VM5QZ26.js +26988 -0
- package/dist/chunk-5VM5QZ26.js.map +1 -0
- package/dist/chunk-72UVAC7B.js +99 -0
- package/dist/chunk-72UVAC7B.js.map +1 -0
- package/dist/chunk-BIWNFKGV.js +22 -0
- package/dist/chunk-BIWNFKGV.js.map +1 -0
- package/dist/chunk-NGBM7T3E.js +76 -0
- package/dist/chunk-NGBM7T3E.js.map +1 -0
- package/dist/chunk-NSFQW6ML.js +362 -0
- package/dist/chunk-NSFQW6ML.js.map +1 -0
- package/dist/index.d.ts +920 -22
- package/dist/index.js +3212 -9
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +0 -2
- package/dist/main.js +19349 -13
- package/dist/main.js.map +1 -1
- package/dist/mountUtils-CCA-bbpK.d.ts +25 -0
- package/dist/sandboxes/daytona.d.ts +8 -5
- package/dist/sandboxes/daytona.js +118 -124
- package/dist/sandboxes/daytona.js.map +1 -1
- package/dist/sandboxes/docker.d.ts +10 -8
- package/dist/sandboxes/docker.js +8 -255
- package/dist/sandboxes/docker.js.map +1 -1
- package/dist/sandboxes/no-sandbox.d.ts +7 -4
- package/dist/sandboxes/no-sandbox.js +6 -114
- package/dist/sandboxes/no-sandbox.js.map +1 -1
- package/dist/sandboxes/podman.d.ts +10 -8
- package/dist/sandboxes/podman.js +287 -297
- package/dist/sandboxes/podman.js.map +1 -1
- package/dist/sandboxes/vercel.d.ts +7 -4
- package/dist/sandboxes/vercel.js +144 -165
- package/dist/sandboxes/vercel.js.map +1 -1
- package/dist/templates/sequential-reviewer/implement-prompt.md +2 -2
- package/dist/templates/simple-loop/prompt.md +2 -2
- package/package.json +15 -14
- package/dist/AgentProvider.d.ts +0 -134
- package/dist/AgentProvider.d.ts.map +0 -1
- package/dist/AgentProvider.js +0 -647
- package/dist/AgentProvider.js.map +0 -1
- package/dist/AgentStreamEmitter.d.ts +0 -36
- package/dist/AgentStreamEmitter.d.ts.map +0 -1
- package/dist/AgentStreamEmitter.js +0 -21
- package/dist/AgentStreamEmitter.js.map +0 -1
- package/dist/CopyToWorktree.d.ts +0 -15
- package/dist/CopyToWorktree.d.ts.map +0 -1
- package/dist/CopyToWorktree.js +0 -60
- package/dist/CopyToWorktree.js.map +0 -1
- package/dist/Display.d.ts +0 -58
- package/dist/Display.d.ts.map +0 -1
- package/dist/Display.js +0 -142
- package/dist/Display.js.map +0 -1
- package/dist/DockerLifecycle.d.ts +0 -54
- package/dist/DockerLifecycle.d.ts.map +0 -1
- package/dist/DockerLifecycle.js +0 -123
- package/dist/DockerLifecycle.js.map +0 -1
- package/dist/EnvResolver.d.ts +0 -11
- package/dist/EnvResolver.d.ts.map +0 -1
- package/dist/EnvResolver.js +0 -63
- package/dist/EnvResolver.js.map +0 -1
- package/dist/ErrorHandler.d.ts +0 -15
- package/dist/ErrorHandler.d.ts.map +0 -1
- package/dist/ErrorHandler.js +0 -85
- package/dist/ErrorHandler.js.map +0 -1
- package/dist/InitService.d.ts +0 -92
- package/dist/InitService.d.ts.map +0 -1
- package/dist/InitService.js +0 -836
- package/dist/InitService.js.map +0 -1
- package/dist/MountConfig.d.ts.map +0 -1
- package/dist/MountConfig.js +0 -7
- package/dist/MountConfig.js.map +0 -1
- package/dist/Orchestrator.d.ts +0 -56
- package/dist/Orchestrator.d.ts.map +0 -1
- package/dist/Orchestrator.js +0 -293
- package/dist/Orchestrator.js.map +0 -1
- package/dist/Output.d.ts +0 -107
- package/dist/Output.d.ts.map +0 -1
- package/dist/Output.js +0 -95
- package/dist/Output.js.map +0 -1
- package/dist/PodmanLifecycle.d.ts +0 -17
- package/dist/PodmanLifecycle.d.ts.map +0 -1
- package/dist/PodmanLifecycle.js +0 -45
- package/dist/PodmanLifecycle.js.map +0 -1
- package/dist/PromptArgumentSubstitution.d.ts +0 -32
- package/dist/PromptArgumentSubstitution.d.ts.map +0 -1
- package/dist/PromptArgumentSubstitution.js +0 -104
- package/dist/PromptArgumentSubstitution.js.map +0 -1
- package/dist/PromptPreprocessor.d.ts +0 -15
- package/dist/PromptPreprocessor.d.ts.map +0 -1
- package/dist/PromptPreprocessor.js +0 -55
- package/dist/PromptPreprocessor.js.map +0 -1
- package/dist/PromptResolver.d.ts +0 -21
- package/dist/PromptResolver.d.ts.map +0 -1
- package/dist/PromptResolver.js +0 -27
- package/dist/PromptResolver.js.map +0 -1
- package/dist/RecoveryMessage.d.ts +0 -15
- package/dist/RecoveryMessage.d.ts.map +0 -1
- package/dist/RecoveryMessage.js +0 -81
- package/dist/RecoveryMessage.js.map +0 -1
- package/dist/SandboxFactory.d.ts +0 -90
- package/dist/SandboxFactory.d.ts.map +0 -1
- package/dist/SandboxFactory.js +0 -324
- package/dist/SandboxFactory.js.map +0 -1
- package/dist/SandboxLifecycle.d.ts +0 -65
- package/dist/SandboxLifecycle.d.ts.map +0 -1
- package/dist/SandboxLifecycle.js +0 -296
- package/dist/SandboxLifecycle.js.map +0 -1
- package/dist/SandboxProvider.d.ts.map +0 -1
- package/dist/SandboxProvider.js +0 -28
- package/dist/SandboxProvider.js.map +0 -1
- package/dist/SessionStore.d.ts +0 -110
- package/dist/SessionStore.d.ts.map +0 -1
- package/dist/SessionStore.js +0 -330
- package/dist/SessionStore.js.map +0 -1
- package/dist/TextDeltaBuffer.d.ts +0 -24
- package/dist/TextDeltaBuffer.d.ts.map +0 -1
- package/dist/TextDeltaBuffer.js +0 -68
- package/dist/TextDeltaBuffer.js.map +0 -1
- package/dist/WorktreeManager.d.ts +0 -79
- package/dist/WorktreeManager.d.ts.map +0 -1
- package/dist/WorktreeManager.js +0 -283
- package/dist/WorktreeManager.js.map +0 -1
- package/dist/boundedTail.d.ts +0 -48
- package/dist/boundedTail.d.ts.map +0 -1
- package/dist/boundedTail.js +0 -64
- package/dist/boundedTail.js.map +0 -1
- package/dist/cli.d.ts +0 -30
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -340
- package/dist/cli.js.map +0 -1
- package/dist/createSandbox.d.ts +0 -154
- package/dist/createSandbox.d.ts.map +0 -1
- package/dist/createSandbox.js +0 -476
- package/dist/createSandbox.js.map +0 -1
- package/dist/createWorktree.d.ts +0 -154
- package/dist/createWorktree.d.ts.map +0 -1
- package/dist/createWorktree.js +0 -391
- package/dist/createWorktree.js.map +0 -1
- package/dist/errors.d.ts +0 -227
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -81
- package/dist/errors.js.map +0 -1
- package/dist/extractStructuredOutput.d.ts +0 -23
- package/dist/extractStructuredOutput.d.ts.map +0 -1
- package/dist/extractStructuredOutput.js +0 -102
- package/dist/extractStructuredOutput.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/interactive.d.ts +0 -74
- package/dist/interactive.d.ts.map +0 -1
- package/dist/interactive.js +0 -279
- package/dist/interactive.js.map +0 -1
- package/dist/main.d.ts.map +0 -1
- package/dist/mergeProviderEnv.d.ts +0 -13
- package/dist/mergeProviderEnv.d.ts.map +0 -1
- package/dist/mergeProviderEnv.js +0 -23
- package/dist/mergeProviderEnv.js.map +0 -1
- package/dist/mountUtils.d.ts +0 -146
- package/dist/mountUtils.d.ts.map +0 -1
- package/dist/mountUtils.js +0 -301
- package/dist/mountUtils.js.map +0 -1
- package/dist/raceAbortSignal.d.ts +0 -18
- package/dist/raceAbortSignal.d.ts.map +0 -1
- package/dist/raceAbortSignal.js +0 -32
- package/dist/raceAbortSignal.js.map +0 -1
- package/dist/resolveCwd.d.ts +0 -24
- package/dist/resolveCwd.d.ts.map +0 -1
- package/dist/resolveCwd.js +0 -32
- package/dist/resolveCwd.js.map +0 -1
- package/dist/resumePrecheck.d.ts +0 -26
- package/dist/resumePrecheck.d.ts.map +0 -1
- package/dist/resumePrecheck.js +0 -40
- package/dist/resumePrecheck.js.map +0 -1
- package/dist/run.d.ts +0 -216
- package/dist/run.d.ts.map +0 -1
- package/dist/run.js +0 -313
- package/dist/run.js.map +0 -1
- package/dist/sandboxExec.d.ts +0 -12
- package/dist/sandboxExec.d.ts.map +0 -1
- package/dist/sandboxExec.js +0 -26
- package/dist/sandboxExec.js.map +0 -1
- package/dist/sandboxes/daytona.d.ts.map +0 -1
- package/dist/sandboxes/docker.d.ts.map +0 -1
- package/dist/sandboxes/no-sandbox.d.ts.map +0 -1
- package/dist/sandboxes/podman.d.ts.map +0 -1
- package/dist/sandboxes/test-bind-mount.d.ts +0 -17
- package/dist/sandboxes/test-bind-mount.d.ts.map +0 -1
- package/dist/sandboxes/test-bind-mount.js +0 -92
- package/dist/sandboxes/test-bind-mount.js.map +0 -1
- package/dist/sandboxes/test-isolated.d.ts +0 -17
- package/dist/sandboxes/test-isolated.d.ts.map +0 -1
- package/dist/sandboxes/test-isolated.js +0 -98
- package/dist/sandboxes/test-isolated.js.map +0 -1
- package/dist/sandboxes/vercel.d.ts.map +0 -1
- package/dist/shutdownRegistry.d.ts +0 -30
- package/dist/shutdownRegistry.d.ts.map +0 -1
- package/dist/shutdownRegistry.js +0 -73
- package/dist/shutdownRegistry.js.map +0 -1
- package/dist/startSandbox.d.ts +0 -50
- package/dist/startSandbox.d.ts.map +0 -1
- package/dist/startSandbox.js +0 -117
- package/dist/startSandbox.js.map +0 -1
- package/dist/syncIn.d.ts +0 -24
- package/dist/syncIn.d.ts.map +0 -1
- package/dist/syncIn.js +0 -107
- package/dist/syncIn.js.map +0 -1
- package/dist/syncOut.d.ts +0 -27
- package/dist/syncOut.d.ts.map +0 -1
- package/dist/syncOut.js +0 -271
- package/dist/syncOut.js.map +0 -1
- package/dist/templates.d.ts +0 -2
- package/dist/templates.d.ts.map +0 -1
- package/dist/templates.js +0 -26
- package/dist/templates.js.map +0 -1
- package/dist/terminalCleanup.d.ts +0 -30
- package/dist/terminalCleanup.d.ts.map +0 -1
- package/dist/terminalCleanup.js +0 -37
- package/dist/terminalCleanup.js.map +0 -1
- package/dist/testSandbox.d.ts +0 -8
- package/dist/testSandbox.d.ts.map +0 -1
- package/dist/testSandbox.js +0 -109
- package/dist/testSandbox.js.map +0 -1
- package/dist/testSetup.d.ts +0 -2
- package/dist/testSetup.d.ts.map +0 -1
- package/dist/testSetup.js +0 -29
- package/dist/testSetup.js.map +0 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { MAX_TAIL_CHARS, BoundedTail } from './chunk-NGBM7T3E.js';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import { createInterface } from 'readline';
|
|
5
|
+
|
|
6
|
+
createRequire(import.meta.url);
|
|
7
|
+
var noSandbox = (options) => ({
|
|
8
|
+
tag: "none",
|
|
9
|
+
name: "no-sandbox",
|
|
10
|
+
env: options?.env ?? {},
|
|
11
|
+
create: async (createOptions) => {
|
|
12
|
+
const worktreePath = createOptions.worktreePath;
|
|
13
|
+
const processEnv = { ...process.env, ...createOptions.env };
|
|
14
|
+
const maxOutputTailChars = options?.maxOutputTailChars ?? MAX_TAIL_CHARS;
|
|
15
|
+
const handle = {
|
|
16
|
+
worktreePath,
|
|
17
|
+
exec: (command, opts) => {
|
|
18
|
+
const cwd = opts?.cwd ?? worktreePath;
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const proc = spawn("sh", ["-c", command], {
|
|
21
|
+
cwd,
|
|
22
|
+
env: processEnv,
|
|
23
|
+
stdio: [
|
|
24
|
+
opts?.stdin !== void 0 ? "pipe" : "ignore",
|
|
25
|
+
"pipe",
|
|
26
|
+
"pipe"
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
if (opts?.stdin !== void 0) {
|
|
30
|
+
proc.stdin.write(opts.stdin);
|
|
31
|
+
proc.stdin.end();
|
|
32
|
+
}
|
|
33
|
+
proc.on("error", (error) => {
|
|
34
|
+
reject(new Error(`exec failed: ${error.message}`));
|
|
35
|
+
});
|
|
36
|
+
if (opts?.onLine) {
|
|
37
|
+
const onLine = opts.onLine;
|
|
38
|
+
const stdoutTail = new BoundedTail(maxOutputTailChars, "\n");
|
|
39
|
+
const stderrTail = new BoundedTail(maxOutputTailChars, "");
|
|
40
|
+
const rl = createInterface({ input: proc.stdout });
|
|
41
|
+
rl.on("line", (line) => {
|
|
42
|
+
stdoutTail.push(line);
|
|
43
|
+
onLine(line);
|
|
44
|
+
});
|
|
45
|
+
proc.stderr.on("data", (chunk) => {
|
|
46
|
+
stderrTail.push(chunk.toString());
|
|
47
|
+
});
|
|
48
|
+
proc.on("close", (code) => {
|
|
49
|
+
resolve({
|
|
50
|
+
stdout: stdoutTail.toString(),
|
|
51
|
+
stderr: stderrTail.toString(),
|
|
52
|
+
exitCode: code ?? 0
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
const stdoutChunks = [];
|
|
57
|
+
const stderrChunks = [];
|
|
58
|
+
proc.stdout.on("data", (chunk) => {
|
|
59
|
+
stdoutChunks.push(chunk.toString());
|
|
60
|
+
});
|
|
61
|
+
proc.stderr.on("data", (chunk) => {
|
|
62
|
+
stderrChunks.push(chunk.toString());
|
|
63
|
+
});
|
|
64
|
+
proc.on("close", (code) => {
|
|
65
|
+
resolve({
|
|
66
|
+
stdout: stdoutChunks.join(""),
|
|
67
|
+
stderr: stderrChunks.join(""),
|
|
68
|
+
exitCode: code ?? 0
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
interactiveExec: (args, opts) => {
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
const [cmd, ...rest] = args;
|
|
77
|
+
const proc = spawn(cmd, rest, {
|
|
78
|
+
cwd: opts.cwd ?? worktreePath,
|
|
79
|
+
env: processEnv,
|
|
80
|
+
stdio: [opts.stdin, opts.stdout, opts.stderr]
|
|
81
|
+
});
|
|
82
|
+
proc.on("error", (error) => {
|
|
83
|
+
reject(new Error(`exec failed: ${error.message}`));
|
|
84
|
+
});
|
|
85
|
+
proc.on("close", (code) => {
|
|
86
|
+
resolve({ exitCode: code ?? 0 });
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
close: async () => {
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
return handle;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
export { noSandbox };
|
|
98
|
+
//# sourceMappingURL=chunk-72UVAC7B.js.map
|
|
99
|
+
//# sourceMappingURL=chunk-72UVAC7B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sandboxes/no-sandbox.ts"],"names":[],"mappings":"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","file":"chunk-72UVAC7B.js","sourcesContent":["/**\n * No-sandbox provider — runs the agent directly on the host with no container isolation.\n *\n * Usage:\n * import { noSandbox } from \"sandcastle/sandboxes/no-sandbox\";\n * await interactive({ agent: claudeCode(\"claude-opus-4-7\"), sandbox: noSandbox() });\n *\n * Accepted by `run()`, `interactive()`, and `createSandbox()`. Skips\n * container isolation entirely — the agent executes on the host. Does not\n * pass `--dangerously-skip-permissions` to the agent — the user manages\n * permissions themselves.\n */\n\nimport { spawn, type StdioOptions } from \"node:child_process\";\nimport { createInterface } from \"node:readline\";\nimport type {\n NoSandboxProvider,\n NoSandboxHandle,\n ExecResult,\n InteractiveExecOptions,\n} from \"../SandboxProvider.js\";\nimport { BoundedTail, MAX_TAIL_CHARS } from \"../boundedTail.js\";\n\nexport interface NoSandboxOptions {\n /** Environment variables injected by this provider. Merged at launch time. */\n readonly env?: Record<string, 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\n/**\n * Create a no-sandbox provider.\n *\n * The returned provider runs the agent directly on the host. All three\n * branch strategies are supported (head, merge-to-head, branch),\n * defaulting to head.\n */\nexport const noSandbox = (options?: NoSandboxOptions): NoSandboxProvider => ({\n tag: \"none\",\n name: \"no-sandbox\",\n env: options?.env ?? {},\n create: async (createOptions): Promise<NoSandboxHandle> => {\n const worktreePath = createOptions.worktreePath;\n const processEnv = { ...process.env, ...createOptions.env };\n const maxOutputTailChars = options?.maxOutputTailChars ?? MAX_TAIL_CHARS;\n\n const handle: NoSandboxHandle = {\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 // sudo is a no-op for no-sandbox — the user is already on the host\n const cwd = opts?.cwd ?? worktreePath;\n\n return new Promise((resolve, reject) => {\n const proc = spawn(\"sh\", [\"-c\", command], {\n cwd,\n env: processEnv,\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(`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 [cmd, ...rest] = args;\n const proc = spawn(cmd!, rest, {\n cwd: opts.cwd ?? worktreePath,\n env: processEnv,\n stdio: [opts.stdin, opts.stdout, opts.stderr] as StdioOptions,\n });\n\n proc.on(\"error\", (error: Error) => {\n reject(new Error(`exec failed: ${error.message}`));\n });\n\n proc.on(\"close\", (code: number | null) => {\n resolve({ exitCode: code ?? 0 });\n });\n });\n },\n\n close: async (): Promise<void> => {\n // No-op — no container to tear down\n },\n };\n\n return handle;\n },\n});\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
|
|
3
|
+
createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
// src/SandboxProvider.ts
|
|
6
|
+
var createBindMountSandboxProvider = (config) => ({
|
|
7
|
+
tag: "bind-mount",
|
|
8
|
+
name: config.name,
|
|
9
|
+
env: config.env ?? {},
|
|
10
|
+
sandboxHomedir: config.sandboxHomedir,
|
|
11
|
+
create: config.create
|
|
12
|
+
});
|
|
13
|
+
var createIsolatedSandboxProvider = (config) => ({
|
|
14
|
+
tag: "isolated",
|
|
15
|
+
name: config.name,
|
|
16
|
+
env: config.env ?? {},
|
|
17
|
+
create: config.create
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export { createBindMountSandboxProvider, createIsolatedSandboxProvider };
|
|
21
|
+
//# sourceMappingURL=chunk-BIWNFKGV.js.map
|
|
22
|
+
//# sourceMappingURL=chunk-BIWNFKGV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/SandboxProvider.ts"],"names":[],"mappings":";;;;;AAoTO,IAAM,8BAAA,GAAiC,CAC5C,MAAA,MAC8B;AAAA,EAC9B,GAAA,EAAK,YAAA;AAAA,EACL,MAAM,MAAA,CAAO,IAAA;AAAA,EACb,GAAA,EAAK,MAAA,CAAO,GAAA,IAAO,EAAC;AAAA,EACpB,gBAAgB,MAAA,CAAO,cAAA;AAAA,EACvB,QAAQ,MAAA,CAAO;AACjB,CAAA;AAMO,IAAM,6BAAA,GAAgC,CAC3C,MAAA,MAC6B;AAAA,EAC7B,GAAA,EAAK,UAAA;AAAA,EACL,MAAM,MAAA,CAAO,IAAA;AAAA,EACb,GAAA,EAAK,MAAA,CAAO,GAAA,IAAO,EAAC;AAAA,EACpB,QAAQ,MAAA,CAAO;AACjB,CAAA","file":"chunk-BIWNFKGV.js","sourcesContent":["/**\n * Sandbox provider types — the pluggable interface for sandbox runtimes.\n *\n * Provider authors implement a small Promise-based interface. Sandcastle\n * handles worktree creation, git mount resolution, and commit extraction.\n */\n\n/** Result of executing a command inside a sandbox. */\nexport interface ExecResult {\n readonly stdout: string;\n readonly stderr: string;\n readonly exitCode: number;\n}\n\n/** Options for interactiveExec — the streams the provider should wire to the spawned process. */\nexport interface InteractiveExecOptions {\n readonly stdin: NodeJS.ReadableStream;\n readonly stdout: NodeJS.WritableStream;\n readonly stderr: NodeJS.WritableStream;\n readonly cwd?: string;\n}\n\n/** Handle to a running bind-mount sandbox. */\nexport interface BindMountSandboxHandle {\n /** Absolute path to the worktree inside the sandbox. */\n readonly worktreePath: string;\n /**\n * Execute a command in the sandbox.\n *\n * Implementations MUST support line-by-line streaming via `onLine`. This is\n * how Sandcastle delivers live feedback to the user and enforces idle timeouts —\n * without a streaming implementation, neither will work. A buffered/batch\n * implementation that only calls `onLine` after the process exits does NOT\n * satisfy this contract.\n *\n * When `stdin` is set, the implementation pipes the string to the child\n * process's stdin and closes it. This avoids the Linux 128 KB per-arg limit.\n */\n exec(\n command: string,\n options?: {\n onLine?: (line: string) => void;\n cwd?: string;\n sudo?: boolean;\n stdin?: string;\n },\n ): Promise<ExecResult>;\n /**\n * Launch an interactive process inside the sandbox.\n * Optional — providers that support interactive sessions implement this.\n * The provider detects TTY mode from the streams (e.g. stdin.isTTY) and\n * allocates a pseudo-terminal accordingly.\n */\n interactiveExec?(\n args: string[],\n options: InteractiveExecOptions,\n ): Promise<{ exitCode: number }>;\n /** Copy a single file from the host into the sandbox. */\n copyFileIn(hostPath: string, sandboxPath: string): Promise<void>;\n /** Copy a single file from the sandbox to the host. */\n copyFileOut(sandboxPath: string, hostPath: string): Promise<void>;\n /** Tear down the sandbox. */\n close(): Promise<void>;\n}\n\n/** Options passed to a bind-mount provider's `create` function. */\nexport interface BindMountCreateOptions {\n /** Host-side path to the worktree directory. */\n readonly worktreePath: string;\n /** Host-side path to the original repo root. */\n readonly hostRepoPath: string;\n /** Volume mounts to apply (host:sandbox pairs). */\n readonly mounts: Array<{\n hostPath: string;\n sandboxPath: string;\n readonly?: boolean;\n }>;\n /** Environment variables to inject into the sandbox. */\n readonly env: Record<string, string>;\n}\n\n/** Configuration for createBindMountSandboxProvider. */\nexport interface BindMountSandboxProviderConfig {\n /** Human-readable name for this provider (e.g. \"docker\", \"podman\"). */\n readonly name: string;\n /** Environment variables injected by this provider. Merged at launch time. */\n readonly env?: Record<string, string>;\n /**\n * Absolute path to the home directory inside the sandbox (e.g. `\"/home/agent\"`).\n * Used to expand `~` in user-provided `sandboxPath` mount configs.\n * Set to `undefined` for providers that do not have a fixed home directory.\n */\n readonly sandboxHomedir?: string;\n /** Create a sandbox handle from the given options. */\n readonly create: (\n options: BindMountCreateOptions,\n ) => Promise<BindMountSandboxHandle>;\n}\n\n/** Handle to a running isolated sandbox (extends bind-mount with file transfer). */\nexport interface IsolatedSandboxHandle {\n /** Absolute path to the worktree inside the sandbox. */\n readonly worktreePath: string;\n /**\n * Execute a command in the sandbox.\n *\n * Implementations MUST support line-by-line streaming via `onLine`. This is\n * how Sandcastle delivers live feedback to the user and enforces idle timeouts —\n * without a streaming implementation, neither will work. A buffered/batch\n * implementation that only calls `onLine` after the process exits does NOT\n * satisfy this contract.\n *\n * When `stdin` is set, the implementation pipes the string to the child\n * process's stdin and closes it. This avoids the Linux 128 KB per-arg limit.\n */\n exec(\n command: string,\n options?: {\n onLine?: (line: string) => void;\n cwd?: string;\n sudo?: boolean;\n stdin?: string;\n },\n ): Promise<ExecResult>;\n /**\n * Launch an interactive process inside the sandbox.\n * Optional — providers that support interactive sessions implement this.\n * The provider detects TTY mode from the streams (e.g. stdin.isTTY) and\n * allocates a pseudo-terminal accordingly.\n */\n interactiveExec?(\n args: string[],\n options: InteractiveExecOptions,\n ): Promise<{ exitCode: number }>;\n /** Copy a file or directory from the host into the sandbox. */\n copyIn(hostPath: string, sandboxPath: string): Promise<void>;\n /** Copy a single file from the sandbox to the host. */\n copyFileOut(sandboxPath: string, hostPath: string): Promise<void>;\n /** Tear down the sandbox. */\n close(): Promise<void>;\n}\n\n/** Options passed to an isolated provider's `create` function. */\nexport interface IsolatedCreateOptions {\n /** Environment variables to inject into the sandbox. */\n readonly env: Record<string, string>;\n}\n\n/** Configuration for createIsolatedSandboxProvider. */\nexport interface IsolatedSandboxProviderConfig {\n /** Human-readable name for this provider (e.g. \"daytona\", \"e2b\"). */\n readonly name: string;\n /** Environment variables injected by this provider. Merged at launch time. */\n readonly env?: Record<string, string>;\n /** Create an isolated sandbox handle from the given options. */\n readonly create: (\n options: IsolatedCreateOptions,\n ) => Promise<IsolatedSandboxHandle>;\n}\n\n/** A bind-mount sandbox provider. */\nexport interface BindMountSandboxProvider {\n /** @internal Discriminator for internal dispatch. */\n readonly tag: \"bind-mount\";\n /** Human-readable provider name. */\n readonly name: string;\n /** Environment variables injected by this provider. */\n readonly env: Record<string, string>;\n /**\n * Absolute path to the home directory inside the sandbox (e.g. `\"/home/agent\"`).\n * `undefined` when the provider does not declare a sandbox home directory.\n */\n readonly sandboxHomedir: string | undefined;\n /** @internal Create a sandbox handle. */\n readonly create: (\n options: BindMountCreateOptions,\n ) => Promise<BindMountSandboxHandle>;\n}\n\n/** An isolated sandbox provider. */\nexport interface IsolatedSandboxProvider {\n /** @internal Discriminator for internal dispatch. */\n readonly tag: \"isolated\";\n /** Human-readable provider name. */\n readonly name: string;\n /** Environment variables injected by this provider. */\n readonly env: Record<string, string>;\n /** @internal Create an isolated sandbox handle. */\n readonly create: (\n options: IsolatedCreateOptions,\n ) => Promise<IsolatedSandboxHandle>;\n}\n\n/** Handle to a no-sandbox session — runs commands directly on the host. */\nexport interface NoSandboxHandle {\n /** Absolute path to the worktree on the host. */\n readonly worktreePath: string;\n /**\n * Execute a command on the host.\n *\n * Implementations MUST support line-by-line streaming via `onLine`. This is\n * how Sandcastle delivers live feedback to the user and enforces idle timeouts —\n * without a streaming implementation, neither will work.\n *\n * When `stdin` is set, the implementation pipes the string to the child\n * process's stdin and closes it. This avoids the Linux 128 KB per-arg limit.\n */\n exec(\n command: string,\n options?: {\n onLine?: (line: string) => void;\n cwd?: string;\n sudo?: boolean;\n stdin?: string;\n },\n ): Promise<ExecResult>;\n /**\n * Launch an interactive process on the host with inherited stdio.\n */\n interactiveExec(\n args: string[],\n options: InteractiveExecOptions,\n ): Promise<{ exitCode: number }>;\n /** No-op — no container to tear down. */\n close(): Promise<void>;\n}\n\n/** A no-sandbox provider — runs the agent directly on the host with no container isolation. */\nexport interface NoSandboxProvider {\n /** @internal Discriminator for internal dispatch. */\n readonly tag: \"none\";\n /** Human-readable provider name. */\n readonly name: string;\n /** Environment variables injected by this provider. */\n readonly env: Record<string, string>;\n /** @internal Create a no-sandbox handle. */\n readonly create: (options: {\n readonly worktreePath: string;\n readonly env: Record<string, string>;\n }) => Promise<NoSandboxHandle>;\n}\n\n// ---------- Branch strategy types ----------\n\n/** Head strategy: agent writes directly to host working directory. Bind-mount only. */\nexport interface HeadBranchStrategy {\n readonly type: \"head\";\n}\n\n/** Merge-to-head strategy: temp branch, merge back to HEAD, delete temp branch. */\nexport interface MergeToHeadBranchStrategy {\n readonly type: \"merge-to-head\";\n}\n\n/** Branch strategy: commits land on an explicit named branch. */\nexport interface NamedBranchStrategy {\n readonly type: \"branch\";\n readonly branch: string;\n /**\n * Git ref to use as the starting point when creating a new branch.\n * Only used when the branch doesn't already exist — ignored otherwise.\n * Callers are responsible for ensuring the ref is current (e.g. `git fetch`).\n * Defaults to `HEAD` when omitted.\n */\n readonly baseBranch?: string;\n}\n\n/** Branch strategy for bind-mount providers (all three variants). */\nexport type BindMountBranchStrategy =\n | HeadBranchStrategy\n | MergeToHeadBranchStrategy\n | NamedBranchStrategy;\n\n/** Branch strategy for isolated providers (no head — can't write to host). */\nexport type IsolatedBranchStrategy =\n | MergeToHeadBranchStrategy\n | NamedBranchStrategy;\n\n/** Branch strategy for no-sandbox providers (all three — same as bind-mount). */\nexport type NoSandboxBranchStrategy =\n | HeadBranchStrategy\n | MergeToHeadBranchStrategy\n | NamedBranchStrategy;\n\n/** Union of all branch strategy variants. */\nexport type BranchStrategy =\n | BindMountBranchStrategy\n | IsolatedBranchStrategy\n | NoSandboxBranchStrategy;\n\n/**\n * A sandbox provider — the pluggable unit that `run()`, `interactive()`, and\n * `createSandbox()` accept. Tagged for internal dispatch: \"bind-mount\",\n * \"isolated\", or \"none\". When `NoSandboxProvider` is used, the agent runs\n * directly on the host with no container isolation — opt in at your own risk.\n */\nexport type SandboxProvider =\n | BindMountSandboxProvider\n | IsolatedSandboxProvider\n | NoSandboxProvider;\n\n/** @deprecated Use `SandboxProvider` — it now includes `NoSandboxProvider`. */\nexport type AnySandboxProvider = SandboxProvider;\n\n/**\n * Create a bind-mount sandbox provider from a config object.\n * The returned provider can be passed to `run()` or `createSandbox()`.\n */\nexport const createBindMountSandboxProvider = (\n config: BindMountSandboxProviderConfig,\n): BindMountSandboxProvider => ({\n tag: \"bind-mount\",\n name: config.name,\n env: config.env ?? {},\n sandboxHomedir: config.sandboxHomedir,\n create: config.create,\n});\n\n/**\n * Create an isolated sandbox provider from a config object.\n * The returned provider can be passed to `run()` or `createSandbox()`.\n */\nexport const createIsolatedSandboxProvider = (\n config: IsolatedSandboxProviderConfig,\n): IsolatedSandboxProvider => ({\n tag: \"isolated\",\n name: config.name,\n env: config.env ?? {},\n create: config.create,\n});\n"]}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
|
|
3
|
+
const require$1 = createRequire(import.meta.url);
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __require = /* @__PURE__ */ ((x) => typeof require$1 !== "undefined" ? require$1 : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
11
|
+
get: (a, b) => (typeof require$1 !== "undefined" ? require$1 : a)[b]
|
|
12
|
+
}) : x)(function(x) {
|
|
13
|
+
if (typeof require$1 !== "undefined") return require$1.apply(this, arguments);
|
|
14
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
15
|
+
});
|
|
16
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
17
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
22
|
+
};
|
|
23
|
+
var __copyProps = (to, from, except, desc) => {
|
|
24
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
25
|
+
for (let key of __getOwnPropNames(from))
|
|
26
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
27
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
28
|
+
}
|
|
29
|
+
return to;
|
|
30
|
+
};
|
|
31
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
32
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
33
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
34
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
35
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
36
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
37
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
38
|
+
mod
|
|
39
|
+
));
|
|
40
|
+
|
|
41
|
+
// src/boundedTail.ts
|
|
42
|
+
var MAX_TAIL_CHARS = 64 * 1024;
|
|
43
|
+
var BoundedTail = class {
|
|
44
|
+
items = [];
|
|
45
|
+
totalChars = 0;
|
|
46
|
+
maxChars;
|
|
47
|
+
separator;
|
|
48
|
+
/**
|
|
49
|
+
* @param maxChars Maximum length of the joined tail. Defaults to {@link MAX_TAIL_CHARS}.
|
|
50
|
+
* @param separator String placed between items by {@link toString}. Must match
|
|
51
|
+
* how the caller would otherwise have joined the accumulated chunks (e.g.
|
|
52
|
+
* `"\n"` for line streams, `""` for raw chunk streams).
|
|
53
|
+
*/
|
|
54
|
+
constructor(maxChars = MAX_TAIL_CHARS, separator = "") {
|
|
55
|
+
this.maxChars = maxChars;
|
|
56
|
+
this.separator = separator;
|
|
57
|
+
}
|
|
58
|
+
/** Append one item to the tail, evicting oldest items to stay within budget. */
|
|
59
|
+
push(item) {
|
|
60
|
+
const bounded = item.length > this.maxChars ? item.slice(item.length - this.maxChars) : item;
|
|
61
|
+
this.totalChars += bounded.length + (this.items.length > 0 ? this.separator.length : 0);
|
|
62
|
+
this.items.push(bounded);
|
|
63
|
+
while (this.totalChars > this.maxChars && this.items.length > 1) {
|
|
64
|
+
const dropped = this.items.shift();
|
|
65
|
+
this.totalChars -= dropped.length + this.separator.length;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Join the retained tail into a single string (length ≤ `maxChars`). */
|
|
69
|
+
toString() {
|
|
70
|
+
return this.items.join(this.separator);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export { BoundedTail, MAX_TAIL_CHARS, __commonJS, __export, __reExport, __require, __toESM };
|
|
75
|
+
//# sourceMappingURL=chunk-NGBM7T3E.js.map
|
|
76
|
+
//# sourceMappingURL=chunk-NGBM7T3E.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/boundedTail.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBO,IAAM,iBAAiB,EAAA,GAAK;AAa5B,IAAM,cAAN,MAAkB;AAAA,EACN,QAAkB,EAAC;AAAA,EAC5B,UAAA,GAAa,CAAA;AAAA,EACJ,QAAA;AAAA,EACA,SAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjB,WAAA,CAAY,QAAA,GAAmB,cAAA,EAAgB,SAAA,GAAY,EAAA,EAAI;AAC7D,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAAA,EACnB;AAAA;AAAA,EAGA,KAAK,IAAA,EAAoB;AACvB,IAAA,MAAM,OAAA,GACJ,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,QAAA,GACf,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,QAAQ,CAAA,GACtC,IAAA;AACN,IAAA,IAAA,CAAK,UAAA,IACH,QAAQ,MAAA,IAAU,IAAA,CAAK,MAAM,MAAA,GAAS,CAAA,GAAI,IAAA,CAAK,SAAA,CAAU,MAAA,GAAS,CAAA,CAAA;AACpE,IAAA,IAAA,CAAK,KAAA,CAAM,KAAK,OAAO,CAAA;AACvB,IAAA,OAAO,KAAK,UAAA,GAAa,IAAA,CAAK,YAAY,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA,EAAG;AAC/D,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,KAAA,EAAM;AACjC,MAAA,IAAA,CAAK,UAAA,IAAc,OAAA,CAAQ,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,MAAA;AAAA,IACrD;AAAA,EACF;AAAA;AAAA,EAGA,QAAA,GAAmB;AACjB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,SAAS,CAAA;AAAA,EACvC;AACF","file":"chunk-NGBM7T3E.js","sourcesContent":["/**\n * A bounded, rolling tail of streamed output — a pure, provider-agnostic\n * utility shared by every sandbox provider that streams `exec` output.\n *\n * When a provider streams output line-by-line, it accumulates the stream only\n * to build the returned `ExecResult.stdout`/`stderr`. Consumers read just the\n * tail of that value (e.g. the last lines of an error, or a fallback for the\n * agent's final result), so retaining the whole stream is unnecessary — and,\n * once the accumulated string passes V8's ~512MB max string length, fatal: a\n * naive `chunks.join()` throws `RangeError: Invalid string length`, which on a\n * long agent run crashes the whole orchestration.\n */\n\n/**\n * Default maximum number of characters retained in a bounded output tail.\n *\n * 64KiB sits comfortably above any agent completion signal or structured-output\n * payload while staying far below V8's max string length.\n */\nexport const MAX_TAIL_CHARS = 64 * 1024;\n\n/**\n * A fixed-size rolling tail of strings, bounded by total character length.\n *\n * `push` appends to the tail; once the joined length would exceed `maxChars`,\n * the oldest items are dropped from the front. A single item longer than\n * `maxChars` is truncated to its own tail, so a newline-free blob can't\n * overflow on one push. `toString` joins the retained items, and its length is\n * always at most `maxChars`.\n *\n * The running length counter is encapsulated so callers can't desync it.\n */\nexport class BoundedTail {\n private readonly items: string[] = [];\n private totalChars = 0;\n private readonly maxChars: number;\n private readonly separator: string;\n\n /**\n * @param maxChars Maximum length of the joined tail. Defaults to {@link MAX_TAIL_CHARS}.\n * @param separator String placed between items by {@link toString}. Must match\n * how the caller would otherwise have joined the accumulated chunks (e.g.\n * `\"\\n\"` for line streams, `\"\"` for raw chunk streams).\n */\n constructor(maxChars: number = MAX_TAIL_CHARS, separator = \"\") {\n this.maxChars = maxChars;\n this.separator = separator;\n }\n\n /** Append one item to the tail, evicting oldest items to stay within budget. */\n push(item: string): void {\n const bounded =\n item.length > this.maxChars\n ? item.slice(item.length - this.maxChars)\n : item;\n this.totalChars +=\n bounded.length + (this.items.length > 0 ? this.separator.length : 0);\n this.items.push(bounded);\n while (this.totalChars > this.maxChars && this.items.length > 1) {\n const dropped = this.items.shift()!;\n this.totalChars -= dropped.length + this.separator.length;\n }\n }\n\n /** Join the retained tail into a single string (length ≤ `maxChars`). */\n toString(): string {\n return this.items.join(this.separator);\n }\n}\n"]}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { Effect_exports, resolveUserMounts, processFileMountParents, defaultImageName, registerShutdown, DockerError, formatVolumeMount } from './chunk-5VM5QZ26.js';
|
|
3
|
+
import { createBindMountSandboxProvider } from './chunk-BIWNFKGV.js';
|
|
4
|
+
import { MAX_TAIL_CHARS, BoundedTail } from './chunk-NGBM7T3E.js';
|
|
5
|
+
import { execFile, execFileSync, spawn } from 'child_process';
|
|
6
|
+
import { randomUUID } from 'crypto';
|
|
7
|
+
import { createInterface } from 'readline';
|
|
8
|
+
import { resolve } from 'path';
|
|
9
|
+
|
|
10
|
+
createRequire(import.meta.url);
|
|
11
|
+
var dockerExec = (args) => Effect_exports.async((resume) => {
|
|
12
|
+
execFile(
|
|
13
|
+
"docker",
|
|
14
|
+
args,
|
|
15
|
+
{ maxBuffer: 10 * 1024 * 1024 },
|
|
16
|
+
(error, stdout, stderr) => {
|
|
17
|
+
if (error) {
|
|
18
|
+
resume(
|
|
19
|
+
Effect_exports.fail(
|
|
20
|
+
new DockerError({
|
|
21
|
+
message: `docker ${args[0]} failed: ${stderr?.toString() || error.message}`
|
|
22
|
+
})
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
} else {
|
|
26
|
+
resume(Effect_exports.succeed(stdout.toString()));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
var buildImage = (imageName, dockerfileDir, options) => Effect_exports.gen(function* () {
|
|
32
|
+
const buildArgFlags = Object.entries(options?.buildArgs ?? {}).flatMap(
|
|
33
|
+
([k, v]) => ["--build-arg", `${k}=${v}`]
|
|
34
|
+
);
|
|
35
|
+
if (options?.dockerfile) {
|
|
36
|
+
yield* dockerExec([
|
|
37
|
+
"build",
|
|
38
|
+
"-t",
|
|
39
|
+
imageName,
|
|
40
|
+
...buildArgFlags,
|
|
41
|
+
"-f",
|
|
42
|
+
resolve(options.dockerfile),
|
|
43
|
+
process.cwd()
|
|
44
|
+
]);
|
|
45
|
+
} else {
|
|
46
|
+
yield* dockerExec([
|
|
47
|
+
"build",
|
|
48
|
+
"-t",
|
|
49
|
+
imageName,
|
|
50
|
+
...buildArgFlags,
|
|
51
|
+
resolve(dockerfileDir)
|
|
52
|
+
]);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
var startContainer = (containerName, imageName, env, options) => Effect_exports.gen(function* () {
|
|
56
|
+
const existing = yield* dockerExec([
|
|
57
|
+
"ps",
|
|
58
|
+
"-a",
|
|
59
|
+
"--filter",
|
|
60
|
+
`name=^${containerName}$`,
|
|
61
|
+
"--format",
|
|
62
|
+
"{{.Names}}"
|
|
63
|
+
]);
|
|
64
|
+
if (existing.trim() === containerName) {
|
|
65
|
+
yield* Effect_exports.fail(
|
|
66
|
+
new DockerError({
|
|
67
|
+
message: `Container '${containerName}' already exists. Run cleanup first.`
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const envFlags = Object.entries(env).flatMap(([k, v]) => [
|
|
72
|
+
"-e",
|
|
73
|
+
`${k}=${v}`
|
|
74
|
+
]);
|
|
75
|
+
const selinuxLabel = options?.selinuxLabel ?? "z";
|
|
76
|
+
const volumeFlags = (options?.volumeMounts ?? []).flatMap((mount) => [
|
|
77
|
+
"-v",
|
|
78
|
+
formatVolumeMount(mount, selinuxLabel)
|
|
79
|
+
]);
|
|
80
|
+
const workdirFlags = options?.workdir ? ["-w", options.workdir] : [];
|
|
81
|
+
const userFlags = options?.user ? ["--user", options.user] : [];
|
|
82
|
+
const networks = options?.network ? Array.isArray(options.network) ? options.network : [options.network] : [];
|
|
83
|
+
const networkFlags = networks.flatMap((n) => ["--network", n]);
|
|
84
|
+
const groupAddFlags = (options?.groups ?? []).flatMap((g) => [
|
|
85
|
+
"--group-add",
|
|
86
|
+
String(g)
|
|
87
|
+
]);
|
|
88
|
+
const deviceFlags = (options?.devices ?? []).flatMap((d) => [
|
|
89
|
+
"--device",
|
|
90
|
+
d
|
|
91
|
+
]);
|
|
92
|
+
const cpusFlags = options?.cpus !== void 0 ? ["--cpus", String(options.cpus)] : [];
|
|
93
|
+
yield* dockerExec([
|
|
94
|
+
"run",
|
|
95
|
+
"-d",
|
|
96
|
+
"--name",
|
|
97
|
+
containerName,
|
|
98
|
+
...envFlags,
|
|
99
|
+
...volumeFlags,
|
|
100
|
+
...workdirFlags,
|
|
101
|
+
...userFlags,
|
|
102
|
+
...networkFlags,
|
|
103
|
+
...groupAddFlags,
|
|
104
|
+
...deviceFlags,
|
|
105
|
+
...cpusFlags,
|
|
106
|
+
imageName
|
|
107
|
+
]);
|
|
108
|
+
});
|
|
109
|
+
var removeContainer = (containerName) => Effect_exports.gen(function* () {
|
|
110
|
+
yield* Effect_exports.ignore(dockerExec(["stop", containerName]));
|
|
111
|
+
yield* Effect_exports.ignore(dockerExec(["rm", containerName]));
|
|
112
|
+
});
|
|
113
|
+
var removeImage = (imageName) => Effect_exports.gen(function* () {
|
|
114
|
+
yield* dockerExec(["rmi", imageName]);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// src/sandboxes/docker.ts
|
|
118
|
+
var docker = (options) => {
|
|
119
|
+
const configuredImageName = options?.imageName;
|
|
120
|
+
const selinuxLabel = options?.selinuxLabel ?? "z";
|
|
121
|
+
const maxOutputTailChars = options?.maxOutputTailChars ?? MAX_TAIL_CHARS;
|
|
122
|
+
const sandboxHomedir = "/home/agent";
|
|
123
|
+
const userMounts = options?.mounts ? resolveUserMounts(options.mounts, sandboxHomedir) : [];
|
|
124
|
+
const parentDirsToCreate = processFileMountParents(
|
|
125
|
+
userMounts,
|
|
126
|
+
sandboxHomedir
|
|
127
|
+
);
|
|
128
|
+
return createBindMountSandboxProvider({
|
|
129
|
+
name: "docker",
|
|
130
|
+
env: options?.env,
|
|
131
|
+
sandboxHomedir,
|
|
132
|
+
create: async (createOptions) => {
|
|
133
|
+
const containerName = `sandcastle-${randomUUID()}`;
|
|
134
|
+
const worktreePath = createOptions.mounts.find(
|
|
135
|
+
(m) => m.hostPath === createOptions.worktreePath
|
|
136
|
+
)?.sandboxPath ?? "/home/agent/workspace";
|
|
137
|
+
const allMounts = [...createOptions.mounts, ...userMounts];
|
|
138
|
+
const volumeMounts = allMounts.map((m) => ({
|
|
139
|
+
hostPath: m.hostPath,
|
|
140
|
+
sandboxPath: m.sandboxPath,
|
|
141
|
+
readonly: m.readonly
|
|
142
|
+
}));
|
|
143
|
+
const imageName = configuredImageName ?? defaultImageName(createOptions.hostRepoPath);
|
|
144
|
+
const containerUid = options?.containerUid ?? process.getuid?.() ?? 1e3;
|
|
145
|
+
const containerGid = options?.containerGid ?? process.getgid?.() ?? 1e3;
|
|
146
|
+
await checkImageUid(imageName, containerUid);
|
|
147
|
+
await Effect_exports.runPromise(
|
|
148
|
+
startContainer(
|
|
149
|
+
containerName,
|
|
150
|
+
imageName,
|
|
151
|
+
{
|
|
152
|
+
...createOptions.env,
|
|
153
|
+
HOME: "/home/agent"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
volumeMounts,
|
|
157
|
+
workdir: worktreePath,
|
|
158
|
+
user: `${containerUid}:${containerGid}`,
|
|
159
|
+
network: options?.network,
|
|
160
|
+
groups: options?.groups,
|
|
161
|
+
devices: options?.devices,
|
|
162
|
+
cpus: options?.cpus,
|
|
163
|
+
selinuxLabel
|
|
164
|
+
}
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
for (const dir of parentDirsToCreate) {
|
|
168
|
+
await new Promise((resolve2, reject) => {
|
|
169
|
+
execFile(
|
|
170
|
+
"docker",
|
|
171
|
+
[
|
|
172
|
+
"exec",
|
|
173
|
+
"--user",
|
|
174
|
+
"0:0",
|
|
175
|
+
containerName,
|
|
176
|
+
"sh",
|
|
177
|
+
"-c",
|
|
178
|
+
`mkdir -p "$1" && chown "$2" "$1"`,
|
|
179
|
+
"sh",
|
|
180
|
+
dir,
|
|
181
|
+
`${containerUid}:${containerGid}`
|
|
182
|
+
],
|
|
183
|
+
(error) => {
|
|
184
|
+
if (error) {
|
|
185
|
+
reject(
|
|
186
|
+
new Error(
|
|
187
|
+
`Failed to create parent directory '${dir}' in container: ${error.message}`
|
|
188
|
+
)
|
|
189
|
+
);
|
|
190
|
+
} else {
|
|
191
|
+
resolve2();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
const removeContainerSync = () => {
|
|
198
|
+
try {
|
|
199
|
+
execFileSync("docker", ["rm", "-f", containerName], {
|
|
200
|
+
stdio: "ignore"
|
|
201
|
+
});
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const unregisterShutdown = registerShutdown(removeContainerSync);
|
|
206
|
+
const handle = {
|
|
207
|
+
worktreePath,
|
|
208
|
+
exec: (command, opts) => {
|
|
209
|
+
const effectiveCommand = opts?.sudo ? `sudo ${command}` : command;
|
|
210
|
+
const args = ["exec"];
|
|
211
|
+
if (opts?.stdin !== void 0) args.push("-i");
|
|
212
|
+
if (opts?.cwd) args.push("-w", opts.cwd);
|
|
213
|
+
args.push(containerName, "sh", "-c", effectiveCommand);
|
|
214
|
+
return new Promise((resolve2, reject) => {
|
|
215
|
+
const proc = spawn("docker", args, {
|
|
216
|
+
stdio: [
|
|
217
|
+
opts?.stdin !== void 0 ? "pipe" : "ignore",
|
|
218
|
+
"pipe",
|
|
219
|
+
"pipe"
|
|
220
|
+
]
|
|
221
|
+
});
|
|
222
|
+
if (opts?.stdin !== void 0) {
|
|
223
|
+
proc.stdin.write(opts.stdin);
|
|
224
|
+
proc.stdin.end();
|
|
225
|
+
}
|
|
226
|
+
proc.on("error", (error) => {
|
|
227
|
+
reject(new Error(`docker exec failed: ${error.message}`));
|
|
228
|
+
});
|
|
229
|
+
if (opts?.onLine) {
|
|
230
|
+
const onLine = opts.onLine;
|
|
231
|
+
const stdoutTail = new BoundedTail(maxOutputTailChars, "\n");
|
|
232
|
+
const stderrTail = new BoundedTail(maxOutputTailChars, "");
|
|
233
|
+
const rl = createInterface({ input: proc.stdout });
|
|
234
|
+
rl.on("line", (line) => {
|
|
235
|
+
stdoutTail.push(line);
|
|
236
|
+
onLine(line);
|
|
237
|
+
});
|
|
238
|
+
proc.stderr.on("data", (chunk) => {
|
|
239
|
+
stderrTail.push(chunk.toString());
|
|
240
|
+
});
|
|
241
|
+
proc.on("close", (code) => {
|
|
242
|
+
resolve2({
|
|
243
|
+
stdout: stdoutTail.toString(),
|
|
244
|
+
stderr: stderrTail.toString(),
|
|
245
|
+
exitCode: code ?? 0
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
} else {
|
|
249
|
+
const stdoutChunks = [];
|
|
250
|
+
const stderrChunks = [];
|
|
251
|
+
proc.stdout.on("data", (chunk) => {
|
|
252
|
+
stdoutChunks.push(chunk.toString());
|
|
253
|
+
});
|
|
254
|
+
proc.stderr.on("data", (chunk) => {
|
|
255
|
+
stderrChunks.push(chunk.toString());
|
|
256
|
+
});
|
|
257
|
+
proc.on("close", (code) => {
|
|
258
|
+
resolve2({
|
|
259
|
+
stdout: stdoutChunks.join(""),
|
|
260
|
+
stderr: stderrChunks.join(""),
|
|
261
|
+
exitCode: code ?? 0
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
},
|
|
267
|
+
interactiveExec: (args, opts) => {
|
|
268
|
+
return new Promise((resolve2, reject) => {
|
|
269
|
+
const dockerArgs = ["exec"];
|
|
270
|
+
if ("isTTY" in opts.stdin && opts.stdin.isTTY) {
|
|
271
|
+
dockerArgs.push("-it");
|
|
272
|
+
} else {
|
|
273
|
+
dockerArgs.push("-i");
|
|
274
|
+
}
|
|
275
|
+
if (opts.cwd) dockerArgs.push("-w", opts.cwd);
|
|
276
|
+
dockerArgs.push(containerName, ...args);
|
|
277
|
+
const proc = spawn("docker", dockerArgs, {
|
|
278
|
+
stdio: [opts.stdin, opts.stdout, opts.stderr]
|
|
279
|
+
});
|
|
280
|
+
proc.on("error", (error) => {
|
|
281
|
+
reject(new Error(`docker exec failed: ${error.message}`));
|
|
282
|
+
});
|
|
283
|
+
proc.on("close", (code) => {
|
|
284
|
+
resolve2({ exitCode: code ?? 0 });
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
},
|
|
288
|
+
copyFileIn: (hostPath, sandboxPath) => new Promise((resolve2, reject) => {
|
|
289
|
+
execFile(
|
|
290
|
+
"docker",
|
|
291
|
+
["cp", hostPath, `${containerName}:${sandboxPath}`],
|
|
292
|
+
(error) => {
|
|
293
|
+
if (error) {
|
|
294
|
+
reject(new Error(`docker cp (in) failed: ${error.message}`));
|
|
295
|
+
} else {
|
|
296
|
+
resolve2();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
);
|
|
300
|
+
}),
|
|
301
|
+
copyFileOut: (sandboxPath, hostPath) => new Promise((resolve2, reject) => {
|
|
302
|
+
execFile(
|
|
303
|
+
"docker",
|
|
304
|
+
["cp", `${containerName}:${sandboxPath}`, hostPath],
|
|
305
|
+
(error) => {
|
|
306
|
+
if (error) {
|
|
307
|
+
reject(new Error(`docker cp (out) failed: ${error.message}`));
|
|
308
|
+
} else {
|
|
309
|
+
resolve2();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
);
|
|
313
|
+
}),
|
|
314
|
+
close: async () => {
|
|
315
|
+
unregisterShutdown();
|
|
316
|
+
await Effect_exports.runPromise(removeContainer(containerName));
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
return handle;
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
};
|
|
323
|
+
var checkImageUid = (imageName, expectedUid) => new Promise((resolve2, reject) => {
|
|
324
|
+
execFile(
|
|
325
|
+
"docker",
|
|
326
|
+
["image", "inspect", imageName, "--format", "{{.Config.User}}"],
|
|
327
|
+
(error, stdout) => {
|
|
328
|
+
if (error) {
|
|
329
|
+
reject(
|
|
330
|
+
new Error(
|
|
331
|
+
`Image '${imageName}' not found locally. Build it first with 'sandcastle docker build-image'.`
|
|
332
|
+
)
|
|
333
|
+
);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const imageUser = (stdout ?? "").toString().trim();
|
|
337
|
+
if (!imageUser) {
|
|
338
|
+
resolve2();
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const uidPart = imageUser.split(":")[0];
|
|
342
|
+
const imageUid = parseInt(uidPart, 10);
|
|
343
|
+
if (isNaN(imageUid)) {
|
|
344
|
+
resolve2();
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (imageUid !== expectedUid) {
|
|
348
|
+
reject(
|
|
349
|
+
new Error(
|
|
350
|
+
`UID mismatch: image '${imageName}' was built with UID ${imageUid}, but the expected UID is ${expectedUid}. Rebuild the image with 'sandcastle docker build-image', or pass containerUid: ${imageUid} to docker() to match the image.`
|
|
351
|
+
)
|
|
352
|
+
);
|
|
353
|
+
} else {
|
|
354
|
+
resolve2();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
export { buildImage, docker, removeImage };
|
|
361
|
+
//# sourceMappingURL=chunk-NSFQW6ML.js.map
|
|
362
|
+
//# sourceMappingURL=chunk-NSFQW6ML.js.map
|