@tickernelz/paperclip-pro-plugin-daytona 2026.925.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 (58) hide show
  1. package/README.md +49 -0
  2. package/dist/duplex-command-stream.d.ts +97 -0
  3. package/dist/duplex-command-stream.d.ts.map +1 -0
  4. package/dist/duplex-command-stream.js +205 -0
  5. package/dist/duplex-command-stream.js.map +1 -0
  6. package/dist/duplex-command-stream.live.test.d.ts +2 -0
  7. package/dist/duplex-command-stream.live.test.d.ts.map +1 -0
  8. package/dist/duplex-command-stream.live.test.js +324 -0
  9. package/dist/duplex-command-stream.live.test.js.map +1 -0
  10. package/dist/duplex-command-stream.test.d.ts +2 -0
  11. package/dist/duplex-command-stream.test.d.ts.map +1 -0
  12. package/dist/duplex-command-stream.test.js +519 -0
  13. package/dist/duplex-command-stream.test.js.map +1 -0
  14. package/dist/file-sync.d.ts +77 -0
  15. package/dist/file-sync.d.ts.map +1 -0
  16. package/dist/file-sync.js +1055 -0
  17. package/dist/file-sync.js.map +1 -0
  18. package/dist/file-sync.test.d.ts +2 -0
  19. package/dist/file-sync.test.d.ts.map +1 -0
  20. package/dist/file-sync.test.js +974 -0
  21. package/dist/file-sync.test.js.map +1 -0
  22. package/dist/index.d.ts +3 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +3 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/login-pty.d.ts +162 -0
  27. package/dist/login-pty.d.ts.map +1 -0
  28. package/dist/login-pty.js +258 -0
  29. package/dist/login-pty.js.map +1 -0
  30. package/dist/login-pty.test.d.ts +2 -0
  31. package/dist/login-pty.test.d.ts.map +1 -0
  32. package/dist/login-pty.test.js +319 -0
  33. package/dist/login-pty.test.js.map +1 -0
  34. package/dist/manifest.d.ts +4 -0
  35. package/dist/manifest.d.ts.map +1 -0
  36. package/dist/manifest.js +179 -0
  37. package/dist/manifest.js.map +1 -0
  38. package/dist/plugin.d.ts +49 -0
  39. package/dist/plugin.d.ts.map +1 -0
  40. package/dist/plugin.js +2563 -0
  41. package/dist/plugin.js.map +1 -0
  42. package/dist/plugin.test.d.ts +2 -0
  43. package/dist/plugin.test.d.ts.map +1 -0
  44. package/dist/plugin.test.js +4701 -0
  45. package/dist/plugin.test.js.map +1 -0
  46. package/dist/pty-chunked-input.d.ts +48 -0
  47. package/dist/pty-chunked-input.d.ts.map +1 -0
  48. package/dist/pty-chunked-input.js +74 -0
  49. package/dist/pty-chunked-input.js.map +1 -0
  50. package/dist/pty-chunked-input.test.d.ts +2 -0
  51. package/dist/pty-chunked-input.test.d.ts.map +1 -0
  52. package/dist/pty-chunked-input.test.js +115 -0
  53. package/dist/pty-chunked-input.test.js.map +1 -0
  54. package/dist/worker.d.ts +3 -0
  55. package/dist/worker.d.ts.map +1 -0
  56. package/dist/worker.js +5 -0
  57. package/dist/worker.js.map +1 -0
  58. package/package.json +44 -0
@@ -0,0 +1,319 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { composeLaunchLine, createDaytonaLoginHomeFs, createDaytonaLoginPtySessionOpener, encodePosixShellArg, openDaytonaLoginPtySession, } from "./login-pty.js";
3
+ // The Enter byte the terminal login UI reads to submit the browser code.
4
+ const ENTER = "\r";
5
+ const HOME = "/tmp/paperclip-adapter-login/11111111-2222-4333-8444-555555555555";
6
+ const CLAUDE = { loginCommandKey: "claude", sessionHome: HOME };
7
+ const CODEX = { loginCommandKey: "codex", sessionHome: HOME };
8
+ const GROK = { loginCommandKey: "grok", sessionHome: HOME };
9
+ /**
10
+ * A fake login-home filesystem. It records each path the caller asks to create
11
+ * and never fails, matching the `mkdir -p` semantics of the real command: a
12
+ * repeat create for the same path succeeds the same as a fresh one.
13
+ */
14
+ function createFakeHomeFs() {
15
+ const created = [];
16
+ return {
17
+ created,
18
+ async createDirectory(path) {
19
+ created.push(path);
20
+ },
21
+ };
22
+ }
23
+ /**
24
+ * A fake Daytona PTY handle. It records each input write, drives the output
25
+ * stream on demand, and records the kill and the disconnect. The tests use it in
26
+ * place of the real SDK `PtyHandle`, so the session runs with no sandbox.
27
+ */
28
+ function createFakePtyHandle(onData, onWaitForConnection) {
29
+ const encoder = new TextEncoder();
30
+ const inputs = [];
31
+ let resolveWait = null;
32
+ const waitPromise = new Promise((resolve) => {
33
+ resolveWait = resolve;
34
+ });
35
+ let killed = 0;
36
+ let disconnected = 0;
37
+ return {
38
+ async waitForConnection() {
39
+ onWaitForConnection?.();
40
+ },
41
+ async sendInput(data) {
42
+ inputs.push(typeof data === "string" ? data : new TextDecoder().decode(data));
43
+ },
44
+ wait() {
45
+ return waitPromise;
46
+ },
47
+ async kill() {
48
+ killed += 1;
49
+ },
50
+ async disconnect() {
51
+ disconnected += 1;
52
+ },
53
+ emitText(text) {
54
+ onData(encoder.encode(text));
55
+ },
56
+ emitBytes(bytes) {
57
+ onData(bytes);
58
+ },
59
+ finish(exitCode) {
60
+ resolveWait?.({ exitCode });
61
+ },
62
+ get inputs() {
63
+ return inputs;
64
+ },
65
+ get killed() {
66
+ return killed;
67
+ },
68
+ get disconnected() {
69
+ return disconnected;
70
+ },
71
+ };
72
+ }
73
+ /**
74
+ * A fake Daytona process. It opens one fake PTY handle and records the create
75
+ * options, so a test asserts the terminal size and the launch line.
76
+ */
77
+ function createFakeProcess() {
78
+ const state = { handle: null, createOptions: null, createCount: 0 };
79
+ return {
80
+ get handle() {
81
+ return state.handle;
82
+ },
83
+ get createOptions() {
84
+ return state.createOptions;
85
+ },
86
+ get createCount() {
87
+ return state.createCount;
88
+ },
89
+ async createPty(options) {
90
+ state.createCount += 1;
91
+ state.createOptions = options;
92
+ const handle = createFakePtyHandle(options.onData);
93
+ state.handle = handle;
94
+ return handle;
95
+ },
96
+ };
97
+ }
98
+ describe("encodePosixShellArg", () => {
99
+ it("wraps a value in single quotes and neutralizes metacharacters", () => {
100
+ expect(encodePosixShellArg("/tmp/x")).toBe("'/tmp/x'");
101
+ // A metacharacter, a space, and a semicolon stay literal inside the quotes.
102
+ expect(encodePosixShellArg("; rm -rf / #")).toBe("'; rm -rf / #'");
103
+ // An embedded single quote closes, escapes, and reopens the quote.
104
+ expect(encodePosixShellArg("a'b")).toBe("'a'\\''b'");
105
+ expect(encodePosixShellArg("$(id)")).toBe("'$(id)'");
106
+ });
107
+ });
108
+ describe("composeLaunchLine", () => {
109
+ it("composes the Claude line with no CODEX_HOME", () => {
110
+ const line = composeLaunchLine(CLAUDE);
111
+ expect(line).toBe("exec claude setup-token");
112
+ expect(line).not.toContain("CODEX_HOME");
113
+ });
114
+ it("composes the Codex line with exactly one encoded CODEX_HOME", () => {
115
+ const line = composeLaunchLine(CODEX);
116
+ expect(line).toBe(`exec env CODEX_HOME='${HOME}' codex login --device-auth`);
117
+ // Exactly one CODEX_HOME assignment, and the exact approved Codex command.
118
+ expect(line.match(/CODEX_HOME=/g)).toHaveLength(1);
119
+ expect(line.endsWith("codex login --device-auth")).toBe(true);
120
+ });
121
+ it("composes the Grok line with exactly one encoded GROK_HOME", () => {
122
+ const line = composeLaunchLine(GROK);
123
+ expect(line).toBe(`exec env GROK_HOME='${HOME}' grok login --device-auth`);
124
+ // Exactly one GROK_HOME assignment, and the exact approved Grok command.
125
+ expect(line.match(/GROK_HOME=/g)).toHaveLength(1);
126
+ expect(line.endsWith("grok login --device-auth")).toBe(true);
127
+ // The Codex encoded variable never leaks into the Grok line.
128
+ expect(line).not.toContain("CODEX_HOME");
129
+ });
130
+ it("composes the launch line from the closed command map only, and ignores a command string smuggled onto the descriptor", () => {
131
+ // Condition 4: a command string in the request confers no command
132
+ // authority. The module maps the closed key to its own fixed command, so a
133
+ // caller cannot select or override it.
134
+ const tampered = {
135
+ ...GROK,
136
+ command: "rm -rf /",
137
+ };
138
+ const line = composeLaunchLine(tampered);
139
+ expect(line).toBe(`exec env GROK_HOME='${HOME}' grok login --device-auth`);
140
+ expect(line).not.toContain("rm -rf");
141
+ });
142
+ });
143
+ describe("openDaytonaLoginPtySession — session home", () => {
144
+ it("creates the session home directory", async () => {
145
+ const process = createFakeProcess();
146
+ const fs = createFakeHomeFs();
147
+ await openDaytonaLoginPtySession(process, fs, CLAUDE);
148
+ // The provider created the exact directory and opened the terminal.
149
+ expect(fs.created).toEqual([HOME]);
150
+ expect(process.createCount).toBe(1);
151
+ expect(process.handle?.inputs[0]).toBe("exec claude setup-token" + ENTER);
152
+ });
153
+ it("sends the Codex launch line with the encoded CODEX_HOME", async () => {
154
+ const process = createFakeProcess();
155
+ const fs = createFakeHomeFs();
156
+ await openDaytonaLoginPtySession(process, fs, CODEX);
157
+ expect(process.handle?.inputs[0]).toBe(`exec env CODEX_HOME='${HOME}' codex login --device-auth` + ENTER);
158
+ // The Claude line carries no CODEX_HOME; the Codex line carries exactly one.
159
+ expect((process.handle?.inputs[0]?.match(/CODEX_HOME=/g) ?? []).length).toBe(1);
160
+ });
161
+ it("opens the login session when the session home already exists", async () => {
162
+ const process = createFakeProcess();
163
+ const fs = createFakeHomeFs();
164
+ // A second login for the same home hits an existing directory. `mkdir -p`
165
+ // succeeds on an existing directory, so the second session opens the same
166
+ // as the first.
167
+ await openDaytonaLoginPtySession(process, fs, CLAUDE);
168
+ await openDaytonaLoginPtySession(process, fs, CLAUDE);
169
+ expect(fs.created).toEqual([HOME, HOME]);
170
+ expect(process.createCount).toBe(2);
171
+ });
172
+ it("rejects a descriptor with a command key outside the closed set", async () => {
173
+ const process = createFakeProcess();
174
+ const fs = createFakeHomeFs();
175
+ await expect(openDaytonaLoginPtySession(process, fs, {
176
+ loginCommandKey: "gemini",
177
+ sessionHome: HOME,
178
+ })).rejects.toThrow("LOGIN_PTY_DESCRIPTOR_REJECTED");
179
+ // The provider never touched the filesystem or the terminal.
180
+ expect(fs.created).toEqual([]);
181
+ expect(process.createCount).toBe(0);
182
+ });
183
+ it("rejects a descriptor whose session home shape is wrong", async () => {
184
+ const process = createFakeProcess();
185
+ const fs = createFakeHomeFs();
186
+ await expect(openDaytonaLoginPtySession(process, fs, {
187
+ loginCommandKey: "codex",
188
+ sessionHome: "/tmp/paperclip-adapter-login/../etc",
189
+ })).rejects.toThrow("LOGIN_PTY_DESCRIPTOR_REJECTED");
190
+ expect(process.createCount).toBe(0);
191
+ });
192
+ });
193
+ describe("openDaytonaLoginPtySession — session mechanics", () => {
194
+ it("starts the login command on a pseudo-terminal with a fixed size", async () => {
195
+ const process = createFakeProcess();
196
+ await openDaytonaLoginPtySession(process, createFakeHomeFs(), CLAUDE);
197
+ expect(process.createOptions?.cols).toBe(120);
198
+ expect(process.createOptions?.rows).toBe(30);
199
+ expect(process.handle?.inputs[0]).toBe("exec claude setup-token" + ENTER);
200
+ });
201
+ it("returns incremental terminal output to the listener", async () => {
202
+ const process = createFakeProcess();
203
+ const received = [];
204
+ const session = await openDaytonaLoginPtySession(process, createFakeHomeFs(), CLAUDE);
205
+ session.onData((chunk) => received.push(chunk));
206
+ process.handle?.emitText("the url below to sign in\n");
207
+ process.handle?.emitText("Paste code here if prompted\n");
208
+ expect(received).toEqual(["the url below to sign in\n", "Paste code here if prompted\n"]);
209
+ });
210
+ it("buffers early output until the listener registers", async () => {
211
+ const process = createFakeProcess();
212
+ const received = [];
213
+ const session = await openDaytonaLoginPtySession(process, createFakeHomeFs(), CLAUDE);
214
+ process.handle?.emitText("early output ");
215
+ process.handle?.emitText("more output");
216
+ expect(received).toEqual([]);
217
+ session.onData((chunk) => received.push(chunk));
218
+ expect(received).toEqual(["early output more output"]);
219
+ });
220
+ it("delivers the browser code plus the Enter byte to the command", async () => {
221
+ const process = createFakeProcess();
222
+ const session = await openDaytonaLoginPtySession(process, createFakeHomeFs(), CLAUDE);
223
+ session.write("BROWSERCODE" + ENTER);
224
+ // The write runs through the serialized chunk chain, so it lands on a later
225
+ // microtask. Flush the chain before the assertion.
226
+ await new Promise((resolve) => setTimeout(resolve, 0));
227
+ expect(process.handle?.inputs[1]).toBe("BROWSERCODE" + ENTER);
228
+ expect(process.handle?.inputs[1]?.endsWith(ENTER)).toBe(true);
229
+ });
230
+ it("keeps a multibyte character whole across two output chunks", async () => {
231
+ const process = createFakeProcess();
232
+ const received = [];
233
+ const session = await openDaytonaLoginPtySession(process, createFakeHomeFs(), CLAUDE);
234
+ session.onData((chunk) => received.push(chunk));
235
+ const euro = new TextEncoder().encode("€");
236
+ process.handle?.emitBytes(euro.subarray(0, 2));
237
+ process.handle?.emitBytes(euro.subarray(2));
238
+ expect(received.join("")).toBe("€");
239
+ });
240
+ it("resolves wait with the command exit code", async () => {
241
+ const process = createFakeProcess();
242
+ const session = await openDaytonaLoginPtySession(process, createFakeHomeFs(), CLAUDE);
243
+ process.handle?.finish(9);
244
+ await expect(session.wait()).resolves.toEqual({ exitCode: 9 });
245
+ });
246
+ it("maps an absent exit code to null", async () => {
247
+ const process = createFakeProcess();
248
+ const session = await openDaytonaLoginPtySession(process, createFakeHomeFs(), CLAUDE);
249
+ process.handle?.finish(undefined);
250
+ await expect(session.wait()).resolves.toEqual({ exitCode: null });
251
+ });
252
+ it("kills the child and closes the session", async () => {
253
+ const process = createFakeProcess();
254
+ const session = await openDaytonaLoginPtySession(process, createFakeHomeFs(), CLAUDE);
255
+ session.kill();
256
+ expect(process.handle?.killed).toBe(1);
257
+ await session.close();
258
+ expect(process.handle?.disconnected).toBe(1);
259
+ });
260
+ it("passes the working directory to the pseudo-terminal", async () => {
261
+ const process = createFakeProcess();
262
+ await openDaytonaLoginPtySession(process, createFakeHomeFs(), CLAUDE, { cwd: "/workspace" });
263
+ expect(process.createOptions?.cwd).toBe("/workspace");
264
+ });
265
+ });
266
+ describe("createDaytonaLoginHomeFs — login-profile preamble", () => {
267
+ // A capturing exec surface. It records each command and returns a fixed result,
268
+ // so a test reads the exact command string the create runs.
269
+ function createCapturingExec(result) {
270
+ const commands = [];
271
+ return {
272
+ commands,
273
+ async executeCommand(command) {
274
+ commands.push(command);
275
+ return result;
276
+ },
277
+ };
278
+ }
279
+ it("sources the login profiles before it creates the session home directory", async () => {
280
+ // The command sources /etc/profile before it runs `mkdir -p`, so the create
281
+ // command stays consistent with the profile chain the rest of the sandbox
282
+ // exec commands use.
283
+ const exec = createCapturingExec({ exitCode: 0, result: "" });
284
+ const fs = createDaytonaLoginHomeFs(exec);
285
+ await fs.createDirectory(HOME);
286
+ const command = exec.commands.find((entry) => entry.includes("mkdir -p"));
287
+ expect(command).toBeDefined();
288
+ const profileIndex = command.indexOf("/etc/profile");
289
+ const mkdirIndex = command.indexOf("mkdir -p");
290
+ expect(profileIndex).toBeGreaterThanOrEqual(0);
291
+ expect(mkdirIndex).toBeGreaterThan(profileIndex);
292
+ });
293
+ it("rejects the session and opens no pseudo-terminal when the create command exits non-zero", async () => {
294
+ // The sandbox `mkdir -p` command fails (for example, a read-only mount).
295
+ // The session must fail closed before it opens a pseudo-terminal.
296
+ const exec = createCapturingExec({ exitCode: 1, result: "" });
297
+ const fs = createDaytonaLoginHomeFs(exec);
298
+ const process = createFakeProcess();
299
+ await expect(openDaytonaLoginPtySession(process, fs, CLAUDE)).rejects.toThrow("LOGIN_PTY_HOME_REJECTED");
300
+ expect(process.createCount).toBe(0);
301
+ });
302
+ });
303
+ describe("createDaytonaLoginPtySessionOpener", () => {
304
+ it("opens a session for the descriptor on each call", async () => {
305
+ const process = createFakeProcess();
306
+ const opener = createDaytonaLoginPtySessionOpener(process, createFakeHomeFs(), {
307
+ cwd: "/workspace",
308
+ });
309
+ const session = await opener(CLAUDE);
310
+ expect(process.createOptions?.cwd).toBe("/workspace");
311
+ expect(process.handle?.inputs[0]).toBe("exec claude setup-token" + ENTER);
312
+ expect(typeof session.onData).toBe("function");
313
+ expect(typeof session.write).toBe("function");
314
+ expect(typeof session.wait).toBe("function");
315
+ expect(typeof session.kill).toBe("function");
316
+ expect(typeof session.close).toBe("function");
317
+ });
318
+ });
319
+ //# sourceMappingURL=login-pty.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-pty.test.js","sourceRoot":"","sources":["../src/login-pty.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { PaperclipPluginManifestV1 } from "@tickernelz/paperclip-pro-plugin-sdk";
2
+ declare const manifest: PaperclipPluginManifestV1;
3
+ export default manifest;
4
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAiBtF,QAAA,MAAM,QAAQ,EAAE,yBAgLf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,179 @@
1
+ const PLUGIN_ID = "paperclip.daytona-sandbox-provider";
2
+ // The bundled-plugin boot reconcile refreshes the persisted manifest for an
3
+ // existing install only when PLUGIN_VERSION changes. A manifest change without a
4
+ // version bump never reaches an existing install. The reconcile also reads the
5
+ // persisted manifest raw and does not re-run the validator, so it never
6
+ // canonicalizes a renamed capability.
7
+ //
8
+ // 0.1.3 renamed the login transport flag from `supportsSetupTokenLogin` to the
9
+ // neutral `supportsLoginPty`.
10
+ // 0.1.4 adds the `concurrentSyncOperations` sandbox capability to the driver.
11
+ // 0.1.5 adds the `duplexCommandStream` sandbox capability to the driver.
12
+ // 0.1.6 adds private authenticated WebSocket ingress for paperclip_runner.
13
+ // 0.1.7 exposes host-owned warm/cold runner lifecycle controls.
14
+ const PLUGIN_VERSION = "0.1.7";
15
+ const manifest = {
16
+ id: PLUGIN_ID,
17
+ apiVersion: 1,
18
+ version: PLUGIN_VERSION,
19
+ displayName: "Daytona Sandbox Provider",
20
+ description: "First-party sandbox provider plugin that provisions Daytona sandboxes as Paperclip execution environments.",
21
+ author: "Paperclip",
22
+ categories: ["automation"],
23
+ capabilities: ["environment.drivers.register"],
24
+ entrypoints: {
25
+ worker: "./dist/worker.js",
26
+ },
27
+ environmentDrivers: [
28
+ {
29
+ driverKey: "daytona",
30
+ kind: "sandbox_provider",
31
+ displayName: "Daytona Sandbox",
32
+ description: "Provisions Daytona sandboxes with configurable image or snapshot selection, startup timeouts, and lease reuse.",
33
+ supportsReusableLeases: true,
34
+ // Daytona keeps a persistent session and tails its callback log form, so it
35
+ // emits incremental session output while the command runs. Declare the
36
+ // opt-in capability so the host selects the session-output streaming path.
37
+ // A generic one-shot provider that omits this key keeps the poll path.
38
+ //
39
+ // Daytona also runs file transfers into and out of the sandbox in parallel.
40
+ // Each concurrent sync hook call uses separate temporary state (random
41
+ // scratch names and per-mapping host temporary directories), and teardown
42
+ // waits for all active calls. Declare the opt-in capability so the host may
43
+ // schedule sync operations concurrently. The host resolves it `true` only
44
+ // when the worker also verifies both sync verbs.
45
+ //
46
+ // Daytona carries the sandbox callback bridge on one live duplex channel
47
+ // over a raw pseudo-terminal. Declare the opt-in capability so the host may
48
+ // select the duplex transport. The host resolves it `true` only when the
49
+ // worker also verifies the `duplexChannelOpen` handler.
50
+ //
51
+ // Daytona is the first provider that runs the HTTP/2 transport over this
52
+ // channel. HTTP/2 is the preferred transport. `queue_v1` is the
53
+ // soft-deprecated fallback.
54
+ sandboxCapabilities: {
55
+ incrementalSessionOutput: true,
56
+ concurrentSyncOperations: true,
57
+ duplexCommandStream: true,
58
+ runnerWebSocketIngress: true,
59
+ },
60
+ supportsInteractiveSetup: true,
61
+ interactiveSetupConnectionTypes: ["ssh"],
62
+ supportsTemplateCapture: true,
63
+ templateRefKind: "snapshot",
64
+ templateConfigBinding: {
65
+ field: "snapshot",
66
+ unsetFields: ["image"],
67
+ },
68
+ templateIdentityPaths: ["apiUrl"],
69
+ supportsTemplateDelete: true,
70
+ // Daytona hosts an interactive login on a real pseudo-terminal. It is the
71
+ // only bundled provider that implements the login pseudo-terminal methods,
72
+ // so it advertises the capability. The session home helpers and the
73
+ // credential reader run on node, and the sandbox already runs node for the
74
+ // Paperclip bridge. So the login has no extra runtime prerequisite, and the
75
+ // advertised capability matches the runtime contract for every configured
76
+ // image or snapshot.
77
+ supportsLoginPty: true,
78
+ configSchema: {
79
+ type: "object",
80
+ properties: {
81
+ apiKey: {
82
+ type: "string",
83
+ format: "secret-ref",
84
+ description: "Environment-specific Daytona API key. Paste a key or an existing Paperclip secret reference; saved environments store pasted values as company secrets. Falls back to DAYTONA_API_KEY if omitted.",
85
+ },
86
+ apiUrl: {
87
+ type: "string",
88
+ description: "Optional Daytona API base URL. If omitted, the Daytona SDK uses its configured default endpoint.",
89
+ },
90
+ target: {
91
+ type: "string",
92
+ description: "Optional Daytona target/region identifier.",
93
+ },
94
+ snapshot: {
95
+ type: "string",
96
+ description: "Optional Daytona snapshot name to start from.",
97
+ },
98
+ image: {
99
+ type: "string",
100
+ description: "Optional base image or Daytona Image reference. If set, the sandbox is created from this image instead of a snapshot.",
101
+ default: "daytonaio/sandbox:0.8.0",
102
+ },
103
+ language: {
104
+ type: "string",
105
+ description: "Optional Daytona language hint for direct code execution. If omitted, Daytona uses its default runtime.",
106
+ },
107
+ cpu: {
108
+ type: "integer",
109
+ description: "Optional CPU allocation in cores.",
110
+ minimum: 1,
111
+ default: 4,
112
+ },
113
+ memory: {
114
+ type: "integer",
115
+ description: "Optional memory allocation in GiB. Supported sandbox sizes are 1, 2, 4, and 8 GiB.",
116
+ enum: [1, 2, 4, 8],
117
+ default: 4,
118
+ },
119
+ disk: {
120
+ type: "integer",
121
+ description: "Optional disk allocation in GiB.",
122
+ minimum: 1,
123
+ default: 10,
124
+ },
125
+ gpu: {
126
+ type: "integer",
127
+ description: "Optional GPU allocation in units.",
128
+ minimum: 1,
129
+ },
130
+ timeoutMs: {
131
+ type: "number",
132
+ description: "Timeout for Daytona create/start/stop/execute operations in milliseconds.",
133
+ default: 300000,
134
+ },
135
+ livenessTimeoutMs: {
136
+ type: "number",
137
+ description: "Per-call timeout in milliseconds for the sandbox liveness read (refreshData). A silently unresponsive sandbox connection surfaces as a fast error instead of stalling until the outer RPC ceiling. The start and recovery calls derive their own deadline from timeoutMs, not this bound. `0` or less disables the bound. Defaults to 30000 when unset.",
138
+ default: 30000,
139
+ },
140
+ autoStopInterval: {
141
+ type: "number",
142
+ description: "Daytona auto-stop interval in minutes. `0` disables auto-stop. Defaults to 15 when unset.",
143
+ default: 15,
144
+ },
145
+ autoArchiveInterval: {
146
+ type: "number",
147
+ description: "Daytona auto-archive interval in minutes. Stopped sandboxes still count against the storage quota until archived, so this defaults to 60 when unset. `0` uses Daytona's max interval.",
148
+ default: 60,
149
+ },
150
+ autoDeleteInterval: {
151
+ type: "number",
152
+ description: "Daytona auto-delete interval in minutes. Backstop reaper for sandboxes nobody resumes; defaults to 10080 (7 days) when unset. `-1` disables auto-delete and `0` deletes immediately after stop.",
153
+ default: 10080,
154
+ },
155
+ reuseLease: {
156
+ type: "boolean",
157
+ description: "Whether to stop and later resume the sandbox across runs instead of deleting it on release.",
158
+ default: false,
159
+ },
160
+ runnerLifecycleMode: {
161
+ type: "string",
162
+ enum: ["inherit", "per_turn", "warm"],
163
+ description: "paperclip_runner lifecycle for this environment. Inherit uses the agent setting; warm keeps runnerd and the sandbox available between turns.",
164
+ default: "inherit",
165
+ },
166
+ runnerIdleTimeoutMs: {
167
+ type: "integer",
168
+ description: "How long an idle warm paperclip_runner stays alive before it checkpoints and suspends.",
169
+ minimum: 1000,
170
+ maximum: 86400000,
171
+ default: 300000,
172
+ },
173
+ },
174
+ },
175
+ },
176
+ ],
177
+ };
178
+ export default manifest;
179
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { PluginContext, PluginTracer } from "@tickernelz/paperclip-pro-plugin-sdk";
2
+ export { createDaytonaLoginPtySessionOpener, openDaytonaLoginPtySession, createDaytonaLoginHomeFs, } from "./login-pty.js";
3
+ export type { LoginPtySession, LoginPtySessionOpener, LoginPtyLaunchDescriptor, DaytonaPtyHandle, DaytonaPtyProcess, DaytonaPtyCreateOptions, DaytonaLoginPtyOptions, DaytonaLoginHomeFs, } from "./login-pty.js";
4
+ export { createDaytonaDuplexChannelSessionOpener, openDaytonaDuplexChannelSession, buildDuplexChannelLaunchWrapper, } from "./duplex-command-stream.js";
5
+ export type { DuplexChannelSession, DuplexChannelSessionOpener, DaytonaDuplexChannelOptions, } from "./duplex-command-stream.js";
6
+ /**
7
+ * Return the plugin tracer. It is the injected `ctx.tracer` after `setup`, or a
8
+ * no-op before it. A provider span opened through it records only when tracing
9
+ * is on and an active host trace context is present.
10
+ */
11
+ export declare function getPluginTracer(): PluginTracer;
12
+ /**
13
+ * Test seam: set the module-level plugin context, and return a restore function.
14
+ * `plugin.test.ts` uses it to inject a recording tracer without running `setup`.
15
+ */
16
+ export declare function __setDaytonaPluginContextForTest(ctx: PluginContext | null): () => void;
17
+ /**
18
+ * Test seam: override the provider-timing clock and return a restore function.
19
+ * Not used in production, where the default wall clock always applies.
20
+ */
21
+ export declare function setDaytonaTimingClockForTest(now: () => number): () => void;
22
+ /**
23
+ * Test seam: override the handle-cache freshness clock and return a restore
24
+ * function. Not used in production, where the default wall clock always applies.
25
+ */
26
+ export declare function setDaytonaHandleFreshnessClockForTest(now: () => number): () => void;
27
+ /**
28
+ * Test seam: clear the process-scoped handle cache between tests so a handle
29
+ * memoized under a reused composite key in one test never leaks into the next.
30
+ * Not used in production.
31
+ */
32
+ export declare function __resetDaytonaSandboxHandleCacheForTest(): void;
33
+ /**
34
+ * Test seam: read the advisory writable directories recorded for a sync scope.
35
+ * The caller passes the same `onEnvironmentSyncIn` inputs, so this rebuilds the
36
+ * exact scope key the hook used. Not used in production.
37
+ */
38
+ export declare function __getDaytonaWritableDirsForTest(input: {
39
+ driverKey: string;
40
+ companyId: string;
41
+ environmentId: string;
42
+ lease: {
43
+ providerLeaseId?: string | null;
44
+ };
45
+ config: Record<string, unknown>;
46
+ }): string[];
47
+ declare const plugin: import("@tickernelz/paperclip-pro-plugin-sdk").PaperclipPlugin;
48
+ export default plugin;
49
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EA8Bb,MAAM,sCAAsC,CAAC;AAS9C,OAAO,EACL,kCAAkC,EAClC,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,eAAe,EACf,qBAAqB,EACrB,wBAAwB,EACxB,gBAAgB,EAChB,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAgBxB,OAAO,EACL,uCAAuC,EACvC,+BAA+B,EAC/B,+BAA+B,GAChC,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,oBAAoB,EACpB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,4BAA4B,CAAC;AAgBpC;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,IAAI,CAMtF;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,MAAM,GAAG,MAAM,IAAI,CAM1E;AAQD;;;GAGG;AACH,wBAAgB,qCAAqC,CAAC,GAAG,EAAE,MAAM,MAAM,GAAG,MAAM,IAAI,CAMnF;AAizCD;;;;GAIG;AACH,wBAAgB,uCAAuC,IAAI,IAAI,CAQ9D;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,GAAG,MAAM,EAAE,CASX;AAkgBD,QAAA,MAAM,MAAM,gEA0jCV,CAAC;AAEH,eAAe,MAAM,CAAC"}