@ai-hero/sandcastle 0.6.4 → 0.6.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 +125 -54
- 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-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-Q5W3WQVU.js +25569 -0
- package/dist/chunk-Q5W3WQVU.js.map +1 -0
- package/dist/chunk-UPDEQ2U7.js +362 -0
- package/dist/chunk-UPDEQ2U7.js.map +1 -0
- package/dist/chunk-Z7O2WNRU.js +26934 -0
- package/dist/chunk-Z7O2WNRU.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 +19256 -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/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 -63
- package/dist/InitService.d.ts.map +0 -1
- package/dist/InitService.js +0 -733
- 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 -309
- 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,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared mount utilities for Docker and Podman sandbox providers.
|
|
3
|
+
*
|
|
4
|
+
* Handles host/sandbox path resolution, tilde expansion, user mount
|
|
5
|
+
* validation, image naming, and Windows path normalization.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SELinux volume label suffix applied to bind mounts.
|
|
10
|
+
*
|
|
11
|
+
* - `"z"` — shared label. No-op on non-SELinux systems.
|
|
12
|
+
* - `"Z"` — private label; only this container can access the mount.
|
|
13
|
+
* - `false` — disable labeling entirely.
|
|
14
|
+
*/
|
|
15
|
+
type SelinuxLabel = "z" | "Z" | false;
|
|
16
|
+
/**
|
|
17
|
+
* Derive the default image name from the repo directory.
|
|
18
|
+
* Returns `sandcastle:<dir-name>` where dir-name is the last path segment,
|
|
19
|
+
* lowercased and sanitized for image tag rules.
|
|
20
|
+
*
|
|
21
|
+
* Handles both POSIX (`/`) and Windows (`\`) path separators.
|
|
22
|
+
*/
|
|
23
|
+
declare const defaultImageName: (repoDir: string) => string;
|
|
24
|
+
|
|
25
|
+
export { type SelinuxLabel as S, defaultImageName as d };
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
import { I as IsolatedSandboxProvider } from '../SandboxProvider-EkSMuBp8.js';
|
|
2
|
+
import { CreateSandboxFromImageParams, CreateSandboxFromSnapshotParams } from '@daytona/sdk';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Daytona isolated sandbox provider.
|
|
3
6
|
*
|
|
4
7
|
* Creates ephemeral Daytona sandboxes via `@daytona/sdk`.
|
|
5
8
|
* Requires `@daytona/sdk` as a peer dependency.
|
|
6
9
|
*/
|
|
7
|
-
|
|
8
|
-
import type { CreateSandboxFromImageParams, CreateSandboxFromSnapshotParams } from "@daytona/sdk";
|
|
10
|
+
|
|
9
11
|
/** Options for the Daytona sandbox provider. */
|
|
10
|
-
|
|
12
|
+
interface DaytonaOptions {
|
|
11
13
|
/**
|
|
12
14
|
* Daytona API key for authentication.
|
|
13
15
|
* Falls back to the `DAYTONA_API_KEY` environment variable if not provided.
|
|
@@ -53,5 +55,6 @@ export interface DaytonaOptions {
|
|
|
53
55
|
* const provider = daytona({ apiKey: "dyt_my_key" });
|
|
54
56
|
* ```
|
|
55
57
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
declare const daytona: (options?: DaytonaOptions) => IsolatedSandboxProvider;
|
|
59
|
+
|
|
60
|
+
export { type DaytonaOptions, daytona };
|
|
@@ -1,128 +1,122 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const execResponse = await sandbox.process.executeSessionCommand(sessionId, {
|
|
52
|
-
command: `cd ${opts?.cwd ?? worktreePath} && ${effectiveCommand}`,
|
|
53
|
-
async: true,
|
|
54
|
-
});
|
|
55
|
-
const cmdId = execResponse.cmdId;
|
|
56
|
-
const stdoutTail = new BoundedTail(maxOutputTailChars, "\n");
|
|
57
|
-
const stderrTail = new BoundedTail(maxOutputTailChars, "");
|
|
58
|
-
let partial = "";
|
|
59
|
-
await sandbox.process.getSessionCommandLogs(sessionId, cmdId, (chunk) => {
|
|
60
|
-
const text = partial + chunk;
|
|
61
|
-
const lines = text.split("\n");
|
|
62
|
-
partial = lines.pop() ?? "";
|
|
63
|
-
for (const line of lines) {
|
|
64
|
-
stdoutTail.push(line);
|
|
65
|
-
onLine(line);
|
|
66
|
-
}
|
|
67
|
-
}, (chunk) => {
|
|
68
|
-
stderrTail.push(chunk);
|
|
69
|
-
});
|
|
70
|
-
if (partial) {
|
|
71
|
-
stdoutTail.push(partial);
|
|
72
|
-
onLine(partial);
|
|
73
|
-
}
|
|
74
|
-
const cmdInfo = await sandbox.process.getSessionCommand(sessionId, cmdId);
|
|
75
|
-
return {
|
|
76
|
-
stdout: stdoutTail.toString(),
|
|
77
|
-
stderr: stderrTail.toString(),
|
|
78
|
-
exitCode: cmdInfo.exitCode ?? 0,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
finally {
|
|
82
|
-
await sandbox.process.deleteSession(sessionId).catch(() => { });
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const response = await sandbox.process.executeCommand(effectiveCommand, opts?.cwd ?? worktreePath);
|
|
86
|
-
return {
|
|
87
|
-
stdout: response.result,
|
|
88
|
-
stderr: "",
|
|
89
|
-
exitCode: response.exitCode,
|
|
90
|
-
};
|
|
91
|
-
},
|
|
92
|
-
copyIn: async (hostPath, sandboxPath) => {
|
|
93
|
-
const info = await stat(hostPath);
|
|
94
|
-
if (info.isDirectory()) {
|
|
95
|
-
const walk = async (dir) => {
|
|
96
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
97
|
-
const files = [];
|
|
98
|
-
for (const entry of entries) {
|
|
99
|
-
const full = join(dir, entry.name);
|
|
100
|
-
if (entry.isDirectory()) {
|
|
101
|
-
files.push(...(await walk(full)));
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
files.push(full);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return files;
|
|
108
|
-
};
|
|
109
|
-
const files = await walk(hostPath);
|
|
110
|
-
for (const file of files) {
|
|
111
|
-
const rel = relative(hostPath, file);
|
|
112
|
-
await sandbox.fs.uploadFile(file, join(sandboxPath, rel));
|
|
113
|
-
}
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { createIsolatedSandboxProvider } from '../chunk-BIWNFKGV.js';
|
|
3
|
+
import { MAX_TAIL_CHARS, BoundedTail } from '../chunk-NGBM7T3E.js';
|
|
4
|
+
import { stat, readdir } from 'fs/promises';
|
|
5
|
+
import { relative, join } from 'path';
|
|
6
|
+
|
|
7
|
+
createRequire(import.meta.url);
|
|
8
|
+
var daytona = (options) => createIsolatedSandboxProvider({
|
|
9
|
+
name: "daytona",
|
|
10
|
+
env: options?.env,
|
|
11
|
+
create: async () => {
|
|
12
|
+
const maxOutputTailChars = options?.maxOutputTailChars ?? MAX_TAIL_CHARS;
|
|
13
|
+
const { Daytona } = await import('@daytona/sdk');
|
|
14
|
+
const config = {};
|
|
15
|
+
if (options?.apiKey) config.apiKey = options.apiKey;
|
|
16
|
+
if (options?.apiUrl) config.apiUrl = options.apiUrl;
|
|
17
|
+
if (options?.target) config.target = options.target;
|
|
18
|
+
const client = new Daytona(config);
|
|
19
|
+
const sandbox = await client.create(options?.create);
|
|
20
|
+
const worktreePath = await sandbox.getWorkDir() ?? await sandbox.getUserHomeDir() ?? "/home/daytona";
|
|
21
|
+
return {
|
|
22
|
+
worktreePath,
|
|
23
|
+
exec: async (command, opts) => {
|
|
24
|
+
const effectiveCommand = opts?.sudo ? `sudo ${command}` : command;
|
|
25
|
+
if (opts?.onLine) {
|
|
26
|
+
const onLine = opts.onLine;
|
|
27
|
+
const sessionId = `sandcastle-${crypto.randomUUID()}`;
|
|
28
|
+
await sandbox.process.createSession(sessionId);
|
|
29
|
+
try {
|
|
30
|
+
const execResponse = await sandbox.process.executeSessionCommand(
|
|
31
|
+
sessionId,
|
|
32
|
+
{
|
|
33
|
+
command: `cd ${opts?.cwd ?? worktreePath} && ${effectiveCommand}`,
|
|
34
|
+
async: true
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
const cmdId = execResponse.cmdId;
|
|
38
|
+
const stdoutTail = new BoundedTail(maxOutputTailChars, "\n");
|
|
39
|
+
const stderrTail = new BoundedTail(maxOutputTailChars, "");
|
|
40
|
+
let partial = "";
|
|
41
|
+
await sandbox.process.getSessionCommandLogs(
|
|
42
|
+
sessionId,
|
|
43
|
+
cmdId,
|
|
44
|
+
(chunk) => {
|
|
45
|
+
const text = partial + chunk;
|
|
46
|
+
const lines = text.split("\n");
|
|
47
|
+
partial = lines.pop() ?? "";
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
stdoutTail.push(line);
|
|
50
|
+
onLine(line);
|
|
114
51
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
52
|
+
},
|
|
53
|
+
(chunk) => {
|
|
54
|
+
stderrTail.push(chunk);
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
if (partial) {
|
|
58
|
+
stdoutTail.push(partial);
|
|
59
|
+
onLine(partial);
|
|
60
|
+
}
|
|
61
|
+
const cmdInfo = await sandbox.process.getSessionCommand(
|
|
62
|
+
sessionId,
|
|
63
|
+
cmdId
|
|
64
|
+
);
|
|
65
|
+
return {
|
|
66
|
+
stdout: stdoutTail.toString(),
|
|
67
|
+
stderr: stderrTail.toString(),
|
|
68
|
+
exitCode: cmdInfo.exitCode ?? 0
|
|
69
|
+
};
|
|
70
|
+
} finally {
|
|
71
|
+
await sandbox.process.deleteSession(sessionId).catch(() => {
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const response = await sandbox.process.executeCommand(
|
|
76
|
+
effectiveCommand,
|
|
77
|
+
opts?.cwd ?? worktreePath
|
|
78
|
+
);
|
|
79
|
+
return {
|
|
80
|
+
stdout: response.result,
|
|
81
|
+
stderr: "",
|
|
82
|
+
exitCode: response.exitCode
|
|
125
83
|
};
|
|
126
|
-
|
|
84
|
+
},
|
|
85
|
+
copyIn: async (hostPath, sandboxPath) => {
|
|
86
|
+
const info = await stat(hostPath);
|
|
87
|
+
if (info.isDirectory()) {
|
|
88
|
+
const walk = async (dir) => {
|
|
89
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
90
|
+
const files2 = [];
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const full = join(dir, entry.name);
|
|
93
|
+
if (entry.isDirectory()) {
|
|
94
|
+
files2.push(...await walk(full));
|
|
95
|
+
} else {
|
|
96
|
+
files2.push(full);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return files2;
|
|
100
|
+
};
|
|
101
|
+
const files = await walk(hostPath);
|
|
102
|
+
for (const file of files) {
|
|
103
|
+
const rel = relative(hostPath, file);
|
|
104
|
+
await sandbox.fs.uploadFile(file, join(sandboxPath, rel));
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
await sandbox.fs.uploadFile(hostPath, sandboxPath);
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
copyFileOut: async (sandboxPath, hostPath) => {
|
|
111
|
+
await sandbox.fs.downloadFile(sandboxPath, hostPath);
|
|
112
|
+
},
|
|
113
|
+
close: async () => {
|
|
114
|
+
await client.delete(sandbox);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
127
118
|
});
|
|
119
|
+
|
|
120
|
+
export { daytona };
|
|
121
|
+
//# sourceMappingURL=daytona.js.map
|
|
128
122
|
//# sourceMappingURL=daytona.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daytona.js","sourceRoot":"","sources":["../../src/sandboxes/daytona.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/sandboxes/daytona.ts"],"names":["files"],"mappings":"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","file":"daytona.js","sourcesContent":["/**\n * Daytona isolated sandbox provider.\n *\n * Creates ephemeral Daytona sandboxes via `@daytona/sdk`.\n * Requires `@daytona/sdk` as a peer dependency.\n */\n\nimport { readdir, stat } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport {\n createIsolatedSandboxProvider,\n type ExecResult,\n type IsolatedSandboxHandle,\n type IsolatedSandboxProvider,\n} from \"../SandboxProvider.js\";\nimport { BoundedTail, MAX_TAIL_CHARS } from \"../boundedTail.js\";\n\nimport type {\n Daytona as DaytonaClient,\n DaytonaConfig,\n CreateSandboxFromImageParams,\n CreateSandboxFromSnapshotParams,\n} from \"@daytona/sdk\";\n\n/** Options for the Daytona sandbox provider. */\nexport interface DaytonaOptions {\n /**\n * Daytona API key for authentication.\n * Falls back to the `DAYTONA_API_KEY` environment variable if not provided.\n */\n readonly apiKey?: string;\n\n /**\n * Daytona API URL.\n * Falls back to the `DAYTONA_API_URL` environment variable if not provided.\n */\n readonly apiUrl?: string;\n\n /**\n * Target environment for sandboxes.\n * Falls back to the `DAYTONA_TARGET` environment variable if not provided.\n */\n readonly target?: string;\n\n /**\n * Options passed through to the Daytona SDK when creating a sandbox.\n * Supports both image-based and snapshot-based creation.\n */\n readonly create?:\n | CreateSandboxFromImageParams\n | CreateSandboxFromSnapshotParams;\n\n /** Environment variables injected by this provider. Merged at launch time with env resolver and agent provider env. */\n readonly env?: Record<string, string>;\n\n /**\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 Daytona isolated sandbox provider.\n *\n * Sandboxes are ephemeral — each `create()` call spins up a new Daytona\n * sandbox and `close()` destroys it.\n *\n * @example\n * ```ts\n * import { daytona } from \"@ai-hero/sandcastle/sandboxes/daytona\";\n *\n * const provider = daytona({ apiKey: \"dyt_my_key\" });\n * ```\n */\nexport const daytona = (options?: DaytonaOptions): IsolatedSandboxProvider =>\n createIsolatedSandboxProvider({\n name: \"daytona\",\n env: options?.env,\n create: async (): Promise<IsolatedSandboxHandle> => {\n const maxOutputTailChars = options?.maxOutputTailChars ?? MAX_TAIL_CHARS;\n const { Daytona } =\n (await import(\"@daytona/sdk\")) as typeof import(\"@daytona/sdk\");\n\n const config: DaytonaConfig = {};\n if (options?.apiKey) config.apiKey = options.apiKey;\n if (options?.apiUrl) config.apiUrl = options.apiUrl;\n if (options?.target) config.target = options.target;\n\n const client: DaytonaClient = new Daytona(config);\n const sandbox = await client.create(options?.create as any);\n\n const worktreePath =\n (await sandbox.getWorkDir()) ??\n (await sandbox.getUserHomeDir()) ??\n \"/home/daytona\";\n\n return {\n worktreePath,\n\n exec: async (\n command: string,\n opts?: {\n onLine?: (line: string) => void;\n cwd?: string;\n sudo?: boolean;\n },\n ): Promise<ExecResult> => {\n const effectiveCommand = opts?.sudo ? `sudo ${command}` : command;\n if (opts?.onLine) {\n const onLine = opts.onLine;\n const sessionId = `sandcastle-${crypto.randomUUID()}`;\n await sandbox.process.createSession(sessionId);\n\n try {\n const execResponse = await sandbox.process.executeSessionCommand(\n sessionId,\n {\n command: `cd ${opts?.cwd ?? worktreePath} && ${effectiveCommand}`,\n async: true,\n },\n );\n\n const cmdId = execResponse.cmdId!;\n\n const stdoutTail = new BoundedTail(maxOutputTailChars, \"\\n\");\n const stderrTail = new BoundedTail(maxOutputTailChars, \"\");\n let partial = \"\";\n\n await sandbox.process.getSessionCommandLogs(\n sessionId,\n cmdId,\n (chunk: string) => {\n const text = partial + chunk;\n const lines = text.split(\"\\n\");\n partial = lines.pop() ?? \"\";\n for (const line of lines) {\n stdoutTail.push(line);\n onLine(line);\n }\n },\n (chunk: string) => {\n stderrTail.push(chunk);\n },\n );\n\n if (partial) {\n stdoutTail.push(partial);\n onLine(partial);\n }\n\n const cmdInfo = await sandbox.process.getSessionCommand(\n sessionId,\n cmdId,\n );\n\n return {\n stdout: stdoutTail.toString(),\n stderr: stderrTail.toString(),\n exitCode: cmdInfo.exitCode ?? 0,\n };\n } finally {\n await sandbox.process.deleteSession(sessionId).catch(() => {});\n }\n }\n\n const response = await sandbox.process.executeCommand(\n effectiveCommand,\n opts?.cwd ?? worktreePath,\n );\n return {\n stdout: response.result,\n stderr: \"\",\n exitCode: response.exitCode,\n };\n },\n\n copyIn: async (\n hostPath: string,\n sandboxPath: string,\n ): Promise<void> => {\n const info = await stat(hostPath);\n if (info.isDirectory()) {\n const walk = async (dir: string): Promise<string[]> => {\n const entries = await readdir(dir, { withFileTypes: true });\n const files: string[] = [];\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await walk(full)));\n } else {\n files.push(full);\n }\n }\n return files;\n };\n const files = await walk(hostPath);\n for (const file of files) {\n const rel = relative(hostPath, file);\n await sandbox.fs.uploadFile(file, join(sandboxPath, rel));\n }\n } else {\n await sandbox.fs.uploadFile(hostPath, sandboxPath);\n }\n },\n\n copyFileOut: async (\n sandboxPath: string,\n hostPath: string,\n ): Promise<void> => {\n await sandbox.fs.downloadFile(sandboxPath, hostPath);\n },\n\n close: async (): Promise<void> => {\n await client.delete(sandbox);\n },\n };\n },\n });\n"]}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { S as SandboxProvider } from '../SandboxProvider-EkSMuBp8.js';
|
|
2
|
+
import { M as MountConfig } from '../MountConfig-CmXclHA5.js';
|
|
3
|
+
import { S as SelinuxLabel } from '../mountUtils-CCA-bbpK.js';
|
|
4
|
+
export { d as defaultImageName } from '../mountUtils-CCA-bbpK.js';
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* Docker sandbox provider — wraps DockerLifecycle into a SandboxProvider.
|
|
3
8
|
*
|
|
@@ -5,11 +10,8 @@
|
|
|
5
10
|
* import { docker } from "sandcastle/sandboxes/docker";
|
|
6
11
|
* await run({ agent: claudeCode("claude-opus-4-7"), sandbox: docker() });
|
|
7
12
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import type { SelinuxLabel } from "../mountUtils.js";
|
|
11
|
-
import { defaultImageName } from "../mountUtils.js";
|
|
12
|
-
export interface DockerOptions {
|
|
13
|
+
|
|
14
|
+
interface DockerOptions {
|
|
13
15
|
/** Docker image name (default: derived from repo directory name). */
|
|
14
16
|
readonly imageName?: string;
|
|
15
17
|
/**
|
|
@@ -103,6 +105,6 @@ export interface DockerOptions {
|
|
|
103
105
|
* The returned provider creates Docker containers with bind-mounts
|
|
104
106
|
* for the worktree and git directories.
|
|
105
107
|
*/
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
declare const docker: (options?: DockerOptions) => SandboxProvider;
|
|
109
|
+
|
|
110
|
+
export { type DockerOptions, docker };
|
package/dist/sandboxes/docker.js
CHANGED
|
@@ -1,256 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import { randomUUID } from "node:crypto";
|
|
10
|
-
import { createInterface } from "node:readline";
|
|
11
|
-
import { Effect } from "effect";
|
|
12
|
-
import { startContainer, removeContainer } from "../DockerLifecycle.js";
|
|
13
|
-
import { createBindMountSandboxProvider, } from "../SandboxProvider.js";
|
|
14
|
-
import { defaultImageName, resolveUserMounts, processFileMountParents, } from "../mountUtils.js";
|
|
15
|
-
import { BoundedTail, MAX_TAIL_CHARS } from "../boundedTail.js";
|
|
16
|
-
import { registerShutdown } from "../shutdownRegistry.js";
|
|
17
|
-
/**
|
|
18
|
-
* Create a Docker sandbox provider.
|
|
19
|
-
*
|
|
20
|
-
* The returned provider creates Docker containers with bind-mounts
|
|
21
|
-
* for the worktree and git directories.
|
|
22
|
-
*/
|
|
23
|
-
export const docker = (options) => {
|
|
24
|
-
const configuredImageName = options?.imageName;
|
|
25
|
-
const selinuxLabel = options?.selinuxLabel ?? "z";
|
|
26
|
-
const maxOutputTailChars = options?.maxOutputTailChars ?? MAX_TAIL_CHARS;
|
|
27
|
-
const sandboxHomedir = "/home/agent";
|
|
28
|
-
const userMounts = options?.mounts
|
|
29
|
-
? resolveUserMounts(options.mounts, sandboxHomedir)
|
|
30
|
-
: [];
|
|
31
|
-
// Validate file mounts and collect parent dirs to create at container start.
|
|
32
|
-
// Throws at construction time if any file mount parent is outside sandboxHomedir.
|
|
33
|
-
const parentDirsToCreate = processFileMountParents(userMounts, sandboxHomedir);
|
|
34
|
-
return createBindMountSandboxProvider({
|
|
35
|
-
name: "docker",
|
|
36
|
-
env: options?.env,
|
|
37
|
-
sandboxHomedir,
|
|
38
|
-
create: async (createOptions) => {
|
|
39
|
-
const containerName = `sandcastle-${randomUUID()}`;
|
|
40
|
-
const worktreePath = createOptions.mounts.find((m) => m.hostPath === createOptions.worktreePath)?.sandboxPath ?? "/home/agent/workspace";
|
|
41
|
-
// Build volume mount list (internal mounts + user-provided mounts)
|
|
42
|
-
const allMounts = [...createOptions.mounts, ...userMounts];
|
|
43
|
-
const volumeMounts = allMounts.map((m) => ({
|
|
44
|
-
hostPath: m.hostPath,
|
|
45
|
-
sandboxPath: m.sandboxPath,
|
|
46
|
-
readonly: m.readonly,
|
|
47
|
-
}));
|
|
48
|
-
// Resolve image name
|
|
49
|
-
const imageName = configuredImageName ?? defaultImageName(createOptions.hostRepoPath);
|
|
50
|
-
const containerUid = options?.containerUid ?? process.getuid?.() ?? 1000;
|
|
51
|
-
const containerGid = options?.containerGid ?? process.getgid?.() ?? 1000;
|
|
52
|
-
// Pre-flight: verify image exists and UID matches
|
|
53
|
-
await checkImageUid(imageName, containerUid);
|
|
54
|
-
// Start container
|
|
55
|
-
await Effect.runPromise(startContainer(containerName, imageName, {
|
|
56
|
-
...createOptions.env,
|
|
57
|
-
HOME: "/home/agent",
|
|
58
|
-
}, {
|
|
59
|
-
volumeMounts,
|
|
60
|
-
workdir: worktreePath,
|
|
61
|
-
user: `${containerUid}:${containerGid}`,
|
|
62
|
-
network: options?.network,
|
|
63
|
-
groups: options?.groups,
|
|
64
|
-
devices: options?.devices,
|
|
65
|
-
cpus: options?.cpus,
|
|
66
|
-
selinuxLabel,
|
|
67
|
-
}));
|
|
68
|
-
// Create parent directories for file mounts and chown to the container user
|
|
69
|
-
for (const dir of parentDirsToCreate) {
|
|
70
|
-
await new Promise((resolve, reject) => {
|
|
71
|
-
execFile("docker", [
|
|
72
|
-
"exec",
|
|
73
|
-
"--user",
|
|
74
|
-
"0:0",
|
|
75
|
-
containerName,
|
|
76
|
-
"sh",
|
|
77
|
-
"-c",
|
|
78
|
-
`mkdir -p "$1" && chown "$2" "$1"`,
|
|
79
|
-
"sh",
|
|
80
|
-
dir,
|
|
81
|
-
`${containerUid}:${containerGid}`,
|
|
82
|
-
], (error) => {
|
|
83
|
-
if (error) {
|
|
84
|
-
reject(new Error(`Failed to create parent directory '${dir}' in container: ${error.message}`));
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
resolve();
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
// Register synchronous container cleanup via the shared shutdown registry
|
|
93
|
-
// so concurrent sandboxes share a single exit/SIGINT/SIGTERM listener
|
|
94
|
-
// instead of tripping Node's MaxListenersExceededWarning.
|
|
95
|
-
const removeContainerSync = () => {
|
|
96
|
-
try {
|
|
97
|
-
execFileSync("docker", ["rm", "-f", containerName], {
|
|
98
|
-
stdio: "ignore",
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
/* best-effort */
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
const unregisterShutdown = registerShutdown(removeContainerSync);
|
|
106
|
-
const handle = {
|
|
107
|
-
worktreePath,
|
|
108
|
-
exec: (command, opts) => {
|
|
109
|
-
const effectiveCommand = opts?.sudo ? `sudo ${command}` : command;
|
|
110
|
-
const args = ["exec"];
|
|
111
|
-
if (opts?.stdin !== undefined)
|
|
112
|
-
args.push("-i");
|
|
113
|
-
if (opts?.cwd)
|
|
114
|
-
args.push("-w", opts.cwd);
|
|
115
|
-
args.push(containerName, "sh", "-c", effectiveCommand);
|
|
116
|
-
return new Promise((resolve, reject) => {
|
|
117
|
-
const proc = spawn("docker", args, {
|
|
118
|
-
stdio: [
|
|
119
|
-
opts?.stdin !== undefined ? "pipe" : "ignore",
|
|
120
|
-
"pipe",
|
|
121
|
-
"pipe",
|
|
122
|
-
],
|
|
123
|
-
});
|
|
124
|
-
if (opts?.stdin !== undefined) {
|
|
125
|
-
proc.stdin.write(opts.stdin);
|
|
126
|
-
proc.stdin.end();
|
|
127
|
-
}
|
|
128
|
-
proc.on("error", (error) => {
|
|
129
|
-
reject(new Error(`docker exec failed: ${error.message}`));
|
|
130
|
-
});
|
|
131
|
-
if (opts?.onLine) {
|
|
132
|
-
const onLine = opts.onLine;
|
|
133
|
-
const stdoutTail = new BoundedTail(maxOutputTailChars, "\n");
|
|
134
|
-
const stderrTail = new BoundedTail(maxOutputTailChars, "");
|
|
135
|
-
const rl = createInterface({ input: proc.stdout });
|
|
136
|
-
rl.on("line", (line) => {
|
|
137
|
-
stdoutTail.push(line);
|
|
138
|
-
onLine(line);
|
|
139
|
-
});
|
|
140
|
-
proc.stderr.on("data", (chunk) => {
|
|
141
|
-
stderrTail.push(chunk.toString());
|
|
142
|
-
});
|
|
143
|
-
proc.on("close", (code) => {
|
|
144
|
-
resolve({
|
|
145
|
-
stdout: stdoutTail.toString(),
|
|
146
|
-
stderr: stderrTail.toString(),
|
|
147
|
-
exitCode: code ?? 0,
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
const stdoutChunks = [];
|
|
153
|
-
const stderrChunks = [];
|
|
154
|
-
proc.stdout.on("data", (chunk) => {
|
|
155
|
-
stdoutChunks.push(chunk.toString());
|
|
156
|
-
});
|
|
157
|
-
proc.stderr.on("data", (chunk) => {
|
|
158
|
-
stderrChunks.push(chunk.toString());
|
|
159
|
-
});
|
|
160
|
-
proc.on("close", (code) => {
|
|
161
|
-
resolve({
|
|
162
|
-
stdout: stdoutChunks.join(""),
|
|
163
|
-
stderr: stderrChunks.join(""),
|
|
164
|
-
exitCode: code ?? 0,
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
},
|
|
170
|
-
interactiveExec: (args, opts) => {
|
|
171
|
-
return new Promise((resolve, reject) => {
|
|
172
|
-
const dockerArgs = ["exec"];
|
|
173
|
-
// Allocate a pseudo-terminal when stdin looks like a TTY
|
|
174
|
-
if ("isTTY" in opts.stdin &&
|
|
175
|
-
opts.stdin.isTTY) {
|
|
176
|
-
dockerArgs.push("-it");
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
dockerArgs.push("-i");
|
|
180
|
-
}
|
|
181
|
-
if (opts.cwd)
|
|
182
|
-
dockerArgs.push("-w", opts.cwd);
|
|
183
|
-
dockerArgs.push(containerName, ...args);
|
|
184
|
-
const proc = spawn("docker", dockerArgs, {
|
|
185
|
-
stdio: [opts.stdin, opts.stdout, opts.stderr],
|
|
186
|
-
});
|
|
187
|
-
proc.on("error", (error) => {
|
|
188
|
-
reject(new Error(`docker exec failed: ${error.message}`));
|
|
189
|
-
});
|
|
190
|
-
proc.on("close", (code) => {
|
|
191
|
-
resolve({ exitCode: code ?? 0 });
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
},
|
|
195
|
-
copyFileIn: (hostPath, sandboxPath) => new Promise((resolve, reject) => {
|
|
196
|
-
execFile("docker", ["cp", hostPath, `${containerName}:${sandboxPath}`], (error) => {
|
|
197
|
-
if (error) {
|
|
198
|
-
reject(new Error(`docker cp (in) failed: ${error.message}`));
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
resolve();
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
}),
|
|
205
|
-
copyFileOut: (sandboxPath, hostPath) => new Promise((resolve, reject) => {
|
|
206
|
-
execFile("docker", ["cp", `${containerName}:${sandboxPath}`, hostPath], (error) => {
|
|
207
|
-
if (error) {
|
|
208
|
-
reject(new Error(`docker cp (out) failed: ${error.message}`));
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
211
|
-
resolve();
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
}),
|
|
215
|
-
close: async () => {
|
|
216
|
-
unregisterShutdown();
|
|
217
|
-
await Effect.runPromise(removeContainer(containerName));
|
|
218
|
-
},
|
|
219
|
-
};
|
|
220
|
-
return handle;
|
|
221
|
-
},
|
|
222
|
-
});
|
|
223
|
-
};
|
|
224
|
-
// Re-export for backwards compatibility
|
|
225
|
-
export { defaultImageName };
|
|
226
|
-
const checkImageUid = (imageName, expectedUid) => new Promise((resolve, reject) => {
|
|
227
|
-
execFile("docker", ["image", "inspect", imageName, "--format", "{{.Config.User}}"], (error, stdout) => {
|
|
228
|
-
if (error) {
|
|
229
|
-
reject(new Error(`Image '${imageName}' not found locally. Build it first with 'sandcastle docker build-image'.`));
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
const imageUser = (stdout ?? "").toString().trim();
|
|
233
|
-
if (!imageUser) {
|
|
234
|
-
// No USER directive in image — skip check
|
|
235
|
-
resolve();
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
const uidPart = imageUser.split(":")[0];
|
|
239
|
-
const imageUid = parseInt(uidPart, 10);
|
|
240
|
-
if (isNaN(imageUid)) {
|
|
241
|
-
// Non-numeric user (e.g. "agent") — can't compare, skip check
|
|
242
|
-
resolve();
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
if (imageUid !== expectedUid) {
|
|
246
|
-
reject(new Error(`UID mismatch: image '${imageName}' was built with UID ${imageUid}, ` +
|
|
247
|
-
`but the expected UID is ${expectedUid}. ` +
|
|
248
|
-
`Rebuild the image with 'sandcastle docker build-image', ` +
|
|
249
|
-
`or pass containerUid: ${imageUid} to docker() to match the image.`));
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
resolve();
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
});
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
export { docker } from '../chunk-UPDEQ2U7.js';
|
|
3
|
+
export { defaultImageName } from '../chunk-Z7O2WNRU.js';
|
|
4
|
+
import '../chunk-BIWNFKGV.js';
|
|
5
|
+
import '../chunk-NGBM7T3E.js';
|
|
6
|
+
|
|
7
|
+
createRequire(import.meta.url);
|
|
8
|
+
//# sourceMappingURL=docker.js.map
|
|
256
9
|
//# sourceMappingURL=docker.js.map
|