@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.
- package/README.md +104 -61
- package/dist/AgentProvider.d.ts +17 -1
- package/dist/AgentProvider.d.ts.map +1 -1
- package/dist/AgentProvider.js +75 -6
- package/dist/AgentProvider.js.map +1 -1
- package/dist/AgentStreamEmitter.d.ts +36 -0
- package/dist/AgentStreamEmitter.d.ts.map +1 -0
- package/dist/AgentStreamEmitter.js +21 -0
- package/dist/AgentStreamEmitter.js.map +1 -0
- package/dist/Display.js +1 -1
- package/dist/Display.js.map +1 -1
- package/dist/DockerLifecycle.d.ts +0 -10
- package/dist/DockerLifecycle.d.ts.map +1 -1
- package/dist/DockerLifecycle.js +0 -22
- package/dist/DockerLifecycle.js.map +1 -1
- package/dist/ErrorHandler.d.ts.map +1 -1
- package/dist/ErrorHandler.js +2 -0
- package/dist/ErrorHandler.js.map +1 -1
- package/dist/InitService.d.ts.map +1 -1
- package/dist/InitService.js +3 -1
- package/dist/InitService.js.map +1 -1
- package/dist/MountConfig.d.ts +1 -2
- package/dist/MountConfig.d.ts.map +1 -1
- package/dist/Orchestrator.d.ts +11 -5
- package/dist/Orchestrator.d.ts.map +1 -1
- package/dist/Orchestrator.js +81 -13
- package/dist/Orchestrator.js.map +1 -1
- package/dist/PodmanLifecycle.d.ts +0 -10
- package/dist/PodmanLifecycle.d.ts.map +1 -1
- package/dist/PodmanLifecycle.js +0 -22
- package/dist/PodmanLifecycle.js.map +1 -1
- package/dist/PromptArgumentSubstitution.d.ts +6 -0
- package/dist/PromptArgumentSubstitution.d.ts.map +1 -1
- package/dist/PromptArgumentSubstitution.js +32 -6
- package/dist/PromptArgumentSubstitution.js.map +1 -1
- package/dist/PromptPreprocessor.d.ts +8 -0
- package/dist/PromptPreprocessor.d.ts.map +1 -1
- package/dist/PromptPreprocessor.js +13 -9
- package/dist/PromptPreprocessor.js.map +1 -1
- package/dist/PromptResolver.d.ts +13 -1
- package/dist/PromptResolver.d.ts.map +1 -1
- package/dist/PromptResolver.js +3 -2
- package/dist/PromptResolver.js.map +1 -1
- package/dist/SandboxFactory.d.ts +5 -5
- package/dist/SandboxFactory.d.ts.map +1 -1
- package/dist/SandboxFactory.js +20 -10
- package/dist/SandboxFactory.js.map +1 -1
- package/dist/SandboxLifecycle.d.ts +4 -1
- package/dist/SandboxLifecycle.d.ts.map +1 -1
- package/dist/SandboxLifecycle.js +40 -12
- package/dist/SandboxLifecycle.js.map +1 -1
- package/dist/SandboxProvider.d.ts +30 -0
- package/dist/SandboxProvider.d.ts.map +1 -1
- package/dist/SandboxProvider.js +1 -0
- package/dist/SandboxProvider.js.map +1 -1
- package/dist/SessionPaths.d.ts +26 -0
- package/dist/SessionPaths.d.ts.map +1 -0
- package/dist/SessionPaths.js +20 -0
- package/dist/SessionPaths.js.map +1 -0
- package/dist/SessionStore.d.ts +2 -3
- package/dist/SessionStore.d.ts.map +1 -1
- package/dist/SessionStore.js +17 -15
- package/dist/SessionStore.js.map +1 -1
- package/dist/WorktreeManager.d.ts +6 -3
- package/dist/WorktreeManager.d.ts.map +1 -1
- package/dist/WorktreeManager.js +47 -5
- package/dist/WorktreeManager.js.map +1 -1
- package/dist/createSandbox.d.ts +32 -3
- package/dist/createSandbox.d.ts.map +1 -1
- package/dist/createSandbox.js +125 -58
- package/dist/createSandbox.js.map +1 -1
- package/dist/createWorktree.d.ts +32 -4
- package/dist/createWorktree.d.ts.map +1 -1
- package/dist/createWorktree.js +88 -27
- package/dist/createWorktree.js.map +1 -1
- package/dist/errors.d.ts +4 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/interactive.d.ts +19 -0
- package/dist/interactive.d.ts.map +1 -1
- package/dist/interactive.js +34 -14
- package/dist/interactive.js.map +1 -1
- package/dist/mountUtils.d.ts +104 -0
- package/dist/mountUtils.d.ts.map +1 -0
- package/dist/mountUtils.js +245 -0
- package/dist/mountUtils.js.map +1 -0
- package/dist/raceAbortSignal.d.ts +18 -0
- package/dist/raceAbortSignal.d.ts.map +1 -0
- package/dist/raceAbortSignal.js +32 -0
- package/dist/raceAbortSignal.js.map +1 -0
- package/dist/resolveCwd.d.ts +24 -0
- package/dist/resolveCwd.d.ts.map +1 -0
- package/dist/resolveCwd.js +32 -0
- package/dist/resolveCwd.js.map +1 -0
- package/dist/run.d.ts +56 -5
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +72 -21
- package/dist/run.js.map +1 -1
- package/dist/sandboxes/docker.d.ts +2 -6
- package/dist/sandboxes/docker.d.ts.map +1 -1
- package/dist/sandboxes/docker.js +44 -78
- package/dist/sandboxes/docker.js.map +1 -1
- package/dist/sandboxes/no-sandbox.d.ts.map +1 -1
- package/dist/sandboxes/no-sandbox.js +9 -1
- package/dist/sandboxes/no-sandbox.js.map +1 -1
- package/dist/sandboxes/podman.d.ts +19 -8
- package/dist/sandboxes/podman.d.ts.map +1 -1
- package/dist/sandboxes/podman.js +49 -87
- package/dist/sandboxes/podman.js.map +1 -1
- package/dist/startSandbox.d.ts.map +1 -1
- package/dist/startSandbox.js +8 -3
- package/dist/startSandbox.js.map +1 -1
- package/dist/templates/parallel-planner/implement-prompt.md +1 -1
- package/dist/templates/parallel-planner-with-review/implement-prompt.md +1 -1
- package/dist/templates/parallel-planner-with-review/main.mts +8 -1
- package/dist/templates/parallel-planner-with-review/review-prompt.md +2 -2
- package/dist/templates/sequential-reviewer/review-prompt.md +2 -2
- package/dist/testSandbox.d.ts.map +1 -1
- package/dist/testSandbox.js +38 -48
- package/dist/testSandbox.js.map +1 -1
- package/dist/testSetup.d.ts +2 -0
- package/dist/testSetup.d.ts.map +1 -0
- package/dist/testSetup.js +29 -0
- package/dist/testSetup.js.map +1 -0
- 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
|
-
/**
|
|
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":"
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
|