@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.
Files changed (227) hide show
  1. package/README.md +125 -54
  2. package/dist/{MountConfig.d.ts → MountConfig-CmXclHA5.d.ts} +3 -2
  3. package/dist/{SandboxProvider.d.ts → SandboxProvider-EkSMuBp8.d.ts} +25 -39
  4. package/dist/chunk-72UVAC7B.js +99 -0
  5. package/dist/chunk-72UVAC7B.js.map +1 -0
  6. package/dist/chunk-BIWNFKGV.js +22 -0
  7. package/dist/chunk-BIWNFKGV.js.map +1 -0
  8. package/dist/chunk-NGBM7T3E.js +76 -0
  9. package/dist/chunk-NGBM7T3E.js.map +1 -0
  10. package/dist/chunk-Q5W3WQVU.js +25569 -0
  11. package/dist/chunk-Q5W3WQVU.js.map +1 -0
  12. package/dist/chunk-UPDEQ2U7.js +362 -0
  13. package/dist/chunk-UPDEQ2U7.js.map +1 -0
  14. package/dist/chunk-Z7O2WNRU.js +26934 -0
  15. package/dist/chunk-Z7O2WNRU.js.map +1 -0
  16. package/dist/index.d.ts +920 -22
  17. package/dist/index.js +3212 -9
  18. package/dist/index.js.map +1 -1
  19. package/dist/main.d.ts +0 -2
  20. package/dist/main.js +19256 -13
  21. package/dist/main.js.map +1 -1
  22. package/dist/mountUtils-CCA-bbpK.d.ts +25 -0
  23. package/dist/sandboxes/daytona.d.ts +8 -5
  24. package/dist/sandboxes/daytona.js +118 -124
  25. package/dist/sandboxes/daytona.js.map +1 -1
  26. package/dist/sandboxes/docker.d.ts +10 -8
  27. package/dist/sandboxes/docker.js +8 -255
  28. package/dist/sandboxes/docker.js.map +1 -1
  29. package/dist/sandboxes/no-sandbox.d.ts +7 -4
  30. package/dist/sandboxes/no-sandbox.js +6 -114
  31. package/dist/sandboxes/no-sandbox.js.map +1 -1
  32. package/dist/sandboxes/podman.d.ts +10 -8
  33. package/dist/sandboxes/podman.js +287 -297
  34. package/dist/sandboxes/podman.js.map +1 -1
  35. package/dist/sandboxes/vercel.d.ts +7 -4
  36. package/dist/sandboxes/vercel.js +144 -165
  37. package/dist/sandboxes/vercel.js.map +1 -1
  38. package/package.json +15 -14
  39. package/dist/AgentProvider.d.ts +0 -134
  40. package/dist/AgentProvider.d.ts.map +0 -1
  41. package/dist/AgentProvider.js +0 -647
  42. package/dist/AgentProvider.js.map +0 -1
  43. package/dist/AgentStreamEmitter.d.ts +0 -36
  44. package/dist/AgentStreamEmitter.d.ts.map +0 -1
  45. package/dist/AgentStreamEmitter.js +0 -21
  46. package/dist/AgentStreamEmitter.js.map +0 -1
  47. package/dist/CopyToWorktree.d.ts +0 -15
  48. package/dist/CopyToWorktree.d.ts.map +0 -1
  49. package/dist/CopyToWorktree.js +0 -60
  50. package/dist/CopyToWorktree.js.map +0 -1
  51. package/dist/Display.d.ts +0 -58
  52. package/dist/Display.d.ts.map +0 -1
  53. package/dist/Display.js +0 -142
  54. package/dist/Display.js.map +0 -1
  55. package/dist/DockerLifecycle.d.ts +0 -54
  56. package/dist/DockerLifecycle.d.ts.map +0 -1
  57. package/dist/DockerLifecycle.js +0 -123
  58. package/dist/DockerLifecycle.js.map +0 -1
  59. package/dist/EnvResolver.d.ts +0 -11
  60. package/dist/EnvResolver.d.ts.map +0 -1
  61. package/dist/EnvResolver.js +0 -63
  62. package/dist/EnvResolver.js.map +0 -1
  63. package/dist/ErrorHandler.d.ts +0 -15
  64. package/dist/ErrorHandler.d.ts.map +0 -1
  65. package/dist/ErrorHandler.js +0 -85
  66. package/dist/ErrorHandler.js.map +0 -1
  67. package/dist/InitService.d.ts +0 -63
  68. package/dist/InitService.d.ts.map +0 -1
  69. package/dist/InitService.js +0 -733
  70. package/dist/InitService.js.map +0 -1
  71. package/dist/MountConfig.d.ts.map +0 -1
  72. package/dist/MountConfig.js +0 -7
  73. package/dist/MountConfig.js.map +0 -1
  74. package/dist/Orchestrator.d.ts +0 -56
  75. package/dist/Orchestrator.d.ts.map +0 -1
  76. package/dist/Orchestrator.js +0 -293
  77. package/dist/Orchestrator.js.map +0 -1
  78. package/dist/Output.d.ts +0 -107
  79. package/dist/Output.d.ts.map +0 -1
  80. package/dist/Output.js +0 -95
  81. package/dist/Output.js.map +0 -1
  82. package/dist/PodmanLifecycle.d.ts +0 -17
  83. package/dist/PodmanLifecycle.d.ts.map +0 -1
  84. package/dist/PodmanLifecycle.js +0 -45
  85. package/dist/PodmanLifecycle.js.map +0 -1
  86. package/dist/PromptArgumentSubstitution.d.ts +0 -32
  87. package/dist/PromptArgumentSubstitution.d.ts.map +0 -1
  88. package/dist/PromptArgumentSubstitution.js +0 -104
  89. package/dist/PromptArgumentSubstitution.js.map +0 -1
  90. package/dist/PromptPreprocessor.d.ts +0 -15
  91. package/dist/PromptPreprocessor.d.ts.map +0 -1
  92. package/dist/PromptPreprocessor.js +0 -55
  93. package/dist/PromptPreprocessor.js.map +0 -1
  94. package/dist/PromptResolver.d.ts +0 -21
  95. package/dist/PromptResolver.d.ts.map +0 -1
  96. package/dist/PromptResolver.js +0 -27
  97. package/dist/PromptResolver.js.map +0 -1
  98. package/dist/RecoveryMessage.d.ts +0 -15
  99. package/dist/RecoveryMessage.d.ts.map +0 -1
  100. package/dist/RecoveryMessage.js +0 -81
  101. package/dist/RecoveryMessage.js.map +0 -1
  102. package/dist/SandboxFactory.d.ts +0 -90
  103. package/dist/SandboxFactory.d.ts.map +0 -1
  104. package/dist/SandboxFactory.js +0 -324
  105. package/dist/SandboxFactory.js.map +0 -1
  106. package/dist/SandboxLifecycle.d.ts +0 -65
  107. package/dist/SandboxLifecycle.d.ts.map +0 -1
  108. package/dist/SandboxLifecycle.js +0 -296
  109. package/dist/SandboxLifecycle.js.map +0 -1
  110. package/dist/SandboxProvider.d.ts.map +0 -1
  111. package/dist/SandboxProvider.js +0 -28
  112. package/dist/SandboxProvider.js.map +0 -1
  113. package/dist/SessionStore.d.ts +0 -110
  114. package/dist/SessionStore.d.ts.map +0 -1
  115. package/dist/SessionStore.js +0 -330
  116. package/dist/SessionStore.js.map +0 -1
  117. package/dist/TextDeltaBuffer.d.ts +0 -24
  118. package/dist/TextDeltaBuffer.d.ts.map +0 -1
  119. package/dist/TextDeltaBuffer.js +0 -68
  120. package/dist/TextDeltaBuffer.js.map +0 -1
  121. package/dist/WorktreeManager.d.ts +0 -79
  122. package/dist/WorktreeManager.d.ts.map +0 -1
  123. package/dist/WorktreeManager.js +0 -283
  124. package/dist/WorktreeManager.js.map +0 -1
  125. package/dist/boundedTail.d.ts +0 -48
  126. package/dist/boundedTail.d.ts.map +0 -1
  127. package/dist/boundedTail.js +0 -64
  128. package/dist/boundedTail.js.map +0 -1
  129. package/dist/cli.d.ts +0 -30
  130. package/dist/cli.d.ts.map +0 -1
  131. package/dist/cli.js +0 -309
  132. package/dist/cli.js.map +0 -1
  133. package/dist/createSandbox.d.ts +0 -154
  134. package/dist/createSandbox.d.ts.map +0 -1
  135. package/dist/createSandbox.js +0 -476
  136. package/dist/createSandbox.js.map +0 -1
  137. package/dist/createWorktree.d.ts +0 -154
  138. package/dist/createWorktree.d.ts.map +0 -1
  139. package/dist/createWorktree.js +0 -391
  140. package/dist/createWorktree.js.map +0 -1
  141. package/dist/errors.d.ts +0 -227
  142. package/dist/errors.d.ts.map +0 -1
  143. package/dist/errors.js +0 -81
  144. package/dist/errors.js.map +0 -1
  145. package/dist/extractStructuredOutput.d.ts +0 -23
  146. package/dist/extractStructuredOutput.d.ts.map +0 -1
  147. package/dist/extractStructuredOutput.js +0 -102
  148. package/dist/extractStructuredOutput.js.map +0 -1
  149. package/dist/index.d.ts.map +0 -1
  150. package/dist/interactive.d.ts +0 -74
  151. package/dist/interactive.d.ts.map +0 -1
  152. package/dist/interactive.js +0 -279
  153. package/dist/interactive.js.map +0 -1
  154. package/dist/main.d.ts.map +0 -1
  155. package/dist/mergeProviderEnv.d.ts +0 -13
  156. package/dist/mergeProviderEnv.d.ts.map +0 -1
  157. package/dist/mergeProviderEnv.js +0 -23
  158. package/dist/mergeProviderEnv.js.map +0 -1
  159. package/dist/mountUtils.d.ts +0 -146
  160. package/dist/mountUtils.d.ts.map +0 -1
  161. package/dist/mountUtils.js +0 -301
  162. package/dist/mountUtils.js.map +0 -1
  163. package/dist/raceAbortSignal.d.ts +0 -18
  164. package/dist/raceAbortSignal.d.ts.map +0 -1
  165. package/dist/raceAbortSignal.js +0 -32
  166. package/dist/raceAbortSignal.js.map +0 -1
  167. package/dist/resolveCwd.d.ts +0 -24
  168. package/dist/resolveCwd.d.ts.map +0 -1
  169. package/dist/resolveCwd.js +0 -32
  170. package/dist/resolveCwd.js.map +0 -1
  171. package/dist/resumePrecheck.d.ts +0 -26
  172. package/dist/resumePrecheck.d.ts.map +0 -1
  173. package/dist/resumePrecheck.js +0 -40
  174. package/dist/resumePrecheck.js.map +0 -1
  175. package/dist/run.d.ts +0 -216
  176. package/dist/run.d.ts.map +0 -1
  177. package/dist/run.js +0 -313
  178. package/dist/run.js.map +0 -1
  179. package/dist/sandboxExec.d.ts +0 -12
  180. package/dist/sandboxExec.d.ts.map +0 -1
  181. package/dist/sandboxExec.js +0 -26
  182. package/dist/sandboxExec.js.map +0 -1
  183. package/dist/sandboxes/daytona.d.ts.map +0 -1
  184. package/dist/sandboxes/docker.d.ts.map +0 -1
  185. package/dist/sandboxes/no-sandbox.d.ts.map +0 -1
  186. package/dist/sandboxes/podman.d.ts.map +0 -1
  187. package/dist/sandboxes/test-bind-mount.d.ts +0 -17
  188. package/dist/sandboxes/test-bind-mount.d.ts.map +0 -1
  189. package/dist/sandboxes/test-bind-mount.js +0 -92
  190. package/dist/sandboxes/test-bind-mount.js.map +0 -1
  191. package/dist/sandboxes/test-isolated.d.ts +0 -17
  192. package/dist/sandboxes/test-isolated.d.ts.map +0 -1
  193. package/dist/sandboxes/test-isolated.js +0 -98
  194. package/dist/sandboxes/test-isolated.js.map +0 -1
  195. package/dist/sandboxes/vercel.d.ts.map +0 -1
  196. package/dist/shutdownRegistry.d.ts +0 -30
  197. package/dist/shutdownRegistry.d.ts.map +0 -1
  198. package/dist/shutdownRegistry.js +0 -73
  199. package/dist/shutdownRegistry.js.map +0 -1
  200. package/dist/startSandbox.d.ts +0 -50
  201. package/dist/startSandbox.d.ts.map +0 -1
  202. package/dist/startSandbox.js +0 -117
  203. package/dist/startSandbox.js.map +0 -1
  204. package/dist/syncIn.d.ts +0 -24
  205. package/dist/syncIn.d.ts.map +0 -1
  206. package/dist/syncIn.js +0 -107
  207. package/dist/syncIn.js.map +0 -1
  208. package/dist/syncOut.d.ts +0 -27
  209. package/dist/syncOut.d.ts.map +0 -1
  210. package/dist/syncOut.js +0 -271
  211. package/dist/syncOut.js.map +0 -1
  212. package/dist/templates.d.ts +0 -2
  213. package/dist/templates.d.ts.map +0 -1
  214. package/dist/templates.js +0 -26
  215. package/dist/templates.js.map +0 -1
  216. package/dist/terminalCleanup.d.ts +0 -30
  217. package/dist/terminalCleanup.d.ts.map +0 -1
  218. package/dist/terminalCleanup.js +0 -37
  219. package/dist/terminalCleanup.js.map +0 -1
  220. package/dist/testSandbox.d.ts +0 -8
  221. package/dist/testSandbox.d.ts.map +0 -1
  222. package/dist/testSandbox.js +0 -109
  223. package/dist/testSandbox.js.map +0 -1
  224. package/dist/testSetup.d.ts +0 -2
  225. package/dist/testSetup.d.ts.map +0 -1
  226. package/dist/testSetup.js +0 -29
  227. 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
- import { type IsolatedSandboxProvider } from "../SandboxProvider.js";
8
- import type { CreateSandboxFromImageParams, CreateSandboxFromSnapshotParams } from "@daytona/sdk";
10
+
9
11
  /** Options for the Daytona sandbox provider. */
10
- export interface DaytonaOptions {
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
- export declare const daytona: (options?: DaytonaOptions | undefined) => IsolatedSandboxProvider;
57
- //# sourceMappingURL=daytona.d.ts.map
58
+ declare const daytona: (options?: DaytonaOptions) => IsolatedSandboxProvider;
59
+
60
+ export { type DaytonaOptions, daytona };
@@ -1,128 +1,122 @@
1
- /**
2
- * Daytona isolated sandbox provider.
3
- *
4
- * Creates ephemeral Daytona sandboxes via `@daytona/sdk`.
5
- * Requires `@daytona/sdk` as a peer dependency.
6
- */
7
- import { readdir, stat } from "node:fs/promises";
8
- import { join, relative } from "node:path";
9
- import { createIsolatedSandboxProvider, } from "../SandboxProvider.js";
10
- import { BoundedTail, MAX_TAIL_CHARS } from "../boundedTail.js";
11
- /**
12
- * Create a Daytona isolated sandbox provider.
13
- *
14
- * Sandboxes are ephemeral — each `create()` call spins up a new Daytona
15
- * sandbox and `close()` destroys it.
16
- *
17
- * @example
18
- * ```ts
19
- * import { daytona } from "@ai-hero/sandcastle/sandboxes/daytona";
20
- *
21
- * const provider = daytona({ apiKey: "dyt_my_key" });
22
- * ```
23
- */
24
- export const daytona = (options) => createIsolatedSandboxProvider({
25
- name: "daytona",
26
- env: options?.env,
27
- create: async () => {
28
- const maxOutputTailChars = options?.maxOutputTailChars ?? MAX_TAIL_CHARS;
29
- const { Daytona } = (await import("@daytona/sdk"));
30
- const config = {};
31
- if (options?.apiKey)
32
- config.apiKey = options.apiKey;
33
- if (options?.apiUrl)
34
- config.apiUrl = options.apiUrl;
35
- if (options?.target)
36
- config.target = options.target;
37
- const client = new Daytona(config);
38
- const sandbox = await client.create(options?.create);
39
- const worktreePath = (await sandbox.getWorkDir()) ??
40
- (await sandbox.getUserHomeDir()) ??
41
- "/home/daytona";
42
- return {
43
- worktreePath,
44
- exec: async (command, opts) => {
45
- const effectiveCommand = opts?.sudo ? `sudo ${command}` : command;
46
- if (opts?.onLine) {
47
- const onLine = opts.onLine;
48
- const sessionId = `sandcastle-${crypto.randomUUID()}`;
49
- await sandbox.process.createSession(sessionId);
50
- try {
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
- else {
116
- await sandbox.fs.uploadFile(hostPath, sandboxPath);
117
- }
118
- },
119
- copyFileOut: async (sandboxPath, hostPath) => {
120
- await sandbox.fs.downloadFile(sandboxPath, hostPath);
121
- },
122
- close: async () => {
123
- await client.delete(sandbox);
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
- import { type SandboxProvider } from "../SandboxProvider.js";
9
- import type { MountConfig } from "../MountConfig.js";
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
- export declare const docker: (options?: DockerOptions | undefined) => SandboxProvider;
107
- export { defaultImageName };
108
- //# sourceMappingURL=docker.d.ts.map
108
+ declare const docker: (options?: DockerOptions) => SandboxProvider;
109
+
110
+ export { type DockerOptions, docker };
@@ -1,256 +1,9 @@
1
- /**
2
- * Docker sandbox provider — wraps DockerLifecycle into a SandboxProvider.
3
- *
4
- * Usage:
5
- * import { docker } from "sandcastle/sandboxes/docker";
6
- * await run({ agent: claudeCode("claude-opus-4-7"), sandbox: docker() });
7
- */
8
- import { execFile, execFileSync, spawn, } from "node:child_process";
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