@paperclipai/plugin-boxd 0.0.0 → 2026.1104.0-canary.13
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/LICENSE +21 -0
- package/README.md +160 -6
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +4 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +74 -0
- package/dist/manifest.js.map +1 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +610 -0
- package/dist/plugin.js.map +1 -0
- package/dist/worker.d.ts +3 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +5 -0
- package/dist/worker.js.map +1 -0
- package/package.json +35 -9
- package/index.js +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Paperclip AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,8 +1,162 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@paperclipai/plugin-boxd`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
boxd sandbox provider for Paperclip. [boxd](https://boxd.sh) runs each sandbox
|
|
4
|
+
as an isolated KVM microVM. This package lives alongside E2B, Daytona and the
|
|
5
|
+
other sandbox providers, outside the root pnpm workspace. It uses the
|
|
6
|
+
[`@boxd-sh/sdk`](https://www.npmjs.com/package/@boxd-sh/sdk) package. Paperclip's
|
|
7
|
+
CI release pipeline publishes this plugin to npm.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
## Install from npm
|
|
10
|
+
|
|
11
|
+
Once a stable release is available, install the package from the Plugins page
|
|
12
|
+
by name, or use the CLI:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
paperclipai plugin install @paperclipai/plugin-boxd
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Before the first stable release, the `latest` tag can still point to the
|
|
19
|
+
`0.0.0` bootstrap placeholder. That version reserves the package name and has
|
|
20
|
+
no plugin functionality. Check the published tags and choose a real release:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm view @paperclipai/plugin-boxd dist-tags --json
|
|
24
|
+
paperclipai plugin install @paperclipai/plugin-boxd --version <published-version>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Replace `<published-version>` with the version shown for the desired tag, such
|
|
28
|
+
as `canary`. If no real release is available yet, use the local-path install
|
|
29
|
+
below. See the [publishing guide](../../../../doc/PUBLISHING.md) for the release
|
|
30
|
+
and bootstrap process.
|
|
31
|
+
|
|
32
|
+
## Build and install locally
|
|
33
|
+
|
|
34
|
+
Requires Node 24.11+, pnpm, and an installed Paperclip checkout.
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
cd packages/plugins/sandbox-providers/boxd
|
|
38
|
+
pnpm install --ignore-workspace --no-lockfile
|
|
39
|
+
pnpm typecheck
|
|
40
|
+
pnpm test
|
|
41
|
+
pnpm build
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
From the Paperclip checkout, with your instance running:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
node cli/node_modules/tsx/dist/cli.mjs cli/src/index.ts plugin install /absolute/path/to/paperclip/packages/plugins/sandbox-providers/boxd
|
|
48
|
+
node cli/node_modules/tsx/dist/cli.mjs cli/src/index.ts plugin inspect paperclip.boxd-sandbox-provider
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Configure an environment
|
|
52
|
+
|
|
53
|
+
Configure boxd under **Instance Settings -> Environments**, not from the
|
|
54
|
+
plugin page. Select the `boxd` provider.
|
|
55
|
+
|
|
56
|
+
- `apiKey`: a boxd API key. Create one with
|
|
57
|
+
`boxd auth keys create paperclip --org <org>`. Each key belongs to one org,
|
|
58
|
+
and machines are created in that org. Paperclip saves a pasted key as a
|
|
59
|
+
company secret. `BOXD_API_KEY` on the Paperclip host is an optional fallback
|
|
60
|
+
when the environment has no key.
|
|
61
|
+
- `reuseLease`: default `false`. With `false`, the plugin deletes the machine
|
|
62
|
+
when the run ends. With `true`, the plugin suspends the machine when the run
|
|
63
|
+
ends, and the next run on the same issue resumes it. Disk, memory and running
|
|
64
|
+
processes stay. The provider lease ID is the machine ID, so it stays the same
|
|
65
|
+
across resumes.
|
|
66
|
+
- `snapshot`: optional snapshot name or ID. Each run restores this snapshot,
|
|
67
|
+
for example a machine with your tools and repository already in place.
|
|
68
|
+
- `vcpu`: optional machine size for fresh machines: 1 vCPU/4 GB, 2/8 GB,
|
|
69
|
+
4/16 GB or 8/32 GB. A blank value uses the org default. A snapshot keeps its
|
|
70
|
+
own size.
|
|
71
|
+
- `org`: optional org name or ID. A blank value uses the API key's org.
|
|
72
|
+
- `namePrefix`: machine name prefix, `paperclip` by default.
|
|
73
|
+
- `timeoutMs`: default command timeout, 3600000 ms by default.
|
|
74
|
+
|
|
75
|
+
The default boxd image is Ubuntu 24.04 with Node 24, `tar`, `git`, Docker,
|
|
76
|
+
Claude Code, Codex and OpenCode on the PATH. It meets
|
|
77
|
+
[the sandbox runtime requirements](../SANDBOX-REQUIREMENTS.md) without a
|
|
78
|
+
setup step. Use a snapshot to add other agent CLIs.
|
|
79
|
+
|
|
80
|
+
The probe creates a machine, prepares the workspace and deletes the machine.
|
|
81
|
+
It uses real boxd resources. The probe machine also has a 15-minute boxd delete
|
|
82
|
+
timer, and a probe whose machine could not be deleted reports a failure.
|
|
83
|
+
|
|
84
|
+
## Implemented behavior
|
|
85
|
+
|
|
86
|
+
- Every machine is created with `isolated: true`. An isolated machine has no
|
|
87
|
+
metadata endpoint, no in-VM `boxd` CLI and no boxd integrations, and other
|
|
88
|
+
machines in the org cannot reach it over the private network. The API key
|
|
89
|
+
stays in the plugin worker and never enters the machine.
|
|
90
|
+
- Machines carry the labels `paperclip-provider=boxd`,
|
|
91
|
+
`paperclip-environment=<id>` and `paperclip-run=<id>`. Use
|
|
92
|
+
`boxd machine list --label paperclip-provider=boxd` to find them.
|
|
93
|
+
- Commands run through `sh` in the workspace, with quoted arguments,
|
|
94
|
+
per-command environment, staged stdin, and separate stdout and stderr. A
|
|
95
|
+
command timeout ends the remote process group and returns `timedOut: true`.
|
|
96
|
+
- Stdin is staged with boxd's file API in a file only the machine user can
|
|
97
|
+
read, and removed after the command. The workspace directory is created the
|
|
98
|
+
same way. A machine whose boxd agent predates the file API, such as one
|
|
99
|
+
restored from an older snapshot, falls back to the older upload and `mkdir`
|
|
100
|
+
calls.
|
|
101
|
+
- A failed acquisition deletes its machine. If boxd cannot confirm the
|
|
102
|
+
deletion, the plugin throws `PluginEnvironmentCreationCleanupError` with the
|
|
103
|
+
machine ID, so the host records it and retries the teardown. The destroy hook
|
|
104
|
+
checks that the machine's labels match before it deletes it.
|
|
105
|
+
- A command on a stopped machine starts the machine and runs the command one
|
|
106
|
+
more time. A suspended or hibernated machine wakes on the command.
|
|
107
|
+
- Release deletes the machine and returns a receipt only after boxd no longer
|
|
108
|
+
lists it. With `reuseLease`, release suspends the machine. A release that
|
|
109
|
+
cancels active work stops the machine and keeps its disk.
|
|
110
|
+
- `onEnvironmentStopLease` stops the machine and keeps its disk.
|
|
111
|
+
`onEnvironmentInspectLease` reads the machine state and does not change it.
|
|
112
|
+
- When the host requests a lease expiry, the plugin sets a boxd delete timer
|
|
113
|
+
at or before that time and returns the expiry on the lease.
|
|
114
|
+
- The plugin keeps one SDK client for each API key, so commands do not
|
|
115
|
+
exchange the key for a new session token each time.
|
|
116
|
+
|
|
117
|
+
## Capability boundaries
|
|
118
|
+
|
|
119
|
+
Interactive login PTYs, template capture, native file sync, persistent
|
|
120
|
+
sessions, incremental output, duplex channels and runner ingress are not
|
|
121
|
+
advertised. Workspace transfer uses the host's base64-over-exec fallback.
|
|
122
|
+
boxd has one region (EU), amd64 machines only, and no GPUs.
|
|
123
|
+
|
|
124
|
+
## Opt-in live tests
|
|
125
|
+
|
|
126
|
+
Default tests use a mocked SDK and do not contact boxd. To run against boxd,
|
|
127
|
+
export `BOXD_API_KEY` (and optionally `BOXD_ORG`), then run:
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
BOXD_LIVE_TEST=1 pnpm test
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The live tests run every hook against boxd. They check:
|
|
134
|
+
|
|
135
|
+
- config validation, and a probe with a sized machine that deletes the machine
|
|
136
|
+
afterwards (a bad API key returns a failed probe);
|
|
137
|
+
- the labels, the isolation and the org of an acquired machine;
|
|
138
|
+
- stdin, env, argument quoting, exit codes and stderr, and the removal of the
|
|
139
|
+
staged stdin file;
|
|
140
|
+
- an empty stdin, and a staged stdin file that only the machine user can read;
|
|
141
|
+
- a 5 MiB round trip through the base64-over-exec path;
|
|
142
|
+
- that a command timeout returns `timedOut` and ends the remote processes;
|
|
143
|
+
- suspend and resume with a file and a running process kept, stop and resume
|
|
144
|
+
with the file kept, and inspect in each state;
|
|
145
|
+
- a command on a stopped machine, which starts the machine and runs;
|
|
146
|
+
- resume and stop of a hibernated machine, stop of a suspended machine, and a
|
|
147
|
+
release with `cancelActiveWork` or `stop_and_retain`;
|
|
148
|
+
- a release without reuse, which deletes the machine;
|
|
149
|
+
- a `requestedExpiresAt` that boxd enforces by deleting the machine;
|
|
150
|
+
- a run restored from a snapshot, and a fresh machine at the configured size;
|
|
151
|
+
- that resume after destroy reports an expired lease, and that no test
|
|
152
|
+
machines are left.
|
|
153
|
+
|
|
154
|
+
Each test deletes its machines in `finally`. The tests print timings and no
|
|
155
|
+
credentials. A full run takes about two minutes.
|
|
156
|
+
|
|
157
|
+
## Optional managed-image inclusion
|
|
158
|
+
|
|
159
|
+
The bundled catalog key is `boxd`. Include the `boxd` directory in the Docker
|
|
160
|
+
`CLOUD_BUNDLED_PLUGINS` build argument, then include `boxd` in the managed
|
|
161
|
+
configuration's `plugins.autoInstall` list. The catalog entry does not
|
|
162
|
+
auto-install the plugin or change the default image.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAKzE,QAAA,MAAM,QAAQ,EAAE,yBA2Ef,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const PLUGIN_ID = "paperclip.boxd-sandbox-provider";
|
|
2
|
+
const PLUGIN_VERSION = "0.1.0";
|
|
3
|
+
const manifest = {
|
|
4
|
+
id: PLUGIN_ID,
|
|
5
|
+
apiVersion: 1,
|
|
6
|
+
version: PLUGIN_VERSION,
|
|
7
|
+
displayName: "boxd Sandbox Provider",
|
|
8
|
+
description: "Sandbox provider plugin that runs Paperclip environments on boxd microVMs, with suspend and resume for reused leases.",
|
|
9
|
+
author: "boxd",
|
|
10
|
+
categories: ["automation"],
|
|
11
|
+
capabilities: ["environment.drivers.register"],
|
|
12
|
+
entrypoints: {
|
|
13
|
+
worker: "./dist/worker.js",
|
|
14
|
+
},
|
|
15
|
+
environmentDrivers: [
|
|
16
|
+
{
|
|
17
|
+
driverKey: "boxd",
|
|
18
|
+
kind: "sandbox_provider",
|
|
19
|
+
displayName: "boxd Machine",
|
|
20
|
+
description: "Creates an isolated boxd machine for each run. With reuse on, the machine is suspended after a run and resumed with its disk, memory and processes for the next run.",
|
|
21
|
+
sandboxCapabilities: { reusableLeases: true },
|
|
22
|
+
configSchema: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
apiKey: {
|
|
26
|
+
type: "string",
|
|
27
|
+
format: "secret-ref",
|
|
28
|
+
description: "Paste a boxd API key (`bxd_...`) or pick a saved Paperclip secret. Create one with `boxd auth keys create paperclip --org <org>`. The key decides which org the machines belong to.",
|
|
29
|
+
},
|
|
30
|
+
reuseLease: {
|
|
31
|
+
type: "boolean",
|
|
32
|
+
description: "Suspend the machine after a run and resume it for the next run on the same issue, instead of deleting it. Disk, memory and running processes are kept.",
|
|
33
|
+
default: false,
|
|
34
|
+
},
|
|
35
|
+
snapshot: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "Optional snapshot name or ID to restore for each run, for example a machine with your tools preinstalled. Leave blank to start from the default boxd image (Ubuntu 24.04 with Node 24, git, Docker, Claude Code, Codex and OpenCode).",
|
|
38
|
+
"x-paperclip-advanced": true,
|
|
39
|
+
"x-paperclip-group": "Machine",
|
|
40
|
+
},
|
|
41
|
+
vcpu: {
|
|
42
|
+
type: "number",
|
|
43
|
+
enum: [1, 2, 4, 8],
|
|
44
|
+
description: "Machine size for fresh machines: 1 vCPU/4 GB, 2/8 GB, 4/16 GB or 8/32 GB. Leave blank for the org default. A snapshot keeps its own size.",
|
|
45
|
+
"x-paperclip-advanced": true,
|
|
46
|
+
"x-paperclip-group": "Machine",
|
|
47
|
+
},
|
|
48
|
+
org: {
|
|
49
|
+
type: "string",
|
|
50
|
+
description: "Optional org name or ID. Leave blank to use the API key's org.",
|
|
51
|
+
"x-paperclip-advanced": true,
|
|
52
|
+
"x-paperclip-group": "Machine",
|
|
53
|
+
},
|
|
54
|
+
namePrefix: {
|
|
55
|
+
type: "string",
|
|
56
|
+
description: "Prefix for machine names. Machines are reachable at https://<name>.boxd.sh.",
|
|
57
|
+
default: "paperclip",
|
|
58
|
+
"x-paperclip-advanced": true,
|
|
59
|
+
"x-paperclip-group": "Machine",
|
|
60
|
+
},
|
|
61
|
+
timeoutMs: {
|
|
62
|
+
type: "number",
|
|
63
|
+
description: "Default command timeout in milliseconds. Paperclip also uses it as the default run timeout for this environment.",
|
|
64
|
+
default: 3600000,
|
|
65
|
+
"x-paperclip-advanced": true,
|
|
66
|
+
"x-paperclip-group": "Runtime",
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
export default manifest;
|
|
74
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG,iCAAiC,CAAC;AACpD,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,MAAM,QAAQ,GAA8B;IAC1C,EAAE,EAAE,SAAS;IACb,UAAU,EAAE,CAAC;IACb,OAAO,EAAE,cAAc;IACvB,WAAW,EAAE,uBAAuB;IACpC,WAAW,EACT,uHAAuH;IACzH,MAAM,EAAE,MAAM;IACd,UAAU,EAAE,CAAC,YAAY,CAAC;IAC1B,YAAY,EAAE,CAAC,8BAA8B,CAAC;IAC9C,WAAW,EAAE;QACX,MAAM,EAAE,kBAAkB;KAC3B;IACD,kBAAkB,EAAE;QAClB;YACE,SAAS,EAAE,MAAM;YACjB,IAAI,EAAE,kBAAkB;YACxB,WAAW,EAAE,cAAc;YAC3B,WAAW,EACT,sKAAsK;YACxK,mBAAmB,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE;YAC7C,YAAY,EAAE;gBACZ,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,MAAM,EAAE;wBACN,IAAI,EAAE,QAAQ;wBACd,MAAM,EAAE,YAAY;wBACpB,WAAW,EACT,qLAAqL;qBACxL;oBACD,UAAU,EAAE;wBACV,IAAI,EAAE,SAAS;wBACf,WAAW,EACT,wJAAwJ;wBAC1J,OAAO,EAAE,KAAK;qBACf;oBACD,QAAQ,EAAE;wBACR,IAAI,EAAE,QAAQ;wBACd,WAAW,EACT,uOAAuO;wBACzO,sBAAsB,EAAE,IAAI;wBAC5B,mBAAmB,EAAE,SAAS;qBAC/B;oBACD,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;wBAClB,WAAW,EACT,2IAA2I;wBAC7I,sBAAsB,EAAE,IAAI;wBAC5B,mBAAmB,EAAE,SAAS;qBAC/B;oBACD,GAAG,EAAE;wBACH,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,gEAAgE;wBAC7E,sBAAsB,EAAE,IAAI;wBAC5B,mBAAmB,EAAE,SAAS;qBAC/B;oBACD,UAAU,EAAE;wBACV,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,6EAA6E;wBAC1F,OAAO,EAAE,WAAW;wBACpB,sBAAsB,EAAE,IAAI;wBAC5B,mBAAmB,EAAE,SAAS;qBAC/B;oBACD,SAAS,EAAE;wBACT,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,kHAAkH;wBAC/H,OAAO,EAAE,OAAO;wBAChB,sBAAsB,EAAE,IAAI;wBAC5B,mBAAmB,EAAE,SAAS;qBAC/B;iBACF;aACF;SACF;KACF;CACF,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAqcA,QAAA,MAAM,MAAM,mDAiRV,CAAC;AAEH,eAAe,MAAM,CAAC"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
import { AgentOutdatedError, Boxd, BoxdError, ConflictError, FilesystemError, NotFoundError } from "@boxd-sh/sdk";
|
|
4
|
+
import { definePlugin, PluginEnvironmentCreationCleanupError, readEnvironmentCreationCleanupError, } from "@paperclipai/plugin-sdk";
|
|
5
|
+
const DEFAULT_TIMEOUT_MS = 3_600_000;
|
|
6
|
+
const READY_TIMEOUT_MS = 120_000;
|
|
7
|
+
const STATE_CONFIRM_TIMEOUT_MS = 60_000;
|
|
8
|
+
const STATE_POLL_INTERVAL_MS = 250;
|
|
9
|
+
const EXPIRY_MARGIN_SECONDS = 5;
|
|
10
|
+
const PROBE_DELETE_AFTER_SECONDS = 900;
|
|
11
|
+
const STDIN_MODE = 0o600;
|
|
12
|
+
const CREATION_CLEANUP_SCHEMA = "paperclip/environment-creation-cleanup/v1";
|
|
13
|
+
const CLEANUP_IDENTIFIER = /^[a-zA-Z0-9_-]{1,200}$/;
|
|
14
|
+
const WORKSPACE_DIR = "paperclip-workspace";
|
|
15
|
+
const FALLBACK_HOME = "/home/boxd";
|
|
16
|
+
const MEMORY_BY_VCPU = { 1: "4G", 2: "8G", 4: "16G", 8: "32G" };
|
|
17
|
+
const ACTIVE_STATES = new Set(["pending", "starting", "running", "migrating"]);
|
|
18
|
+
const STOPPED_STATES = new Set(["suspended", "hibernated", "stopped"]);
|
|
19
|
+
const clients = new Map();
|
|
20
|
+
function parseOptionalString(value) {
|
|
21
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
22
|
+
}
|
|
23
|
+
function parseOptionalInteger(value) {
|
|
24
|
+
if (value == null || value === "")
|
|
25
|
+
return null;
|
|
26
|
+
const parsed = Number(value);
|
|
27
|
+
return Number.isFinite(parsed) ? Math.trunc(parsed) : null;
|
|
28
|
+
}
|
|
29
|
+
function normalizeNamePrefix(value) {
|
|
30
|
+
const normalized = (value ?? "paperclip")
|
|
31
|
+
.toLowerCase()
|
|
32
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
33
|
+
.replace(/^-+|-+$/g, "")
|
|
34
|
+
.replace(/-{2,}/g, "-");
|
|
35
|
+
return normalized.length > 0 ? normalized.slice(0, 24).replace(/-+$/, "") : "paperclip";
|
|
36
|
+
}
|
|
37
|
+
function parseDriverConfig(raw) {
|
|
38
|
+
const timeoutMs = Number(raw.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
39
|
+
return {
|
|
40
|
+
apiKey: parseOptionalString(raw.apiKey),
|
|
41
|
+
org: parseOptionalString(raw.org),
|
|
42
|
+
snapshot: parseOptionalString(raw.snapshot),
|
|
43
|
+
vcpu: parseOptionalInteger(raw.vcpu),
|
|
44
|
+
namePrefix: normalizeNamePrefix(parseOptionalString(raw.namePrefix)),
|
|
45
|
+
timeoutMs: Number.isFinite(timeoutMs) ? Math.trunc(timeoutMs) : DEFAULT_TIMEOUT_MS,
|
|
46
|
+
reuseLease: raw.reuseLease === true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function resolveApiKey(config) {
|
|
50
|
+
if (config.apiKey)
|
|
51
|
+
return config.apiKey;
|
|
52
|
+
const envApiKey = process.env.BOXD_API_KEY?.trim() ?? "";
|
|
53
|
+
if (!envApiKey) {
|
|
54
|
+
throw new Error("boxd environments require an API key in config or BOXD_API_KEY.");
|
|
55
|
+
}
|
|
56
|
+
return envApiKey;
|
|
57
|
+
}
|
|
58
|
+
function accountFingerprint(config) {
|
|
59
|
+
return createHash("sha256").update(resolveApiKey(config)).digest("hex");
|
|
60
|
+
}
|
|
61
|
+
function clientFor(config) {
|
|
62
|
+
const cacheKey = accountFingerprint(config);
|
|
63
|
+
let client = clients.get(cacheKey);
|
|
64
|
+
if (!client) {
|
|
65
|
+
client = new Boxd({ apiKey: resolveApiKey(config) });
|
|
66
|
+
clients.set(cacheKey, client);
|
|
67
|
+
}
|
|
68
|
+
return client;
|
|
69
|
+
}
|
|
70
|
+
function shellQuote(value) {
|
|
71
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
72
|
+
}
|
|
73
|
+
function isValidShellEnvKey(value) {
|
|
74
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);
|
|
75
|
+
}
|
|
76
|
+
function formatErrorMessage(error) {
|
|
77
|
+
return error instanceof Error ? error.message : String(error);
|
|
78
|
+
}
|
|
79
|
+
function sleep(ms) {
|
|
80
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
81
|
+
}
|
|
82
|
+
function namePart(value) {
|
|
83
|
+
return value.replace(/[^a-z0-9]+/gi, "").slice(0, 8).toLowerCase();
|
|
84
|
+
}
|
|
85
|
+
function buildMachineName(config, environmentId, runId) {
|
|
86
|
+
const envPart = namePart(environmentId) || "env";
|
|
87
|
+
const runPart = namePart(runId) || randomUUID().slice(0, 8);
|
|
88
|
+
return `${config.namePrefix}-${envPart}-${runPart}-${randomUUID().slice(0, 4)}`.slice(0, 63);
|
|
89
|
+
}
|
|
90
|
+
function machineLabels(environmentId, runId) {
|
|
91
|
+
const labels = { "paperclip-provider": "boxd" };
|
|
92
|
+
const environment = environmentId.replace(/[^A-Za-z0-9._-]+/g, "").slice(0, 63);
|
|
93
|
+
const run = runId.replace(/[^A-Za-z0-9._-]+/g, "").slice(0, 63);
|
|
94
|
+
if (environment)
|
|
95
|
+
labels["paperclip-environment"] = environment;
|
|
96
|
+
if (run)
|
|
97
|
+
labels["paperclip-run"] = run;
|
|
98
|
+
return labels;
|
|
99
|
+
}
|
|
100
|
+
function expirySeconds(requestedExpiresAt, now) {
|
|
101
|
+
const deadline = Date.parse(requestedExpiresAt);
|
|
102
|
+
if (!Number.isFinite(deadline)) {
|
|
103
|
+
throw new Error(`requestedExpiresAt is not a valid timestamp: ${requestedExpiresAt}`);
|
|
104
|
+
}
|
|
105
|
+
const seconds = Math.floor((deadline - now) / 1000) - EXPIRY_MARGIN_SECONDS;
|
|
106
|
+
if (seconds < 1) {
|
|
107
|
+
throw new Error("boxd cannot bound a lease whose requested expiry is less than six seconds away.");
|
|
108
|
+
}
|
|
109
|
+
return seconds;
|
|
110
|
+
}
|
|
111
|
+
async function createMachine(client, config, input) {
|
|
112
|
+
const common = {
|
|
113
|
+
name: input.name,
|
|
114
|
+
...(config.org ? { org: config.org } : {}),
|
|
115
|
+
isolated: true,
|
|
116
|
+
labels: input.labels,
|
|
117
|
+
};
|
|
118
|
+
return config.snapshot
|
|
119
|
+
? await client.machines.create({
|
|
120
|
+
...common,
|
|
121
|
+
fromSnapshot: config.snapshot,
|
|
122
|
+
config: { autoSuspendTimeout: 0 },
|
|
123
|
+
})
|
|
124
|
+
: await client.machines.create({
|
|
125
|
+
...common,
|
|
126
|
+
config: {
|
|
127
|
+
autoSuspendTimeout: 0,
|
|
128
|
+
...(config.vcpu ? { vcpu: config.vcpu, memory: MEMORY_BY_VCPU[config.vcpu] } : {}),
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
async function boundLifetime(client, machineId, requestedExpiresAt) {
|
|
133
|
+
const deleteAt = await client.machines.setDeleteAfter(machineId, expirySeconds(requestedExpiresAt, Date.now()));
|
|
134
|
+
const requested = Date.parse(requestedExpiresAt);
|
|
135
|
+
return new Date(Math.min(deleteAt?.getTime() ?? requested, requested)).toISOString();
|
|
136
|
+
}
|
|
137
|
+
function creationCleanup(config, machineId, owner, labels) {
|
|
138
|
+
return {
|
|
139
|
+
providerLeaseId: machineId,
|
|
140
|
+
companyId: owner.companyId,
|
|
141
|
+
environmentId: owner.environmentId,
|
|
142
|
+
runId: owner.runId,
|
|
143
|
+
attemptId: randomUUID(),
|
|
144
|
+
accountFingerprint: accountFingerprint(config),
|
|
145
|
+
labels: Object.fromEntries(Object.entries(labels).filter(([, value]) => CLEANUP_IDENTIFIER.test(value))),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
async function machineOrNull(client, machineId) {
|
|
149
|
+
try {
|
|
150
|
+
return await client.machines.get(machineId);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (error instanceof NotFoundError)
|
|
154
|
+
return null;
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function checkFailedCreation(client, config, params) {
|
|
159
|
+
const cleanup = readEnvironmentCreationCleanupError({
|
|
160
|
+
data: { schema: CREATION_CLEANUP_SCHEMA, cleanup: params.leaseMetadata?.failedCreateCleanup },
|
|
161
|
+
});
|
|
162
|
+
const matches = cleanup !== null
|
|
163
|
+
&& cleanup.companyId === params.companyId
|
|
164
|
+
&& cleanup.environmentId === params.environmentId
|
|
165
|
+
&& cleanup.providerLeaseId === params.providerLeaseId
|
|
166
|
+
&& cleanup.accountFingerprint === accountFingerprint(config);
|
|
167
|
+
const machine = matches ? await machineOrNull(client, cleanup.providerLeaseId) : null;
|
|
168
|
+
if (!matches || (machine && Object.entries(cleanup.labels).some(([key, value]) => machine.labels[key] !== value))) {
|
|
169
|
+
throw new Error("The failed-creation cleanup does not match a boxd machine that this environment created.");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function confirmState(client, machineId, accept, description) {
|
|
173
|
+
const deadline = Date.now() + STATE_CONFIRM_TIMEOUT_MS;
|
|
174
|
+
for (;;) {
|
|
175
|
+
let machine;
|
|
176
|
+
try {
|
|
177
|
+
machine = await client.machines.get(machineId);
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
if (!(error instanceof NotFoundError))
|
|
181
|
+
throw error;
|
|
182
|
+
machine = null;
|
|
183
|
+
}
|
|
184
|
+
if (accept(machine))
|
|
185
|
+
return machine;
|
|
186
|
+
if (Date.now() >= deadline) {
|
|
187
|
+
throw new Error(`boxd did not confirm that machine ${machineId} is ${description} (last status: ${machine?.status ?? "missing"}).`);
|
|
188
|
+
}
|
|
189
|
+
await sleep(STATE_POLL_INTERVAL_MS);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async function withAgentFallback(work, fallback) {
|
|
193
|
+
try {
|
|
194
|
+
await work();
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
if (!(error instanceof AgentOutdatedError))
|
|
198
|
+
throw error;
|
|
199
|
+
await fallback();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async function destroyMachine(client, machineId) {
|
|
203
|
+
try {
|
|
204
|
+
await client.machines.delete(machineId);
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
if (!(error instanceof NotFoundError))
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
await confirmState(client, machineId, (machine) => machine === null || machine.status === "destroyed", "destroyed");
|
|
211
|
+
return { providerLeaseId: machineId, state: "destroyed" };
|
|
212
|
+
}
|
|
213
|
+
async function stopMachine(client, machineId) {
|
|
214
|
+
let machine;
|
|
215
|
+
try {
|
|
216
|
+
machine = await client.machines.get(machineId);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
if (error instanceof NotFoundError)
|
|
220
|
+
return { providerLeaseId: machineId, state: "destroyed" };
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
if (machine.status === "suspended")
|
|
224
|
+
await client.machines.resume(machineId);
|
|
225
|
+
if (machine.status === "hibernated")
|
|
226
|
+
await client.machines.wake(machineId);
|
|
227
|
+
if (machine.status !== "stopped")
|
|
228
|
+
await client.machines.stop(machineId);
|
|
229
|
+
const confirmed = await confirmState(client, machineId, (current) => current === null || current.status === "stopped", "stopped");
|
|
230
|
+
return { providerLeaseId: machineId, state: confirmed ? "stopped" : "destroyed" };
|
|
231
|
+
}
|
|
232
|
+
async function pauseOrDestroy(client, machineId) {
|
|
233
|
+
try {
|
|
234
|
+
const machine = await client.machines.get(machineId);
|
|
235
|
+
if (machine.status === "running")
|
|
236
|
+
await client.machines.pause(machineId);
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
if (error instanceof NotFoundError)
|
|
240
|
+
return;
|
|
241
|
+
console.warn(`Failed to suspend boxd machine ${machineId} for reuse: ${formatErrorMessage(error)}. Deleting it instead.`);
|
|
242
|
+
return await destroyMachine(client, machineId);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async function wakeMachine(client, machine) {
|
|
246
|
+
if (machine.status === "suspended")
|
|
247
|
+
await client.machines.resume(machine.id);
|
|
248
|
+
if (machine.status === "hibernated")
|
|
249
|
+
await client.machines.wake(machine.id);
|
|
250
|
+
if (machine.status === "stopped")
|
|
251
|
+
await client.machines.start(machine.id);
|
|
252
|
+
await client.machines.waitUntilReady(machine.id, { timeout: READY_TIMEOUT_MS });
|
|
253
|
+
}
|
|
254
|
+
function isStoppedConflict(error) {
|
|
255
|
+
return error instanceof ConflictError && /\bstopped\b/i.test(error.message);
|
|
256
|
+
}
|
|
257
|
+
async function withStartedMachine(client, machineId, work) {
|
|
258
|
+
try {
|
|
259
|
+
return await work();
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
if (!isStoppedConflict(error))
|
|
263
|
+
throw error;
|
|
264
|
+
await client.machines.start(machineId);
|
|
265
|
+
await client.machines.waitUntilReady(machineId, { timeout: READY_TIMEOUT_MS });
|
|
266
|
+
return await work();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function isExecTimeout(error) {
|
|
270
|
+
return error instanceof BoxdError && (error.grpcCode === 4 || /timed out/i.test(error.message));
|
|
271
|
+
}
|
|
272
|
+
async function detectHome(client, machineId) {
|
|
273
|
+
const result = await client.machines.exec(machineId, {
|
|
274
|
+
command: 'printf "%s\\n" "${HOME:-$(pwd)}"',
|
|
275
|
+
});
|
|
276
|
+
const home = result.exitCode === 0 ? result.stdout.trim().split(/\r?\n/)[0]?.trim() : "";
|
|
277
|
+
return home && home.startsWith("/") ? home : FALLBACK_HOME;
|
|
278
|
+
}
|
|
279
|
+
async function makeWorkspaceWithShell(client, machineId, remoteCwd) {
|
|
280
|
+
const result = await client.machines.exec(machineId, { command: `mkdir -p ${shellQuote(remoteCwd)}` });
|
|
281
|
+
if (result.exitCode !== 0) {
|
|
282
|
+
throw new Error(`Failed to create ${remoteCwd} on boxd machine ${machineId}: ${result.stderr.trim() || result.stdout.trim()}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async function ensureWorkspace(client, machineId, remoteCwd) {
|
|
286
|
+
try {
|
|
287
|
+
await withStartedMachine(client, machineId, () => withAgentFallback(() => client.machines.fs.mkdir(machineId, remoteCwd), () => makeWorkspaceWithShell(client, machineId, remoteCwd)));
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
if (!(error instanceof FilesystemError))
|
|
291
|
+
throw error;
|
|
292
|
+
throw new Error(`Failed to create ${remoteCwd} on boxd machine ${machineId}: ${error.message}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function leaseMetadata(input) {
|
|
296
|
+
return {
|
|
297
|
+
provider: "boxd",
|
|
298
|
+
machineId: input.machine.id,
|
|
299
|
+
machineName: input.machine.name,
|
|
300
|
+
sandboxName: input.machine.name,
|
|
301
|
+
url: `https://${input.machine.name}.boxd.sh`,
|
|
302
|
+
org: input.config.org,
|
|
303
|
+
snapshot: input.config.snapshot,
|
|
304
|
+
shellCommand: "bash",
|
|
305
|
+
remoteCwd: input.remoteCwd,
|
|
306
|
+
timeoutMs: input.config.timeoutMs,
|
|
307
|
+
reuseLease: input.config.reuseLease,
|
|
308
|
+
resumedLease: input.resumedLease,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
function buildLoginShellScript(input) {
|
|
312
|
+
const env = input.env ?? {};
|
|
313
|
+
for (const key of Object.keys(env)) {
|
|
314
|
+
if (!isValidShellEnvKey(key)) {
|
|
315
|
+
throw new Error(`Invalid sandbox environment variable key: ${key}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const envArgs = Object.entries(env)
|
|
319
|
+
.filter((entry) => typeof entry[1] === "string")
|
|
320
|
+
.map(([key, value]) => `${key}=${shellQuote(value)}`);
|
|
321
|
+
const commandParts = [shellQuote(input.command), ...input.args.map(shellQuote)].join(" ");
|
|
322
|
+
const execLine = envArgs.length > 0
|
|
323
|
+
? `exec env ${envArgs.join(" ")} ${commandParts}`
|
|
324
|
+
: `exec ${commandParts}`;
|
|
325
|
+
return [
|
|
326
|
+
'if [ -f /etc/profile ]; then . /etc/profile >/dev/null 2>&1 || true; fi',
|
|
327
|
+
'if [ -f "$HOME/.profile" ]; then . "$HOME/.profile" >/dev/null 2>&1 || true; fi',
|
|
328
|
+
'if [ -f "$HOME/.bash_profile" ]; then . "$HOME/.bash_profile" >/dev/null 2>&1 || true; elif [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" >/dev/null 2>&1 || true; fi',
|
|
329
|
+
'if [ -f "$HOME/.zprofile" ]; then . "$HOME/.zprofile" >/dev/null 2>&1 || true; fi',
|
|
330
|
+
execLine,
|
|
331
|
+
].join(" && ");
|
|
332
|
+
}
|
|
333
|
+
async function acquireMachine(config, input) {
|
|
334
|
+
const client = clientFor(config);
|
|
335
|
+
if (input.requestedExpiresAt)
|
|
336
|
+
expirySeconds(input.requestedExpiresAt, Date.now());
|
|
337
|
+
const labels = machineLabels(input.environmentId, input.runId);
|
|
338
|
+
const machine = await createMachine(client, config, {
|
|
339
|
+
name: buildMachineName(config, input.environmentId, input.runId),
|
|
340
|
+
labels,
|
|
341
|
+
});
|
|
342
|
+
try {
|
|
343
|
+
const expiresAt = input.requestedExpiresAt
|
|
344
|
+
? await boundLifetime(client, machine.id, input.requestedExpiresAt)
|
|
345
|
+
: undefined;
|
|
346
|
+
await client.machines.waitUntilReady(machine.id, { timeout: READY_TIMEOUT_MS });
|
|
347
|
+
const remoteCwd = input.requestedCwd?.trim() || path.posix.join(await detectHome(client, machine.id), WORKSPACE_DIR);
|
|
348
|
+
await ensureWorkspace(client, machine.id, remoteCwd);
|
|
349
|
+
return {
|
|
350
|
+
providerLeaseId: machine.id,
|
|
351
|
+
metadata: leaseMetadata({ config, machine, remoteCwd, resumedLease: false }),
|
|
352
|
+
...(expiresAt ? { expiresAt } : {}),
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
try {
|
|
357
|
+
await destroyMachine(client, machine.id);
|
|
358
|
+
}
|
|
359
|
+
catch (cleanupError) {
|
|
360
|
+
throw new PluginEnvironmentCreationCleanupError([error, cleanupError], `boxd machine ${machine.id} could not be deleted after its acquisition failed.`, creationCleanup(config, machine.id, input, labels));
|
|
361
|
+
}
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
const plugin = definePlugin({
|
|
366
|
+
async setup(ctx) {
|
|
367
|
+
ctx.logger.info("boxd sandbox provider plugin ready");
|
|
368
|
+
},
|
|
369
|
+
async onHealth() {
|
|
370
|
+
return { status: "ok", message: "boxd sandbox provider plugin healthy" };
|
|
371
|
+
},
|
|
372
|
+
async onShutdown() {
|
|
373
|
+
const open = [...clients.values()];
|
|
374
|
+
clients.clear();
|
|
375
|
+
await Promise.all(open.map((client) => client.close().catch(() => undefined)));
|
|
376
|
+
},
|
|
377
|
+
async onEnvironmentValidateConfig(params) {
|
|
378
|
+
const config = parseDriverConfig(params.config);
|
|
379
|
+
const errors = [];
|
|
380
|
+
if (config.timeoutMs < 1 || config.timeoutMs > 86_400_000) {
|
|
381
|
+
errors.push("timeoutMs must be between 1 and 86400000.");
|
|
382
|
+
}
|
|
383
|
+
if (config.vcpu != null && !(config.vcpu in MEMORY_BY_VCPU)) {
|
|
384
|
+
errors.push("vcpu must be 1, 2, 4 or 8. boxd sizes are 1 vCPU/4 GB, 2/8 GB, 4/16 GB and 8/32 GB.");
|
|
385
|
+
}
|
|
386
|
+
if (config.vcpu != null && config.snapshot) {
|
|
387
|
+
errors.push("vcpu applies to fresh machines only. A machine restored from a snapshot keeps the snapshot's size; clear vcpu or snapshot.");
|
|
388
|
+
}
|
|
389
|
+
if (!config.apiKey && !(process.env.BOXD_API_KEY?.trim())) {
|
|
390
|
+
errors.push("boxd environments require an API key in config or BOXD_API_KEY.");
|
|
391
|
+
}
|
|
392
|
+
if (errors.length > 0) {
|
|
393
|
+
return { ok: false, errors };
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
ok: true,
|
|
397
|
+
normalizedConfig: { ...config },
|
|
398
|
+
};
|
|
399
|
+
},
|
|
400
|
+
async onEnvironmentProbe(params) {
|
|
401
|
+
const config = parseDriverConfig(params.config);
|
|
402
|
+
const configMetadata = {
|
|
403
|
+
provider: "boxd",
|
|
404
|
+
org: config.org,
|
|
405
|
+
snapshot: config.snapshot,
|
|
406
|
+
timeoutMs: config.timeoutMs,
|
|
407
|
+
reuseLease: config.reuseLease,
|
|
408
|
+
};
|
|
409
|
+
let machine = null;
|
|
410
|
+
let result;
|
|
411
|
+
try {
|
|
412
|
+
const client = clientFor(config);
|
|
413
|
+
machine = await createMachine(client, config, {
|
|
414
|
+
name: `${config.namePrefix}-probe-${randomUUID().slice(0, 8)}`,
|
|
415
|
+
labels: machineLabels(params.environmentId, "probe"),
|
|
416
|
+
});
|
|
417
|
+
await client.machines.setDeleteAfter(machine.id, PROBE_DELETE_AFTER_SECONDS);
|
|
418
|
+
await client.machines.waitUntilReady(machine.id, { timeout: READY_TIMEOUT_MS });
|
|
419
|
+
const remoteCwd = path.posix.join(await detectHome(client, machine.id), WORKSPACE_DIR);
|
|
420
|
+
await ensureWorkspace(client, machine.id, remoteCwd);
|
|
421
|
+
result = {
|
|
422
|
+
ok: true,
|
|
423
|
+
summary: `Connected to boxd machine ${machine.name}.`,
|
|
424
|
+
metadata: { ...configMetadata, machineName: machine.name, remoteCwd },
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
result = {
|
|
429
|
+
ok: false,
|
|
430
|
+
summary: "boxd environment probe failed.",
|
|
431
|
+
metadata: { ...configMetadata, error: formatErrorMessage(error) },
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
if (!machine)
|
|
435
|
+
return result;
|
|
436
|
+
try {
|
|
437
|
+
await destroyMachine(clientFor(config), machine.id);
|
|
438
|
+
return result;
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
return {
|
|
442
|
+
ok: false,
|
|
443
|
+
summary: `boxd environment probe could not delete its machine ${machine.name}.`,
|
|
444
|
+
metadata: {
|
|
445
|
+
...result.metadata,
|
|
446
|
+
machineId: machine.id,
|
|
447
|
+
machineName: machine.name,
|
|
448
|
+
cleanupError: formatErrorMessage(error),
|
|
449
|
+
},
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
async onEnvironmentAcquireLease(params) {
|
|
454
|
+
return await acquireMachine(parseDriverConfig(params.config), {
|
|
455
|
+
companyId: params.companyId,
|
|
456
|
+
environmentId: params.environmentId,
|
|
457
|
+
runId: params.runId,
|
|
458
|
+
requestedCwd: params.requestedCwd,
|
|
459
|
+
requestedExpiresAt: params.requestedExpiresAt,
|
|
460
|
+
});
|
|
461
|
+
},
|
|
462
|
+
async onEnvironmentResumeLease(params) {
|
|
463
|
+
const config = parseDriverConfig(params.config);
|
|
464
|
+
const client = clientFor(config);
|
|
465
|
+
let machine;
|
|
466
|
+
try {
|
|
467
|
+
machine = await client.machines.get(params.providerLeaseId);
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
if (error instanceof NotFoundError)
|
|
471
|
+
return { providerLeaseId: null, metadata: { expired: true } };
|
|
472
|
+
throw error;
|
|
473
|
+
}
|
|
474
|
+
if (machine.status === "destroyed" || machine.status === "failed") {
|
|
475
|
+
return { providerLeaseId: null, metadata: { expired: true } };
|
|
476
|
+
}
|
|
477
|
+
await wakeMachine(client, machine);
|
|
478
|
+
const remoteCwd = parseOptionalString(params.leaseMetadata?.remoteCwd)
|
|
479
|
+
?? path.posix.join(await detectHome(client, machine.id), WORKSPACE_DIR);
|
|
480
|
+
await ensureWorkspace(client, machine.id, remoteCwd);
|
|
481
|
+
return {
|
|
482
|
+
providerLeaseId: machine.id,
|
|
483
|
+
metadata: leaseMetadata({ config, machine, remoteCwd, resumedLease: true }),
|
|
484
|
+
};
|
|
485
|
+
},
|
|
486
|
+
async onEnvironmentReleaseLease(params) {
|
|
487
|
+
if (!params.providerLeaseId)
|
|
488
|
+
return;
|
|
489
|
+
const config = parseDriverConfig(params.config);
|
|
490
|
+
const client = clientFor(config);
|
|
491
|
+
if (params.resourceDisposition === "stop_and_retain") {
|
|
492
|
+
return await stopMachine(client, params.providerLeaseId);
|
|
493
|
+
}
|
|
494
|
+
if (config.reuseLease) {
|
|
495
|
+
if (params.cancelActiveWork)
|
|
496
|
+
return await stopMachine(client, params.providerLeaseId);
|
|
497
|
+
return await pauseOrDestroy(client, params.providerLeaseId);
|
|
498
|
+
}
|
|
499
|
+
return await destroyMachine(client, params.providerLeaseId);
|
|
500
|
+
},
|
|
501
|
+
async onEnvironmentStopLease(params) {
|
|
502
|
+
if (!params.providerLeaseId) {
|
|
503
|
+
throw new Error("No provider lease ID available to stop.");
|
|
504
|
+
}
|
|
505
|
+
const config = parseDriverConfig(params.config);
|
|
506
|
+
return await stopMachine(clientFor(config), params.providerLeaseId);
|
|
507
|
+
},
|
|
508
|
+
async onEnvironmentDestroyLease(params) {
|
|
509
|
+
if (!params.providerLeaseId)
|
|
510
|
+
return;
|
|
511
|
+
const config = parseDriverConfig(params.config);
|
|
512
|
+
const client = clientFor(config);
|
|
513
|
+
if (params.leaseMetadata?.failedCreateCleanup !== undefined)
|
|
514
|
+
await checkFailedCreation(client, config, params);
|
|
515
|
+
return await destroyMachine(client, params.providerLeaseId);
|
|
516
|
+
},
|
|
517
|
+
async onEnvironmentInspectLease(params) {
|
|
518
|
+
const config = parseDriverConfig(params.config);
|
|
519
|
+
try {
|
|
520
|
+
const machine = await clientFor(config).machines.get(params.providerLeaseId);
|
|
521
|
+
if (ACTIVE_STATES.has(machine.status))
|
|
522
|
+
return { providerLeaseId: params.providerLeaseId, state: "active" };
|
|
523
|
+
if (STOPPED_STATES.has(machine.status))
|
|
524
|
+
return { providerLeaseId: params.providerLeaseId, state: "stopped" };
|
|
525
|
+
if (machine.status === "destroyed")
|
|
526
|
+
return { providerLeaseId: params.providerLeaseId, state: "destroyed" };
|
|
527
|
+
return { providerLeaseId: params.providerLeaseId, state: "unknown" };
|
|
528
|
+
}
|
|
529
|
+
catch (error) {
|
|
530
|
+
if (error instanceof NotFoundError)
|
|
531
|
+
return { providerLeaseId: params.providerLeaseId, state: "destroyed" };
|
|
532
|
+
throw error;
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
async onEnvironmentRealizeWorkspace(params) {
|
|
536
|
+
const config = parseDriverConfig(params.config);
|
|
537
|
+
const remoteCwd = parseOptionalString(params.lease.metadata?.remoteCwd)
|
|
538
|
+
?? params.workspace.remotePath
|
|
539
|
+
?? path.posix.join(FALLBACK_HOME, WORKSPACE_DIR);
|
|
540
|
+
if (params.lease.providerLeaseId) {
|
|
541
|
+
await ensureWorkspace(clientFor(config), params.lease.providerLeaseId, remoteCwd);
|
|
542
|
+
}
|
|
543
|
+
return {
|
|
544
|
+
cwd: remoteCwd,
|
|
545
|
+
metadata: {
|
|
546
|
+
provider: "boxd",
|
|
547
|
+
remoteCwd,
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
},
|
|
551
|
+
async onEnvironmentExecute(params) {
|
|
552
|
+
const machineId = params.lease.providerLeaseId;
|
|
553
|
+
if (!machineId) {
|
|
554
|
+
return {
|
|
555
|
+
exitCode: 1,
|
|
556
|
+
timedOut: false,
|
|
557
|
+
stdout: "",
|
|
558
|
+
stderr: "No provider lease ID available for execution.",
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
const config = parseDriverConfig(params.config);
|
|
562
|
+
const client = clientFor(config);
|
|
563
|
+
const script = buildLoginShellScript({
|
|
564
|
+
command: params.command,
|
|
565
|
+
args: params.args ?? [],
|
|
566
|
+
env: params.env,
|
|
567
|
+
});
|
|
568
|
+
const timeoutMs = params.timeoutMs != null && params.timeoutMs > 0 ? params.timeoutMs : config.timeoutMs;
|
|
569
|
+
const cwd = params.cwd ?? parseOptionalString(params.lease.metadata?.remoteCwd) ?? undefined;
|
|
570
|
+
const stdinPath = params.stdin != null ? `/tmp/paperclip-stdin-${randomUUID()}` : null;
|
|
571
|
+
const command = stdinPath ? `${script} < ${shellQuote(stdinPath)}` : script;
|
|
572
|
+
try {
|
|
573
|
+
const result = await withStartedMachine(client, machineId, async () => {
|
|
574
|
+
if (stdinPath) {
|
|
575
|
+
const stdin = params.stdin ?? "";
|
|
576
|
+
await withAgentFallback(async () => {
|
|
577
|
+
await client.machines.fs.write(machineId, stdinPath, stdin, { mode: STDIN_MODE });
|
|
578
|
+
}, async () => {
|
|
579
|
+
await client.machines.files.upload(machineId, stdinPath, stdin);
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
return await client.machines.exec(machineId, { command, ...(cwd ? { cwd } : {}), timeout: timeoutMs });
|
|
583
|
+
});
|
|
584
|
+
return {
|
|
585
|
+
exitCode: result.exitCode,
|
|
586
|
+
timedOut: false,
|
|
587
|
+
stdout: result.stdout,
|
|
588
|
+
stderr: result.stderr,
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
catch (error) {
|
|
592
|
+
if (isExecTimeout(error)) {
|
|
593
|
+
return {
|
|
594
|
+
exitCode: null,
|
|
595
|
+
timedOut: true,
|
|
596
|
+
stdout: "",
|
|
597
|
+
stderr: `${formatErrorMessage(error)}\n`,
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
throw error;
|
|
601
|
+
}
|
|
602
|
+
finally {
|
|
603
|
+
if (stdinPath) {
|
|
604
|
+
await withAgentFallback(() => client.machines.fs.remove(machineId, stdinPath), () => client.machines.files.delete(machineId, stdinPath)).catch(() => undefined);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
});
|
|
609
|
+
export default plugin;
|
|
610
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,eAAe,MAAM,CAAC"}
|
package/dist/worker.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,eAAe,MAAM,CAAC;AACtB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,18 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paperclipai/plugin-boxd",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2026.1104.0-canary.13",
|
|
4
|
+
"description": "boxd sandbox provider plugin for Paperclip environments",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
6
|
+
"homepage": "https://github.com/paperclipai/paperclip",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/paperclipai/paperclip/issues"
|
|
9
|
+
},
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
|
-
"url": "
|
|
12
|
+
"url": "https://github.com/paperclipai/paperclip",
|
|
13
|
+
"directory": "packages/plugins/sandbox-providers/boxd"
|
|
13
14
|
},
|
|
14
|
-
"
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"main": "./dist/index.js",
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
15
24
|
"publishConfig": {
|
|
16
25
|
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"paperclipPlugin": {
|
|
31
|
+
"manifest": "./dist/manifest.js",
|
|
32
|
+
"worker": "./dist/worker.js"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"paperclip",
|
|
36
|
+
"plugin",
|
|
37
|
+
"sandbox",
|
|
38
|
+
"boxd"
|
|
39
|
+
],
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@boxd-sh/sdk": "^0.2.20",
|
|
42
|
+
"@paperclipai/plugin-sdk": "2026.1104.0-canary.13"
|
|
17
43
|
}
|
|
18
|
-
}
|
|
44
|
+
}
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
throw new Error("@paperclipai/plugin-boxd@0.0.0 is a placeholder that reserves the package name for Paperclip's release pipeline. It contains no functionality; the first real release supersedes it. See https://github.com/paperclipai/paperclip");
|