@snappedly-tools/shipyard 0.5.0-staging.36072068333 → 0.6.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.
- package/README.md +165 -64
- package/dist/MountConfig-bZoCs4Dd.d.ts +26 -0
- package/dist/SandboxProvider-XJQqEdSf.d.ts +261 -0
- package/dist/{chunk-JI3HDDMS.js → chunk-56TDSWFU.js} +3 -3
- package/dist/{chunk-JI3HDDMS.js.map → chunk-56TDSWFU.js.map} +1 -1
- package/dist/chunk-ACD46ZM4.js +136 -0
- package/dist/chunk-ACD46ZM4.js.map +1 -0
- package/dist/{chunk-L6PX5QTU.js → chunk-FDYOTN55.js} +887 -262
- package/dist/chunk-FDYOTN55.js.map +1 -0
- package/dist/chunk-KMGNFXKN.js +38 -0
- package/dist/chunk-KMGNFXKN.js.map +1 -0
- package/dist/chunk-SOJTAJTF.js +78 -0
- package/dist/chunk-SOJTAJTF.js.map +1 -0
- package/dist/{chunk-44I2BL6E.js → chunk-WAXEMZUV.js} +33 -225
- package/dist/chunk-WAXEMZUV.js.map +1 -0
- package/dist/index.d.ts +97 -117
- package/dist/index.js +344 -322
- package/dist/index.js.map +1 -1
- package/dist/main.js +139 -235
- package/dist/main.js.map +1 -1
- package/dist/sandboxes/docker.d.ts +3 -1
- package/dist/sandboxes/docker.js +4 -2
- package/dist/sandboxes/no-sandbox.d.ts +37 -0
- package/dist/sandboxes/no-sandbox.js +4 -0
- package/dist/sandboxes/no-sandbox.js.map +1 -0
- package/dist/sandboxes/vercel.d.ts +104 -0
- package/dist/sandboxes/vercel.js +166 -0
- package/dist/sandboxes/vercel.js.map +1 -0
- package/dist/templates/blank/main.mts +13 -0
- package/dist/templates/blank/prompt.md +12 -0
- package/dist/templates/blank/template.json +4 -0
- package/dist/templates/parallel-planner/main.mts +9 -67
- package/dist/templates/parallel-planner-with-review/main.mts +12 -70
- package/dist/templates/sequential-reviewer/main.mts +3 -52
- package/dist/templates/simple-loop/main.mts +2 -51
- package/package.json +17 -1
- package/dist/MountConfig-BHnKnA4h.d.ts +0 -145
- package/dist/chunk-44I2BL6E.js.map +0 -1
- package/dist/chunk-L6PX5QTU.js.map +0 -1
- package/dist/templates/parallel-planner/planner-branch.mts +0 -151
- package/dist/templates/parallel-planner-with-review/planner-branch.mts +0 -151
package/README.md
CHANGED
|
@@ -8,100 +8,201 @@
|
|
|
8
8
|
|
|
9
9
|
[](https://github.com/snappedly/shipyard/actions/workflows/ci.yml)
|
|
10
10
|
|
|
11
|
-
Give Shipyard a
|
|
12
|
-
isolated
|
|
13
|
-
|
|
11
|
+
Give Shipyard a backlog and a policy. It plans dependencies, runs AI coding
|
|
12
|
+
agents in isolated sandboxes, reviews their work, and returns reviewable
|
|
13
|
+
commits—without babysitting.
|
|
14
14
|
|
|
15
15
|
## The Shipyard advantage
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- **Built for real projects.** Shipyard can sort issue dependencies, work on
|
|
20
|
-
independent tasks in parallel, and review the combined result.
|
|
21
|
-
- **You stay in control.** Runs have limits and logs. Issue workflows return a
|
|
22
|
-
pull request for you to review and merge.
|
|
17
|
+
Most agent setups launch a CLI and hope for the best. Shipyard is the control
|
|
18
|
+
plane around the agent:
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
- **Protected execution:** Run Codex or Claude Code in an isolated Docker-backed
|
|
21
|
+
sandbox with explicit mounts, credentials, and network access.
|
|
22
|
+
- **Real orchestration:** Plan dependencies, parallelize safe work, leave
|
|
23
|
+
blocked work alone, review each branch, and merge completed work.
|
|
24
|
+
- **Failure-aware by design:** Use finite budgets, no-progress detection,
|
|
25
|
+
cancellation, logs, and recovery artifacts instead of runaway loops.
|
|
26
|
+
- **Reviewable output:** Runs preserve branches, worktrees, logs, and evidence;
|
|
27
|
+
completed work comes back as commits. You keep control of the repository and
|
|
28
|
+
the final release.
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
with a subscription login or API key.
|
|
30
|
+
## Install and run
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
Before running Shipyard, install the [Snappedly skills](https://github.com/snappedly/skills)
|
|
33
|
+
and run `setup-snapedly-skills` in the target repository.
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Ask your coding agent to run `setup-snappedly-skills` in that repository.
|
|
35
|
+
Requirements: Node.js 20.18.1+, Git, Docker, and credentials for your chosen
|
|
36
|
+
agent. Run these commands in the repository Shipyard should change:
|
|
36
37
|
|
|
37
38
|
```sh
|
|
38
39
|
npm install --save-dev @snappedly-tools/shipyard
|
|
39
40
|
npx shipyard init
|
|
40
41
|
```
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
`init` asks for the agent, authentication, sandbox, issue tracker, and workflow
|
|
44
|
+
template, then creates `.shipyard/`. For the first run, choose Docker and
|
|
45
|
+
`blank` or `sequential-reviewer`.
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
Add the requested credentials to `.shipyard/.env`, write a task in
|
|
48
|
+
`.shipyard/prompt.md` when using the `blank` template, then run:
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Fill in any credentials required in `.shipyard/.env`.
|
|
53
|
-
`GH_TOKEN` in `.shipyard/.env` to a GH token with Contents, Issues, and Pull
|
|
54
|
-
Requests read/write access and Metadata read access.
|
|
55
|
-
Set `SHIPYARD_ROUTINE_MODEL` and `SHIPYARD_STRONG_MODEL` in `.shipyard/.env`
|
|
56
|
-
for the roles your template uses. `simple-loop` uses routine for triage and
|
|
57
|
-
implementation. `sequential-reviewer` also uses strong for issue reviews.
|
|
58
|
-
Parallel planner templates use routine for ticket work and strong for planning,
|
|
59
|
-
conflict resolution, and integration. The review-enabled planner also uses
|
|
60
|
-
strong for ticket and final specification reviews. See
|
|
61
|
-
[agent setup](docs/content/docs/agents.mdx).
|
|
50
|
+
```sh
|
|
51
|
+
npx shipyard run
|
|
52
|
+
```
|
|
62
53
|
|
|
63
|
-
|
|
64
|
-
|
|
54
|
+
The first run builds the Docker image automatically. Reuse it when the
|
|
55
|
+
Dockerfile has not changed:
|
|
65
56
|
|
|
66
57
|
```sh
|
|
67
|
-
npx shipyard run
|
|
58
|
+
npx shipyard run --skip-build
|
|
68
59
|
```
|
|
69
60
|
|
|
70
|
-
|
|
61
|
+
For Codex, `init` can sign in with a ChatGPT subscription or configure an OpenAI
|
|
62
|
+
API key. Claude Code supports a subscription token or an Anthropic API key. See
|
|
63
|
+
the [agent guide](docs/content/docs/agents.mdx) for authentication details.
|
|
64
|
+
|
|
65
|
+
## Pick the workflow you need
|
|
66
|
+
|
|
67
|
+
| Template | Best for | Built-in flow |
|
|
68
|
+
| ------------------------------ | --------------------- | --------------------------------------------- |
|
|
69
|
+
| `blank` | One custom task | One agent run |
|
|
70
|
+
| `simple-loop` | A small issue backlog | Implement issues sequentially → review PRs |
|
|
71
|
+
| `sequential-reviewer` | Safer issue delivery | Implement → review → review PR |
|
|
72
|
+
| `parallel-planner` | Independent issues | Plan → implement in parallel → review PRs |
|
|
73
|
+
| `parallel-planner-with-review` | Maximum autonomy | Plan → implement and review in parallel → PRs |
|
|
74
|
+
|
|
75
|
+
All templates are generated TypeScript. Adjust prompts, models, iteration
|
|
76
|
+
limits, branch strategy, hooks, and checks in `.shipyard/main.ts` or
|
|
77
|
+
`.shipyard/main.mts`.
|
|
78
|
+
|
|
79
|
+
## Keep a repository running
|
|
80
|
+
|
|
81
|
+
On Apple Silicon macOS, the optional repository runner keeps a foreground
|
|
82
|
+
Shipyard controller ready for GitHub Issues. Label an issue `shipyard`; the
|
|
83
|
+
controller wakes, drains a finite batch of eligible work, coalesces duplicate
|
|
84
|
+
wake-ups, and stops when it makes no progress. Restarting it recovers work
|
|
85
|
+
labelled while the host was offline.
|
|
86
|
+
GitHub-backed `shipyard init` provisions `shipyard`, `shipyard:blocked`,
|
|
87
|
+
`shipyard:pending`, `shipyard:complete`, and `shipyard:outstanding-tasks` in the repository.
|
|
88
|
+
It also provisions the `bug`, `enhancement`, and five triage state labels.
|
|
89
|
+
For a connected repository, init reports an error if any label cannot be created.
|
|
90
|
+
|
|
91
|
+
The bundled issue workflows install Snappedly skills and the candidate's
|
|
92
|
+
dependencies in Docker. When Shipyard takes an activated ticket, it runs
|
|
93
|
+
`/triage` first and checks the current GitHub labels. Implementation requires
|
|
94
|
+
both `shipyard` and `ready-for-agent`, with no conflicting triage state. Other
|
|
95
|
+
triage outcomes follow the normal blocked flow: Shipyard adds
|
|
96
|
+
`shipyard:blocked`, removes `shipyard`, and records the reason on the ticket.
|
|
97
|
+
A standalone ready issue then runs through `/implement`. Activating
|
|
98
|
+
a planning spec or a linked executable child resolves the parent and only
|
|
99
|
+
linked tickets labelled `shipyard` into one `/implement-spec` scope. The sequential
|
|
100
|
+
templates deliver selected tickets on one branch; the parallel templates assign
|
|
101
|
+
ready tickets to `/implement` workers, integrate dependency waves, resolve ticket
|
|
102
|
+
merge conflicts on the spec branch, and review the integrated change. One
|
|
103
|
+
non-draft PR per spec awaits human merge. Later selected tickets update that PR.
|
|
104
|
+
Shipyard also recognizes a ticket added to an open verified spec PR's `Source
|
|
105
|
+
issues:` line as belonging to that spec, even without a GitHub sub-issue or
|
|
106
|
+
`## Parent` link. Conflicting links block the selected ticket for correction.
|
|
107
|
+
Selected tickets receive `shipyard:pending` while Shipyard works on them.
|
|
108
|
+
Successful handoff replaces it with `shipyard:complete` and removes `shipyard`.
|
|
109
|
+
The parent spec and PR show `shipyard:blocked` if an unfinished child is blocked,
|
|
110
|
+
`shipyard:outstanding-tasks` if children remain, or `shipyard:complete` when all
|
|
111
|
+
linked tickets are complete. Spec labels report child state; they never prevent
|
|
112
|
+
a reactivated child from running. The issues remain open under the target
|
|
113
|
+
repository's closure policy.
|
|
114
|
+
With no labelled tickets yet, Shipyard marks the parent outstanding and waits
|
|
115
|
+
to create the PR until a ticket is selected.
|
|
116
|
+
If an attempted issue cannot be completed, Shipyard comments with the reason,
|
|
117
|
+
marks the attempted tickets `shipyard:blocked`, clears `shipyard:pending`, and
|
|
118
|
+
removes `shipyard` from the scope. The parent spec and any existing PR show
|
|
119
|
+
`shipyard:blocked` while an unfinished child remains blocked. It does not
|
|
120
|
+
publish a new PR for failed work. Resolve the problem, remove
|
|
121
|
+
`shipyard:blocked` from a ticket, then add `shipyard` to retry that ticket;
|
|
122
|
+
the parent spec's status label needs no manual change. Missing or ambiguous
|
|
123
|
+
relationships block the affected selected issue and record the reason. If GitHub cannot confirm whether a
|
|
124
|
+
PR became ready, Shipyard leaves the issue active for reconciliation. The GitHub token
|
|
125
|
+
needs Contents, Issues, and Pull requests read/write permission plus Metadata
|
|
126
|
+
read permission. Keep the Mac and foreground controller running for wake-ups.
|
|
127
|
+
If GitHub rejects a failure comment, Shipyard keeps a local pending report for
|
|
128
|
+
replay. A fresh `shipyard` activation on an unblocked ticket supersedes that
|
|
129
|
+
report. Spec and PR status label failures are logged without stopping ticket
|
|
130
|
+
work; retained activation lets the next invocation recalculate their labels.
|
|
131
|
+
|
|
132
|
+
Accept runner installation during `init`, or install it later:
|
|
71
133
|
|
|
72
134
|
```sh
|
|
135
|
+
npx shipyard runner install
|
|
136
|
+
git add .shipyard .github/workflows/shipyard-wake.yml
|
|
137
|
+
git commit -m "Add Shipyard wake workflow"
|
|
138
|
+
git push
|
|
73
139
|
npx shipyard runner start
|
|
74
140
|
```
|
|
75
141
|
|
|
76
|
-
|
|
142
|
+
Run `npx shipyard runner purge` to remove every dated run-log folder and
|
|
143
|
+
root-level `.log` file under `.shipyard/logs/`. Shipyard automatically removes
|
|
144
|
+
entries older than eight days before `shipyard run`, at runner startup, and
|
|
145
|
+
daily while the runner stays active. Use a path outside `.shipyard/logs/` for
|
|
146
|
+
logs that must be retained separately.
|
|
147
|
+
|
|
148
|
+
See the [repository runner guide](docs/content/docs/repository-runner.mdx) for
|
|
149
|
+
requirements, lifecycle commands, and the security model.
|
|
77
150
|
|
|
78
|
-
|
|
151
|
+
## Build your own coordinator
|
|
152
|
+
|
|
153
|
+
Shipyard is also a TypeScript library. Compose your own workflow with
|
|
154
|
+
`run()`, `createSandbox()`, and `createWorktree()` while reusing its agent,
|
|
155
|
+
sandbox, branch, prompt, logging, cancellation, and session primitives.
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { CODEX_MODELS, codex, run } from "@snappedly-tools/shipyard";
|
|
159
|
+
import { docker } from "@snappedly-tools/shipyard/sandboxes/docker";
|
|
160
|
+
|
|
161
|
+
await run({
|
|
162
|
+
agent: codex(CODEX_MODELS.routine),
|
|
163
|
+
sandbox: docker(),
|
|
164
|
+
promptFile: ".shipyard/prompt.md",
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Docker is the default path. Vercel Sandbox is available for isolated cloud
|
|
169
|
+
execution; `noSandbox()` is available only for trusted repositories and prompts.
|
|
170
|
+
|
|
171
|
+
## What gets created
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
.shipyard/
|
|
175
|
+
├── main.ts or main.mts # workflow configuration
|
|
176
|
+
├── prompt.md # task or issue instructions
|
|
177
|
+
├── Dockerfile # sandbox image definition
|
|
178
|
+
├── .env # untracked credentials
|
|
179
|
+
├── logs/ # run logs
|
|
180
|
+
├── worktrees/ # isolated branch worktrees
|
|
181
|
+
└── patches/ # recovery artifacts
|
|
182
|
+
```
|
|
79
183
|
|
|
80
|
-
|
|
81
|
-
`ready-for-agent` labels.
|
|
82
|
-
2. Make sure the runner is running, or start `npx shipyard run`. Shipyard checks the issue, implements it in Docker,
|
|
83
|
-
reviews the work, and opens a pull request.
|
|
84
|
-
3. Inspect the pull request and merge it when you are happy with the result.
|
|
184
|
+
## Security and control
|
|
85
185
|
|
|
86
|
-
|
|
186
|
+
Docker keeps the agent's repository and Git storage inside the sandbox by
|
|
187
|
+
default. It is not a magic security boundary: mounts, credentials, devices,
|
|
188
|
+
network access, host hooks, and `noSandbox()` can expand what an agent can do.
|
|
189
|
+
Use least-privilege credentials and review generated configuration before
|
|
190
|
+
running untrusted code. Read the [security evaluation](docs/security-evaluation.md)
|
|
191
|
+
and [SECURITY.md](SECURITY.md).
|
|
87
192
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
| `simple-loop` | Works through labeled issues one at a time. |
|
|
91
|
-
| `sequential-reviewer` | Implements and reviews issues before PR handoff. |
|
|
92
|
-
| `parallel-planner` | Plans and works on independent issues in parallel. |
|
|
93
|
-
| `parallel-planner-with-review` | Adds review to the parallel workflow. |
|
|
193
|
+
Shipyard runs in your infrastructure. There is no required hosted control
|
|
194
|
+
plane; you control the host, Docker, model access, logs, and release policy.
|
|
94
195
|
|
|
95
|
-
|
|
96
|
-
branches, limits, and hooks in the generated `.shipyard/main.ts` or
|
|
97
|
-
`.shipyard/main.mts`. See [configuration](docs/content/docs/configuration.mdx)
|
|
98
|
-
and [agent setup](docs/content/docs/agents.mdx).
|
|
196
|
+
## Learn more
|
|
99
197
|
|
|
100
|
-
|
|
198
|
+
- [Getting started](docs/content/docs/index.mdx)
|
|
199
|
+
- [Configuration](docs/content/docs/configuration.mdx)
|
|
200
|
+
- [Repository runner operations](docs/runbooks/repository-runner-macos-validation.md)
|
|
201
|
+
- [Contributing](CONTRIBUTING.md)
|
|
101
202
|
|
|
102
|
-
|
|
103
|
-
mounts, credentials, and network settings you choose. Read the
|
|
104
|
-
[security guide](docs/security-evaluation.md) before using untrusted code.
|
|
203
|
+
## License
|
|
105
204
|
|
|
106
|
-
Shipyard is source-available under the
|
|
107
|
-
|
|
205
|
+
Shipyard is source-available under the
|
|
206
|
+
[PolyForm Strict License 1.0.0](LICENSE). It is available for permitted
|
|
207
|
+
noncommercial use; the license does not permit redistribution, modification, or
|
|
208
|
+
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,261 @@
|
|
|
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
|
+
/** Terminate the interactive process when the caller cancels the session. */
|
|
20
|
+
readonly signal?: AbortSignal;
|
|
21
|
+
}
|
|
22
|
+
/** Handle to a running bind-mount sandbox. */
|
|
23
|
+
interface BindMountSandboxHandle {
|
|
24
|
+
/** Absolute path to the worktree inside the sandbox. */
|
|
25
|
+
readonly worktreePath: string;
|
|
26
|
+
/**
|
|
27
|
+
* Execute a command in the sandbox.
|
|
28
|
+
*
|
|
29
|
+
* Implementations MUST support line-by-line streaming via `onLine`. This is
|
|
30
|
+
* how Shipyard delivers live feedback to the user and enforces idle timeouts —
|
|
31
|
+
* without a streaming implementation, neither will work. A buffered/batch
|
|
32
|
+
* implementation that only calls `onLine` after the process exits does NOT
|
|
33
|
+
* satisfy this contract.
|
|
34
|
+
*
|
|
35
|
+
* When `stdin` is set, the implementation pipes the string to the child
|
|
36
|
+
* process's stdin and closes it. This avoids the Linux 128 KB per-arg limit.
|
|
37
|
+
*/
|
|
38
|
+
exec(command: string, options?: {
|
|
39
|
+
onLine?: (line: string) => void;
|
|
40
|
+
cwd?: string;
|
|
41
|
+
sudo?: boolean;
|
|
42
|
+
stdin?: string;
|
|
43
|
+
/** Abort the command when the caller's operation is cancelled. */
|
|
44
|
+
signal?: AbortSignal;
|
|
45
|
+
/** Reject/terminate the command after this many combined output bytes. */
|
|
46
|
+
maxOutputBytes?: number;
|
|
47
|
+
}): Promise<ExecResult>;
|
|
48
|
+
/**
|
|
49
|
+
* Launch an interactive process inside the sandbox.
|
|
50
|
+
* Optional — providers that support interactive sessions implement this.
|
|
51
|
+
* The provider detects TTY mode from the streams (e.g. stdin.isTTY) and
|
|
52
|
+
* allocates a pseudo-terminal accordingly.
|
|
53
|
+
* Implementations MUST terminate the underlying process when `signal` aborts.
|
|
54
|
+
*/
|
|
55
|
+
interactiveExec?(args: string[], options: InteractiveExecOptions): Promise<{
|
|
56
|
+
exitCode: number;
|
|
57
|
+
}>;
|
|
58
|
+
/** Copy a single file from the host into the sandbox. */
|
|
59
|
+
copyFileIn(hostPath: string, sandboxPath: string): Promise<void>;
|
|
60
|
+
/** Copy a single file from the sandbox to the host. */
|
|
61
|
+
copyFileOut(sandboxPath: string, hostPath: string): Promise<void>;
|
|
62
|
+
/** Tear down the sandbox. */
|
|
63
|
+
close(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
/** Options passed to a bind-mount provider's `create` function. */
|
|
66
|
+
interface BindMountCreateOptions {
|
|
67
|
+
/** Host-side path to the worktree directory. */
|
|
68
|
+
readonly worktreePath: string;
|
|
69
|
+
/** Host-side path to the original repo root. */
|
|
70
|
+
readonly hostRepoPath: string;
|
|
71
|
+
/** Volume mounts to apply (host:sandbox pairs). */
|
|
72
|
+
readonly mounts: Array<{
|
|
73
|
+
hostPath: string;
|
|
74
|
+
sandboxPath: string;
|
|
75
|
+
readonly?: boolean;
|
|
76
|
+
}>;
|
|
77
|
+
/** Environment variables to inject into the sandbox. */
|
|
78
|
+
readonly env: Record<string, string>;
|
|
79
|
+
}
|
|
80
|
+
/** Configuration for createBindMountSandboxProvider. */
|
|
81
|
+
interface BindMountSandboxProviderConfig {
|
|
82
|
+
/** Human-readable name for this provider (e.g. "docker"). */
|
|
83
|
+
readonly name: string;
|
|
84
|
+
/** Environment variables injected by this provider. Merged at launch time. */
|
|
85
|
+
readonly env?: Record<string, string>;
|
|
86
|
+
/**
|
|
87
|
+
* Absolute path to the home directory inside the sandbox (e.g. `"/home/agent"`).
|
|
88
|
+
* Used to expand `~` in user-provided `sandboxPath` mount configs.
|
|
89
|
+
* Set to `undefined` for providers that do not have a fixed home directory.
|
|
90
|
+
*/
|
|
91
|
+
readonly sandboxHomedir?: string;
|
|
92
|
+
/** Create a sandbox handle from the given options. */
|
|
93
|
+
readonly create: (options: BindMountCreateOptions) => Promise<BindMountSandboxHandle>;
|
|
94
|
+
}
|
|
95
|
+
/** Handle to a running isolated sandbox (extends bind-mount with file transfer). */
|
|
96
|
+
interface IsolatedSandboxHandle {
|
|
97
|
+
/** Absolute path to the worktree inside the sandbox. */
|
|
98
|
+
readonly worktreePath: string;
|
|
99
|
+
/**
|
|
100
|
+
* Execute a command in the sandbox.
|
|
101
|
+
*
|
|
102
|
+
* Implementations MUST support line-by-line streaming via `onLine`. This is
|
|
103
|
+
* how Shipyard delivers live feedback to the user and enforces idle timeouts —
|
|
104
|
+
* without a streaming implementation, neither will work. A buffered/batch
|
|
105
|
+
* implementation that only calls `onLine` after the process exits does NOT
|
|
106
|
+
* satisfy this contract.
|
|
107
|
+
*
|
|
108
|
+
* When `stdin` is set, the implementation pipes the string to the child
|
|
109
|
+
* process's stdin and closes it. This avoids the Linux 128 KB per-arg limit.
|
|
110
|
+
*/
|
|
111
|
+
exec(command: string, options?: {
|
|
112
|
+
onLine?: (line: string) => void;
|
|
113
|
+
cwd?: string;
|
|
114
|
+
sudo?: boolean;
|
|
115
|
+
stdin?: string;
|
|
116
|
+
/** Abort the command when the caller's operation is cancelled. */
|
|
117
|
+
signal?: AbortSignal;
|
|
118
|
+
/** Reject/terminate the command after this many combined output bytes. */
|
|
119
|
+
maxOutputBytes?: number;
|
|
120
|
+
}): Promise<ExecResult>;
|
|
121
|
+
/**
|
|
122
|
+
* Launch an interactive process inside the sandbox.
|
|
123
|
+
* Optional — providers that support interactive sessions implement this.
|
|
124
|
+
* The provider detects TTY mode from the streams (e.g. stdin.isTTY) and
|
|
125
|
+
* allocates a pseudo-terminal accordingly.
|
|
126
|
+
* Implementations MUST terminate the underlying process when `signal` aborts.
|
|
127
|
+
*/
|
|
128
|
+
interactiveExec?(args: string[], options: InteractiveExecOptions): Promise<{
|
|
129
|
+
exitCode: number;
|
|
130
|
+
}>;
|
|
131
|
+
/** Copy a file or directory from the host into the sandbox. */
|
|
132
|
+
copyIn(hostPath: string, sandboxPath: string): Promise<void>;
|
|
133
|
+
/** Copy a single file from the sandbox to the host. */
|
|
134
|
+
copyFileOut(sandboxPath: string, hostPath: string): Promise<void>;
|
|
135
|
+
/** Tear down the sandbox. */
|
|
136
|
+
close(): Promise<void>;
|
|
137
|
+
}
|
|
138
|
+
/** Options passed to an isolated provider's `create` function. */
|
|
139
|
+
interface IsolatedCreateOptions {
|
|
140
|
+
/** Original host repository path, used only for image naming; never mounted. */
|
|
141
|
+
readonly hostRepoPath?: string;
|
|
142
|
+
/** Environment variables to inject into the sandbox. */
|
|
143
|
+
readonly env: Record<string, string>;
|
|
144
|
+
}
|
|
145
|
+
/** Configuration for createIsolatedSandboxProvider. */
|
|
146
|
+
interface IsolatedSandboxProviderConfig {
|
|
147
|
+
/** Human-readable name for this provider (e.g. "vercel"). */
|
|
148
|
+
readonly name: string;
|
|
149
|
+
/** Environment variables injected by this provider. Merged at launch time. */
|
|
150
|
+
readonly env?: Record<string, string>;
|
|
151
|
+
/** Create an isolated sandbox handle from the given options. */
|
|
152
|
+
readonly create: (options: IsolatedCreateOptions) => Promise<IsolatedSandboxHandle>;
|
|
153
|
+
}
|
|
154
|
+
/** A bind-mount sandbox provider. */
|
|
155
|
+
interface BindMountSandboxProvider {
|
|
156
|
+
/** Human-readable provider name. */
|
|
157
|
+
readonly name: string;
|
|
158
|
+
/** Environment variables injected by this provider. */
|
|
159
|
+
readonly env: Record<string, string>;
|
|
160
|
+
/**
|
|
161
|
+
* Absolute path to the home directory inside the sandbox (e.g. `"/home/agent"`).
|
|
162
|
+
* `undefined` when the provider does not declare a sandbox home directory.
|
|
163
|
+
*/
|
|
164
|
+
readonly sandboxHomedir: string | undefined;
|
|
165
|
+
}
|
|
166
|
+
/** An isolated sandbox provider. */
|
|
167
|
+
interface IsolatedSandboxProvider {
|
|
168
|
+
/** Human-readable provider name. */
|
|
169
|
+
readonly name: string;
|
|
170
|
+
/** Environment variables injected by this provider. */
|
|
171
|
+
readonly env: Record<string, string>;
|
|
172
|
+
}
|
|
173
|
+
/** Handle to a no-sandbox session — runs commands directly on the host. */
|
|
174
|
+
interface NoSandboxHandle {
|
|
175
|
+
/** Absolute path to the worktree on the host. */
|
|
176
|
+
readonly worktreePath: string;
|
|
177
|
+
/**
|
|
178
|
+
* Execute a command on the host.
|
|
179
|
+
*
|
|
180
|
+
* Implementations MUST support line-by-line streaming via `onLine`. This is
|
|
181
|
+
* how Shipyard delivers live feedback to the user and enforces idle timeouts —
|
|
182
|
+
* without a streaming implementation, neither will work.
|
|
183
|
+
*
|
|
184
|
+
* When `stdin` is set, the implementation pipes the string to the child
|
|
185
|
+
* process's stdin and closes it. This avoids the Linux 128 KB per-arg limit.
|
|
186
|
+
*/
|
|
187
|
+
exec(command: string, options?: {
|
|
188
|
+
onLine?: (line: string) => void;
|
|
189
|
+
cwd?: string;
|
|
190
|
+
sudo?: boolean;
|
|
191
|
+
stdin?: string;
|
|
192
|
+
/** Abort the command when the caller's operation is cancelled. */
|
|
193
|
+
signal?: AbortSignal;
|
|
194
|
+
/** Reject/terminate the command after this many combined output bytes. */
|
|
195
|
+
maxOutputBytes?: number;
|
|
196
|
+
}): Promise<ExecResult>;
|
|
197
|
+
/**
|
|
198
|
+
* Launch an interactive process on the host with inherited stdio.
|
|
199
|
+
*/
|
|
200
|
+
interactiveExec(args: string[], options: InteractiveExecOptions): Promise<{
|
|
201
|
+
exitCode: number;
|
|
202
|
+
}>;
|
|
203
|
+
/** No-op — no container to tear down. */
|
|
204
|
+
close(): Promise<void>;
|
|
205
|
+
}
|
|
206
|
+
/** A no-sandbox provider — runs the agent directly on the host with no container isolation. */
|
|
207
|
+
interface NoSandboxProvider {
|
|
208
|
+
/** Human-readable provider name. */
|
|
209
|
+
readonly name: string;
|
|
210
|
+
/** Environment variables injected by this provider. */
|
|
211
|
+
readonly env: Record<string, string>;
|
|
212
|
+
}
|
|
213
|
+
/** Head strategy: agent writes directly to host working directory. Bind-mount only. */
|
|
214
|
+
interface HeadBranchStrategy {
|
|
215
|
+
readonly type: "head";
|
|
216
|
+
}
|
|
217
|
+
/** Merge-to-head strategy: temp branch, merge back to HEAD, delete temp branch. */
|
|
218
|
+
interface MergeToHeadBranchStrategy {
|
|
219
|
+
readonly type: "merge-to-head";
|
|
220
|
+
}
|
|
221
|
+
/** Branch strategy: commits land on an explicit named branch. */
|
|
222
|
+
interface NamedBranchStrategy {
|
|
223
|
+
readonly type: "branch";
|
|
224
|
+
readonly branch: string;
|
|
225
|
+
/**
|
|
226
|
+
* Git ref to use as the starting point when creating a new branch.
|
|
227
|
+
* Only used when the branch doesn't already exist — ignored otherwise.
|
|
228
|
+
* Callers are responsible for ensuring the ref is current (e.g. `git fetch`).
|
|
229
|
+
* Defaults to `HEAD` when omitted.
|
|
230
|
+
*/
|
|
231
|
+
readonly baseBranch?: string;
|
|
232
|
+
}
|
|
233
|
+
/** Branch strategy for bind-mount providers (all three variants). */
|
|
234
|
+
type BindMountBranchStrategy = HeadBranchStrategy | MergeToHeadBranchStrategy | NamedBranchStrategy;
|
|
235
|
+
/** Branch strategy for isolated providers (no head — can't write to host). */
|
|
236
|
+
type IsolatedBranchStrategy = MergeToHeadBranchStrategy | NamedBranchStrategy;
|
|
237
|
+
/** Branch strategy for no-sandbox providers (all three — same as bind-mount). */
|
|
238
|
+
type NoSandboxBranchStrategy = HeadBranchStrategy | MergeToHeadBranchStrategy | NamedBranchStrategy;
|
|
239
|
+
/** Union of all branch strategy variants. */
|
|
240
|
+
type BranchStrategy = BindMountBranchStrategy | IsolatedBranchStrategy | NoSandboxBranchStrategy;
|
|
241
|
+
/**
|
|
242
|
+
* A sandbox provider — the pluggable unit that `run()`, `interactive()`, and
|
|
243
|
+
* `createSandbox()` accept. Tagged for internal dispatch: "bind-mount",
|
|
244
|
+
* "isolated", or "none". When `NoSandboxProvider` is used, the agent runs
|
|
245
|
+
* directly on the host with no container isolation — opt in at your own risk.
|
|
246
|
+
*/
|
|
247
|
+
type SandboxProvider = BindMountSandboxProvider | IsolatedSandboxProvider | NoSandboxProvider;
|
|
248
|
+
/** @deprecated Use `SandboxProvider` — it now includes `NoSandboxProvider`. */
|
|
249
|
+
type AnySandboxProvider = SandboxProvider;
|
|
250
|
+
/**
|
|
251
|
+
* Create a bind-mount sandbox provider from a config object.
|
|
252
|
+
* The returned provider can be passed to `run()` or `createSandbox()`.
|
|
253
|
+
*/
|
|
254
|
+
declare const createBindMountSandboxProvider: (config: BindMountSandboxProviderConfig) => BindMountSandboxProvider;
|
|
255
|
+
/**
|
|
256
|
+
* Create an isolated sandbox provider from a config object.
|
|
257
|
+
* The returned provider can be passed to `run()` or `createSandbox()`.
|
|
258
|
+
*/
|
|
259
|
+
declare const createIsolatedSandboxProvider: (config: IsolatedSandboxProviderConfig) => IsolatedSandboxProvider;
|
|
260
|
+
|
|
261
|
+
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 };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CONFIG_DIR, ConfigDirError, assertNoSymlinkComponents, LOGS_DIR, Display } from './chunk-
|
|
1
|
+
import { CONFIG_DIR, ConfigDirError, assertNoSymlinkComponents, LOGS_DIR, Display } from './chunk-FDYOTN55.js';
|
|
2
2
|
import { Effect } from 'effect';
|
|
3
3
|
import { FileSystem } from '@effect/platform';
|
|
4
4
|
import { join } from 'path';
|
|
@@ -251,5 +251,5 @@ var purgeRunLogs = async (options) => {
|
|
|
251
251
|
};
|
|
252
252
|
|
|
253
253
|
export { CODEX_MODELS, CODEX_REASONING_EFFORTS, DEFAULT_LOG_RETENTION_DAYS, buildLogDirectoryName, formatErrorMessage, purgeRunLogs, resolveEnv, withFriendlyErrors };
|
|
254
|
-
//# sourceMappingURL=chunk-
|
|
255
|
-
//# sourceMappingURL=chunk-
|
|
254
|
+
//# sourceMappingURL=chunk-56TDSWFU.js.map
|
|
255
|
+
//# sourceMappingURL=chunk-56TDSWFU.js.map
|