diff --git a/packages/plugins/sandbox-providers/daytona/package.json b/packages/plugins/sandbox-providers/daytona/package.json index 293db61c91..25c45046e9 100644 --- a/packages/plugins/sandbox-providers/daytona/package.json +++ b/packages/plugins/sandbox-providers/daytona/package.json @@ -1,6 +1,6 @@ { "name": "@paperclipai/plugin-daytona", - "version": "0.1.0", + "version": "0.1.1", "description": "Daytona sandbox provider plugin for Paperclip environments", "license": "MIT", "homepage": "https://github.com/paperclipai/paperclip", diff --git a/packages/plugins/sandbox-providers/daytona/src/manifest.ts b/packages/plugins/sandbox-providers/daytona/src/manifest.ts index c83a49275f..38eedf238a 100644 --- a/packages/plugins/sandbox-providers/daytona/src/manifest.ts +++ b/packages/plugins/sandbox-providers/daytona/src/manifest.ts @@ -1,7 +1,7 @@ import type { PaperclipPluginManifestV1 } from "@paperclipai/plugin-sdk"; const PLUGIN_ID = "paperclip.daytona-sandbox-provider"; -const PLUGIN_VERSION = "0.1.0"; +const PLUGIN_VERSION = "0.1.1"; const manifest: PaperclipPluginManifestV1 = { id: PLUGIN_ID, @@ -60,6 +60,7 @@ const manifest: PaperclipPluginManifestV1 = { type: "string", description: "Optional base image or Daytona Image reference. If set, the sandbox is created from this image instead of a snapshot.", + default: "daytonaio/sandbox:0.8.0", }, language: { type: "string", @@ -70,17 +71,20 @@ const manifest: PaperclipPluginManifestV1 = { type: "integer", description: "Optional CPU allocation in cores.", minimum: 1, + default: 4, }, memory: { type: "integer", description: - "Optional memory allocation in GiB. Leave unset to use Daytona defaults; supported sandbox sizes are 1, 2, 4, and 8 GiB.", + "Optional memory allocation in GiB. Supported sandbox sizes are 1, 2, 4, and 8 GiB.", enum: [1, 2, 4, 8], + default: 4, }, disk: { type: "integer", description: "Optional disk allocation in GiB.", minimum: 1, + default: 10, }, gpu: { type: "integer", diff --git a/packages/plugins/sandbox-providers/daytona/src/plugin.test.ts b/packages/plugins/sandbox-providers/daytona/src/plugin.test.ts index d5588335e9..4dd11030a8 100644 --- a/packages/plugins/sandbox-providers/daytona/src/plugin.test.ts +++ b/packages/plugins/sandbox-providers/daytona/src/plugin.test.ts @@ -3901,6 +3901,43 @@ describe("daytona manifest memory config", () => { }); }); +describe("daytona manifest form defaults", () => { + const configSchema = ( + manifest.environmentDrivers?.[0]?.configSchema as { + properties?: Record< + string, + { format?: string; enum?: unknown[]; minimum?: number; default?: unknown } + >; + } + ); + const properties = configSchema.properties ?? {}; + + it("pre-fills sizing and image fields for the environment form", () => { + expect(properties.cpu?.default).toBe(4); + expect(properties.memory?.default).toBe(4); + expect(properties.disk?.default).toBe(10); + expect(properties.image?.default).toBe("daytonaio/sandbox:0.8.0"); + }); + + it("keeps each default within its own schema constraints", () => { + expect(properties.memory?.enum).toContain(properties.memory?.default); + expect(properties.cpu?.default as number).toBeGreaterThanOrEqual( + properties.cpu?.minimum ?? 1, + ); + expect(properties.disk?.default as number).toBeGreaterThanOrEqual( + properties.disk?.minimum ?? 1, + ); + }); + + it("declares no default on secret-ref fields, which would be persisted as a company secret", () => { + for (const prop of Object.values(properties)) { + if (prop.format === "secret-ref") { + expect(prop.default).toBeUndefined(); + } + } + }); +}); + describe("buildBwrapCommand advisory wrapper builder", () => { it("uses su to drop to sandbox user without --unshare-user", () => { const command = buildBwrapCommand( diff --git a/packages/plugins/sandbox-providers/exe-dev/package.json b/packages/plugins/sandbox-providers/exe-dev/package.json index c54ef85973..23dfd89f82 100644 --- a/packages/plugins/sandbox-providers/exe-dev/package.json +++ b/packages/plugins/sandbox-providers/exe-dev/package.json @@ -1,6 +1,6 @@ { "name": "@paperclipai/plugin-exe-dev", - "version": "0.1.1", + "version": "0.1.2", "description": "exe.dev sandbox provider plugin for Paperclip environments", "license": "MIT", "homepage": "https://github.com/paperclipai/paperclip", diff --git a/packages/plugins/sandbox-providers/exe-dev/src/manifest.ts b/packages/plugins/sandbox-providers/exe-dev/src/manifest.ts index 6455294e4b..bef86f3def 100644 --- a/packages/plugins/sandbox-providers/exe-dev/src/manifest.ts +++ b/packages/plugins/sandbox-providers/exe-dev/src/manifest.ts @@ -1,7 +1,7 @@ import type { PaperclipPluginManifestV1 } from "@paperclipai/plugin-sdk"; const PLUGIN_ID = "paperclip.exe-dev-sandbox-provider"; -const PLUGIN_VERSION = "0.1.1"; +const PLUGIN_VERSION = "0.1.2"; const manifest: PaperclipPluginManifestV1 = { id: PLUGIN_ID, @@ -80,18 +80,21 @@ const manifest: PaperclipPluginManifestV1 = { cpu: { type: "number", description: "Optional CPU count passed to `exe.dev new --cpu`.", + default: 4, "x-paperclip-advanced": true, "x-paperclip-group": "VM resources", }, memory: { type: "string", description: "Optional memory size such as `4GB`.", + default: "4GB", "x-paperclip-advanced": true, "x-paperclip-group": "VM resources", }, disk: { type: "string", description: "Optional disk size such as `20GB`.", + default: "20GB", "x-paperclip-advanced": true, "x-paperclip-group": "VM resources", }, diff --git a/packages/plugins/sandbox-providers/exe-dev/src/plugin.test.ts b/packages/plugins/sandbox-providers/exe-dev/src/plugin.test.ts index a562b00fd3..0432bfecf8 100644 --- a/packages/plugins/sandbox-providers/exe-dev/src/plugin.test.ts +++ b/packages/plugins/sandbox-providers/exe-dev/src/plugin.test.ts @@ -15,6 +15,7 @@ vi.mock("node:child_process", async () => { }); import plugin, { validateSshPrivateKey } from "./plugin.js"; +import manifest from "./manifest.js"; class MockChildProcess extends EventEmitter { stdout = new EventEmitter(); @@ -842,3 +843,26 @@ describe("exe.dev sandbox provider plugin", () => { expect(result?.cwd).toBe("/srv/paperclip/no-vm"); }); }); + +describe("exe-dev manifest form defaults", () => { + const configSchema = ( + manifest.environmentDrivers?.[0]?.configSchema as { + properties?: Record; + } + ); + const properties = configSchema.properties ?? {}; + + it("pre-fills VM sizing for the environment form", () => { + expect(properties.cpu?.default).toBe(4); + expect(properties.memory?.default).toBe("4GB"); + expect(properties.disk?.default).toBe("20GB"); + }); + + it("declares no default on secret-ref fields, which would be persisted as a company secret", () => { + for (const prop of Object.values(properties)) { + if (prop.format === "secret-ref") { + expect(prop.default).toBeUndefined(); + } + } + }); +}); diff --git a/packages/plugins/sandbox-providers/modal/package.json b/packages/plugins/sandbox-providers/modal/package.json index 952900a5c1..8d6b0bf92e 100644 --- a/packages/plugins/sandbox-providers/modal/package.json +++ b/packages/plugins/sandbox-providers/modal/package.json @@ -1,6 +1,6 @@ { "name": "@paperclipai/plugin-modal", - "version": "0.1.0", + "version": "0.1.1", "description": "Modal sandbox provider plugin for Paperclip environments", "license": "MIT", "homepage": "https://github.com/paperclipai/paperclip", diff --git a/packages/plugins/sandbox-providers/modal/src/manifest.ts b/packages/plugins/sandbox-providers/modal/src/manifest.ts index bd694622c0..9a0ef1bc60 100644 --- a/packages/plugins/sandbox-providers/modal/src/manifest.ts +++ b/packages/plugins/sandbox-providers/modal/src/manifest.ts @@ -1,7 +1,7 @@ import type { PaperclipPluginManifestV1 } from "@paperclipai/plugin-sdk"; const PLUGIN_ID = "paperclip.modal-sandbox-provider"; -const PLUGIN_VERSION = "0.1.0"; +const PLUGIN_VERSION = "0.1.1"; const manifest: PaperclipPluginManifestV1 = { id: PLUGIN_ID, @@ -31,11 +31,13 @@ const manifest: PaperclipPluginManifestV1 = { type: "string", description: "Modal App name used as the parent for sandboxes. The plugin calls `modal.apps.fromName(appName, { createIfMissing: true })`, so the App is created on first acquire if it does not already exist.", + default: "paperclip", }, image: { type: "string", description: - "Container image reference passed to `modal.images.fromRegistry()`, e.g. `python:3.13` or `node:20`.", + "Container image reference passed to `modal.images.fromRegistry()`, e.g. `python:3.13` or `node:22`. The default `node:22` satisfies the sandbox runtime contract (node, sh, and tar on PATH).", + default: "node:22", }, tokenId: { type: "string", diff --git a/packages/plugins/sandbox-providers/modal/src/plugin.test.ts b/packages/plugins/sandbox-providers/modal/src/plugin.test.ts index 831030b1ca..7fabac055e 100644 --- a/packages/plugins/sandbox-providers/modal/src/plugin.test.ts +++ b/packages/plugins/sandbox-providers/modal/src/plugin.test.ts @@ -1,5 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; +import manifest from "./manifest.js"; + const { MockNotFoundError, MockTimeoutError, MockSandboxTimeoutError } = vi.hoisted(() => { class MockNotFoundError extends Error {} class MockTimeoutError extends Error {} @@ -704,3 +706,25 @@ describe("Modal sandbox provider plugin", () => { }); }); }); + +describe("modal manifest form defaults", () => { + const configSchema = ( + manifest.environmentDrivers?.[0]?.configSchema as { + properties?: Record; + } + ); + const properties = configSchema.properties ?? {}; + + it("pre-fills the required app name and image so the form works out of the box", () => { + expect(properties.appName?.default).toBe("paperclip"); + expect(properties.image?.default).toBe("node:22"); + }); + + it("declares no default on secret-ref fields, which would be persisted as a company secret", () => { + for (const prop of Object.values(properties)) { + if (prop.format === "secret-ref") { + expect(prop.default).toBeUndefined(); + } + } + }); +});