@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.
Files changed (111) hide show
  1. package/README.md +106 -79
  2. package/dist/AgentProvider.d.ts +56 -3
  3. package/dist/AgentProvider.d.ts.map +1 -1
  4. package/dist/AgentProvider.js +324 -9
  5. package/dist/AgentProvider.js.map +1 -1
  6. package/dist/DockerLifecycle.d.ts +6 -0
  7. package/dist/DockerLifecycle.d.ts.map +1 -1
  8. package/dist/DockerLifecycle.js +12 -0
  9. package/dist/DockerLifecycle.js.map +1 -1
  10. package/dist/InitService.d.ts.map +1 -1
  11. package/dist/InitService.js +115 -14
  12. package/dist/InitService.js.map +1 -1
  13. package/dist/Orchestrator.d.ts +4 -2
  14. package/dist/Orchestrator.d.ts.map +1 -1
  15. package/dist/Orchestrator.js +15 -14
  16. package/dist/Orchestrator.js.map +1 -1
  17. package/dist/SandboxFactory.d.ts.map +1 -1
  18. package/dist/SandboxFactory.js +51 -64
  19. package/dist/SandboxFactory.js.map +1 -1
  20. package/dist/SandboxLifecycle.d.ts +3 -0
  21. package/dist/SandboxLifecycle.d.ts.map +1 -1
  22. package/dist/SandboxLifecycle.js +44 -18
  23. package/dist/SandboxLifecycle.js.map +1 -1
  24. package/dist/SessionStore.d.ts +71 -10
  25. package/dist/SessionStore.d.ts.map +1 -1
  26. package/dist/SessionStore.js +222 -17
  27. package/dist/SessionStore.js.map +1 -1
  28. package/dist/WorktreeManager.d.ts +27 -0
  29. package/dist/WorktreeManager.d.ts.map +1 -1
  30. package/dist/WorktreeManager.js +50 -8
  31. package/dist/WorktreeManager.js.map +1 -1
  32. package/dist/boundedTail.d.ts +48 -0
  33. package/dist/boundedTail.d.ts.map +1 -0
  34. package/dist/boundedTail.js +64 -0
  35. package/dist/boundedTail.js.map +1 -0
  36. package/dist/cli.d.ts +1 -0
  37. package/dist/cli.d.ts.map +1 -1
  38. package/dist/cli.js +19 -3
  39. package/dist/cli.js.map +1 -1
  40. package/dist/createSandbox.d.ts.map +1 -1
  41. package/dist/createSandbox.js +116 -122
  42. package/dist/createSandbox.js.map +1 -1
  43. package/dist/createWorktree.d.ts.map +1 -1
  44. package/dist/createWorktree.js +10 -9
  45. package/dist/createWorktree.js.map +1 -1
  46. package/dist/errors.d.ts +3 -0
  47. package/dist/errors.d.ts.map +1 -1
  48. package/dist/errors.js.map +1 -1
  49. package/dist/index.d.ts +3 -4
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +2 -3
  52. package/dist/index.js.map +1 -1
  53. package/dist/interactive.d.ts.map +1 -1
  54. package/dist/interactive.js +55 -46
  55. package/dist/interactive.js.map +1 -1
  56. package/dist/resumePrecheck.d.ts +26 -0
  57. package/dist/resumePrecheck.d.ts.map +1 -0
  58. package/dist/resumePrecheck.js +40 -0
  59. package/dist/resumePrecheck.js.map +1 -0
  60. package/dist/run.d.ts +15 -5
  61. package/dist/run.d.ts.map +1 -1
  62. package/dist/run.js +23 -9
  63. package/dist/run.js.map +1 -1
  64. package/dist/sandboxes/daytona.d.ts +9 -0
  65. package/dist/sandboxes/daytona.d.ts.map +1 -1
  66. package/dist/sandboxes/daytona.js +9 -7
  67. package/dist/sandboxes/daytona.js.map +1 -1
  68. package/dist/sandboxes/docker.d.ts +45 -0
  69. package/dist/sandboxes/docker.d.ts.map +1 -1
  70. package/dist/sandboxes/docker.js +40 -28
  71. package/dist/sandboxes/docker.js.map +1 -1
  72. package/dist/sandboxes/no-sandbox.d.ts +9 -0
  73. package/dist/sandboxes/no-sandbox.d.ts.map +1 -1
  74. package/dist/sandboxes/no-sandbox.js +32 -17
  75. package/dist/sandboxes/no-sandbox.js.map +1 -1
  76. package/dist/sandboxes/podman.d.ts +47 -0
  77. package/dist/sandboxes/podman.d.ts.map +1 -1
  78. package/dist/sandboxes/podman.js +49 -28
  79. package/dist/sandboxes/podman.js.map +1 -1
  80. package/dist/sandboxes/test-bind-mount.d.ts.map +1 -1
  81. package/dist/sandboxes/test-bind-mount.js +7 -6
  82. package/dist/sandboxes/test-bind-mount.js.map +1 -1
  83. package/dist/sandboxes/test-isolated.d.ts.map +1 -1
  84. package/dist/sandboxes/test-isolated.js +7 -6
  85. package/dist/sandboxes/test-isolated.js.map +1 -1
  86. package/dist/sandboxes/vercel.d.ts +9 -0
  87. package/dist/sandboxes/vercel.d.ts.map +1 -1
  88. package/dist/sandboxes/vercel.js +9 -7
  89. package/dist/sandboxes/vercel.js.map +1 -1
  90. package/dist/shutdownRegistry.d.ts +30 -0
  91. package/dist/shutdownRegistry.d.ts.map +1 -0
  92. package/dist/shutdownRegistry.js +73 -0
  93. package/dist/shutdownRegistry.js.map +1 -0
  94. package/dist/syncOut.js +1 -1
  95. package/dist/syncOut.js.map +1 -1
  96. package/dist/templates/parallel-planner/main.mts +19 -17
  97. package/dist/templates/parallel-planner/plan-prompt.md +4 -2
  98. package/dist/templates/parallel-planner-with-review/main.mts +19 -17
  99. package/dist/templates/parallel-planner-with-review/plan-prompt.md +4 -2
  100. package/dist/templates/parallel-planner-with-review/review-prompt.md +2 -2
  101. package/dist/templates/sequential-reviewer/main.mts +13 -5
  102. package/dist/templates/sequential-reviewer/review-prompt.md +2 -2
  103. package/dist/templates/simple-loop/main.mts +1 -1
  104. package/dist/testSandbox.d.ts.map +1 -1
  105. package/dist/testSandbox.js +32 -19
  106. package/dist/testSandbox.js.map +1 -1
  107. package/package.json +3 -2
  108. package/dist/SessionPaths.d.ts +0 -26
  109. package/dist/SessionPaths.d.ts.map +0 -1
  110. package/dist/SessionPaths.js +0 -22
  111. 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 default timeouts (e.g. `{ copyToWorktreeMs: 120_000 }`) |
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 default timeouts (e.g. `{ copyToWorktreeMs: 120_000 }`) |
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 Claude Code session by ID. Incompatible with `maxIterations > 1`. Session file must exist on host. |
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 default timeouts (e.g. `{ copyToWorktreeMs: 120_000 }`) |
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 20`
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
- | `--template` | No | Interactive prompt | Template to scaffold (e.g. `blank`, `simple-loop`) |
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 Claude Code session by ID. Incompatible with `maxIterations > 1`. Session file must exist on host. |
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. Currently supports `{ copyToWorktreeMs?: number }` (default: 60 000). |
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? | Claude Code session ID from the init line, or `undefined` for non-Claude agents |
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 Claude Code iteration, Sandcastle automatically captures the agent's session JSONL from the sandbox to the host at `~/.claude/projects/<encoded-path>/sessions/<session-id>.jsonl`. The `cwd` fields inside each JSONL entry are rewritten to match the host repo root, so `claude --resume` works natively.
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`. Non-Claude agent providers never attempt capture. Capture failure fails the run.
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
- 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. The Claude Code agent receives `--resume <id>` on its print command for iteration 1.
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 at `~/.claude/projects/<encoded-path>/sessions/<id>.jsonl` (throws before sandbox creation).
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
- - Non-Claude agent providers ignore `resumeSession`.
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 | Default | Description |
816
- | ----------------- | -------------------------------------------- | ------- | --------------------------------------------------------- |
817
- | `effort` | `"low"` \| `"medium"` \| `"high"` \| `"max"` | — | Claude Code reasoning effort level (`max` is Opus only) |
818
- | `env` | `Record<string, string>` | `{}` | Environment variables injected by this agent provider |
819
- | `captureSessions` | `boolean` | `true` | Capture agent session JSONL to host for `claude --resume` |
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 | Type | Default | Description |
830
- | -------- | ---------------------------------------------- | ------- | --------------------------------------------------------- |
831
- | `effort` | `"low"` \| `"medium"` \| `"high"` \| `"xhigh"` | — | Codex reasoning effort level via `model_reasoning_effort` |
832
- | `env` | `Record<string, string>` | `{}` | Environment variables injected by this agent provider |
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
 
@@ -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":"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"}
1
+ {"version":3,"file":"AgentProvider.d.ts","sourceRoot":"","sources":["../src/AgentProvider.ts"],"names":[],"mappings":"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"}