@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
@@ -1,309 +1,299 @@
1
- /**
2
- * Podman sandbox provider creates Podman containers with bind-mounts.
3
- *
4
- * Usage:
5
- * import { podman } from "sandcastle/sandboxes/podman";
6
- * await run({ agent: claudeCode("claude-opus-4-7"), sandbox: podman() });
7
- */
8
- import { execFile, execFileSync, spawn, } from "node:child_process";
9
- import { randomUUID } from "node:crypto";
10
- import { createInterface } from "node:readline";
11
- import { createBindMountSandboxProvider, } from "../SandboxProvider.js";
12
- import { defaultImageName, resolveUserMounts, formatVolumeMount, processFileMountParents, } from "../mountUtils.js";
13
- import { BoundedTail, MAX_TAIL_CHARS } from "../boundedTail.js";
14
- import { registerShutdown } from "../shutdownRegistry.js";
15
- /**
16
- * Create a Podman sandbox provider.
17
- *
18
- * The returned provider creates Podman containers with bind-mounts
19
- * for the worktree and git directories. Calls the `podman` binary
20
- * on PATH directly. On macOS/Windows, verifies that a Podman Machine
21
- * is running before container creation.
22
- */
23
- export const podman = (options) => {
24
- const configuredImageName = options?.imageName;
25
- const selinuxLabel = options?.selinuxLabel ?? "z";
26
- const userns = options?.userns ?? "keep-id";
27
- const containerUid = options?.containerUid ?? 1000;
28
- const containerGid = options?.containerGid ?? 1000;
29
- const maxOutputTailChars = options?.maxOutputTailChars ?? MAX_TAIL_CHARS;
30
- const sandboxHomedir = "/home/agent";
31
- const userMounts = options?.mounts
32
- ? resolveUserMounts(options.mounts, sandboxHomedir)
33
- : [];
34
- // Validate file mounts and collect parent dirs to create at container start.
35
- // Throws at construction time if any file mount parent is outside sandboxHomedir.
36
- const parentDirsToCreate = processFileMountParents(userMounts, sandboxHomedir);
37
- return createBindMountSandboxProvider({
38
- name: "podman",
39
- env: options?.env,
40
- sandboxHomedir,
41
- create: async (createOptions) => {
42
- const containerName = `sandcastle-${randomUUID()}`;
43
- const worktreePath = createOptions.mounts.find((m) => m.hostPath === createOptions.worktreePath)?.sandboxPath ?? "/home/agent/workspace";
44
- // Build volume mount strings with optional SELinux label (internal + user mounts)
45
- const allMounts = [...createOptions.mounts, ...userMounts];
46
- const volumeMounts = allMounts.map((m) => formatVolumeMount(m, selinuxLabel));
47
- // Resolve image name
48
- const imageName = configuredImageName ?? defaultImageName(createOptions.hostRepoPath);
49
- // Pre-flight: check Podman Machine on macOS/Windows
50
- if (process.platform === "darwin" || process.platform === "win32") {
51
- await checkPodmanMachine();
1
+ import { createRequire } from 'node:module';
2
+ import { resolveUserMounts, processFileMountParents, formatVolumeMount, defaultImageName, registerShutdown } from '../chunk-Z7O2WNRU.js';
3
+ export { defaultImageName } from '../chunk-Z7O2WNRU.js';
4
+ import { createBindMountSandboxProvider } from '../chunk-BIWNFKGV.js';
5
+ import { MAX_TAIL_CHARS, BoundedTail } from '../chunk-NGBM7T3E.js';
6
+ import { execFile, execFileSync, spawn } from 'child_process';
7
+ import { randomUUID } from 'crypto';
8
+ import { createInterface } from 'readline';
9
+
10
+ createRequire(import.meta.url);
11
+ var podman = (options) => {
12
+ const configuredImageName = options?.imageName;
13
+ const selinuxLabel = options?.selinuxLabel ?? "z";
14
+ const userns = options?.userns ?? "keep-id";
15
+ const containerUid = options?.containerUid ?? 1e3;
16
+ const containerGid = options?.containerGid ?? 1e3;
17
+ const maxOutputTailChars = options?.maxOutputTailChars ?? MAX_TAIL_CHARS;
18
+ const sandboxHomedir = "/home/agent";
19
+ const userMounts = options?.mounts ? resolveUserMounts(options.mounts, sandboxHomedir) : [];
20
+ const parentDirsToCreate = processFileMountParents(
21
+ userMounts,
22
+ sandboxHomedir
23
+ );
24
+ return createBindMountSandboxProvider({
25
+ name: "podman",
26
+ env: options?.env,
27
+ sandboxHomedir,
28
+ create: async (createOptions) => {
29
+ const containerName = `sandcastle-${randomUUID()}`;
30
+ const worktreePath = createOptions.mounts.find(
31
+ (m) => m.hostPath === createOptions.worktreePath
32
+ )?.sandboxPath ?? "/home/agent/workspace";
33
+ const allMounts = [...createOptions.mounts, ...userMounts];
34
+ const volumeMounts = allMounts.map(
35
+ (m) => formatVolumeMount(m, selinuxLabel)
36
+ );
37
+ const imageName = configuredImageName ?? defaultImageName(createOptions.hostRepoPath);
38
+ if (process.platform === "darwin" || process.platform === "win32") {
39
+ await checkPodmanMachine();
40
+ }
41
+ await checkImageExists(imageName);
42
+ const env = { ...createOptions.env, HOME: "/home/agent" };
43
+ const envArgs = Object.entries(env).flatMap(([key, value]) => [
44
+ "-e",
45
+ `${key}=${value}`
46
+ ]);
47
+ const volumeArgs = volumeMounts.flatMap((v) => ["-v", v]);
48
+ const usernsArgs = userns ? [`--userns=keep-id:uid=${containerUid},gid=${containerGid}`] : [];
49
+ const userArgs = ["--user", `${containerUid}:${containerGid}`];
50
+ const networks = options?.network ? Array.isArray(options.network) ? options.network : [options.network] : [];
51
+ const networkArgs = networks.flatMap((n) => ["--network", n]);
52
+ const groupArgs = (options?.groups ?? []).flatMap((g) => [
53
+ "--group-add",
54
+ String(g)
55
+ ]);
56
+ const deviceArgs = (options?.devices ?? []).flatMap((d) => [
57
+ "--device",
58
+ d
59
+ ]);
60
+ const cpusArgs = options?.cpus !== void 0 ? ["--cpus", String(options.cpus)] : [];
61
+ await new Promise((resolve, reject) => {
62
+ execFile(
63
+ "podman",
64
+ [
65
+ "run",
66
+ "-d",
67
+ "--name",
68
+ containerName,
69
+ ...userArgs,
70
+ ...usernsArgs,
71
+ ...networkArgs,
72
+ ...groupArgs,
73
+ ...deviceArgs,
74
+ ...cpusArgs,
75
+ "-w",
76
+ worktreePath,
77
+ ...envArgs,
78
+ ...volumeArgs,
79
+ "--entrypoint",
80
+ "sleep",
81
+ imageName,
82
+ "infinity"
83
+ ],
84
+ (error) => {
85
+ if (error) {
86
+ reject(new Error(`podman run failed: ${error.message}`));
87
+ } else {
88
+ resolve();
52
89
  }
53
- // Pre-flight: verify image exists locally
54
- await checkImageExists(imageName);
55
- const env = { ...createOptions.env, HOME: "/home/agent" };
56
- const envArgs = Object.entries(env).flatMap(([key, value]) => [
57
- "-e",
58
- `${key}=${value}`,
59
- ]);
60
- const volumeArgs = volumeMounts.flatMap((v) => ["-v", v]);
61
- const usernsArgs = userns
62
- ? [`--userns=keep-id:uid=${containerUid},gid=${containerGid}`]
63
- : [];
64
- const userArgs = ["--user", `${containerUid}:${containerGid}`];
65
- const networks = options?.network
66
- ? Array.isArray(options.network)
67
- ? options.network
68
- : [options.network]
69
- : [];
70
- const networkArgs = networks.flatMap((n) => ["--network", n]);
71
- const groupArgs = (options?.groups ?? []).flatMap((g) => [
72
- "--group-add",
73
- String(g),
74
- ]);
75
- const deviceArgs = (options?.devices ?? []).flatMap((d) => [
76
- "--device",
77
- d,
78
- ]);
79
- const cpusArgs = options?.cpus !== undefined ? ["--cpus", String(options.cpus)] : [];
80
- // Start container via podman run
81
- await new Promise((resolve, reject) => {
82
- execFile("podman", [
83
- "run",
84
- "-d",
85
- "--name",
86
- containerName,
87
- ...userArgs,
88
- ...usernsArgs,
89
- ...networkArgs,
90
- ...groupArgs,
91
- ...deviceArgs,
92
- ...cpusArgs,
93
- "-w",
94
- worktreePath,
95
- ...envArgs,
96
- ...volumeArgs,
97
- "--entrypoint",
98
- "sleep",
99
- imageName,
100
- "infinity",
101
- ], (error) => {
102
- if (error) {
103
- reject(new Error(`podman run failed: ${error.message}`));
104
- }
105
- else {
106
- resolve();
107
- }
108
- });
90
+ }
91
+ );
92
+ });
93
+ for (const dir of parentDirsToCreate) {
94
+ await new Promise((resolve, reject) => {
95
+ execFile(
96
+ "podman",
97
+ [
98
+ "exec",
99
+ "--user",
100
+ "0:0",
101
+ containerName,
102
+ "sh",
103
+ "-c",
104
+ `mkdir -p "$1" && chown "$2" "$1"`,
105
+ "sh",
106
+ dir,
107
+ `${containerUid}:${containerGid}`
108
+ ],
109
+ (error) => {
110
+ if (error) {
111
+ reject(
112
+ new Error(
113
+ `Failed to create parent directory '${dir}' in container: ${error.message}`
114
+ )
115
+ );
116
+ } else {
117
+ resolve();
118
+ }
119
+ }
120
+ );
121
+ });
122
+ }
123
+ const removeContainerSync = () => {
124
+ try {
125
+ execFileSync("podman", ["rm", "-f", containerName], {
126
+ stdio: "ignore",
127
+ timeout: 5e3
128
+ });
129
+ } catch {
130
+ }
131
+ };
132
+ const unregisterShutdown = registerShutdown(removeContainerSync);
133
+ const handle = {
134
+ worktreePath,
135
+ exec: (command, opts) => {
136
+ const effectiveCommand = opts?.sudo ? `sudo ${command}` : command;
137
+ const args = ["exec"];
138
+ if (opts?.stdin !== void 0) args.push("-i");
139
+ if (opts?.cwd) args.push("-w", opts.cwd);
140
+ args.push(containerName, "sh", "-c", effectiveCommand);
141
+ return new Promise((resolve, reject) => {
142
+ const proc = spawn("podman", args, {
143
+ stdio: [
144
+ opts?.stdin !== void 0 ? "pipe" : "ignore",
145
+ "pipe",
146
+ "pipe"
147
+ ]
148
+ });
149
+ if (opts?.stdin !== void 0) {
150
+ proc.stdin.write(opts.stdin);
151
+ proc.stdin.end();
152
+ }
153
+ proc.on("error", (error) => {
154
+ reject(new Error(`podman exec failed: ${error.message}`));
109
155
  });
110
- // Create parent directories for file mounts and chown to the container user
111
- for (const dir of parentDirsToCreate) {
112
- await new Promise((resolve, reject) => {
113
- execFile("podman", [
114
- "exec",
115
- "--user",
116
- "0:0",
117
- containerName,
118
- "sh",
119
- "-c",
120
- `mkdir -p "$1" && chown "$2" "$1"`,
121
- "sh",
122
- dir,
123
- `${containerUid}:${containerGid}`,
124
- ], (error) => {
125
- if (error) {
126
- reject(new Error(`Failed to create parent directory '${dir}' in container: ${error.message}`));
127
- }
128
- else {
129
- resolve();
130
- }
131
- });
156
+ if (opts?.onLine) {
157
+ const onLine = opts.onLine;
158
+ const stdoutTail = new BoundedTail(maxOutputTailChars, "\n");
159
+ const stderrTail = new BoundedTail(maxOutputTailChars, "");
160
+ const rl = createInterface({ input: proc.stdout });
161
+ rl.on("line", (line) => {
162
+ stdoutTail.push(line);
163
+ onLine(line);
164
+ });
165
+ proc.stderr.on("data", (chunk) => {
166
+ stderrTail.push(chunk.toString());
167
+ });
168
+ proc.on("close", (code) => {
169
+ resolve({
170
+ stdout: stdoutTail.toString(),
171
+ stderr: stderrTail.toString(),
172
+ exitCode: code ?? 0
173
+ });
174
+ });
175
+ } else {
176
+ const stdoutChunks = [];
177
+ const stderrChunks = [];
178
+ proc.stdout.on("data", (chunk) => {
179
+ stdoutChunks.push(chunk.toString());
180
+ });
181
+ proc.stderr.on("data", (chunk) => {
182
+ stderrChunks.push(chunk.toString());
183
+ });
184
+ proc.on("close", (code) => {
185
+ resolve({
186
+ stdout: stdoutChunks.join(""),
187
+ stderr: stderrChunks.join(""),
188
+ exitCode: code ?? 0
132
189
  });
190
+ });
133
191
  }
134
- // Register synchronous container cleanup via the shared shutdown registry
135
- // so concurrent sandboxes share a single exit/SIGINT/SIGTERM listener
136
- // instead of tripping Node's MaxListenersExceededWarning.
137
- const removeContainerSync = () => {
138
- try {
139
- execFileSync("podman", ["rm", "-f", containerName], {
140
- stdio: "ignore",
141
- timeout: 5000,
142
- });
143
- }
144
- catch {
145
- /* best-effort */
146
- }
147
- };
148
- const unregisterShutdown = registerShutdown(removeContainerSync);
149
- const handle = {
150
- worktreePath,
151
- exec: (command, opts) => {
152
- const effectiveCommand = opts?.sudo ? `sudo ${command}` : command;
153
- const args = ["exec"];
154
- if (opts?.stdin !== undefined)
155
- args.push("-i");
156
- if (opts?.cwd)
157
- args.push("-w", opts.cwd);
158
- args.push(containerName, "sh", "-c", effectiveCommand);
159
- return new Promise((resolve, reject) => {
160
- const proc = spawn("podman", args, {
161
- stdio: [
162
- opts?.stdin !== undefined ? "pipe" : "ignore",
163
- "pipe",
164
- "pipe",
165
- ],
166
- });
167
- if (opts?.stdin !== undefined) {
168
- proc.stdin.write(opts.stdin);
169
- proc.stdin.end();
170
- }
171
- proc.on("error", (error) => {
172
- reject(new Error(`podman exec failed: ${error.message}`));
173
- });
174
- if (opts?.onLine) {
175
- const onLine = opts.onLine;
176
- const stdoutTail = new BoundedTail(maxOutputTailChars, "\n");
177
- const stderrTail = new BoundedTail(maxOutputTailChars, "");
178
- const rl = createInterface({ input: proc.stdout });
179
- rl.on("line", (line) => {
180
- stdoutTail.push(line);
181
- onLine(line);
182
- });
183
- proc.stderr.on("data", (chunk) => {
184
- stderrTail.push(chunk.toString());
185
- });
186
- proc.on("close", (code) => {
187
- resolve({
188
- stdout: stdoutTail.toString(),
189
- stderr: stderrTail.toString(),
190
- exitCode: code ?? 0,
191
- });
192
- });
193
- }
194
- else {
195
- const stdoutChunks = [];
196
- const stderrChunks = [];
197
- proc.stdout.on("data", (chunk) => {
198
- stdoutChunks.push(chunk.toString());
199
- });
200
- proc.stderr.on("data", (chunk) => {
201
- stderrChunks.push(chunk.toString());
202
- });
203
- proc.on("close", (code) => {
204
- resolve({
205
- stdout: stdoutChunks.join(""),
206
- stderr: stderrChunks.join(""),
207
- exitCode: code ?? 0,
208
- });
209
- });
210
- }
211
- });
212
- },
213
- interactiveExec: (args, opts) => {
214
- return new Promise((resolve, reject) => {
215
- const podmanArgs = ["exec"];
216
- // Allocate a pseudo-terminal when stdin looks like a TTY
217
- if ("isTTY" in opts.stdin &&
218
- opts.stdin.isTTY) {
219
- podmanArgs.push("-it");
220
- }
221
- else {
222
- podmanArgs.push("-i");
223
- }
224
- if (opts.cwd)
225
- podmanArgs.push("-w", opts.cwd);
226
- podmanArgs.push(containerName, ...args);
227
- const proc = spawn("podman", podmanArgs, {
228
- stdio: [opts.stdin, opts.stdout, opts.stderr],
229
- });
230
- proc.on("error", (error) => {
231
- reject(new Error(`podman exec failed: ${error.message}`));
232
- });
233
- proc.on("close", (code) => {
234
- resolve({ exitCode: code ?? 0 });
235
- });
236
- });
237
- },
238
- copyFileIn: (hostPath, sandboxPath) => new Promise((resolve, reject) => {
239
- execFile("podman", ["cp", hostPath, `${containerName}:${sandboxPath}`], (error) => {
240
- if (error) {
241
- reject(new Error(`podman cp (in) failed: ${error.message}`));
242
- }
243
- else {
244
- resolve();
245
- }
246
- });
247
- }),
248
- copyFileOut: (sandboxPath, hostPath) => new Promise((resolve, reject) => {
249
- execFile("podman", ["cp", `${containerName}:${sandboxPath}`, hostPath], (error) => {
250
- if (error) {
251
- reject(new Error(`podman cp (out) failed: ${error.message}`));
252
- }
253
- else {
254
- resolve();
255
- }
256
- });
257
- }),
258
- close: async () => {
259
- unregisterShutdown();
260
- await new Promise((resolve, reject) => {
261
- execFile("podman", ["rm", "-f", containerName], (error) => {
262
- if (error) {
263
- reject(new Error(`podman rm failed: ${error.message}`));
264
- }
265
- else {
266
- resolve();
267
- }
268
- });
269
- });
270
- },
271
- };
272
- return handle;
192
+ });
273
193
  },
274
- });
275
- };
276
- // Re-export for backwards compatibility
277
- export { defaultImageName };
278
- const checkImageExists = (imageName) => new Promise((resolve, reject) => {
279
- execFile("podman", ["image", "inspect", imageName], (error) => {
280
- if (error) {
281
- reject(new Error(`Image '${imageName}' not found locally. Build it first with 'podman build -t ${imageName} .'`));
282
- }
283
- else {
284
- resolve();
285
- }
286
- });
287
- });
288
- const podmanMachineError = () => new Error("Podman Machine is not running. Run 'podman machine init && podman machine start' first.");
289
- const checkPodmanMachine = () => new Promise((resolve, reject) => {
290
- execFile("podman", ["machine", "list", "--format", "json"], (error, stdout) => {
291
- if (error) {
292
- reject(podmanMachineError());
293
- return;
294
- }
295
- try {
296
- const machines = JSON.parse(stdout.toString());
297
- if (machines.some((m) => m.Running)) {
194
+ interactiveExec: (args, opts) => {
195
+ return new Promise((resolve, reject) => {
196
+ const podmanArgs = ["exec"];
197
+ if ("isTTY" in opts.stdin && opts.stdin.isTTY) {
198
+ podmanArgs.push("-it");
199
+ } else {
200
+ podmanArgs.push("-i");
201
+ }
202
+ if (opts.cwd) podmanArgs.push("-w", opts.cwd);
203
+ podmanArgs.push(containerName, ...args);
204
+ const proc = spawn("podman", podmanArgs, {
205
+ stdio: [opts.stdin, opts.stdout, opts.stderr]
206
+ });
207
+ proc.on("error", (error) => {
208
+ reject(new Error(`podman exec failed: ${error.message}`));
209
+ });
210
+ proc.on("close", (code) => {
211
+ resolve({ exitCode: code ?? 0 });
212
+ });
213
+ });
214
+ },
215
+ copyFileIn: (hostPath, sandboxPath) => new Promise((resolve, reject) => {
216
+ execFile(
217
+ "podman",
218
+ ["cp", hostPath, `${containerName}:${sandboxPath}`],
219
+ (error) => {
220
+ if (error) {
221
+ reject(new Error(`podman cp (in) failed: ${error.message}`));
222
+ } else {
298
223
  resolve();
224
+ }
299
225
  }
300
- else {
301
- reject(podmanMachineError());
226
+ );
227
+ }),
228
+ copyFileOut: (sandboxPath, hostPath) => new Promise((resolve, reject) => {
229
+ execFile(
230
+ "podman",
231
+ ["cp", `${containerName}:${sandboxPath}`, hostPath],
232
+ (error) => {
233
+ if (error) {
234
+ reject(new Error(`podman cp (out) failed: ${error.message}`));
235
+ } else {
236
+ resolve();
237
+ }
302
238
  }
239
+ );
240
+ }),
241
+ close: async () => {
242
+ unregisterShutdown();
243
+ await new Promise((resolve, reject) => {
244
+ execFile("podman", ["rm", "-f", containerName], (error) => {
245
+ if (error) {
246
+ reject(new Error(`podman rm failed: ${error.message}`));
247
+ } else {
248
+ resolve();
249
+ }
250
+ });
251
+ });
303
252
  }
304
- catch {
305
- reject(podmanMachineError());
253
+ };
254
+ return handle;
255
+ }
256
+ });
257
+ };
258
+ var checkImageExists = (imageName) => new Promise((resolve, reject) => {
259
+ execFile("podman", ["image", "inspect", imageName], (error) => {
260
+ if (error) {
261
+ reject(
262
+ new Error(
263
+ `Image '${imageName}' not found locally. Build it first with 'podman build -t ${imageName} .'`
264
+ )
265
+ );
266
+ } else {
267
+ resolve();
268
+ }
269
+ });
270
+ });
271
+ var podmanMachineError = () => new Error(
272
+ "Podman Machine is not running. Run 'podman machine init && podman machine start' first."
273
+ );
274
+ var checkPodmanMachine = () => new Promise((resolve, reject) => {
275
+ execFile(
276
+ "podman",
277
+ ["machine", "list", "--format", "json"],
278
+ (error, stdout) => {
279
+ if (error) {
280
+ reject(podmanMachineError());
281
+ return;
282
+ }
283
+ try {
284
+ const machines = JSON.parse(stdout.toString());
285
+ if (machines.some((m) => m.Running)) {
286
+ resolve();
287
+ } else {
288
+ reject(podmanMachineError());
306
289
  }
307
- });
290
+ } catch {
291
+ reject(podmanMachineError());
292
+ }
293
+ }
294
+ );
308
295
  });
296
+
297
+ export { podman };
298
+ //# sourceMappingURL=podman.js.map
309
299
  //# sourceMappingURL=podman.js.map