@ai-hero/sandcastle 0.5.12 → 0.6.1
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 +106 -79
- package/dist/AgentProvider.d.ts +56 -3
- package/dist/AgentProvider.d.ts.map +1 -1
- package/dist/AgentProvider.js +324 -9
- package/dist/AgentProvider.js.map +1 -1
- package/dist/DockerLifecycle.d.ts +6 -0
- package/dist/DockerLifecycle.d.ts.map +1 -1
- package/dist/DockerLifecycle.js +12 -0
- package/dist/DockerLifecycle.js.map +1 -1
- package/dist/InitService.d.ts.map +1 -1
- package/dist/InitService.js +115 -14
- package/dist/InitService.js.map +1 -1
- package/dist/Orchestrator.d.ts +4 -2
- package/dist/Orchestrator.d.ts.map +1 -1
- package/dist/Orchestrator.js +15 -14
- package/dist/Orchestrator.js.map +1 -1
- package/dist/SandboxFactory.d.ts.map +1 -1
- package/dist/SandboxFactory.js +51 -64
- package/dist/SandboxFactory.js.map +1 -1
- package/dist/SandboxLifecycle.d.ts +3 -0
- package/dist/SandboxLifecycle.d.ts.map +1 -1
- package/dist/SandboxLifecycle.js +44 -18
- package/dist/SandboxLifecycle.js.map +1 -1
- package/dist/SessionStore.d.ts +71 -10
- package/dist/SessionStore.d.ts.map +1 -1
- package/dist/SessionStore.js +222 -17
- package/dist/SessionStore.js.map +1 -1
- package/dist/WorktreeManager.d.ts +27 -0
- package/dist/WorktreeManager.d.ts.map +1 -1
- package/dist/WorktreeManager.js +50 -8
- package/dist/WorktreeManager.js.map +1 -1
- package/dist/boundedTail.d.ts +48 -0
- package/dist/boundedTail.d.ts.map +1 -0
- package/dist/boundedTail.js +64 -0
- package/dist/boundedTail.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +19 -3
- package/dist/cli.js.map +1 -1
- package/dist/createSandbox.d.ts.map +1 -1
- package/dist/createSandbox.js +116 -122
- package/dist/createSandbox.js.map +1 -1
- package/dist/createWorktree.d.ts.map +1 -1
- package/dist/createWorktree.js +10 -9
- package/dist/createWorktree.js.map +1 -1
- package/dist/errors.d.ts +3 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/interactive.d.ts.map +1 -1
- package/dist/interactive.js +55 -46
- package/dist/interactive.js.map +1 -1
- package/dist/resumePrecheck.d.ts +26 -0
- package/dist/resumePrecheck.d.ts.map +1 -0
- package/dist/resumePrecheck.js +40 -0
- package/dist/resumePrecheck.js.map +1 -0
- package/dist/run.d.ts +15 -5
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +23 -9
- package/dist/run.js.map +1 -1
- package/dist/sandboxes/daytona.d.ts +9 -0
- package/dist/sandboxes/daytona.d.ts.map +1 -1
- package/dist/sandboxes/daytona.js +9 -7
- package/dist/sandboxes/daytona.js.map +1 -1
- package/dist/sandboxes/docker.d.ts +45 -0
- package/dist/sandboxes/docker.d.ts.map +1 -1
- package/dist/sandboxes/docker.js +40 -28
- package/dist/sandboxes/docker.js.map +1 -1
- package/dist/sandboxes/no-sandbox.d.ts +9 -0
- package/dist/sandboxes/no-sandbox.d.ts.map +1 -1
- package/dist/sandboxes/no-sandbox.js +32 -17
- package/dist/sandboxes/no-sandbox.js.map +1 -1
- package/dist/sandboxes/podman.d.ts +47 -0
- package/dist/sandboxes/podman.d.ts.map +1 -1
- package/dist/sandboxes/podman.js +49 -28
- package/dist/sandboxes/podman.js.map +1 -1
- package/dist/sandboxes/test-bind-mount.d.ts.map +1 -1
- package/dist/sandboxes/test-bind-mount.js +7 -6
- package/dist/sandboxes/test-bind-mount.js.map +1 -1
- package/dist/sandboxes/test-isolated.d.ts.map +1 -1
- package/dist/sandboxes/test-isolated.js +7 -6
- package/dist/sandboxes/test-isolated.js.map +1 -1
- package/dist/sandboxes/vercel.d.ts +9 -0
- package/dist/sandboxes/vercel.d.ts.map +1 -1
- package/dist/sandboxes/vercel.js +9 -7
- package/dist/sandboxes/vercel.js.map +1 -1
- package/dist/shutdownRegistry.d.ts +30 -0
- package/dist/shutdownRegistry.d.ts.map +1 -0
- package/dist/shutdownRegistry.js +73 -0
- package/dist/shutdownRegistry.js.map +1 -0
- package/dist/syncOut.js +1 -1
- package/dist/syncOut.js.map +1 -1
- package/dist/templates/parallel-planner/main.mts +19 -17
- package/dist/templates/parallel-planner/plan-prompt.md +4 -2
- package/dist/templates/parallel-planner-with-review/main.mts +19 -17
- package/dist/templates/parallel-planner-with-review/plan-prompt.md +4 -2
- package/dist/templates/parallel-planner-with-review/review-prompt.md +2 -2
- package/dist/templates/sequential-reviewer/main.mts +13 -5
- package/dist/templates/sequential-reviewer/review-prompt.md +2 -2
- package/dist/templates/simple-loop/main.mts +1 -1
- package/dist/testSandbox.d.ts.map +1 -1
- package/dist/testSandbox.js +32 -19
- package/dist/testSandbox.js.map +1 -1
- package/package.json +3 -2
- package/dist/SessionPaths.d.ts +0 -26
- package/dist/SessionPaths.d.ts.map +0 -1
- package/dist/SessionPaths.js +0 -22
- package/dist/SessionPaths.js.map +0 -1
package/README.md
CHANGED
|
@@ -154,6 +154,14 @@ const result = await run({
|
|
|
154
154
|
env: { DOCKER_SPECIFIC: "value" },
|
|
155
155
|
// Optional: attach container to Docker network(s) — string or string[]
|
|
156
156
|
network: "my-network",
|
|
157
|
+
// Optional: add the container user to supplementary groups via --group-add.
|
|
158
|
+
// Accepts group names or numeric GIDs (e.g. for a bind-mounted Docker socket).
|
|
159
|
+
groups: ["docker", 999],
|
|
160
|
+
// Optional: expose host devices via --device. Each entry is a full device
|
|
161
|
+
// spec in host[:container[:permissions]] form (e.g. "/dev/kvm").
|
|
162
|
+
devices: ["/dev/kvm"],
|
|
163
|
+
// Optional: limit CPU resources via --cpus. Fractional values allowed (e.g. 1.5).
|
|
164
|
+
// cpus: 2,
|
|
157
165
|
}),
|
|
158
166
|
|
|
159
167
|
// Host repo directory — replaces process.cwd() as the anchor for
|
|
@@ -200,6 +208,9 @@ const result = await run({
|
|
|
200
208
|
// Unset keys keep their defaults.
|
|
201
209
|
timeouts: {
|
|
202
210
|
copyToWorktreeMs: 120_000, // default: 60_000
|
|
211
|
+
gitSetupMs: 30_000, // default: 10_000
|
|
212
|
+
commitCollectionMs: 60_000, // default: 30_000
|
|
213
|
+
mergeToHostMs: 60_000, // default: 30_000
|
|
203
214
|
},
|
|
204
215
|
|
|
205
216
|
// How to record progress. Default: write to a file under .sandcastle/logs/
|
|
@@ -308,14 +319,14 @@ if (closeResult.preservedWorktreePath) {
|
|
|
308
319
|
|
|
309
320
|
#### `CreateSandboxOptions`
|
|
310
321
|
|
|
311
|
-
| Option | Type | Default | Description
|
|
312
|
-
| ---------------- | --------------- | --------------- |
|
|
313
|
-
| `branch` | string | — | **Required.** Explicit branch for the sandbox
|
|
314
|
-
| `sandbox` | SandboxProvider | — | **Required.** Sandbox provider (e.g. `docker()`, `podman()`)
|
|
315
|
-
| `cwd` | string | `process.cwd()` | Host repo directory — relative paths resolve against `process.cwd()`
|
|
316
|
-
| `hooks` | SandboxHooks | — | Lifecycle hooks (`host.*`, `sandbox.*`) — run once at creation time
|
|
317
|
-
| `copyToWorktree` | string[] | — | Host-relative file paths to copy into the sandbox at creation time
|
|
318
|
-
| `timeouts` | Timeouts | — | Override
|
|
322
|
+
| Option | Type | Default | Description |
|
|
323
|
+
| ---------------- | --------------- | --------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
324
|
+
| `branch` | string | — | **Required.** Explicit branch for the sandbox |
|
|
325
|
+
| `sandbox` | SandboxProvider | — | **Required.** Sandbox provider (e.g. `docker()`, `podman()`) |
|
|
326
|
+
| `cwd` | string | `process.cwd()` | Host repo directory — relative paths resolve against `process.cwd()` |
|
|
327
|
+
| `hooks` | SandboxHooks | — | Lifecycle hooks (`host.*`, `sandbox.*`) — run once at creation time |
|
|
328
|
+
| `copyToWorktree` | string[] | — | Host-relative file paths to copy into the sandbox at creation time |
|
|
329
|
+
| `timeouts` | Timeouts | — | Override built-in lifecycle step timeouts (`copyToWorktreeMs`, `gitSetupMs`, `commitCollectionMs`, `mergeToHostMs`) |
|
|
319
330
|
|
|
320
331
|
#### `Sandbox`
|
|
321
332
|
|
|
@@ -414,11 +425,11 @@ await sandbox.close();
|
|
|
414
425
|
|
|
415
426
|
#### `CreateWorktreeOptions`
|
|
416
427
|
|
|
417
|
-
| Option | Type | Default | Description
|
|
418
|
-
| ---------------- | ---------------------- | ------- |
|
|
419
|
-
| `branchStrategy` | WorktreeBranchStrategy | — | **Required.** `{ type: "branch", branch }` or `{ type: "merge-to-head" }`
|
|
420
|
-
| `copyToWorktree` | string[] | — | Host-relative file paths to copy into the worktree at creation time
|
|
421
|
-
| `timeouts` | Timeouts | — | Override
|
|
428
|
+
| Option | Type | Default | Description |
|
|
429
|
+
| ---------------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
430
|
+
| `branchStrategy` | WorktreeBranchStrategy | — | **Required.** `{ type: "branch", branch }` or `{ type: "merge-to-head" }` |
|
|
431
|
+
| `copyToWorktree` | string[] | — | Host-relative file paths to copy into the worktree at creation time |
|
|
432
|
+
| `timeouts` | Timeouts | — | Override built-in lifecycle step timeouts (`copyToWorktreeMs`, `gitSetupMs`, `commitCollectionMs`, `mergeToHostMs`) |
|
|
422
433
|
|
|
423
434
|
#### `Worktree`
|
|
424
435
|
|
|
@@ -448,22 +459,22 @@ await sandbox.close();
|
|
|
448
459
|
|
|
449
460
|
#### `WorktreeRunOptions`
|
|
450
461
|
|
|
451
|
-
| Option | Type | Default | Description
|
|
452
|
-
| -------------------- | ---------------------- | ------- |
|
|
453
|
-
| `agent` | AgentProvider | — | **Required.** Agent provider
|
|
454
|
-
| `sandbox` | SandboxProvider | — | **Required.** Sandbox provider (AFK agents must be sandboxed)
|
|
455
|
-
| `prompt` | string | — | Inline prompt (mutually exclusive with `promptFile`)
|
|
456
|
-
| `promptFile` | string | — | Path to prompt file
|
|
457
|
-
| `maxIterations` | number | 1 | Maximum iterations to run
|
|
458
|
-
| `completionSignal` | string \| string[] | — | Substring(s) to stop the iteration loop early
|
|
459
|
-
| `idleTimeoutSeconds` | number | 600 | Idle timeout in seconds
|
|
460
|
-
| `name` | string | — | Optional run name
|
|
461
|
-
| `logging` | LoggingOption | file | Logging mode
|
|
462
|
-
| `hooks` | SandboxHooks | — | Lifecycle hooks (`host.*`, `sandbox.*`)
|
|
463
|
-
| `promptArgs` | PromptArgs | — | Key-value map for `{{KEY}}` placeholder substitution
|
|
464
|
-
| `env` | Record<string, string> | — | Environment variables to inject into the sandbox
|
|
465
|
-
| `resumeSession` | string | — | Resume a prior
|
|
466
|
-
| `signal` | AbortSignal | — | Cancel the run when aborted. Kills the in-flight agent subprocess; the worktree is preserved on disk. Rejects with `signal.reason`.
|
|
462
|
+
| Option | Type | Default | Description |
|
|
463
|
+
| -------------------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
464
|
+
| `agent` | AgentProvider | — | **Required.** Agent provider |
|
|
465
|
+
| `sandbox` | SandboxProvider | — | **Required.** Sandbox provider (AFK agents must be sandboxed) |
|
|
466
|
+
| `prompt` | string | — | Inline prompt (mutually exclusive with `promptFile`) |
|
|
467
|
+
| `promptFile` | string | — | Path to prompt file |
|
|
468
|
+
| `maxIterations` | number | 1 | Maximum iterations to run |
|
|
469
|
+
| `completionSignal` | string \| string[] | — | Substring(s) to stop the iteration loop early |
|
|
470
|
+
| `idleTimeoutSeconds` | number | 600 | Idle timeout in seconds |
|
|
471
|
+
| `name` | string | — | Optional run name |
|
|
472
|
+
| `logging` | LoggingOption | file | Logging mode |
|
|
473
|
+
| `hooks` | SandboxHooks | — | Lifecycle hooks (`host.*`, `sandbox.*`) |
|
|
474
|
+
| `promptArgs` | PromptArgs | — | Key-value map for `{{KEY}}` placeholder substitution |
|
|
475
|
+
| `env` | Record<string, string> | — | Environment variables to inject into the sandbox |
|
|
476
|
+
| `resumeSession` | string | — | Resume a prior session by ID for agents that support resume. Incompatible with `maxIterations > 1`. Session file must exist on host. |
|
|
477
|
+
| `signal` | AbortSignal | — | Cancel the run when aborted. Kills the in-flight agent subprocess; the worktree is preserved on disk. Rejects with `signal.reason`. |
|
|
467
478
|
|
|
468
479
|
#### `WorktreeRunResult`
|
|
469
480
|
|
|
@@ -478,12 +489,12 @@ await sandbox.close();
|
|
|
478
489
|
|
|
479
490
|
#### `WorktreeCreateSandboxOptions`
|
|
480
491
|
|
|
481
|
-
| Option | Type | Default | Description
|
|
482
|
-
| ---------------- | --------------- | ------- |
|
|
483
|
-
| `sandbox` | SandboxProvider | — | **Required.** Sandbox provider (e.g. `docker()`)
|
|
484
|
-
| `hooks` | SandboxHooks | — | Lifecycle hooks (`host.*`, `sandbox.*`)
|
|
485
|
-
| `copyToWorktree` | string[] | — | Host-relative file paths to copy into the worktree at creation time
|
|
486
|
-
| `timeouts` | Timeouts | — | Override
|
|
492
|
+
| Option | Type | Default | Description |
|
|
493
|
+
| ---------------- | --------------- | ------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
494
|
+
| `sandbox` | SandboxProvider | — | **Required.** Sandbox provider (e.g. `docker()`) |
|
|
495
|
+
| `hooks` | SandboxHooks | — | Lifecycle hooks (`host.*`, `sandbox.*`) |
|
|
496
|
+
| `copyToWorktree` | string[] | — | Host-relative file paths to copy into the worktree at creation time |
|
|
497
|
+
| `timeouts` | Timeouts | — | Override built-in lifecycle step timeouts (`copyToWorktreeMs`, `gitSetupMs`, `commitCollectionMs`, `mergeToHostMs`) |
|
|
487
498
|
|
|
488
499
|
## How it works
|
|
489
500
|
|
|
@@ -525,7 +536,7 @@ Commands run **inside the sandbox** after `sandbox.onSandboxReady` hooks complet
|
|
|
525
536
|
```markdown
|
|
526
537
|
# Open issues
|
|
527
538
|
|
|
528
|
-
!`gh issue list --state open --label Sandcastle --json number,title,body,comments,labels --limit
|
|
539
|
+
!`gh issue list --state open --label Sandcastle --json number,title,body,comments,labels --limit 100`
|
|
529
540
|
|
|
530
541
|
# Recent commits
|
|
531
542
|
|
|
@@ -605,7 +616,7 @@ Tell the agent to output your chosen string(s) in the prompt, and the orchestrat
|
|
|
605
616
|
|
|
606
617
|
### Structured output
|
|
607
618
|
|
|
608
|
-
Use `Output.object()` to extract a typed, schema-validated JSON payload from the agent's stdout. The agent emits its answer inside an XML tag you specify, and Sandcastle parses, validates, and returns it on `result.output`. See [ADR 0010](docs/adr/0010-structured-output.md) for design rationale.
|
|
619
|
+
Use `Output.object()` to extract a typed, schema-validated JSON payload from the agent's stdout. The agent emits its answer inside an XML tag you specify, and Sandcastle parses, validates, and returns it on `result.output`. The schema can be any [Standard Schema](https://standardschema.dev) validator — the examples below use [Zod](https://zod.dev), but Valibot, ArkType, and others work identically. See [ADR 0010](docs/adr/0010-structured-output.md) for design rationale.
|
|
609
620
|
|
|
610
621
|
```ts
|
|
611
622
|
import { run, Output, claudeCode } from "@ai-hero/sandcastle";
|
|
@@ -671,12 +682,13 @@ Select a template during `sandcastle init` when prompted, or re-run init in a fr
|
|
|
671
682
|
|
|
672
683
|
Scaffolds the `.sandcastle/` config directory and builds the container image. This is the first command you run in a new repo. You choose a sandbox provider (Docker or Podman) during init — selecting Podman writes a `Containerfile` instead of `Dockerfile` and uses `sandcastle podman build-image` for the build step.
|
|
673
684
|
|
|
674
|
-
| Option | Required | Default | Description
|
|
675
|
-
| -------------- | -------- | ---------------------------- |
|
|
676
|
-
| `--image-name` | No | `sandcastle:<repo-dir-name>` | Docker image name
|
|
677
|
-
| `--agent` | No | Interactive prompt | Agent to use (`claude-code`, `pi`, `codex`, `opencode`)
|
|
678
|
-
| `--model` | No | Agent's default model | Model to use (e.g. `claude-sonnet-4-6`). Defaults to agent's default
|
|
679
|
-
| `--
|
|
685
|
+
| Option | Required | Default | Description |
|
|
686
|
+
| -------------- | -------- | ---------------------------- | ---------------------------------------------------------------------------- |
|
|
687
|
+
| `--image-name` | No | `sandcastle:<repo-dir-name>` | Docker image name |
|
|
688
|
+
| `--agent` | No | Interactive prompt | Agent to use (`claude-code`, `pi`, `codex`, `cursor`, `opencode`, `copilot`) |
|
|
689
|
+
| `--model` | No | Agent's default model | Model to use (e.g. `claude-sonnet-4-6`). Defaults to agent's default |
|
|
690
|
+
| `--sandbox` | No | Interactive prompt | Sandbox provider to use (`docker`, `podman`) |
|
|
691
|
+
| `--template` | No | Interactive prompt | Template to scaffold (e.g. `blank`, `simple-loop`) |
|
|
680
692
|
|
|
681
693
|
Creates the following files:
|
|
682
694
|
|
|
@@ -726,26 +738,26 @@ Removes the Podman image.
|
|
|
726
738
|
|
|
727
739
|
### `RunOptions`
|
|
728
740
|
|
|
729
|
-
| Option | Type | Default | Description
|
|
730
|
-
| -------------------- | ------------------ | ----------------------------- |
|
|
731
|
-
| `agent` | AgentProvider | — | **Required.** Agent provider (e.g. `claudeCode("claude-opus-4-7")`, `pi("claude-sonnet-4-6")`, `codex("gpt-5.4-mini")`, `opencode("opencode/big-pickle")`)
|
|
732
|
-
| `sandbox` | SandboxProvider | — | **Required.** Sandbox provider (e.g. `docker()`, `podman()`, `docker({ imageName: "sandcastle:local" })`)
|
|
733
|
-
| `cwd` | string | `process.cwd()` | Host repo directory — anchor for `.sandcastle/` artifacts and git operations. Relative paths resolve against `process.cwd()`.
|
|
734
|
-
| `prompt` | string | — | Inline prompt (mutually exclusive with `promptFile`)
|
|
735
|
-
| `promptFile` | string | — | Path to prompt file (mutually exclusive with `prompt`). Resolves against `process.cwd()`, **not** `cwd`.
|
|
736
|
-
| `maxIterations` | number | `1` | Maximum iterations to run
|
|
737
|
-
| `hooks` | SandboxHooks | — | Lifecycle hooks (`host.*`, `sandbox.*`)
|
|
738
|
-
| `name` | string | — | Display name for the run, shown as a prefix in log output
|
|
739
|
-
| `promptArgs` | PromptArgs | — | Key-value map for `{{KEY}}` placeholder substitution
|
|
740
|
-
| `branchStrategy` | BranchStrategy | per-provider default | Branch strategy: `{ type: 'head' }`, `{ type: 'merge-to-head' }`, or `{ type: 'branch', branch: '…' }`
|
|
741
|
-
| `copyToWorktree` | string[] | — | Host-relative file paths to copy into the sandbox before start (not supported with `branchStrategy: { type: 'head' }`)
|
|
742
|
-
| `logging` | object | file (auto-generated) | `{ type: 'file', path }` or `{ type: 'stdout' }`
|
|
743
|
-
| `completionSignal` | string \| string[] | `<promise>COMPLETE</promise>` | String or array of strings the agent emits to stop the iteration loop early
|
|
744
|
-
| `idleTimeoutSeconds` | number | `600` | Idle timeout in seconds — resets on each agent output event
|
|
745
|
-
| `resumeSession` | string | — | Resume a prior
|
|
746
|
-
| `signal` | AbortSignal | — | Cancel the run when aborted. Kills the in-flight agent subprocess and cancels lifecycle hooks; the worktree is preserved on disk. Rejects with `signal.reason`.
|
|
747
|
-
| `timeouts` | Timeouts | — | Override default timeouts for built-in lifecycle steps
|
|
748
|
-
| `output` | OutputDefinition | — | Structured output definition (`Output.object(…)` or `Output.string(…)`). Requires `maxIterations === 1`. See [Structured output](#structured-output).
|
|
741
|
+
| Option | Type | Default | Description |
|
|
742
|
+
| -------------------- | ------------------ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
743
|
+
| `agent` | AgentProvider | — | **Required.** Agent provider (e.g. `claudeCode("claude-opus-4-7")`, `pi("claude-sonnet-4-6")`, `codex("gpt-5.4-mini")`, `cursor("composer-2")`, `opencode("opencode/big-pickle")`, `copilot("claude-sonnet-4.5")`) |
|
|
744
|
+
| `sandbox` | SandboxProvider | — | **Required.** Sandbox provider (e.g. `docker()`, `podman()`, `docker({ imageName: "sandcastle:local" })`) |
|
|
745
|
+
| `cwd` | string | `process.cwd()` | Host repo directory — anchor for `.sandcastle/` artifacts and git operations. Relative paths resolve against `process.cwd()`. |
|
|
746
|
+
| `prompt` | string | — | Inline prompt (mutually exclusive with `promptFile`) |
|
|
747
|
+
| `promptFile` | string | — | Path to prompt file (mutually exclusive with `prompt`). Resolves against `process.cwd()`, **not** `cwd`. |
|
|
748
|
+
| `maxIterations` | number | `1` | Maximum iterations to run |
|
|
749
|
+
| `hooks` | SandboxHooks | — | Lifecycle hooks (`host.*`, `sandbox.*`) |
|
|
750
|
+
| `name` | string | — | Display name for the run, shown as a prefix in log output |
|
|
751
|
+
| `promptArgs` | PromptArgs | — | Key-value map for `{{KEY}}` placeholder substitution |
|
|
752
|
+
| `branchStrategy` | BranchStrategy | per-provider default | Branch strategy: `{ type: 'head' }`, `{ type: 'merge-to-head' }`, or `{ type: 'branch', branch: '…' }` |
|
|
753
|
+
| `copyToWorktree` | string[] | — | Host-relative file paths to copy into the sandbox before start (not supported with `branchStrategy: { type: 'head' }`) |
|
|
754
|
+
| `logging` | object | file (auto-generated) | `{ type: 'file', path }` or `{ type: 'stdout' }` |
|
|
755
|
+
| `completionSignal` | string \| string[] | `<promise>COMPLETE</promise>` | String or array of strings the agent emits to stop the iteration loop early |
|
|
756
|
+
| `idleTimeoutSeconds` | number | `600` | Idle timeout in seconds — resets on each agent output event |
|
|
757
|
+
| `resumeSession` | string | — | Resume a prior session by ID for agents that support resume. Incompatible with `maxIterations > 1`. Session file must exist on host. |
|
|
758
|
+
| `signal` | AbortSignal | — | Cancel the run when aborted. Kills the in-flight agent subprocess and cancels lifecycle hooks; the worktree is preserved on disk. Rejects with `signal.reason`. |
|
|
759
|
+
| `timeouts` | Timeouts | — | Override default timeouts for built-in lifecycle steps: `copyToWorktreeMs` (60 000), `gitSetupMs` (10 000), `commitCollectionMs` (30 000), `mergeToHostMs` (30 000). |
|
|
760
|
+
| `output` | OutputDefinition | — | Structured output definition (`Output.object(…)` or `Output.string(…)`). Requires `maxIterations === 1`. See [Structured output](#structured-output). |
|
|
749
761
|
|
|
750
762
|
### `RunResult`
|
|
751
763
|
|
|
@@ -763,7 +775,7 @@ Removes the Podman image.
|
|
|
763
775
|
|
|
764
776
|
| Field | Type | Description |
|
|
765
777
|
| ----------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
766
|
-
| `sessionId` | string? |
|
|
778
|
+
| `sessionId` | string? | Agent session ID from the provider stream, or `undefined` if the provider does not emit one |
|
|
767
779
|
| `sessionFilePath` | string? | Absolute host path to the captured session JSONL, or `undefined` when capture is off |
|
|
768
780
|
| `usage` | `IterationUsage`? | Token usage snapshot from the last assistant message, or `undefined` when capture is off or provider does not support usage parsing |
|
|
769
781
|
|
|
@@ -778,13 +790,13 @@ Removes the Podman image.
|
|
|
778
790
|
|
|
779
791
|
### Session capture
|
|
780
792
|
|
|
781
|
-
After each
|
|
793
|
+
After each resumable provider iteration, Sandcastle automatically captures the agent's session file from the sandbox to the host. Claude Code sessions are stored under `~/.claude/projects/<encoded-path>/<session-id>.jsonl`; Codex sessions are stored under `~/.codex/sessions/YYYY/MM/DD/rollout-*-<session-id>.jsonl`. Any provider-specific `cwd` fields are rewritten to match the host repo root, so the provider's native resume command works.
|
|
782
794
|
|
|
783
|
-
Session capture is enabled by default for `claudeCode()` and can be opted out via `captureSessions: false`.
|
|
795
|
+
Session capture is enabled by default for `claudeCode()` and `codex()` and can be opted out via `captureSessions: false`. Providers without `sessionStorage` do not attempt capture. Capture failure fails the run.
|
|
784
796
|
|
|
785
797
|
### Session resume
|
|
786
798
|
|
|
787
|
-
Pass `resumeSession` to `run()` to continue a prior Claude Code conversation inside a new sandbox:
|
|
799
|
+
Pass `resumeSession` to `run()` to continue a prior Claude Code or Codex conversation inside a new sandbox:
|
|
788
800
|
|
|
789
801
|
```typescript
|
|
790
802
|
const result = await run({
|
|
@@ -795,14 +807,28 @@ const result = await run({
|
|
|
795
807
|
});
|
|
796
808
|
```
|
|
797
809
|
|
|
798
|
-
|
|
810
|
+
You can also continue the last captured session from a result:
|
|
811
|
+
|
|
812
|
+
```typescript
|
|
813
|
+
const first = await run({
|
|
814
|
+
agent: codex("gpt-5.4-mini"),
|
|
815
|
+
sandbox: docker(),
|
|
816
|
+
prompt: "Draft a plan",
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
const second = await first.resume?.("Now implement the plan");
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
`resume` is present only on results from resumable providers (Claude Code, Codex) — hence the optional-chaining call.
|
|
823
|
+
|
|
824
|
+
Before the sandbox starts, Sandcastle validates that the session file exists on the host and transfers it into the sandbox with `cwd` fields rewritten to match the sandbox-side path. Claude Code receives `--resume <id>`; Codex receives `codex exec resume <id>` with the prompt piped over stdin.
|
|
799
825
|
|
|
800
826
|
Constraints:
|
|
801
827
|
|
|
802
828
|
- `resumeSession` is incompatible with `maxIterations > 1` (throws before sandbox creation).
|
|
803
|
-
- The session file must exist
|
|
829
|
+
- The provider's host session file must exist (throws before sandbox creation).
|
|
804
830
|
- Only iteration 1 receives the resume flag; subsequent iterations (if any) start fresh.
|
|
805
|
-
-
|
|
831
|
+
- Providers without resume support reject `resumeSession`.
|
|
806
832
|
|
|
807
833
|
### `ClaudeCodeOptions`
|
|
808
834
|
|
|
@@ -812,11 +838,11 @@ The `claudeCode()` factory accepts an optional second argument for provider-spec
|
|
|
812
838
|
agent: claudeCode("claude-opus-4-7", { effort: "high" });
|
|
813
839
|
```
|
|
814
840
|
|
|
815
|
-
| Option | Type
|
|
816
|
-
| ----------------- |
|
|
817
|
-
| `effort` | `"low"` \| `"medium"` \| `"high"` \| `"max"` | — | Claude Code reasoning effort level (`max` is Opus only) |
|
|
818
|
-
| `env` | `Record<string, string>`
|
|
819
|
-
| `captureSessions` | `boolean`
|
|
841
|
+
| Option | Type | Default | Description |
|
|
842
|
+
| ----------------- | --------------------------------------------------------- | ------- | --------------------------------------------------------- |
|
|
843
|
+
| `effort` | `"low"` \| `"medium"` \| `"high"` \| `"xhigh"` \| `"max"` | — | Claude Code reasoning effort level (`max` is Opus only) |
|
|
844
|
+
| `env` | `Record<string, string>` | `{}` | Environment variables injected by this agent provider |
|
|
845
|
+
| `captureSessions` | `boolean` | `true` | Capture agent session JSONL to host for `claude --resume` |
|
|
820
846
|
|
|
821
847
|
### `CodexOptions`
|
|
822
848
|
|
|
@@ -826,10 +852,11 @@ The `codex()` factory accepts an optional second argument for provider-specific
|
|
|
826
852
|
agent: codex("gpt-5.4", { effort: "high" });
|
|
827
853
|
```
|
|
828
854
|
|
|
829
|
-
| Option
|
|
830
|
-
|
|
|
831
|
-
| `effort`
|
|
832
|
-
| `env`
|
|
855
|
+
| Option | Type | Default | Description |
|
|
856
|
+
| ----------------- | ---------------------------------------------- | ------- | --------------------------------------------------------- |
|
|
857
|
+
| `effort` | `"low"` \| `"medium"` \| `"high"` \| `"xhigh"` | — | Codex reasoning effort level via `model_reasoning_effort` |
|
|
858
|
+
| `env` | `Record<string, string>` | `{}` | Environment variables injected by this agent provider |
|
|
859
|
+
| `captureSessions` | `boolean` | `true` | Capture Codex rollout JSONL to host for resume |
|
|
833
860
|
|
|
834
861
|
### Provider `env`
|
|
835
862
|
|
package/dist/AgentProvider.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type HostSessionLookup, type SessionStore } from "./SessionStore.js";
|
|
2
|
+
import type { BindMountSandboxHandle } from "./SandboxProvider.js";
|
|
1
3
|
export type ParsedStreamEvent = {
|
|
2
4
|
type: "text";
|
|
3
5
|
text: string;
|
|
@@ -33,12 +35,27 @@ export interface IterationUsage {
|
|
|
33
35
|
readonly cacheReadInputTokens: number;
|
|
34
36
|
readonly outputTokens: number;
|
|
35
37
|
}
|
|
38
|
+
export interface AgentSessionStorage {
|
|
39
|
+
hostStore(cwd: string): SessionStore;
|
|
40
|
+
sandboxStore(cwd: string, handle: BindMountSandboxHandle): SessionStore;
|
|
41
|
+
transfer(from: SessionStore, to: SessionStore, id: string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Locate a session on the host by its unique id, independent of cwd encoding.
|
|
44
|
+
* Used by the no-sandbox resume precheck, where the agent runs on the host and
|
|
45
|
+
* writes the session in place under a cwd-derived directory Sandcastle cannot
|
|
46
|
+
* reliably reconstruct. Returns the located path (or `undefined`) plus the
|
|
47
|
+
* directory that was searched (for not-found errors).
|
|
48
|
+
*/
|
|
49
|
+
findByIdOnHost(id: string): Promise<HostSessionLookup>;
|
|
50
|
+
}
|
|
36
51
|
export interface AgentProvider {
|
|
37
52
|
readonly name: string;
|
|
38
53
|
/** Environment variables injected by this agent provider. Merged at launch time with env resolver and sandbox provider env. */
|
|
39
54
|
readonly env: Record<string, string>;
|
|
40
55
|
/** When true, session capture is enabled for this provider. Default: true for Claude Code, false for others. */
|
|
41
56
|
readonly captureSessions: boolean;
|
|
57
|
+
/** Provider-owned storage and transfer behavior for resumable agent sessions. */
|
|
58
|
+
readonly sessionStorage?: AgentSessionStorage;
|
|
42
59
|
buildPrintCommand(options: AgentCommandOptions): PrintCommand;
|
|
43
60
|
buildInteractiveArgs?(options: AgentCommandOptions): string[];
|
|
44
61
|
parseStreamLine(line: string): ParsedStreamEvent[];
|
|
@@ -57,22 +74,58 @@ export interface CodexOptions {
|
|
|
57
74
|
readonly effort?: "low" | "medium" | "high" | "xhigh";
|
|
58
75
|
/** Environment variables injected by this agent provider. */
|
|
59
76
|
readonly env?: Record<string, string>;
|
|
77
|
+
/** When false, session capture is disabled. Default: true. */
|
|
78
|
+
readonly captureSessions?: boolean;
|
|
79
|
+
/** Override Codex session directories for tests or non-standard installs. */
|
|
80
|
+
readonly sessionStorage?: {
|
|
81
|
+
readonly hostSessionsDir?: string;
|
|
82
|
+
readonly sandboxSessionsDir?: string;
|
|
83
|
+
};
|
|
60
84
|
}
|
|
61
|
-
export declare const codex: (model: string, options?: CodexOptions | undefined) => AgentProvider
|
|
85
|
+
export declare const codex: (model: string, options?: CodexOptions | undefined) => AgentProvider & {
|
|
86
|
+
readonly sessionStorage: AgentSessionStorage;
|
|
87
|
+
};
|
|
88
|
+
/** Options for the cursor agent provider. */
|
|
89
|
+
export interface CursorOptions {
|
|
90
|
+
/** Environment variables injected by this agent provider. */
|
|
91
|
+
readonly env?: Record<string, string>;
|
|
92
|
+
}
|
|
93
|
+
export declare const cursor: (model: string, options?: CursorOptions | undefined) => AgentProvider;
|
|
62
94
|
/** Options for the opencode agent provider. */
|
|
63
95
|
export interface OpenCodeOptions {
|
|
64
96
|
/** Provider-specific reasoning effort variant (e.g. "high", "max", "low", "minimal"). */
|
|
65
97
|
readonly variant?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Named OpenCode agent/mode to run, mapped to OpenCode's own `--agent` flag
|
|
100
|
+
* (e.g. "build", "plan"). This is distinct from Sandcastle's `--agent`
|
|
101
|
+
* provider selector — it chooses an agent *inside* OpenCode.
|
|
102
|
+
*/
|
|
103
|
+
readonly agent?: string;
|
|
66
104
|
/** Environment variables injected by this agent provider. */
|
|
67
105
|
readonly env?: Record<string, string>;
|
|
68
106
|
}
|
|
69
107
|
export declare const opencode: (model: string, options?: OpenCodeOptions | undefined) => AgentProvider;
|
|
108
|
+
/** Options for the GitHub Copilot CLI agent provider. */
|
|
109
|
+
export interface CopilotOptions {
|
|
110
|
+
/** Reasoning effort level. Maps to the CLI's --effort flag. */
|
|
111
|
+
readonly effort?: "low" | "medium" | "high";
|
|
112
|
+
/** Environment variables injected by this agent provider. */
|
|
113
|
+
readonly env?: Record<string, string>;
|
|
114
|
+
}
|
|
115
|
+
export declare const copilot: (model: string, options?: CopilotOptions | undefined) => AgentProvider;
|
|
70
116
|
export interface ClaudeCodeOptions {
|
|
71
|
-
readonly effort?: "low" | "medium" | "high" | "max";
|
|
117
|
+
readonly effort?: "low" | "medium" | "high" | "xhigh" | "max";
|
|
72
118
|
/** Environment variables injected by this agent provider. */
|
|
73
119
|
readonly env?: Record<string, string>;
|
|
74
120
|
/** When false, session capture is disabled. Default: true. */
|
|
75
121
|
readonly captureSessions?: boolean;
|
|
122
|
+
/** Override Claude session directories for tests or non-standard installs. */
|
|
123
|
+
readonly sessionStorage?: {
|
|
124
|
+
readonly hostProjectsDir?: string;
|
|
125
|
+
readonly sandboxProjectsDir?: string;
|
|
126
|
+
};
|
|
76
127
|
}
|
|
77
|
-
export declare const claudeCode: (model: string, options?: ClaudeCodeOptions | undefined) => AgentProvider
|
|
128
|
+
export declare const claudeCode: (model: string, options?: ClaudeCodeOptions | undefined) => AgentProvider & {
|
|
129
|
+
readonly sessionStorage: AgentSessionStorage;
|
|
130
|
+
};
|
|
78
131
|
//# sourceMappingURL=AgentProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentProvider.d.ts","sourceRoot":"","sources":["../src/AgentProvider.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"AgentProvider.d.ts","sourceRoot":"","sources":["../src/AgentProvider.ts"],"names":[],"mappings":"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"}
|