@ai-hero/sandcastle 0.5.0 → 0.5.4

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 (130) hide show
  1. package/README.md +104 -61
  2. package/dist/AgentProvider.d.ts +17 -1
  3. package/dist/AgentProvider.d.ts.map +1 -1
  4. package/dist/AgentProvider.js +75 -6
  5. package/dist/AgentProvider.js.map +1 -1
  6. package/dist/AgentStreamEmitter.d.ts +36 -0
  7. package/dist/AgentStreamEmitter.d.ts.map +1 -0
  8. package/dist/AgentStreamEmitter.js +21 -0
  9. package/dist/AgentStreamEmitter.js.map +1 -0
  10. package/dist/Display.js +1 -1
  11. package/dist/Display.js.map +1 -1
  12. package/dist/DockerLifecycle.d.ts +0 -10
  13. package/dist/DockerLifecycle.d.ts.map +1 -1
  14. package/dist/DockerLifecycle.js +0 -22
  15. package/dist/DockerLifecycle.js.map +1 -1
  16. package/dist/ErrorHandler.d.ts.map +1 -1
  17. package/dist/ErrorHandler.js +2 -0
  18. package/dist/ErrorHandler.js.map +1 -1
  19. package/dist/InitService.d.ts.map +1 -1
  20. package/dist/InitService.js +3 -1
  21. package/dist/InitService.js.map +1 -1
  22. package/dist/MountConfig.d.ts +1 -2
  23. package/dist/MountConfig.d.ts.map +1 -1
  24. package/dist/Orchestrator.d.ts +11 -5
  25. package/dist/Orchestrator.d.ts.map +1 -1
  26. package/dist/Orchestrator.js +81 -13
  27. package/dist/Orchestrator.js.map +1 -1
  28. package/dist/PodmanLifecycle.d.ts +0 -10
  29. package/dist/PodmanLifecycle.d.ts.map +1 -1
  30. package/dist/PodmanLifecycle.js +0 -22
  31. package/dist/PodmanLifecycle.js.map +1 -1
  32. package/dist/PromptArgumentSubstitution.d.ts +6 -0
  33. package/dist/PromptArgumentSubstitution.d.ts.map +1 -1
  34. package/dist/PromptArgumentSubstitution.js +32 -6
  35. package/dist/PromptArgumentSubstitution.js.map +1 -1
  36. package/dist/PromptPreprocessor.d.ts +8 -0
  37. package/dist/PromptPreprocessor.d.ts.map +1 -1
  38. package/dist/PromptPreprocessor.js +13 -9
  39. package/dist/PromptPreprocessor.js.map +1 -1
  40. package/dist/PromptResolver.d.ts +13 -1
  41. package/dist/PromptResolver.d.ts.map +1 -1
  42. package/dist/PromptResolver.js +3 -2
  43. package/dist/PromptResolver.js.map +1 -1
  44. package/dist/SandboxFactory.d.ts +5 -5
  45. package/dist/SandboxFactory.d.ts.map +1 -1
  46. package/dist/SandboxFactory.js +20 -10
  47. package/dist/SandboxFactory.js.map +1 -1
  48. package/dist/SandboxLifecycle.d.ts +4 -1
  49. package/dist/SandboxLifecycle.d.ts.map +1 -1
  50. package/dist/SandboxLifecycle.js +40 -12
  51. package/dist/SandboxLifecycle.js.map +1 -1
  52. package/dist/SandboxProvider.d.ts +30 -0
  53. package/dist/SandboxProvider.d.ts.map +1 -1
  54. package/dist/SandboxProvider.js +1 -0
  55. package/dist/SandboxProvider.js.map +1 -1
  56. package/dist/SessionPaths.d.ts +26 -0
  57. package/dist/SessionPaths.d.ts.map +1 -0
  58. package/dist/SessionPaths.js +20 -0
  59. package/dist/SessionPaths.js.map +1 -0
  60. package/dist/SessionStore.d.ts +2 -3
  61. package/dist/SessionStore.d.ts.map +1 -1
  62. package/dist/SessionStore.js +17 -15
  63. package/dist/SessionStore.js.map +1 -1
  64. package/dist/WorktreeManager.d.ts +6 -3
  65. package/dist/WorktreeManager.d.ts.map +1 -1
  66. package/dist/WorktreeManager.js +47 -5
  67. package/dist/WorktreeManager.js.map +1 -1
  68. package/dist/createSandbox.d.ts +32 -3
  69. package/dist/createSandbox.d.ts.map +1 -1
  70. package/dist/createSandbox.js +125 -58
  71. package/dist/createSandbox.js.map +1 -1
  72. package/dist/createWorktree.d.ts +32 -4
  73. package/dist/createWorktree.d.ts.map +1 -1
  74. package/dist/createWorktree.js +88 -27
  75. package/dist/createWorktree.js.map +1 -1
  76. package/dist/errors.d.ts +4 -2
  77. package/dist/errors.d.ts.map +1 -1
  78. package/dist/errors.js +2 -0
  79. package/dist/errors.js.map +1 -1
  80. package/dist/index.d.ts +5 -2
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +2 -0
  83. package/dist/index.js.map +1 -1
  84. package/dist/interactive.d.ts +19 -0
  85. package/dist/interactive.d.ts.map +1 -1
  86. package/dist/interactive.js +34 -14
  87. package/dist/interactive.js.map +1 -1
  88. package/dist/mountUtils.d.ts +104 -0
  89. package/dist/mountUtils.d.ts.map +1 -0
  90. package/dist/mountUtils.js +245 -0
  91. package/dist/mountUtils.js.map +1 -0
  92. package/dist/raceAbortSignal.d.ts +18 -0
  93. package/dist/raceAbortSignal.d.ts.map +1 -0
  94. package/dist/raceAbortSignal.js +32 -0
  95. package/dist/raceAbortSignal.js.map +1 -0
  96. package/dist/resolveCwd.d.ts +24 -0
  97. package/dist/resolveCwd.d.ts.map +1 -0
  98. package/dist/resolveCwd.js +32 -0
  99. package/dist/resolveCwd.js.map +1 -0
  100. package/dist/run.d.ts +56 -5
  101. package/dist/run.d.ts.map +1 -1
  102. package/dist/run.js +72 -21
  103. package/dist/run.js.map +1 -1
  104. package/dist/sandboxes/docker.d.ts +2 -6
  105. package/dist/sandboxes/docker.d.ts.map +1 -1
  106. package/dist/sandboxes/docker.js +44 -78
  107. package/dist/sandboxes/docker.js.map +1 -1
  108. package/dist/sandboxes/no-sandbox.d.ts.map +1 -1
  109. package/dist/sandboxes/no-sandbox.js +9 -1
  110. package/dist/sandboxes/no-sandbox.js.map +1 -1
  111. package/dist/sandboxes/podman.d.ts +19 -8
  112. package/dist/sandboxes/podman.d.ts.map +1 -1
  113. package/dist/sandboxes/podman.js +49 -87
  114. package/dist/sandboxes/podman.js.map +1 -1
  115. package/dist/startSandbox.d.ts.map +1 -1
  116. package/dist/startSandbox.js +8 -3
  117. package/dist/startSandbox.js.map +1 -1
  118. package/dist/templates/parallel-planner/implement-prompt.md +1 -1
  119. package/dist/templates/parallel-planner-with-review/implement-prompt.md +1 -1
  120. package/dist/templates/parallel-planner-with-review/main.mts +8 -1
  121. package/dist/templates/parallel-planner-with-review/review-prompt.md +2 -2
  122. package/dist/templates/sequential-reviewer/review-prompt.md +2 -2
  123. package/dist/testSandbox.d.ts.map +1 -1
  124. package/dist/testSandbox.js +38 -48
  125. package/dist/testSandbox.js.map +1 -1
  126. package/dist/testSetup.d.ts +2 -0
  127. package/dist/testSetup.d.ts.map +1 -0
  128. package/dist/testSetup.js +29 -0
  129. package/dist/testSetup.js.map +1 -0
  130. package/package.json +1 -1
@@ -0,0 +1,104 @@
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
+ import type { MountConfig } from "./MountConfig.js";
8
+ /**
9
+ * Deterministic mount point inside the sandbox for the parent repo's .git
10
+ * directory when the workspace is a git worktree. See ADR-0006.
11
+ */
12
+ export declare const PARENT_GIT_SANDBOX_DIR = "/.sandcastle-parent-git";
13
+ /**
14
+ * Derive the default image name from the repo directory.
15
+ * Returns `sandcastle:<dir-name>` where dir-name is the last path segment,
16
+ * lowercased and sanitized for image tag rules.
17
+ *
18
+ * Handles both POSIX (`/`) and Windows (`\`) path separators.
19
+ */
20
+ export declare const defaultImageName: (repoDir: string) => string;
21
+ /**
22
+ * Expand tilde (`~`) to the given home directory (or `os.homedir()` if omitted).
23
+ * Handles both `~/path` (POSIX) and `~\path` (Windows).
24
+ */
25
+ export declare const expandTilde: (p: string, homeDirPath?: string | undefined) => string;
26
+ /**
27
+ * Resolve a host path: expand tilde, then resolve relative paths from `process.cwd()`.
28
+ */
29
+ export declare const resolveHostPath: (hostPath: string) => string;
30
+ /**
31
+ * Resolve a sandbox path: expands tilde using `sandboxHomedir`, then resolves
32
+ * relative paths from `SANDBOX_REPO_DIR`.
33
+ *
34
+ * Throws if `sandboxPath` starts with `~` but `sandboxHomedir` is `undefined`.
35
+ */
36
+ export declare const resolveSandboxPath: (sandboxPath: string, sandboxHomedir?: string | undefined) => string;
37
+ /**
38
+ * Resolve and validate user-provided mount configurations.
39
+ * Throws if a hostPath does not exist on the filesystem.
40
+ * Throws if a sandboxPath uses tilde but `sandboxHomedir` is `undefined`.
41
+ */
42
+ export declare const resolveUserMounts: (mounts: readonly MountConfig[], sandboxHomedir?: string | undefined) => {
43
+ hostPath: string;
44
+ sandboxPath: string;
45
+ readonly?: boolean | undefined;
46
+ }[];
47
+ /**
48
+ * Normalize mount entries for cross-platform compatibility.
49
+ *
50
+ * On Windows (`platform === "win32"`):
51
+ * - Replaces backslashes with forward slashes in all `hostPath` values
52
+ * - Remaps `sandboxPath` values that look like Windows paths to valid POSIX
53
+ * paths relative to `sandboxRepoDir` when the host path is under the
54
+ * worktree host path
55
+ *
56
+ * On non-Windows platforms, returns mounts unchanged (preserving
57
+ * `sandboxPath === hostPath` for git mounts so that `gitdir:` references
58
+ * resolve correctly inside the container).
59
+ *
60
+ * This is a pure function — no filesystem access, accepts a `platform`
61
+ * parameter so it can be unit-tested with fake Windows paths.
62
+ */
63
+ export declare const normalizeMounts: <M extends {
64
+ hostPath: string;
65
+ sandboxPath: string;
66
+ }>(mounts: M[], worktreeHostPath: string, sandboxRepoDir: string, platform?: string) => M[];
67
+ /**
68
+ * Parse a `gitdir:` path into its parent .git directory and worktree name.
69
+ *
70
+ * The gitdir path is like `/path/to/repo/.git/worktrees/<name>` or
71
+ * `C:\Users\project\.git\worktrees\<name>`. We split on both `/` and `\`
72
+ * so this works regardless of the host platform or which platform runs tests.
73
+ */
74
+ export declare const parseGitdirPath: (gitdirPath: string) => {
75
+ parentGitDir: string;
76
+ worktreeName: string;
77
+ };
78
+ /**
79
+ * On Windows, patch git mounts so that worktree `.git` files resolve inside
80
+ * the Linux sandbox. See ADR-0006 for the full rationale.
81
+ *
82
+ * Two fixes are applied:
83
+ * 1. The parent `.git` directory mount is remapped to `PARENT_GIT_SANDBOX_DIR`.
84
+ * 2. A corrected `.git` file (with a POSIX `gitdir:` path) is created and
85
+ * mounted at `sandboxRepoDir/.git`, overlaying the original.
86
+ *
87
+ * On non-Windows platforms, or when the worktree's `.git` is a directory
88
+ * (not a worktree pointer), returns the mounts unchanged.
89
+ *
90
+ * @param gitMounts - Raw mounts from `resolveGitMounts`.
91
+ * @param worktreeHostPath - Host path to the directory mounted at `sandboxRepoDir`.
92
+ * @param sandboxRepoDir - Where the worktree is mounted inside the sandbox.
93
+ * @param readFile - Read a file's content (injectable for tests).
94
+ * @param statFile - Stat a file to check if it's a directory (injectable for tests).
95
+ * @param platform - Override for `process.platform` (injectable for tests).
96
+ */
97
+ export declare const patchGitMountsForWindows: (gitMounts: {
98
+ hostPath: string;
99
+ sandboxPath: string;
100
+ }[], worktreeHostPath: string, sandboxRepoDir: string, readFile?: ((path: string) => Promise<string>) | undefined, statFile?: ((path: string) => Promise<"directory" | "file">) | undefined, platform?: string) => Promise<{
101
+ hostPath: string;
102
+ sandboxPath: string;
103
+ }[]>;
104
+ //# sourceMappingURL=mountUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mountUtils.d.ts","sourceRoot":"","sources":["../src/mountUtils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,4BAA4B,CAAC;AAEhE;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,6BAQ5B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,yDAKvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,8BAG3B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,sEAiB9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;GAqB1B,CAAC;AAEL;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,eAAe,GAC1B,CAAC;;;2FAuCF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;CAS3B,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,wBAAwB;;;;;;IAwFpC,CAAC"}
@@ -0,0 +1,245 @@
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
+ import { existsSync } from "node:fs";
8
+ import { tmpdir, homedir } from "node:os";
9
+ import { isAbsolute, resolve, join } from "node:path";
10
+ import { mkdtemp, writeFile } from "node:fs/promises";
11
+ import { SANDBOX_REPO_DIR } from "./SandboxFactory.js";
12
+ /**
13
+ * Deterministic mount point inside the sandbox for the parent repo's .git
14
+ * directory when the workspace is a git worktree. See ADR-0006.
15
+ */
16
+ export const PARENT_GIT_SANDBOX_DIR = "/.sandcastle-parent-git";
17
+ /**
18
+ * Derive the default image name from the repo directory.
19
+ * Returns `sandcastle:<dir-name>` where dir-name is the last path segment,
20
+ * lowercased and sanitized for image tag rules.
21
+ *
22
+ * Handles both POSIX (`/`) and Windows (`\`) path separators.
23
+ */
24
+ export const defaultImageName = (repoDir) => {
25
+ const dirName = repoDir
26
+ .replace(/[\\/]+$/, "")
27
+ .split(/[\\/]/)
28
+ .pop() ?? "local";
29
+ const sanitized = dirName.toLowerCase().replace(/[^a-z0-9_.-]/g, "-");
30
+ return `sandcastle:${sanitized || "local"}`;
31
+ };
32
+ /**
33
+ * Expand tilde (`~`) to the given home directory (or `os.homedir()` if omitted).
34
+ * Handles both `~/path` (POSIX) and `~\path` (Windows).
35
+ */
36
+ export const expandTilde = (p, homeDirPath) => {
37
+ const home = homeDirPath ?? homedir();
38
+ if (p === "~")
39
+ return home;
40
+ if (p.startsWith("~/") || p.startsWith("~\\"))
41
+ return home + "/" + p.slice(2);
42
+ return p;
43
+ };
44
+ /**
45
+ * Resolve a host path: expand tilde, then resolve relative paths from `process.cwd()`.
46
+ */
47
+ export const resolveHostPath = (hostPath) => {
48
+ const expanded = expandTilde(hostPath);
49
+ return isAbsolute(expanded) ? expanded : resolve(process.cwd(), expanded);
50
+ };
51
+ /**
52
+ * Resolve a sandbox path: expands tilde using `sandboxHomedir`, then resolves
53
+ * relative paths from `SANDBOX_REPO_DIR`.
54
+ *
55
+ * Throws if `sandboxPath` starts with `~` but `sandboxHomedir` is `undefined`.
56
+ */
57
+ export const resolveSandboxPath = (sandboxPath, sandboxHomedir) => {
58
+ const hasTilde = sandboxPath === "~" ||
59
+ sandboxPath.startsWith("~/") ||
60
+ sandboxPath.startsWith("~\\");
61
+ if (hasTilde && sandboxHomedir === undefined) {
62
+ throw new Error(`sandboxPath "${sandboxPath}" contains a tilde but the provider has no sandboxHomedir set`);
63
+ }
64
+ const expanded = hasTilde
65
+ ? expandTilde(sandboxPath, sandboxHomedir)
66
+ : sandboxPath;
67
+ return isAbsolute(expanded) ? expanded : resolve(SANDBOX_REPO_DIR, expanded);
68
+ };
69
+ /**
70
+ * Resolve and validate user-provided mount configurations.
71
+ * Throws if a hostPath does not exist on the filesystem.
72
+ * Throws if a sandboxPath uses tilde but `sandboxHomedir` is `undefined`.
73
+ */
74
+ export const resolveUserMounts = (mounts, sandboxHomedir) => mounts.map((m) => {
75
+ const resolvedHostPath = resolveHostPath(m.hostPath);
76
+ if (!existsSync(resolvedHostPath)) {
77
+ throw new Error(`Mount hostPath does not exist: ${m.hostPath}` +
78
+ (m.hostPath !== resolvedHostPath
79
+ ? ` (resolved to ${resolvedHostPath})`
80
+ : ""));
81
+ }
82
+ return {
83
+ hostPath: resolvedHostPath,
84
+ sandboxPath: resolveSandboxPath(m.sandboxPath, sandboxHomedir),
85
+ ...(m.readonly ? { readonly: true } : {}),
86
+ };
87
+ });
88
+ /**
89
+ * Normalize mount entries for cross-platform compatibility.
90
+ *
91
+ * On Windows (`platform === "win32"`):
92
+ * - Replaces backslashes with forward slashes in all `hostPath` values
93
+ * - Remaps `sandboxPath` values that look like Windows paths to valid POSIX
94
+ * paths relative to `sandboxRepoDir` when the host path is under the
95
+ * worktree host path
96
+ *
97
+ * On non-Windows platforms, returns mounts unchanged (preserving
98
+ * `sandboxPath === hostPath` for git mounts so that `gitdir:` references
99
+ * resolve correctly inside the container).
100
+ *
101
+ * This is a pure function — no filesystem access, accepts a `platform`
102
+ * parameter so it can be unit-tested with fake Windows paths.
103
+ */
104
+ export const normalizeMounts = (mounts, worktreeHostPath, sandboxRepoDir, platform = process.platform) => {
105
+ if (platform !== "win32")
106
+ return mounts;
107
+ const normalizedWorktree = worktreeHostPath.replace(/\\/g, "/");
108
+ return mounts.map((m) => {
109
+ const hostPath = m.hostPath.replace(/\\/g, "/");
110
+ let sandboxPath = m.sandboxPath;
111
+ // If sandboxPath is already a valid POSIX absolute path (e.g., user-specified
112
+ // sandbox paths like /mnt/data or /home/agent/workspace), leave it as-is.
113
+ // Otherwise, normalize it — Windows-style sandboxPaths (from resolveGitMounts
114
+ // setting sandboxPath === hostPath) need remapping.
115
+ if (/^[A-Za-z]:[/\\]/.test(sandboxPath) || sandboxPath.includes("\\")) {
116
+ // This is a Windows-style path — remap it
117
+ const normalizedSandboxPath = sandboxPath.replace(/\\/g, "/");
118
+ if (normalizedSandboxPath.startsWith(normalizedWorktree + "/")) {
119
+ // Under the worktree: derive sandbox path relative to sandboxRepoDir
120
+ const relativeSuffix = normalizedSandboxPath.slice(normalizedWorktree.length);
121
+ sandboxPath = sandboxRepoDir + relativeSuffix;
122
+ }
123
+ else if (normalizedSandboxPath === normalizedWorktree) {
124
+ sandboxPath = sandboxRepoDir;
125
+ }
126
+ else {
127
+ // Not under the worktree — just normalize slashes
128
+ sandboxPath = normalizedSandboxPath;
129
+ }
130
+ }
131
+ return { ...m, hostPath, sandboxPath };
132
+ });
133
+ };
134
+ /**
135
+ * Parse a `gitdir:` path into its parent .git directory and worktree name.
136
+ *
137
+ * The gitdir path is like `/path/to/repo/.git/worktrees/<name>` or
138
+ * `C:\Users\project\.git\worktrees\<name>`. We split on both `/` and `\`
139
+ * so this works regardless of the host platform or which platform runs tests.
140
+ */
141
+ export const parseGitdirPath = (gitdirPath) => {
142
+ const normalized = gitdirPath.replace(/\\/g, "/").replace(/\/+$/, "");
143
+ const segments = normalized.split("/");
144
+ const worktreeName = segments.pop(); // <name>
145
+ segments.pop(); // "worktrees"
146
+ const parentGitDir = segments.join("/");
147
+ return { worktreeName, parentGitDir };
148
+ };
149
+ /**
150
+ * On Windows, patch git mounts so that worktree `.git` files resolve inside
151
+ * the Linux sandbox. See ADR-0006 for the full rationale.
152
+ *
153
+ * Two fixes are applied:
154
+ * 1. The parent `.git` directory mount is remapped to `PARENT_GIT_SANDBOX_DIR`.
155
+ * 2. A corrected `.git` file (with a POSIX `gitdir:` path) is created and
156
+ * mounted at `sandboxRepoDir/.git`, overlaying the original.
157
+ *
158
+ * On non-Windows platforms, or when the worktree's `.git` is a directory
159
+ * (not a worktree pointer), returns the mounts unchanged.
160
+ *
161
+ * @param gitMounts - Raw mounts from `resolveGitMounts`.
162
+ * @param worktreeHostPath - Host path to the directory mounted at `sandboxRepoDir`.
163
+ * @param sandboxRepoDir - Where the worktree is mounted inside the sandbox.
164
+ * @param readFile - Read a file's content (injectable for tests).
165
+ * @param statFile - Stat a file to check if it's a directory (injectable for tests).
166
+ * @param platform - Override for `process.platform` (injectable for tests).
167
+ */
168
+ export const patchGitMountsForWindows = async (gitMounts, worktreeHostPath, sandboxRepoDir, readFile, statFile, platform = process.platform) => {
169
+ if (platform !== "win32")
170
+ return gitMounts;
171
+ const _readFile = readFile ??
172
+ (async (p) => {
173
+ const { readFile: rf } = await import("node:fs/promises");
174
+ return rf(p, "utf-8");
175
+ });
176
+ const _statFile = statFile ??
177
+ (async (p) => {
178
+ const { stat } = await import("node:fs/promises");
179
+ const s = await stat(p);
180
+ return s.isDirectory() ? "directory" : "file";
181
+ });
182
+ // Check the worktree's .git entry
183
+ const gitEntryPath = join(worktreeHostPath, ".git");
184
+ let gitEntryType;
185
+ try {
186
+ gitEntryType = await _statFile(gitEntryPath);
187
+ }
188
+ catch {
189
+ return gitMounts;
190
+ }
191
+ if (gitEntryType === "directory")
192
+ return gitMounts;
193
+ // Read and parse the gitdir: line
194
+ let content;
195
+ try {
196
+ content = (await _readFile(gitEntryPath)).trim();
197
+ }
198
+ catch {
199
+ return gitMounts;
200
+ }
201
+ const match = content.match(/^gitdir:\s*(.+)$/);
202
+ if (!match)
203
+ return gitMounts;
204
+ const gitdirPath = match[1];
205
+ const { parentGitDir, worktreeName } = parseGitdirPath(gitdirPath);
206
+ // Create a temp file with the corrected gitdir content
207
+ const correctedGitdir = `${PARENT_GIT_SANDBOX_DIR}/worktrees/${worktreeName}`;
208
+ const tempDir = await mkdtemp(join(tmpdir(), "sandcastle-git-"));
209
+ const tempGitFile = join(tempDir, "git-override");
210
+ await writeFile(tempGitFile, `gitdir: ${correctedGitdir}\n`);
211
+ // Build corrected mounts
212
+ const normalizedParentGitDir = parentGitDir.replace(/\\/g, "/");
213
+ const gitFileHostPath = gitEntryPath.replace(/\\/g, "/");
214
+ const correctedMounts = [];
215
+ let replacedGitFile = false;
216
+ for (const m of gitMounts) {
217
+ const normalizedHostPath = m.hostPath.replace(/\\/g, "/");
218
+ if (normalizedHostPath === normalizedParentGitDir) {
219
+ // Remap parent .git dir to deterministic sandbox path
220
+ correctedMounts.push({ ...m, sandboxPath: PARENT_GIT_SANDBOX_DIR });
221
+ }
222
+ else if (normalizedHostPath === gitFileHostPath) {
223
+ // Replace .git file mount with corrected version (host repo is a worktree)
224
+ correctedMounts.push({
225
+ ...m,
226
+ hostPath: tempGitFile,
227
+ sandboxPath: `${sandboxRepoDir}/.git`,
228
+ });
229
+ replacedGitFile = true;
230
+ }
231
+ else {
232
+ correctedMounts.push(m);
233
+ }
234
+ }
235
+ // If the .git file wasn't in gitMounts (Sandcastle-created worktree),
236
+ // add an overlay mount for the corrected .git file
237
+ if (!replacedGitFile) {
238
+ correctedMounts.push({
239
+ hostPath: tempGitFile,
240
+ sandboxPath: `${sandboxRepoDir}/.git`,
241
+ });
242
+ }
243
+ return correctedMounts;
244
+ };
245
+ //# sourceMappingURL=mountUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mountUtils.js","sourceRoot":"","sources":["../src/mountUtils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { Effect } from "effect";
2
+ /**
3
+ * Race an Effect against an optional `AbortSignal`.
4
+ *
5
+ * - If no signal is provided, the effect runs unmodified.
6
+ * - If the signal is already aborted at call time, dies immediately with
7
+ * `signal.reason`.
8
+ * - Otherwise, races the effect against a Deferred that fires when the
9
+ * signal aborts.
10
+ *
11
+ * Uses `Effect.die` so the abort reason propagates as a defect — callers
12
+ * should use `signal.throwIfAborted()` in their catch handler to surface
13
+ * the original reason without Sandcastle-specific wrapping.
14
+ *
15
+ * The abort listener is always cleaned up, even when the effect wins the race.
16
+ */
17
+ export declare const raceAbortSignal: <A, E, R>(effect: Effect.Effect<A, E, R>, signal?: AbortSignal | undefined) => Effect.Effect<A, E, R>;
18
+ //# sourceMappingURL=raceAbortSignal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raceAbortSignal.d.ts","sourceRoot":"","sources":["../src/raceAbortSignal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE1C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,6FA4BtC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { Deferred, Effect } from "effect";
2
+ /**
3
+ * Race an Effect against an optional `AbortSignal`.
4
+ *
5
+ * - If no signal is provided, the effect runs unmodified.
6
+ * - If the signal is already aborted at call time, dies immediately with
7
+ * `signal.reason`.
8
+ * - Otherwise, races the effect against a Deferred that fires when the
9
+ * signal aborts.
10
+ *
11
+ * Uses `Effect.die` so the abort reason propagates as a defect — callers
12
+ * should use `signal.throwIfAborted()` in their catch handler to surface
13
+ * the original reason without Sandcastle-specific wrapping.
14
+ *
15
+ * The abort listener is always cleaned up, even when the effect wins the race.
16
+ */
17
+ export const raceAbortSignal = (effect, signal) => {
18
+ if (!signal)
19
+ return effect;
20
+ return Effect.gen(function* () {
21
+ if (signal.aborted) {
22
+ return yield* Effect.die(signal.reason);
23
+ }
24
+ const abortDeferred = yield* Deferred.make();
25
+ const onAbort = () => {
26
+ Effect.runPromise(Deferred.die(abortDeferred, signal.reason)).catch(() => { });
27
+ };
28
+ signal.addEventListener("abort", onAbort, { once: true });
29
+ return yield* Effect.raceFirst(effect, Deferred.await(abortDeferred)).pipe(Effect.ensuring(Effect.sync(() => signal.removeEventListener("abort", onAbort))));
30
+ });
31
+ };
32
+ //# sourceMappingURL=raceAbortSignal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raceAbortSignal.js","sourceRoot":"","sources":["../src/raceAbortSignal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE1C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,MAA8B,EAC9B,MAAoB,EACI,EAAE;IAC1B,IAAI,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC;IAE3B,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC;QAED,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAgB,CAAC;QAC3D,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CACjE,GAAG,EAAE,GAAE,CAAC,CACT,CAAC;QACJ,CAAC,CAAC;QACF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1D,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAC5B,MAAM,EACN,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAuC,CACpE,CAAC,IAAI,CACJ,MAAM,CAAC,QAAQ,CACb,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAChE,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { FileSystem } from "@effect/platform";
2
+ import { Effect } from "effect";
3
+ declare const CwdError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
4
+ readonly _tag: "CwdError";
5
+ } & Readonly<A>;
6
+ /** The provided `cwd` path does not exist or is not a directory. */
7
+ export declare class CwdError extends CwdError_base<{
8
+ readonly message: string;
9
+ readonly cwd: string;
10
+ }> {
11
+ }
12
+ /**
13
+ * Resolve an optional `cwd` string to an absolute, validated host repo directory.
14
+ *
15
+ * - `undefined` → `process.cwd()` (resolved to absolute).
16
+ * - Relative path → resolved against `process.cwd()`.
17
+ * - Absolute path → passed through.
18
+ *
19
+ * Stats the result via Effect's `FileSystem`; fails with {@link CwdError}
20
+ * when the path is missing or is not a directory.
21
+ */
22
+ export declare const resolveCwd: (cwd: string | undefined) => Effect.Effect<string, CwdError, FileSystem.FileSystem>;
23
+ export {};
24
+ //# sourceMappingURL=resolveCwd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveCwd.d.ts","sourceRoot":"","sources":["../src/resolveCwd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;AAEtC,oEAAoE;AACpE,qBAAa,QAAS,SAAQ,cAA6B;IACzD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB,CAAC;CAAG;AAEL;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,qFA0BnB,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { FileSystem } from "@effect/platform";
2
+ import { resolve } from "node:path";
3
+ import { Data, Effect } from "effect";
4
+ /** The provided `cwd` path does not exist or is not a directory. */
5
+ export class CwdError extends Data.TaggedError("CwdError") {
6
+ }
7
+ /**
8
+ * Resolve an optional `cwd` string to an absolute, validated host repo directory.
9
+ *
10
+ * - `undefined` → `process.cwd()` (resolved to absolute).
11
+ * - Relative path → resolved against `process.cwd()`.
12
+ * - Absolute path → passed through.
13
+ *
14
+ * Stats the result via Effect's `FileSystem`; fails with {@link CwdError}
15
+ * when the path is missing or is not a directory.
16
+ */
17
+ export const resolveCwd = (cwd) => Effect.gen(function* () {
18
+ const resolved = cwd !== undefined ? resolve(process.cwd(), cwd) : resolve(process.cwd());
19
+ const fs = yield* FileSystem.FileSystem;
20
+ const stat = yield* fs.stat(resolved).pipe(Effect.mapError(() => new CwdError({
21
+ message: `cwd does not exist: ${resolved}`,
22
+ cwd: resolved,
23
+ })));
24
+ if (stat.type !== "Directory") {
25
+ return yield* new CwdError({
26
+ message: `cwd is not a directory: ${resolved}`,
27
+ cwd: resolved,
28
+ });
29
+ }
30
+ return resolved;
31
+ });
32
+ //# sourceMappingURL=resolveCwd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveCwd.js","sourceRoot":"","sources":["../src/resolveCwd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEtC,oEAAoE;AACpE,MAAM,OAAO,QAAS,SAAQ,IAAI,CAAC,WAAW,CAAC,UAAU,CAGvD;CAAG;AAEL;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,GAAuB,EACiC,EAAE,CAC1D,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,QAAQ,GACZ,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAE3E,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IAExC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CACxC,MAAM,CAAC,QAAQ,CACb,GAAG,EAAE,CACH,IAAI,QAAQ,CAAC;QACX,OAAO,EAAE,uBAAuB,QAAQ,EAAE;QAC1C,GAAG,EAAE,QAAQ;KACd,CAAC,CACL,CACF,CAAC;IACF,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC,CAAC,IAAI,QAAQ,CAAC;YACzB,OAAO,EAAE,2BAA2B,QAAQ,EAAE;YAC9C,GAAG,EAAE,QAAQ;SACd,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/run.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import type { AgentProvider } from "./AgentProvider.js";
2
2
  import { type Severity } from "./Display.js";
3
- import { type IterationResult } from "./Orchestrator.js";
3
+ import { type IterationResult, type IterationUsage } from "./Orchestrator.js";
4
4
  import type { SandboxProvider, BranchStrategy } from "./SandboxProvider.js";
5
+ import { type AgentStreamEvent } from "./AgentStreamEmitter.js";
5
6
  import type { SandboxHooks } from "./SandboxLifecycle.js";
6
7
  import { type PromptArgs } from "./PromptArgumentSubstitution.js";
7
8
  /** Default maximum number of iterations for a run. */
@@ -12,6 +13,11 @@ export interface FileDisplayStartupOptions {
12
13
  readonly logPath: string;
13
14
  readonly agentName?: string;
14
15
  readonly branch?: string;
16
+ /** Resolved host repo directory. When it differs from `process.cwd()`, the
17
+ * log-file hint is printed as an absolute path so it can be pasted into any
18
+ * terminal. When it equals `process.cwd()` (or is omitted), a relative path
19
+ * is printed instead. */
20
+ readonly hostRepoDir?: string;
15
21
  }
16
22
  /**
17
23
  * Print the startup message to the terminal when using file-based logging.
@@ -48,6 +54,18 @@ export declare const buildCompletionMessage: (completionSignal: string | undefin
48
54
  readonly message: string;
49
55
  readonly severity: Severity;
50
56
  };
57
+ /**
58
+ * Format the context window size from an iteration's usage data.
59
+ * Returns a string like "103k" representing the total input-side tokens
60
+ * (inputTokens + cacheCreationInputTokens + cacheReadInputTokens)
61
+ * rounded up to the nearest 1000.
62
+ */
63
+ export declare const formatContextWindowSize: (usage: IterationUsage) => string;
64
+ /**
65
+ * Build "Context window: NNNk" lines for iterations that have usage data.
66
+ * Returns an empty array when no iterations carry usage.
67
+ */
68
+ export declare const buildContextWindowLines: (iterations: readonly Pick<IterationResult, "usage">[]) => string[];
51
69
  /**
52
70
  * Controls where Sandcastle writes iteration progress and agent output.
53
71
  * Use `"file"` (log-to-file mode) to write to a log file on disk, or
@@ -58,6 +76,13 @@ export type LoggingOption =
58
76
  {
59
77
  readonly type: "file";
60
78
  readonly path: string;
79
+ /**
80
+ * Optional callback invoked for each agent stream event (text chunk or
81
+ * tool call) in addition to being written to the log file. Intended for
82
+ * forwarding the agent's output stream to external observability
83
+ * systems. Errors thrown by the callback are swallowed.
84
+ */
85
+ readonly onAgentStreamEvent?: (event: AgentStreamEvent) => void;
61
86
  }
62
87
  /** Render progress and agent output as an interactive UI in the terminal (terminal mode). */
63
88
  | {
@@ -68,9 +93,25 @@ export interface RunOptions {
68
93
  readonly agent: AgentProvider;
69
94
  /** Sandbox provider (e.g. docker({ imageName: "sandcastle:myrepo" })). */
70
95
  readonly sandbox: SandboxProvider;
96
+ /**
97
+ * Host repo directory. Replaces `process.cwd()` as the anchor for
98
+ * `.sandcastle/worktrees/`, `.sandcastle/.env`, `.sandcastle/logs/`,
99
+ * `.sandcastle/patches/`, and git operations.
100
+ *
101
+ * - Relative paths are resolved against `process.cwd()`.
102
+ * - Absolute paths are used as-is.
103
+ * - Defaults to `process.cwd()` when omitted.
104
+ */
105
+ readonly cwd?: string;
71
106
  /** Inline prompt string (mutually exclusive with promptFile) */
72
107
  readonly prompt?: string;
73
- /** Path to a prompt file (mutually exclusive with prompt) */
108
+ /**
109
+ * Path to a prompt file (mutually exclusive with prompt).
110
+ *
111
+ * **Note:** `promptFile` is always resolved against `process.cwd()`, not
112
+ * against the `cwd` option. If you set a custom `cwd`, pass an absolute
113
+ * `promptFile` to avoid ambiguity.
114
+ */
74
115
  readonly promptFile?: string;
75
116
  /** Maximum iterations to run (default: 1) */
76
117
  readonly maxIterations?: number;
@@ -91,12 +132,22 @@ export interface RunOptions {
91
132
  /** Branch strategy — controls how the agent's changes relate to branches.
92
133
  * Defaults to { type: "head" } for bind-mount providers and { type: "merge-to-head" } for isolated providers. */
93
134
  readonly branchStrategy?: BranchStrategy;
94
- /** When false, reuse an existing worktree for the target branch instead of failing on collision. Default: true. */
95
- readonly throwOnDuplicateWorktree?: boolean;
96
135
  /** Resume a prior Claude Code session by ID. The session JSONL must exist on the host. Incompatible with maxIterations > 1. */
97
136
  readonly resumeSession?: string;
137
+ /**
138
+ * An `AbortSignal` that cancels the run when aborted.
139
+ *
140
+ * - If `signal.aborted` is already `true` at entry, `run()` rejects
141
+ * immediately without doing any setup work.
142
+ * - Aborting mid-iteration kills the in-flight agent subprocess.
143
+ * - Phase boundaries (between iterations) also check the signal.
144
+ * - The rejected promise surfaces `signal.reason` via
145
+ * `signal.throwIfAborted()` — no Sandcastle-specific wrapping.
146
+ * - The worktree is preserved on disk after abort (error-path behavior).
147
+ */
148
+ readonly signal?: AbortSignal;
98
149
  }
99
- export type { IterationResult } from "./Orchestrator.js";
150
+ export type { IterationResult, IterationUsage } from "./Orchestrator.js";
100
151
  export interface RunResult {
101
152
  /** Per-iteration results (use `iterations.length` for the count). */
102
153
  readonly iterations: IterationResult[];
package/dist/run.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}