@snappedly-tools/shipyard 0.2.0

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 (57) hide show
  1. package/LICENSE +59 -0
  2. package/NOTICE +4 -0
  3. package/README.md +197 -0
  4. package/dist/MountConfig-bZoCs4Dd.d.ts +26 -0
  5. package/dist/SandboxProvider-KeFp_nju.d.ts +257 -0
  6. package/dist/chunk-4VDXZY7T.js +27624 -0
  7. package/dist/chunk-4VDXZY7T.js.map +1 -0
  8. package/dist/chunk-BU6XJFJ2.js +90 -0
  9. package/dist/chunk-BU6XJFJ2.js.map +1 -0
  10. package/dist/chunk-CP6YEQKU.js +42 -0
  11. package/dist/chunk-CP6YEQKU.js.map +1 -0
  12. package/dist/chunk-OAHPDSOJ.js +407 -0
  13. package/dist/chunk-OAHPDSOJ.js.map +1 -0
  14. package/dist/chunk-SRUH232X.js +26712 -0
  15. package/dist/chunk-SRUH232X.js.map +1 -0
  16. package/dist/chunk-YVJHSJUW.js +127 -0
  17. package/dist/chunk-YVJHSJUW.js.map +1 -0
  18. package/dist/index.d.ts +2780 -0
  19. package/dist/index.js +9843 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/main.d.ts +1 -0
  22. package/dist/main.js +20475 -0
  23. package/dist/main.js.map +1 -0
  24. package/dist/sandboxes/docker.d.ts +125 -0
  25. package/dist/sandboxes/docker.js +9 -0
  26. package/dist/sandboxes/docker.js.map +1 -0
  27. package/dist/sandboxes/no-sandbox.d.ts +37 -0
  28. package/dist/sandboxes/no-sandbox.js +7 -0
  29. package/dist/sandboxes/no-sandbox.js.map +1 -0
  30. package/dist/sandboxes/vercel.d.ts +104 -0
  31. package/dist/sandboxes/vercel.js +188 -0
  32. package/dist/sandboxes/vercel.js.map +1 -0
  33. package/dist/templates/blank/main.mts +13 -0
  34. package/dist/templates/blank/prompt.md +12 -0
  35. package/dist/templates/blank/template.json +4 -0
  36. package/dist/templates/parallel-planner/implement-prompt.md +62 -0
  37. package/dist/templates/parallel-planner/main.mts +205 -0
  38. package/dist/templates/parallel-planner/merge-prompt.md +26 -0
  39. package/dist/templates/parallel-planner/plan-prompt.md +37 -0
  40. package/dist/templates/parallel-planner/template.json +4 -0
  41. package/dist/templates/parallel-planner-with-review/CODING_STANDARDS.md +27 -0
  42. package/dist/templates/parallel-planner-with-review/implement-prompt.md +62 -0
  43. package/dist/templates/parallel-planner-with-review/main.mts +227 -0
  44. package/dist/templates/parallel-planner-with-review/merge-prompt.md +26 -0
  45. package/dist/templates/parallel-planner-with-review/plan-prompt.md +37 -0
  46. package/dist/templates/parallel-planner-with-review/review-prompt.md +55 -0
  47. package/dist/templates/parallel-planner-with-review/template.json +4 -0
  48. package/dist/templates/sequential-reviewer/CODING_STANDARDS.md +27 -0
  49. package/dist/templates/sequential-reviewer/implement-prompt.md +53 -0
  50. package/dist/templates/sequential-reviewer/main.mts +120 -0
  51. package/dist/templates/sequential-reviewer/review-prompt.md +55 -0
  52. package/dist/templates/sequential-reviewer/template.json +4 -0
  53. package/dist/templates/simple-loop/main.mts +51 -0
  54. package/dist/templates/simple-loop/prompt.md +53 -0
  55. package/dist/templates/simple-loop/template.json +4 -0
  56. package/dist/workflow/coordinator/migrations/001_initial.sql +131 -0
  57. package/package.json +103 -0
package/LICENSE ADDED
@@ -0,0 +1,59 @@
1
+ # PolyForm Strict License 1.0.0
2
+
3
+ <https://polyformproject.org/licenses/strict/1.0.0>
4
+
5
+ ## Acceptance
6
+
7
+ In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
8
+
9
+ ## Copyright License
10
+
11
+ The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose, other than distributing the software or making changes or new works based on the software.
12
+
13
+ ## Patent License
14
+
15
+ The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
16
+
17
+ ## Noncommercial Purposes
18
+
19
+ Any noncommercial purpose is a permitted purpose.
20
+
21
+ ## Personal Uses
22
+
23
+ Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, is use for a permitted purpose.
24
+
25
+ ## Noncommercial Organizations
26
+
27
+ Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution is use for a permitted purpose regardless of the source of funding or obligations resulting from the funding.
28
+
29
+ ## Fair Use
30
+
31
+ You may have "fair use" rights for the software under the law. These terms do not limit them.
32
+
33
+ ## No Other Rights
34
+
35
+ These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
36
+
37
+ ## Patent Defense
38
+
39
+ If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
40
+
41
+ ## Violations
42
+
43
+ The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
44
+
45
+ ## No Liability
46
+
47
+ ***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
48
+
49
+ ## Definitions
50
+
51
+ The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
52
+
53
+ **You** refers to the individual or entity agreeing to these terms.
54
+
55
+ **Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
56
+
57
+ **Your licenses** are all the licenses granted to you for the software under these terms.
58
+
59
+ **Use** means anything you do with the software requiring one of your licenses.
package/NOTICE ADDED
@@ -0,0 +1,4 @@
1
+ Shipyard
2
+ Copyright 2026 Snappedly
3
+
4
+ This product includes software developed by Shipyard contributors.
package/README.md ADDED
@@ -0,0 +1,197 @@
1
+ # Shipyard
2
+
3
+ <p align="center">
4
+ <img src="assets/brand/shipyard-robot-on-boat.png" alt="A friendly robot steering a blue boat for Shipyard" width="320">
5
+ </p>
6
+
7
+ > **Source-available toolkit for running AI coding agents in isolated sandboxes.**
8
+
9
+ [![CI](https://github.com/snappedly/shipyard/actions/workflows/ci.yml/badge.svg)](https://github.com/snappedly/shipyard/actions/workflows/ci.yml)
10
+
11
+ Shipyard runs AI coding agents in isolated sandboxes. Choose an agent, a
12
+ sandbox provider, and a prompt; Shipyard manages the sandbox lifecycle,
13
+ branches, logs, sessions, and commits.
14
+
15
+ ## Why Shipyard
16
+
17
+ - **Isolated by default.** Keep agent work inside Docker locally or Vercel
18
+ Sandbox remotely.
19
+ - **Purpose-built agents.** Use Codex or Claude Code without carrying support
20
+ for unrelated coding-agent CLIs.
21
+ - **Reviewable changes.** Control how branches and worktrees move changes back
22
+ to the host repository.
23
+
24
+ ## Quick start
25
+
26
+ You need Node.js, Git, Docker, and credentials for your chosen coding agent.
27
+ Run these commands inside the Git repository the agent should change:
28
+
29
+ ```sh
30
+ npm install --save-dev @snappedly-tools/shipyard
31
+ npx shipyard init
32
+ cp .shipyard/.env.example .shipyard/.env
33
+ ```
34
+
35
+ `init` asks which agent, sandbox provider, issue tracker, and starter template
36
+ to use. Start with the `blank` template. Put the requested credentials in
37
+ `.shipyard/.env`, then write one concrete task in `.shipyard/prompt.md`.
38
+
39
+ Run it:
40
+
41
+ ```sh
42
+ npx shipyard run
43
+ ```
44
+
45
+ `shipyard run` builds the generated Docker image, executes the
46
+ generated TypeScript entry point, and cleans up the sandbox. Reuse the cached
47
+ image when its definition has not changed:
48
+
49
+ ```sh
50
+ npx shipyard run --skip-build
51
+ ```
52
+
53
+ Inspect the generated branch strategy and start from a clean working tree. A
54
+ completion marker means the agent stopped; inspect its commits and run the
55
+ repository's checks before keeping the result.
56
+
57
+ ## JavaScript API
58
+
59
+ The generated `.shipyard/main.ts` or `.shipyard/main.mts` is ordinary
60
+ TypeScript:
61
+
62
+ ```ts
63
+ import { CODEX_MODELS, codex, run } from "@snappedly-tools/shipyard";
64
+ import { docker } from "@snappedly-tools/shipyard/sandboxes/docker";
65
+
66
+ const result = await run({
67
+ agent: codex(CODEX_MODELS.routine),
68
+ sandbox: docker(),
69
+ promptFile: ".shipyard/prompt.md",
70
+ });
71
+
72
+ console.log(result.commits);
73
+ ```
74
+
75
+ Use a dedicated branch when the scaffold has already been committed:
76
+
77
+ ```ts
78
+ const result = await run({
79
+ agent: codex(CODEX_MODELS.routine),
80
+ sandbox: docker(),
81
+ promptFile: ".shipyard/prompt.md",
82
+ branchStrategy: { type: "branch", branch: "agent/my-task" },
83
+ maxIterations: 1,
84
+ logging: { type: "stdout" },
85
+ });
86
+ ```
87
+
88
+ Shipyard supports Codex and Claude Code agents, with Docker, Vercel Sandbox,
89
+ and no-sandbox providers. `shipyard init` scaffolds Docker; configure Vercel
90
+ Sandbox or no-sandbox mode through the JavaScript interface.
91
+
92
+ To run directly on the host without isolation:
93
+
94
+ ```ts
95
+ import { CODEX_MODELS, codex, run } from "@snappedly-tools/shipyard";
96
+ import { noSandbox } from "@snappedly-tools/shipyard/sandboxes/no-sandbox";
97
+
98
+ const result = await run({
99
+ agent: codex(CODEX_MODELS.routine),
100
+ sandbox: noSandbox(),
101
+ promptFile: ".shipyard/prompt.md",
102
+ });
103
+ ```
104
+
105
+ No-sandbox mode grants the agent the permissions of the Shipyard process. Use
106
+ it only with trusted repositories and prompts.
107
+
108
+ ## Branch behavior
109
+
110
+ Docker keeps the repository and Git metadata inside the sandbox. It starts
111
+ from committed history and syncs changes back. The generated blank
112
+ template omits `branchStrategy`, which defaults to `merge-to-head`: commits
113
+ are transferred to a temporary host branch and merged into your current
114
+ branch. Direct `head` mode is not supported by Docker or Vercel Sandbox.
115
+
116
+ The explicit `branch` strategy keeps commits on the named branch for review.
117
+ Commit input files before either strategy, or use `copyToWorktree` for specific
118
+ untracked or ignored files.
119
+
120
+ ## Authentication
121
+
122
+ `shipyard init` generates the environment variables and mounts required by
123
+ the chosen agent. Keep `.shipyard/.env`, agent login files, logs, and recovery
124
+ patches private.
125
+
126
+ For Codex, choose either:
127
+
128
+ - ChatGPT authentication: select `chatgpt` during init and complete the
129
+ browser login. The generated configuration mounts `~/.codex/auth.json`
130
+ read-only.
131
+ - API authentication: select `api-key` and put `OPENAI_API_KEY` in
132
+ `.shipyard/.env`.
133
+
134
+ For Claude Code, run `claude setup-token` and put the resulting value in the
135
+ generated `CLAUDE_CODE_OAUTH_TOKEN` entry.
136
+
137
+ ## Generated files
138
+
139
+ | Path | Purpose |
140
+ | --------------------------------- | ------------------------------------------------------------ |
141
+ | `.shipyard/main.ts` or `main.mts` | Agent, sandbox, prompt, branch, hook, and iteration settings |
142
+ | `.shipyard/prompt.md` | Task given to the agent |
143
+ | `.shipyard/Dockerfile` | Sandbox image definition |
144
+ | `.shipyard/.env` | Untracked credentials passed into the sandbox |
145
+ | `.shipyard/logs/` | Run logs |
146
+ | `.shipyard/worktrees/` | Worktrees for separate-branch runs |
147
+ | `.shipyard/patches/` | Recovery artifacts preserved after some failures |
148
+
149
+ ## Workflow templates
150
+
151
+ The bundled templates are:
152
+
153
+ - `blank`: one agent and your prompt;
154
+ - `simple-loop`: process issue-tracker tasks sequentially;
155
+ - `sequential-reviewer`: implement and review each task;
156
+ - `parallel-planner`: plan parallel work and merge its branches; and
157
+ - `parallel-planner-with-review`: add review to each parallel branch.
158
+
159
+ Read generated prompts before running an issue or merge workflow. Those
160
+ templates can close issues, create branches, and merge work.
161
+
162
+ The package also exports contracts for triage, implementation, review,
163
+ repair, handoff, and release recording. They are building blocks for hosted
164
+ automation, not a hosted service started by the quick-start commands.
165
+
166
+ ## Security
167
+
168
+ Agents receive the permissions granted by their sandbox, mounts, credentials,
169
+ and hooks. Docker isolates repository and Git storage; it does not
170
+ mount the host checkout or Git metadata automatically. Explicit mounts must
171
+ stay outside the sandbox workspace and its ancestors.
172
+
173
+ Mounted credentials, devices, Docker sockets, groups, and network access can
174
+ still broaden an agent's access. Host hooks, no-sandbox mode, and custom
175
+ provider code retain their own trust requirements. Use
176
+ least-privilege credentials and review generated configuration before running
177
+ untrusted code.
178
+
179
+ See the [security evaluation](docs/security-evaluation.md) for findings,
180
+ fixes, and validation limits. Report vulnerabilities according to
181
+ [SECURITY.md](SECURITY.md).
182
+
183
+ ## Contributing
184
+
185
+ See [CONTRIBUTING.md](CONTRIBUTING.md). The standard repository check is:
186
+
187
+ ```sh
188
+ npm ci
189
+ npm run check
190
+ ```
191
+
192
+ ## License
193
+
194
+ Shipyard is source-available under the
195
+ [PolyForm Strict License 1.0.0](LICENSE). It is available for permitted
196
+ noncommercial use; the license does not permit redistribution, modification,
197
+ or derivative works. Contact Snappedly to request a commercial license.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * User-facing mount configuration for bind-mount sandbox providers.
3
+ *
4
+ * Each entry describes a host directory to mount into the sandbox container.
5
+ */
6
+ /** A single bind-mount descriptor for the Docker provider. */
7
+ interface MountConfig {
8
+ /**
9
+ * Path on the host. Supports:
10
+ * - Absolute paths (`/data/cache`)
11
+ * - Tilde-expanded paths (`~/data` → `<home>/data`)
12
+ * - Relative paths (`data` or `./data`) — resolved from `process.cwd()`
13
+ */
14
+ readonly hostPath: string;
15
+ /**
16
+ * Path inside the sandbox container. Supports:
17
+ * - Absolute paths (`/mnt/data`)
18
+ * - Tilde-expanded paths (`~/.npm` → `/home/agent/.npm`) — expanded using the provider's sandbox home directory
19
+ * - Relative paths (`data` or `./data`) — resolved from the worktree directory (`/home/agent/workspace`)
20
+ */
21
+ readonly sandboxPath: string;
22
+ /** Mount as read-only. Defaults to `false`. */
23
+ readonly readonly?: boolean;
24
+ }
25
+
26
+ export type { MountConfig as M };
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Sandbox provider types — the pluggable interface for sandbox runtimes.
3
+ *
4
+ * Provider authors implement a small Promise-based interface. Shipyard
5
+ * handles worktree creation, git mount resolution, and commit extraction.
6
+ */
7
+ /** Result of executing a command inside a sandbox. */
8
+ interface ExecResult {
9
+ readonly stdout: string;
10
+ readonly stderr: string;
11
+ readonly exitCode: number;
12
+ }
13
+ /** Options for interactiveExec — the streams the provider should wire to the spawned process. */
14
+ interface InteractiveExecOptions {
15
+ readonly stdin: NodeJS.ReadableStream;
16
+ readonly stdout: NodeJS.WritableStream;
17
+ readonly stderr: NodeJS.WritableStream;
18
+ readonly cwd?: string;
19
+ }
20
+ /** Handle to a running bind-mount sandbox. */
21
+ interface BindMountSandboxHandle {
22
+ /** Absolute path to the worktree inside the sandbox. */
23
+ readonly worktreePath: string;
24
+ /**
25
+ * Execute a command in the sandbox.
26
+ *
27
+ * Implementations MUST support line-by-line streaming via `onLine`. This is
28
+ * how Shipyard delivers live feedback to the user and enforces idle timeouts —
29
+ * without a streaming implementation, neither will work. A buffered/batch
30
+ * implementation that only calls `onLine` after the process exits does NOT
31
+ * satisfy this contract.
32
+ *
33
+ * When `stdin` is set, the implementation pipes the string to the child
34
+ * process's stdin and closes it. This avoids the Linux 128 KB per-arg limit.
35
+ */
36
+ exec(command: string, options?: {
37
+ onLine?: (line: string) => void;
38
+ cwd?: string;
39
+ sudo?: boolean;
40
+ stdin?: string;
41
+ /** Abort the command when the caller's operation is cancelled. */
42
+ signal?: AbortSignal;
43
+ /** Reject/terminate the command after this many combined output bytes. */
44
+ maxOutputBytes?: number;
45
+ }): Promise<ExecResult>;
46
+ /**
47
+ * Launch an interactive process inside the sandbox.
48
+ * Optional — providers that support interactive sessions implement this.
49
+ * The provider detects TTY mode from the streams (e.g. stdin.isTTY) and
50
+ * allocates a pseudo-terminal accordingly.
51
+ */
52
+ interactiveExec?(args: string[], options: InteractiveExecOptions): Promise<{
53
+ exitCode: number;
54
+ }>;
55
+ /** Copy a single file from the host into the sandbox. */
56
+ copyFileIn(hostPath: string, sandboxPath: string): Promise<void>;
57
+ /** Copy a single file from the sandbox to the host. */
58
+ copyFileOut(sandboxPath: string, hostPath: string): Promise<void>;
59
+ /** Tear down the sandbox. */
60
+ close(): Promise<void>;
61
+ }
62
+ /** Options passed to a bind-mount provider's `create` function. */
63
+ interface BindMountCreateOptions {
64
+ /** Host-side path to the worktree directory. */
65
+ readonly worktreePath: string;
66
+ /** Host-side path to the original repo root. */
67
+ readonly hostRepoPath: string;
68
+ /** Volume mounts to apply (host:sandbox pairs). */
69
+ readonly mounts: Array<{
70
+ hostPath: string;
71
+ sandboxPath: string;
72
+ readonly?: boolean;
73
+ }>;
74
+ /** Environment variables to inject into the sandbox. */
75
+ readonly env: Record<string, string>;
76
+ }
77
+ /** Configuration for createBindMountSandboxProvider. */
78
+ interface BindMountSandboxProviderConfig {
79
+ /** Human-readable name for this provider (e.g. "docker"). */
80
+ readonly name: string;
81
+ /** Environment variables injected by this provider. Merged at launch time. */
82
+ readonly env?: Record<string, string>;
83
+ /**
84
+ * Absolute path to the home directory inside the sandbox (e.g. `"/home/agent"`).
85
+ * Used to expand `~` in user-provided `sandboxPath` mount configs.
86
+ * Set to `undefined` for providers that do not have a fixed home directory.
87
+ */
88
+ readonly sandboxHomedir?: string;
89
+ /** Create a sandbox handle from the given options. */
90
+ readonly create: (options: BindMountCreateOptions) => Promise<BindMountSandboxHandle>;
91
+ }
92
+ /** Handle to a running isolated sandbox (extends bind-mount with file transfer). */
93
+ interface IsolatedSandboxHandle {
94
+ /** Absolute path to the worktree inside the sandbox. */
95
+ readonly worktreePath: string;
96
+ /**
97
+ * Execute a command in the sandbox.
98
+ *
99
+ * Implementations MUST support line-by-line streaming via `onLine`. This is
100
+ * how Shipyard delivers live feedback to the user and enforces idle timeouts —
101
+ * without a streaming implementation, neither will work. A buffered/batch
102
+ * implementation that only calls `onLine` after the process exits does NOT
103
+ * satisfy this contract.
104
+ *
105
+ * When `stdin` is set, the implementation pipes the string to the child
106
+ * process's stdin and closes it. This avoids the Linux 128 KB per-arg limit.
107
+ */
108
+ exec(command: string, options?: {
109
+ onLine?: (line: string) => void;
110
+ cwd?: string;
111
+ sudo?: boolean;
112
+ stdin?: string;
113
+ /** Abort the command when the caller's operation is cancelled. */
114
+ signal?: AbortSignal;
115
+ /** Reject/terminate the command after this many combined output bytes. */
116
+ maxOutputBytes?: number;
117
+ }): Promise<ExecResult>;
118
+ /**
119
+ * Launch an interactive process inside the sandbox.
120
+ * Optional — providers that support interactive sessions implement this.
121
+ * The provider detects TTY mode from the streams (e.g. stdin.isTTY) and
122
+ * allocates a pseudo-terminal accordingly.
123
+ */
124
+ interactiveExec?(args: string[], options: InteractiveExecOptions): Promise<{
125
+ exitCode: number;
126
+ }>;
127
+ /** Copy a file or directory from the host into the sandbox. */
128
+ copyIn(hostPath: string, sandboxPath: string): Promise<void>;
129
+ /** Copy a single file from the sandbox to the host. */
130
+ copyFileOut(sandboxPath: string, hostPath: string): Promise<void>;
131
+ /** Tear down the sandbox. */
132
+ close(): Promise<void>;
133
+ }
134
+ /** Options passed to an isolated provider's `create` function. */
135
+ interface IsolatedCreateOptions {
136
+ /** Original host repository path, used only for image naming; never mounted. */
137
+ readonly hostRepoPath?: string;
138
+ /** Environment variables to inject into the sandbox. */
139
+ readonly env: Record<string, string>;
140
+ }
141
+ /** Configuration for createIsolatedSandboxProvider. */
142
+ interface IsolatedSandboxProviderConfig {
143
+ /** Human-readable name for this provider (e.g. "vercel"). */
144
+ readonly name: string;
145
+ /** Environment variables injected by this provider. Merged at launch time. */
146
+ readonly env?: Record<string, string>;
147
+ /** Create an isolated sandbox handle from the given options. */
148
+ readonly create: (options: IsolatedCreateOptions) => Promise<IsolatedSandboxHandle>;
149
+ }
150
+ /** A bind-mount sandbox provider. */
151
+ interface BindMountSandboxProvider {
152
+ /** Human-readable provider name. */
153
+ readonly name: string;
154
+ /** Environment variables injected by this provider. */
155
+ readonly env: Record<string, string>;
156
+ /**
157
+ * Absolute path to the home directory inside the sandbox (e.g. `"/home/agent"`).
158
+ * `undefined` when the provider does not declare a sandbox home directory.
159
+ */
160
+ readonly sandboxHomedir: string | undefined;
161
+ }
162
+ /** An isolated sandbox provider. */
163
+ interface IsolatedSandboxProvider {
164
+ /** Human-readable provider name. */
165
+ readonly name: string;
166
+ /** Environment variables injected by this provider. */
167
+ readonly env: Record<string, string>;
168
+ }
169
+ /** Handle to a no-sandbox session — runs commands directly on the host. */
170
+ interface NoSandboxHandle {
171
+ /** Absolute path to the worktree on the host. */
172
+ readonly worktreePath: string;
173
+ /**
174
+ * Execute a command on the host.
175
+ *
176
+ * Implementations MUST support line-by-line streaming via `onLine`. This is
177
+ * how Shipyard delivers live feedback to the user and enforces idle timeouts —
178
+ * without a streaming implementation, neither will work.
179
+ *
180
+ * When `stdin` is set, the implementation pipes the string to the child
181
+ * process's stdin and closes it. This avoids the Linux 128 KB per-arg limit.
182
+ */
183
+ exec(command: string, options?: {
184
+ onLine?: (line: string) => void;
185
+ cwd?: string;
186
+ sudo?: boolean;
187
+ stdin?: string;
188
+ /** Abort the command when the caller's operation is cancelled. */
189
+ signal?: AbortSignal;
190
+ /** Reject/terminate the command after this many combined output bytes. */
191
+ maxOutputBytes?: number;
192
+ }): Promise<ExecResult>;
193
+ /**
194
+ * Launch an interactive process on the host with inherited stdio.
195
+ */
196
+ interactiveExec(args: string[], options: InteractiveExecOptions): Promise<{
197
+ exitCode: number;
198
+ }>;
199
+ /** No-op — no container to tear down. */
200
+ close(): Promise<void>;
201
+ }
202
+ /** A no-sandbox provider — runs the agent directly on the host with no container isolation. */
203
+ interface NoSandboxProvider {
204
+ /** Human-readable provider name. */
205
+ readonly name: string;
206
+ /** Environment variables injected by this provider. */
207
+ readonly env: Record<string, string>;
208
+ }
209
+ /** Head strategy: agent writes directly to host working directory. Bind-mount only. */
210
+ interface HeadBranchStrategy {
211
+ readonly type: "head";
212
+ }
213
+ /** Merge-to-head strategy: temp branch, merge back to HEAD, delete temp branch. */
214
+ interface MergeToHeadBranchStrategy {
215
+ readonly type: "merge-to-head";
216
+ }
217
+ /** Branch strategy: commits land on an explicit named branch. */
218
+ interface NamedBranchStrategy {
219
+ readonly type: "branch";
220
+ readonly branch: string;
221
+ /**
222
+ * Git ref to use as the starting point when creating a new branch.
223
+ * Only used when the branch doesn't already exist — ignored otherwise.
224
+ * Callers are responsible for ensuring the ref is current (e.g. `git fetch`).
225
+ * Defaults to `HEAD` when omitted.
226
+ */
227
+ readonly baseBranch?: string;
228
+ }
229
+ /** Branch strategy for bind-mount providers (all three variants). */
230
+ type BindMountBranchStrategy = HeadBranchStrategy | MergeToHeadBranchStrategy | NamedBranchStrategy;
231
+ /** Branch strategy for isolated providers (no head — can't write to host). */
232
+ type IsolatedBranchStrategy = MergeToHeadBranchStrategy | NamedBranchStrategy;
233
+ /** Branch strategy for no-sandbox providers (all three — same as bind-mount). */
234
+ type NoSandboxBranchStrategy = HeadBranchStrategy | MergeToHeadBranchStrategy | NamedBranchStrategy;
235
+ /** Union of all branch strategy variants. */
236
+ type BranchStrategy = BindMountBranchStrategy | IsolatedBranchStrategy | NoSandboxBranchStrategy;
237
+ /**
238
+ * A sandbox provider — the pluggable unit that `run()`, `interactive()`, and
239
+ * `createSandbox()` accept. Tagged for internal dispatch: "bind-mount",
240
+ * "isolated", or "none". When `NoSandboxProvider` is used, the agent runs
241
+ * directly on the host with no container isolation — opt in at your own risk.
242
+ */
243
+ type SandboxProvider = BindMountSandboxProvider | IsolatedSandboxProvider | NoSandboxProvider;
244
+ /** @deprecated Use `SandboxProvider` — it now includes `NoSandboxProvider`. */
245
+ type AnySandboxProvider = SandboxProvider;
246
+ /**
247
+ * Create a bind-mount sandbox provider from a config object.
248
+ * The returned provider can be passed to `run()` or `createSandbox()`.
249
+ */
250
+ declare const createBindMountSandboxProvider: (config: BindMountSandboxProviderConfig) => BindMountSandboxProvider;
251
+ /**
252
+ * Create an isolated sandbox provider from a config object.
253
+ * The returned provider can be passed to `run()` or `createSandbox()`.
254
+ */
255
+ declare const createIsolatedSandboxProvider: (config: IsolatedSandboxProviderConfig) => IsolatedSandboxProvider;
256
+
257
+ export { type AnySandboxProvider as A, type BindMountSandboxHandle as B, type ExecResult as E, type HeadBranchStrategy as H, type IsolatedSandboxProvider as I, type MergeToHeadBranchStrategy as M, type NoSandboxProvider as N, type SandboxProvider as S, type BranchStrategy as a, type NamedBranchStrategy as b, type BindMountBranchStrategy as c, type BindMountCreateOptions as d, type BindMountSandboxProvider as e, type BindMountSandboxProviderConfig as f, type InteractiveExecOptions as g, type IsolatedBranchStrategy as h, type IsolatedCreateOptions as i, type IsolatedSandboxHandle as j, type IsolatedSandboxProviderConfig as k, type NoSandboxBranchStrategy as l, type NoSandboxHandle as m, createBindMountSandboxProvider as n, createIsolatedSandboxProvider as o };