@yolk-sdk/sandbox 0.1.0-canary.18
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 +60 -0
- package/dist/agent.d.mts +48 -0
- package/dist/agent.d.mts.map +1 -0
- package/dist/agent.mjs +173 -0
- package/dist/agent.mjs.map +1 -0
- package/dist/errors.d.mts +44 -0
- package/dist/errors.d.mts.map +1 -0
- package/dist/errors.mjs +40 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +7 -0
- package/dist/lifecycle.d.mts +52 -0
- package/dist/lifecycle.d.mts.map +1 -0
- package/dist/lifecycle.mjs +118 -0
- package/dist/lifecycle.mjs.map +1 -0
- package/dist/model.d.mts +84 -0
- package/dist/model.d.mts.map +1 -0
- package/dist/model.mjs +72 -0
- package/dist/model.mjs.map +1 -0
- package/dist/name.d.mts +5 -0
- package/dist/name.d.mts.map +1 -0
- package/dist/name.mjs +19 -0
- package/dist/name.mjs.map +1 -0
- package/dist/service.d.mts +15 -0
- package/dist/service.d.mts.map +1 -0
- package/dist/service.mjs +7 -0
- package/dist/service.mjs.map +1 -0
- package/dist/state-store.d.mts +18 -0
- package/dist/state-store.d.mts.map +1 -0
- package/dist/state-store.mjs +7 -0
- package/dist/state-store.mjs.map +1 -0
- package/dist/testing/index.d.mts +21 -0
- package/dist/testing/index.d.mts.map +1 -0
- package/dist/testing/index.mjs +25 -0
- package/dist/testing/index.mjs.map +1 -0
- package/dist/vercel/client.d.mts +70 -0
- package/dist/vercel/client.d.mts.map +1 -0
- package/dist/vercel/client.mjs +113 -0
- package/dist/vercel/client.mjs.map +1 -0
- package/dist/vercel/index.d.mts +3 -0
- package/dist/vercel/index.mjs +3 -0
- package/dist/vercel/layer.d.mts +23 -0
- package/dist/vercel/layer.d.mts.map +1 -0
- package/dist/vercel/layer.mjs +250 -0
- package/dist/vercel/layer.mjs.map +1 -0
- package/package.json +72 -0
- package/src/agent.ts +304 -0
- package/src/errors.ts +71 -0
- package/src/index.ts +52 -0
- package/src/lifecycle.ts +186 -0
- package/src/model.ts +122 -0
- package/src/name.ts +23 -0
- package/src/service.ts +19 -0
- package/src/state-store.ts +17 -0
- package/src/testing/index.ts +63 -0
- package/src/vercel/client.ts +223 -0
- package/src/vercel/index.ts +24 -0
- package/src/vercel/layer.ts +396 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yolk SDK contributors
|
|
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
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# @yolk-sdk/sandbox
|
|
2
|
+
|
|
3
|
+
Effect-native sandbox execution plane primitives plus a Vercel Sandbox adapter for Yolk agents.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @yolk-sdk/sandbox@canary effect
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Canary APIs are unstable. Keep all `@yolk-sdk/*` packages on the same version.
|
|
12
|
+
|
|
13
|
+
## Subpaths
|
|
14
|
+
|
|
15
|
+
| Subpath | Purpose |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `@yolk-sdk/sandbox` | Core `Sandbox` service, state store, models, lifecycle helpers, errors |
|
|
18
|
+
| `@yolk-sdk/sandbox/agent` | One trusted `sandbox` tool module for `@yolk-sdk/agent/tools` |
|
|
19
|
+
| `@yolk-sdk/sandbox/vercel` | Vercel Sandbox provider layer |
|
|
20
|
+
| `@yolk-sdk/sandbox/testing` | Fake sandbox + in-memory state store layers |
|
|
21
|
+
|
|
22
|
+
## Imports
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { Sandbox, SandboxStateStore } from '@yolk-sdk/sandbox'
|
|
26
|
+
import { makeSandboxToolModule } from '@yolk-sdk/sandbox/agent'
|
|
27
|
+
import { makeVercelSandboxLayer } from '@yolk-sdk/sandbox/vercel'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Example
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { Effect, Layer } from 'effect'
|
|
34
|
+
import { Sandbox } from '@yolk-sdk/sandbox'
|
|
35
|
+
import { makeVercelSandboxLayer } from '@yolk-sdk/sandbox/vercel'
|
|
36
|
+
import { makeInMemorySandboxStateStoreLayer } from '@yolk-sdk/sandbox/testing'
|
|
37
|
+
|
|
38
|
+
const layer = makeVercelSandboxLayer({ sandboxSessionId: 'user_1:session_1' }).pipe(
|
|
39
|
+
Layer.provide(makeInMemorySandboxStateStoreLayer())
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
const program = Effect.gen(function* () {
|
|
43
|
+
const sandbox = yield* Sandbox
|
|
44
|
+
return yield* sandbox.run({ command: 'node --version' })
|
|
45
|
+
}).pipe(Effect.provide(layer))
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Host responsibilities
|
|
49
|
+
|
|
50
|
+
- Build `sandboxSessionId` from host user/session scope.
|
|
51
|
+
- Provide a durable `SandboxStateStore` adapter.
|
|
52
|
+
- Inject env/secrets and choose source/snapshot/git policy.
|
|
53
|
+
- Run cleanup for expired disposable sandboxes.
|
|
54
|
+
- Own approvals, auth, UI, diffs, commit/push/PR, and audit policy.
|
|
55
|
+
|
|
56
|
+
## Boundaries
|
|
57
|
+
|
|
58
|
+
- Core is provider-free and app-free.
|
|
59
|
+
- Vercel SDK imports live only under `@yolk-sdk/sandbox/vercel`.
|
|
60
|
+
- The package exposes one agent tool; hosts decide where to enable it.
|
package/dist/agent.d.mts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { SandboxCommandResult } from "./model.mjs";
|
|
2
|
+
import { Sandbox, SandboxApi } from "./service.mjs";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
import { ToolCall, ToolResult } from "@yolk-sdk/agent/protocol";
|
|
6
|
+
import { ToolModule, ToolRegistryError } from "@yolk-sdk/agent/tools";
|
|
7
|
+
|
|
8
|
+
//#region src/agent.d.ts
|
|
9
|
+
declare const sandboxToolName = "sandbox";
|
|
10
|
+
declare const SandboxToolParams: Schema.Struct<{
|
|
11
|
+
readonly command: Schema.String;
|
|
12
|
+
readonly cwd: Schema.optional<Schema.NullOr<Schema.String>>;
|
|
13
|
+
readonly stdin: Schema.optional<Schema.NullOr<Schema.String>>;
|
|
14
|
+
readonly timeoutSeconds: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
15
|
+
readonly background: Schema.optional<Schema.NullOr<Schema.Boolean>>;
|
|
16
|
+
}>;
|
|
17
|
+
type SandboxToolParams = typeof SandboxToolParams.Type;
|
|
18
|
+
type SandboxToolModuleOptions<Context> = {
|
|
19
|
+
readonly capabilities?: ReadonlyArray<string>;
|
|
20
|
+
readonly workspaceDescription?: string;
|
|
21
|
+
readonly lifecycleDescription?: string;
|
|
22
|
+
readonly previewPorts?: ReadonlyArray<number>;
|
|
23
|
+
readonly isEnabled?: (context: Context) => Effect.Effect<boolean, ToolRegistryError>;
|
|
24
|
+
};
|
|
25
|
+
type SandboxToolStructuredContent = {
|
|
26
|
+
readonly exitCode: number | null;
|
|
27
|
+
readonly durationMs: number;
|
|
28
|
+
readonly timedOut: boolean;
|
|
29
|
+
readonly truncated: boolean;
|
|
30
|
+
readonly workspaceReset: boolean;
|
|
31
|
+
readonly backgroundId?: string;
|
|
32
|
+
readonly previewUrls: SandboxCommandResult['previewUrls'];
|
|
33
|
+
readonly state: SandboxCommandResult['state'];
|
|
34
|
+
};
|
|
35
|
+
declare const makeSandboxToolResult: (input: {
|
|
36
|
+
readonly callId: string;
|
|
37
|
+
readonly result: SandboxCommandResult;
|
|
38
|
+
}) => ToolResult;
|
|
39
|
+
declare const makeSandboxToolModuleFromApi: <Context>(sandbox: SandboxApi, options?: SandboxToolModuleOptions<Context>) => ToolModule<Context>;
|
|
40
|
+
declare const makeSandboxToolModule: <Context>(options?: SandboxToolModuleOptions<Context>) => Effect.Effect<ToolModule<Context>, never, Sandbox>;
|
|
41
|
+
type SandboxToolExecutionInput<Context> = {
|
|
42
|
+
readonly call: ToolCall;
|
|
43
|
+
readonly context: Context;
|
|
44
|
+
readonly params: SandboxToolParams;
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { SandboxToolExecutionInput, SandboxToolModuleOptions, SandboxToolParams, SandboxToolStructuredContent, makeSandboxToolModule, makeSandboxToolModuleFromApi, makeSandboxToolResult, sandboxToolName };
|
|
48
|
+
//# sourceMappingURL=agent.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.mts","names":[],"sources":["../src/agent.ts"],"mappings":";;;;;;;;cAuBa,eAAA;AAAA,cAEP,iBAAA,EAAiB,MAAA,CAAA,MAAA;EAAA;;;;;;KAkCX,iBAAA,UAA2B,iBAAA,CAAkB,IAAI;AAAA,KAEjD,wBAAA;EAAA,SACD,YAAA,GAAe,aAAA;EAAA,SACf,oBAAA;EAAA,SACA,oBAAA;EAAA,SACA,YAAA,GAAe,aAAA;EAAA,SACf,SAAA,IAAa,OAAA,EAAS,OAAA,KAAY,MAAA,CAAO,MAAA,UAAgB,iBAAA;AAAA;AAAA,KAGxD,4BAAA;EAAA,SACD,QAAA;EAAA,SACA,UAAA;EAAA,SACA,QAAA;EAAA,SACA,SAAA;EAAA,SACA,cAAA;EAAA,SACA,YAAA;EAAA,SACA,WAAA,EAAa,oBAAA;EAAA,SACb,KAAA,EAAO,oBAAoB;AAAA;AAAA,cAyIzB,qBAAA,GAAyB,KAAA;EAAA,SAC3B,MAAA;EAAA,SACA,MAAA,EAAQ,oBAAA;AAAA,MAClB,UASA;AAAA,cAwBY,4BAAA,YACX,OAAA,EAAS,UAAA,EACT,OAAA,GAAS,wBAAA,CAAyB,OAAA,MACjC,UAAA,CAAW,OAAA;AAAA,cAsCD,qBAAA,YACX,OAAA,GAAS,wBAAA,CAAyB,OAAA,MACjC,MAAA,CAAO,MAAA,CAAO,UAAA,CAAW,OAAA,UAAiB,OAAA;AAAA,KAMjC,yBAAA;EAAA,SACD,IAAA,EAAM,QAAA;EAAA,SACN,OAAA,EAAS,OAAA;EAAA,SACT,MAAA,EAAQ,iBAAA;AAAA"}
|
package/dist/agent.mjs
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxToolOutputLimit, validateSandboxCommand } from "./lifecycle.mjs";
|
|
2
|
+
import { Sandbox } from "./service.mjs";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
import { ToolError } from "@yolk-sdk/agent/loop";
|
|
6
|
+
import { ToolResult } from "@yolk-sdk/agent/protocol";
|
|
7
|
+
import { makeTool, modelVisibleToolError } from "@yolk-sdk/agent/tools";
|
|
8
|
+
//#region src/agent.ts
|
|
9
|
+
const sandboxToolName = "sandbox";
|
|
10
|
+
const SandboxToolParams = Schema.Struct({
|
|
11
|
+
command: Schema.String.pipe(Schema.annotate({ description: "Shell command to run. Multiline commands are allowed." })),
|
|
12
|
+
cwd: Schema.optional(Schema.NullOr(Schema.String.pipe(Schema.annotate({ description: "Workspace-relative working directory. Absolute paths are rejected." })))),
|
|
13
|
+
stdin: Schema.optional(Schema.NullOr(Schema.String.pipe(Schema.annotate({ description: "Optional stdin text passed to the command." })))),
|
|
14
|
+
timeoutSeconds: Schema.optional(Schema.NullOr(Schema.Number.pipe(Schema.annotate({ description: "Foreground timeout in seconds. Default 120, max 600." })))),
|
|
15
|
+
background: Schema.optional(Schema.NullOr(Schema.Boolean.pipe(Schema.annotate({ description: "Start command in background and return after a quick probe." }))))
|
|
16
|
+
});
|
|
17
|
+
const nullToUndefined = (value) => value === null ? void 0 : value;
|
|
18
|
+
const toolError = (message, cause) => new ToolError({
|
|
19
|
+
tool: sandboxToolName,
|
|
20
|
+
message,
|
|
21
|
+
cause
|
|
22
|
+
});
|
|
23
|
+
const modelVisibleSandboxError = (error) => {
|
|
24
|
+
switch (error._tag) {
|
|
25
|
+
case "SandboxInputError": return modelVisibleToolError({
|
|
26
|
+
tool: sandboxToolName,
|
|
27
|
+
message: error.message,
|
|
28
|
+
reason: "invalid_input"
|
|
29
|
+
});
|
|
30
|
+
case "SandboxExpiredError": return modelVisibleToolError({
|
|
31
|
+
tool: sandboxToolName,
|
|
32
|
+
message: error.message,
|
|
33
|
+
reason: "unavailable",
|
|
34
|
+
details: { expiredAtMs: error.expiredAtMs }
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const sandboxInfraToolError = (error) => {
|
|
39
|
+
switch (error._tag) {
|
|
40
|
+
case "SandboxConfigError": return toolError(error.message, "invalid_input");
|
|
41
|
+
case "SandboxProviderError": return toolError(error.message, "execution");
|
|
42
|
+
case "SandboxStateError":
|
|
43
|
+
case "SandboxStateStoreError": return toolError(error.message, "unavailable");
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const normalizeTimeoutMs = (timeoutSeconds) => {
|
|
47
|
+
const value = nullToUndefined(timeoutSeconds);
|
|
48
|
+
if (value === void 0) return Effect.succeed(sandboxCommandTimeoutMs(void 0));
|
|
49
|
+
if (!Number.isFinite(value) || value <= 0) return Effect.fail(modelVisibleToolError({
|
|
50
|
+
tool: sandboxToolName,
|
|
51
|
+
message: "timeoutSeconds must be greater than 0",
|
|
52
|
+
reason: "invalid_input"
|
|
53
|
+
}));
|
|
54
|
+
return Effect.succeed(sandboxCommandTimeoutMs(Math.floor(value * 1e3)));
|
|
55
|
+
};
|
|
56
|
+
const normalizeToolParams = (params) => Effect.gen(function* () {
|
|
57
|
+
const command = yield* validateSandboxCommand(params.command).pipe(Effect.mapError(modelVisibleSandboxError));
|
|
58
|
+
const cwd = yield* normalizeWorkspaceCwd(params.cwd).pipe(Effect.mapError(modelVisibleSandboxError));
|
|
59
|
+
const timeoutMs = yield* normalizeTimeoutMs(params.timeoutSeconds);
|
|
60
|
+
return {
|
|
61
|
+
command,
|
|
62
|
+
cwd,
|
|
63
|
+
stdin: nullToUndefined(params.stdin),
|
|
64
|
+
timeoutMs,
|
|
65
|
+
background: nullToUndefined(params.background)
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
const truncateOutputs = (stdout, stderr, limit) => {
|
|
69
|
+
if (stdout.length + stderr.length <= limit) return {
|
|
70
|
+
stdout,
|
|
71
|
+
stderr,
|
|
72
|
+
truncated: false
|
|
73
|
+
};
|
|
74
|
+
const initialStderrBudget = Math.min(stderr.length, Math.floor(limit / 2));
|
|
75
|
+
const initialStdoutBudget = Math.min(stdout.length, limit - initialStderrBudget);
|
|
76
|
+
const unused = limit - initialStdoutBudget - initialStderrBudget;
|
|
77
|
+
const stdoutBudget = Math.min(stdout.length, initialStdoutBudget + unused);
|
|
78
|
+
const stderrBudget = Math.min(stderr.length, limit - stdoutBudget);
|
|
79
|
+
return {
|
|
80
|
+
stdout: stdout.slice(0, stdoutBudget),
|
|
81
|
+
stderr: stderr.slice(0, stderrBudget),
|
|
82
|
+
truncated: true
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
const formatSandboxToolContent = (result, output) => [
|
|
86
|
+
`exit_code: ${result.exitCode === null ? "null" : String(result.exitCode)}`,
|
|
87
|
+
`duration_ms: ${result.durationMs}`,
|
|
88
|
+
`truncated: ${output.truncated}`,
|
|
89
|
+
`timed_out: ${result.timedOut}`,
|
|
90
|
+
`workspace_reset: ${result.workspaceReset}`,
|
|
91
|
+
result.backgroundId === void 0 ? void 0 : `background_id: ${result.backgroundId}`,
|
|
92
|
+
"<stdout>",
|
|
93
|
+
output.stdout,
|
|
94
|
+
"</stdout>",
|
|
95
|
+
"<stderr>",
|
|
96
|
+
output.stderr,
|
|
97
|
+
"</stderr>"
|
|
98
|
+
].filter((line) => line !== void 0).join("\n");
|
|
99
|
+
const structuredContent = (result, truncated) => ({
|
|
100
|
+
exitCode: result.exitCode,
|
|
101
|
+
durationMs: result.durationMs,
|
|
102
|
+
timedOut: result.timedOut,
|
|
103
|
+
truncated,
|
|
104
|
+
workspaceReset: result.workspaceReset,
|
|
105
|
+
...result.backgroundId === void 0 ? {} : { backgroundId: result.backgroundId },
|
|
106
|
+
previewUrls: result.previewUrls,
|
|
107
|
+
state: result.state
|
|
108
|
+
});
|
|
109
|
+
const makeSandboxToolResult = (input) => {
|
|
110
|
+
const output = truncateOutputs(input.result.stdout, input.result.stderr, sandboxToolOutputLimit);
|
|
111
|
+
return ToolResult.make({
|
|
112
|
+
toolCallId: input.callId,
|
|
113
|
+
content: formatSandboxToolContent(input.result, output),
|
|
114
|
+
isError: input.result.timedOut || input.result.exitCode !== null && input.result.exitCode !== 0,
|
|
115
|
+
structuredContent: structuredContent(input.result, output.truncated)
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
const sandboxToolDescription = (options) => {
|
|
119
|
+
const capabilities = options.capabilities ?? [
|
|
120
|
+
"run project commands such as typechecks, lint, tests, and builds",
|
|
121
|
+
"edit files with shell tools such as apply_patch when available",
|
|
122
|
+
"start dev servers and use preview ports",
|
|
123
|
+
"run browser checks through agent-browser when available"
|
|
124
|
+
];
|
|
125
|
+
const ports = options.previewPorts ?? [];
|
|
126
|
+
return [
|
|
127
|
+
"Run one non-interactive bash command inside a real sandbox workspace.",
|
|
128
|
+
options.workspaceDescription ?? "The working directory is the sandbox workspace root.",
|
|
129
|
+
options.lifecycleDescription ?? "The sandbox is disposable and may reset after idle or max lifetime expiry.",
|
|
130
|
+
`Foreground timeout defaults to 120s and is capped at ${Math.floor(maxSandboxCommandTimeoutMs / 1e3)}s.`,
|
|
131
|
+
"Use workspace-relative cwd only; absolute paths and workspace escapes are rejected.",
|
|
132
|
+
"Use stdin for large patches, scripts, or data.",
|
|
133
|
+
"Set background=true for long-running servers; the tool returns after a quick probe.",
|
|
134
|
+
ports.length === 0 ? "Preview URLs are returned when configured by the host." : `Preview ports: ${ports.join(", ")}.`,
|
|
135
|
+
`Available capabilities:\n${capabilities.map((capability) => `- ${capability}`).join("\n")}`
|
|
136
|
+
].join("\n\n");
|
|
137
|
+
};
|
|
138
|
+
const makeSandboxToolModuleFromApi = (sandbox, options = {}) => ({
|
|
139
|
+
id: "sandbox",
|
|
140
|
+
tools: [makeTool({
|
|
141
|
+
name: sandboxToolName,
|
|
142
|
+
description: sandboxToolDescription(options),
|
|
143
|
+
parameters: SandboxToolParams,
|
|
144
|
+
access: "destructive",
|
|
145
|
+
isEnabled: options.isEnabled,
|
|
146
|
+
invalidParamsMessage: (error) => `Invalid sandbox arguments: ${error instanceof Error ? error.message : String(error)}`,
|
|
147
|
+
execute: ({ call, params }) => Effect.gen(function* () {
|
|
148
|
+
if (call.name !== "sandbox") return yield* Effect.fail(toolError(`Tool is not configured: ${call.name}`, "not_found"));
|
|
149
|
+
const normalized = yield* normalizeToolParams(params);
|
|
150
|
+
const result = yield* sandbox.run(normalized).pipe(Effect.mapError((error) => {
|
|
151
|
+
switch (error._tag) {
|
|
152
|
+
case "SandboxInputError":
|
|
153
|
+
case "SandboxExpiredError": return modelVisibleSandboxError(error);
|
|
154
|
+
case "SandboxConfigError":
|
|
155
|
+
case "SandboxProviderError":
|
|
156
|
+
case "SandboxStateError":
|
|
157
|
+
case "SandboxStateStoreError": return sandboxInfraToolError(error);
|
|
158
|
+
}
|
|
159
|
+
}));
|
|
160
|
+
return makeSandboxToolResult({
|
|
161
|
+
callId: call.id,
|
|
162
|
+
result
|
|
163
|
+
});
|
|
164
|
+
})
|
|
165
|
+
})]
|
|
166
|
+
});
|
|
167
|
+
const makeSandboxToolModule = (options = {}) => Effect.gen(function* () {
|
|
168
|
+
return makeSandboxToolModuleFromApi(yield* Sandbox, options);
|
|
169
|
+
});
|
|
170
|
+
//#endregion
|
|
171
|
+
export { makeSandboxToolModule, makeSandboxToolModuleFromApi, makeSandboxToolResult, sandboxToolName };
|
|
172
|
+
|
|
173
|
+
//# sourceMappingURL=agent.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.mjs","names":[],"sources":["../src/agent.ts"],"sourcesContent":["import { Effect } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport { ToolError } from '@yolk-sdk/agent/loop'\nimport { ToolResult, type ToolCall } from '@yolk-sdk/agent/protocol'\nimport {\n makeTool,\n modelVisibleToolError,\n type ModelVisibleToolError,\n type ToolModule,\n type ToolRegistryError\n} from '@yolk-sdk/agent/tools'\nimport {\n maxSandboxCommandTimeoutMs,\n normalizeWorkspaceCwd,\n sandboxCommandTimeoutMs,\n sandboxToolOutputLimit,\n validateSandboxCommand\n} from './lifecycle.ts'\nimport type { SandboxError, SandboxExpiredError, SandboxInputError } from './errors.ts'\nimport type { SandboxApi } from './service.ts'\nimport { Sandbox } from './service.ts'\nimport type { SandboxCommandResult } from './model.ts'\n\nexport const sandboxToolName = 'sandbox'\n\nconst SandboxToolParams = Schema.Struct({\n command: Schema.String.pipe(\n Schema.annotate({ description: 'Shell command to run. Multiline commands are allowed.' })\n ),\n cwd: Schema.optional(\n Schema.NullOr(\n Schema.String.pipe(\n Schema.annotate({ description: 'Workspace-relative working directory. Absolute paths are rejected.' })\n )\n )\n ),\n stdin: Schema.optional(\n Schema.NullOr(\n Schema.String.pipe(\n Schema.annotate({ description: 'Optional stdin text passed to the command.' })\n )\n )\n ),\n timeoutSeconds: Schema.optional(\n Schema.NullOr(\n Schema.Number.pipe(\n Schema.annotate({ description: 'Foreground timeout in seconds. Default 120, max 600.' })\n )\n )\n ),\n background: Schema.optional(\n Schema.NullOr(\n Schema.Boolean.pipe(\n Schema.annotate({ description: 'Start command in background and return after a quick probe.' })\n )\n )\n )\n})\n\nexport type SandboxToolParams = typeof SandboxToolParams.Type\n\nexport type SandboxToolModuleOptions<Context> = {\n readonly capabilities?: ReadonlyArray<string>\n readonly workspaceDescription?: string\n readonly lifecycleDescription?: string\n readonly previewPorts?: ReadonlyArray<number>\n readonly isEnabled?: (context: Context) => Effect.Effect<boolean, ToolRegistryError>\n}\n\nexport type SandboxToolStructuredContent = {\n readonly exitCode: number | null\n readonly durationMs: number\n readonly timedOut: boolean\n readonly truncated: boolean\n readonly workspaceReset: boolean\n readonly backgroundId?: string\n readonly previewUrls: SandboxCommandResult['previewUrls']\n readonly state: SandboxCommandResult['state']\n}\n\ntype OutputSlice = {\n readonly stdout: string\n readonly stderr: string\n readonly truncated: boolean\n}\n\nconst nullToUndefined = <A>(value: A | null | undefined) => value === null ? undefined : value\n\nconst toolError = (message: string, cause: ToolError['cause']) =>\n new ToolError({\n tool: sandboxToolName,\n message,\n cause\n })\n\nconst modelVisibleSandboxError = (\n error: SandboxInputError | SandboxExpiredError\n): ModelVisibleToolError => {\n switch (error._tag) {\n case 'SandboxInputError':\n return modelVisibleToolError({\n tool: sandboxToolName,\n message: error.message,\n reason: 'invalid_input'\n })\n case 'SandboxExpiredError':\n return modelVisibleToolError({\n tool: sandboxToolName,\n message: error.message,\n reason: 'unavailable',\n details: { expiredAtMs: error.expiredAtMs }\n })\n }\n}\n\nconst sandboxInfraToolError = (error: Exclude<SandboxError, SandboxInputError | SandboxExpiredError>) => {\n switch (error._tag) {\n case 'SandboxConfigError':\n return toolError(error.message, 'invalid_input')\n case 'SandboxProviderError':\n return toolError(error.message, 'execution')\n case 'SandboxStateError':\n case 'SandboxStateStoreError':\n return toolError(error.message, 'unavailable')\n }\n}\n\nconst normalizeTimeoutMs = (timeoutSeconds: number | null | undefined) => {\n const value = nullToUndefined(timeoutSeconds)\n\n if (value === undefined) {\n return Effect.succeed(sandboxCommandTimeoutMs(undefined))\n }\n\n if (!Number.isFinite(value) || value <= 0) {\n return Effect.fail(\n modelVisibleToolError({\n tool: sandboxToolName,\n message: 'timeoutSeconds must be greater than 0',\n reason: 'invalid_input'\n })\n )\n }\n\n return Effect.succeed(sandboxCommandTimeoutMs(Math.floor(value * 1_000)))\n}\n\nconst normalizeToolParams = (params: SandboxToolParams) =>\n Effect.gen(function* () {\n const command = yield* validateSandboxCommand(params.command).pipe(\n Effect.mapError(modelVisibleSandboxError)\n )\n const cwd = yield* normalizeWorkspaceCwd(params.cwd).pipe(\n Effect.mapError(modelVisibleSandboxError)\n )\n const timeoutMs = yield* normalizeTimeoutMs(params.timeoutSeconds)\n\n return {\n command,\n cwd,\n stdin: nullToUndefined(params.stdin),\n timeoutMs,\n background: nullToUndefined(params.background)\n }\n })\n\nconst truncateOutputs = (stdout: string, stderr: string, limit: number): OutputSlice => {\n if (stdout.length + stderr.length <= limit) {\n return { stdout, stderr, truncated: false }\n }\n\n const initialStderrBudget = Math.min(stderr.length, Math.floor(limit / 2))\n const initialStdoutBudget = Math.min(stdout.length, limit - initialStderrBudget)\n const unused = limit - initialStdoutBudget - initialStderrBudget\n const stdoutBudget = Math.min(stdout.length, initialStdoutBudget + unused)\n const stderrBudget = Math.min(stderr.length, limit - stdoutBudget)\n\n return {\n stdout: stdout.slice(0, stdoutBudget),\n stderr: stderr.slice(0, stderrBudget),\n truncated: true\n }\n}\n\nconst formatSandboxToolContent = (result: SandboxCommandResult, output: OutputSlice) =>\n [\n `exit_code: ${result.exitCode === null ? 'null' : String(result.exitCode)}`,\n `duration_ms: ${result.durationMs}`,\n `truncated: ${output.truncated}`,\n `timed_out: ${result.timedOut}`,\n `workspace_reset: ${result.workspaceReset}`,\n result.backgroundId === undefined ? undefined : `background_id: ${result.backgroundId}`,\n '<stdout>',\n output.stdout,\n '</stdout>',\n '<stderr>',\n output.stderr,\n '</stderr>'\n ].filter(line => line !== undefined).join('\\n')\n\nconst structuredContent = (\n result: SandboxCommandResult,\n truncated: boolean\n): SandboxToolStructuredContent => ({\n exitCode: result.exitCode,\n durationMs: result.durationMs,\n timedOut: result.timedOut,\n truncated,\n workspaceReset: result.workspaceReset,\n ...(result.backgroundId === undefined ? {} : { backgroundId: result.backgroundId }),\n previewUrls: result.previewUrls,\n state: result.state\n})\n\nexport const makeSandboxToolResult = (input: {\n readonly callId: string\n readonly result: SandboxCommandResult\n}) => {\n const output = truncateOutputs(input.result.stdout, input.result.stderr, sandboxToolOutputLimit)\n\n return ToolResult.make({\n toolCallId: input.callId,\n content: formatSandboxToolContent(input.result, output),\n isError: input.result.timedOut || (input.result.exitCode !== null && input.result.exitCode !== 0),\n structuredContent: structuredContent(input.result, output.truncated)\n })\n}\n\nconst sandboxToolDescription = <Context>(options: SandboxToolModuleOptions<Context>) => {\n const capabilities = options.capabilities ?? [\n 'run project commands such as typechecks, lint, tests, and builds',\n 'edit files with shell tools such as apply_patch when available',\n 'start dev servers and use preview ports',\n 'run browser checks through agent-browser when available'\n ]\n const ports = options.previewPorts ?? []\n\n return [\n 'Run one non-interactive bash command inside a real sandbox workspace.',\n options.workspaceDescription ?? 'The working directory is the sandbox workspace root.',\n options.lifecycleDescription ?? 'The sandbox is disposable and may reset after idle or max lifetime expiry.',\n `Foreground timeout defaults to 120s and is capped at ${Math.floor(maxSandboxCommandTimeoutMs / 1_000)}s.`,\n 'Use workspace-relative cwd only; absolute paths and workspace escapes are rejected.',\n 'Use stdin for large patches, scripts, or data.',\n 'Set background=true for long-running servers; the tool returns after a quick probe.',\n ports.length === 0 ? 'Preview URLs are returned when configured by the host.' : `Preview ports: ${ports.join(', ')}.`,\n `Available capabilities:\\n${capabilities.map(capability => `- ${capability}`).join('\\n')}`\n ].join('\\n\\n')\n}\n\nexport const makeSandboxToolModuleFromApi = <Context>(\n sandbox: SandboxApi,\n options: SandboxToolModuleOptions<Context> = {}\n): ToolModule<Context> => ({\n id: 'sandbox',\n tools: [\n makeTool({\n name: sandboxToolName,\n description: sandboxToolDescription(options),\n parameters: SandboxToolParams,\n access: 'destructive',\n isEnabled: options.isEnabled,\n invalidParamsMessage: error => `Invalid sandbox arguments: ${error instanceof Error ? error.message : String(error)}`,\n execute: ({ call, params }) =>\n Effect.gen(function* () {\n if (call.name !== sandboxToolName) {\n return yield* Effect.fail(toolError(`Tool is not configured: ${call.name}`, 'not_found'))\n }\n\n const normalized = yield* normalizeToolParams(params)\n const result = yield* sandbox.run(normalized).pipe(\n Effect.mapError(error => {\n switch (error._tag) {\n case 'SandboxInputError':\n case 'SandboxExpiredError':\n return modelVisibleSandboxError(error)\n case 'SandboxConfigError':\n case 'SandboxProviderError':\n case 'SandboxStateError':\n case 'SandboxStateStoreError':\n return sandboxInfraToolError(error)\n }\n })\n )\n\n return makeSandboxToolResult({ callId: call.id, result })\n })\n })\n ]\n})\n\nexport const makeSandboxToolModule = <Context>(\n options: SandboxToolModuleOptions<Context> = {}\n): Effect.Effect<ToolModule<Context>, never, Sandbox> =>\n Effect.gen(function* () {\n const sandbox = yield* Sandbox\n return makeSandboxToolModuleFromApi(sandbox, options)\n })\n\nexport type SandboxToolExecutionInput<Context> = {\n readonly call: ToolCall\n readonly context: Context\n readonly params: SandboxToolParams\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
|
|
3
|
+
//#region src/errors.d.ts
|
|
4
|
+
declare const SandboxInputErrorCause: Schema.Literals<readonly ["empty_command", "invalid_cwd", "invalid_timeout"]>;
|
|
5
|
+
type SandboxInputErrorCause = typeof SandboxInputErrorCause.Type;
|
|
6
|
+
declare const SandboxInputError_base: Schema.Class<SandboxInputError, Schema.TaggedStruct<"SandboxInputError", {
|
|
7
|
+
readonly cause: Schema.Literals<readonly ["empty_command", "invalid_cwd", "invalid_timeout"]>;
|
|
8
|
+
readonly message: Schema.String;
|
|
9
|
+
}>, import("effect/Cause").YieldableError>;
|
|
10
|
+
declare class SandboxInputError extends SandboxInputError_base {}
|
|
11
|
+
declare const SandboxConfigError_base: Schema.Class<SandboxConfigError, Schema.TaggedStruct<"SandboxConfigError", {
|
|
12
|
+
readonly message: Schema.String;
|
|
13
|
+
readonly cause: Schema.String;
|
|
14
|
+
}>, import("effect/Cause").YieldableError>;
|
|
15
|
+
declare class SandboxConfigError extends SandboxConfigError_base {}
|
|
16
|
+
declare const SandboxExpiredError_base: Schema.Class<SandboxExpiredError, Schema.TaggedStruct<"SandboxExpiredError", {
|
|
17
|
+
readonly message: Schema.String;
|
|
18
|
+
readonly expiredAtMs: Schema.Number;
|
|
19
|
+
}>, import("effect/Cause").YieldableError>;
|
|
20
|
+
declare class SandboxExpiredError extends SandboxExpiredError_base {}
|
|
21
|
+
declare const SandboxStateError_base: Schema.Class<SandboxStateError, Schema.TaggedStruct<"SandboxStateError", {
|
|
22
|
+
readonly message: Schema.String;
|
|
23
|
+
readonly cause: Schema.String;
|
|
24
|
+
readonly underlying: Schema.optional<Schema.Unknown>;
|
|
25
|
+
}>, import("effect/Cause").YieldableError>;
|
|
26
|
+
declare class SandboxStateError extends SandboxStateError_base {}
|
|
27
|
+
declare const SandboxStateStoreError_base: Schema.Class<SandboxStateStoreError, Schema.TaggedStruct<"SandboxStateStoreError", {
|
|
28
|
+
readonly message: Schema.String;
|
|
29
|
+
readonly operation: Schema.String;
|
|
30
|
+
readonly underlying: Schema.optional<Schema.Unknown>;
|
|
31
|
+
}>, import("effect/Cause").YieldableError>;
|
|
32
|
+
declare class SandboxStateStoreError extends SandboxStateStoreError_base {}
|
|
33
|
+
declare const SandboxProviderError_base: Schema.Class<SandboxProviderError, Schema.TaggedStruct<"SandboxProviderError", {
|
|
34
|
+
readonly provider: Schema.Literal<"vercel">;
|
|
35
|
+
readonly operation: Schema.String;
|
|
36
|
+
readonly message: Schema.String;
|
|
37
|
+
readonly underlying: Schema.optional<Schema.Unknown>;
|
|
38
|
+
}>, import("effect/Cause").YieldableError>;
|
|
39
|
+
declare class SandboxProviderError extends SandboxProviderError_base {}
|
|
40
|
+
type SandboxError = SandboxInputError | SandboxConfigError | SandboxExpiredError | SandboxStateError | SandboxStateStoreError | SandboxProviderError;
|
|
41
|
+
declare const unknownToMessage: (error: unknown) => string;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { SandboxConfigError, SandboxError, SandboxExpiredError, SandboxInputError, SandboxInputErrorCause, SandboxProviderError, SandboxStateError, SandboxStateStoreError, unknownToMessage };
|
|
44
|
+
//# sourceMappingURL=errors.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.mts","names":[],"sources":["../src/errors.ts"],"mappings":";;;cAEa,sBAAA,EAAsB,MAAA,CAAA,QAAA;AAAA,KAKvB,sBAAA,UAAgC,sBAAA,CAAuB,IAAI;AAAA,cAAA,sBAAA;;;;cAE1D,iBAAA,SAA0B,sBAMtC;AAAA,cAAG,uBAAA;;;;cAES,kBAAA,SAA2B,uBAMvC;AAAA,cAAG,wBAAA;;;;cAES,mBAAA,SAA4B,wBAMxC;AAAA,cAAG,sBAAA;;;;;cAES,iBAAA,SAA0B,sBAOtC;AAAA,cAAG,2BAAA;;;;;cAES,sBAAA,SAA+B,2BAO3C;AAAA,cAAG,yBAAA;;;;;;cAES,oBAAA,SAA6B,yBAQzC;AAAA,KAEW,YAAA,GACR,iBAAA,GACA,kBAAA,GACA,mBAAA,GACA,iBAAA,GACA,sBAAA,GACA,oBAAA;AAAA,cAES,gBAAA,GAAoB,KAAc"}
|
package/dist/errors.mjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
//#region src/errors.ts
|
|
3
|
+
const SandboxInputErrorCause = Schema.Literals([
|
|
4
|
+
"empty_command",
|
|
5
|
+
"invalid_cwd",
|
|
6
|
+
"invalid_timeout"
|
|
7
|
+
]);
|
|
8
|
+
var SandboxInputError = class extends Schema.TaggedErrorClass()("SandboxInputError", {
|
|
9
|
+
cause: SandboxInputErrorCause,
|
|
10
|
+
message: Schema.String
|
|
11
|
+
}) {};
|
|
12
|
+
var SandboxConfigError = class extends Schema.TaggedErrorClass()("SandboxConfigError", {
|
|
13
|
+
message: Schema.String,
|
|
14
|
+
cause: Schema.String
|
|
15
|
+
}) {};
|
|
16
|
+
var SandboxExpiredError = class extends Schema.TaggedErrorClass()("SandboxExpiredError", {
|
|
17
|
+
message: Schema.String,
|
|
18
|
+
expiredAtMs: Schema.Number
|
|
19
|
+
}) {};
|
|
20
|
+
var SandboxStateError = class extends Schema.TaggedErrorClass()("SandboxStateError", {
|
|
21
|
+
message: Schema.String,
|
|
22
|
+
cause: Schema.String,
|
|
23
|
+
underlying: Schema.optional(Schema.Unknown)
|
|
24
|
+
}) {};
|
|
25
|
+
var SandboxStateStoreError = class extends Schema.TaggedErrorClass()("SandboxStateStoreError", {
|
|
26
|
+
message: Schema.String,
|
|
27
|
+
operation: Schema.String,
|
|
28
|
+
underlying: Schema.optional(Schema.Unknown)
|
|
29
|
+
}) {};
|
|
30
|
+
var SandboxProviderError = class extends Schema.TaggedErrorClass()("SandboxProviderError", {
|
|
31
|
+
provider: Schema.Literal("vercel"),
|
|
32
|
+
operation: Schema.String,
|
|
33
|
+
message: Schema.String,
|
|
34
|
+
underlying: Schema.optional(Schema.Unknown)
|
|
35
|
+
}) {};
|
|
36
|
+
const unknownToMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
37
|
+
//#endregion
|
|
38
|
+
export { SandboxConfigError, SandboxExpiredError, SandboxInputError, SandboxInputErrorCause, SandboxProviderError, SandboxStateError, SandboxStateStoreError, unknownToMessage };
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=errors.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import * as Schema from 'effect/Schema'\n\nexport const SandboxInputErrorCause = Schema.Literals([\n 'empty_command',\n 'invalid_cwd',\n 'invalid_timeout'\n])\nexport type SandboxInputErrorCause = typeof SandboxInputErrorCause.Type\n\nexport class SandboxInputError extends Schema.TaggedErrorClass<SandboxInputError>()(\n 'SandboxInputError',\n {\n cause: SandboxInputErrorCause,\n message: Schema.String\n }\n) {}\n\nexport class SandboxConfigError extends Schema.TaggedErrorClass<SandboxConfigError>()(\n 'SandboxConfigError',\n {\n message: Schema.String,\n cause: Schema.String\n }\n) {}\n\nexport class SandboxExpiredError extends Schema.TaggedErrorClass<SandboxExpiredError>()(\n 'SandboxExpiredError',\n {\n message: Schema.String,\n expiredAtMs: Schema.Number\n }\n) {}\n\nexport class SandboxStateError extends Schema.TaggedErrorClass<SandboxStateError>()(\n 'SandboxStateError',\n {\n message: Schema.String,\n cause: Schema.String,\n underlying: Schema.optional(Schema.Unknown)\n }\n) {}\n\nexport class SandboxStateStoreError extends Schema.TaggedErrorClass<SandboxStateStoreError>()(\n 'SandboxStateStoreError',\n {\n message: Schema.String,\n operation: Schema.String,\n underlying: Schema.optional(Schema.Unknown)\n }\n) {}\n\nexport class SandboxProviderError extends Schema.TaggedErrorClass<SandboxProviderError>()(\n 'SandboxProviderError',\n {\n provider: Schema.Literal('vercel'),\n operation: Schema.String,\n message: Schema.String,\n underlying: Schema.optional(Schema.Unknown)\n }\n) {}\n\nexport type SandboxError =\n | SandboxInputError\n | SandboxConfigError\n | SandboxExpiredError\n | SandboxStateError\n | SandboxStateStoreError\n | SandboxProviderError\n\nexport const unknownToMessage = (error: unknown) =>\n error instanceof Error ? error.message : String(error)\n"],"mappings":";;AAEA,MAAa,yBAAyB,OAAO,SAAS;CACpD;CACA;CACA;AACF,CAAC;AAGD,IAAa,oBAAb,cAAuC,OAAO,iBAAoC,EAChF,qBACA;CACE,OAAO;CACP,SAAS,OAAO;AAClB,CACF,EAAE,CAAC;AAEH,IAAa,qBAAb,cAAwC,OAAO,iBAAqC,EAClF,sBACA;CACE,SAAS,OAAO;CAChB,OAAO,OAAO;AAChB,CACF,EAAE,CAAC;AAEH,IAAa,sBAAb,cAAyC,OAAO,iBAAsC,EACpF,uBACA;CACE,SAAS,OAAO;CAChB,aAAa,OAAO;AACtB,CACF,EAAE,CAAC;AAEH,IAAa,oBAAb,cAAuC,OAAO,iBAAoC,EAChF,qBACA;CACE,SAAS,OAAO;CAChB,OAAO,OAAO;CACd,YAAY,OAAO,SAAS,OAAO,OAAO;AAC5C,CACF,EAAE,CAAC;AAEH,IAAa,yBAAb,cAA4C,OAAO,iBAAyC,EAC1F,0BACA;CACE,SAAS,OAAO;CAChB,WAAW,OAAO;CAClB,YAAY,OAAO,SAAS,OAAO,OAAO;AAC5C,CACF,EAAE,CAAC;AAEH,IAAa,uBAAb,cAA0C,OAAO,iBAAuC,EACtF,wBACA;CACE,UAAU,OAAO,QAAQ,QAAQ;CACjC,WAAW,OAAO;CAClB,SAAS,OAAO;CAChB,YAAY,OAAO,SAAS,OAAO,OAAO;AAC5C,CACF,EAAE,CAAC;AAUH,MAAa,oBAAoB,UAC/B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SandboxConfigError, SandboxError, SandboxExpiredError, SandboxInputError, SandboxInputErrorCause, SandboxProviderError, SandboxStateError, SandboxStateStoreError } from "./errors.mjs";
|
|
2
|
+
import { DisposableSandboxLifecycle, EmptySandboxInitialSource, GitSandboxInitialSource, PersistentSandboxLifecycle, SandboxCommandInput, SandboxCommandResult, SandboxInitialSource, SandboxLifecycle, SandboxPreviewUrl, SandboxResources, SandboxSnapshotRetention, SandboxState, SnapshotSandboxInitialSource, TarballSandboxInitialSource, VercelSandboxState } from "./model.mjs";
|
|
3
|
+
import { Sandbox, SandboxApi } from "./service.mjs";
|
|
4
|
+
import { backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand } from "./lifecycle.mjs";
|
|
5
|
+
import { makeVercelSandboxName } from "./name.mjs";
|
|
6
|
+
import { SandboxStateStore, SandboxStateStoreApi } from "./state-store.mjs";
|
|
7
|
+
export { DisposableSandboxLifecycle, EmptySandboxInitialSource, GitSandboxInitialSource, PersistentSandboxLifecycle, Sandbox, type SandboxApi, SandboxCommandInput, SandboxCommandResult, SandboxConfigError, type SandboxError, SandboxExpiredError, SandboxInitialSource, SandboxInputError, SandboxInputErrorCause, SandboxLifecycle, SandboxPreviewUrl, SandboxProviderError, SandboxResources, SandboxSnapshotRetention, SandboxState, SandboxStateError, SandboxStateStore, type SandboxStateStoreApi, SandboxStateStoreError, SnapshotSandboxInitialSource, TarballSandboxInitialSource, VercelSandboxState, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, makeVercelSandboxName, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SandboxConfigError, SandboxExpiredError, SandboxInputError, SandboxInputErrorCause, SandboxProviderError, SandboxStateError, SandboxStateStoreError } from "./errors.mjs";
|
|
2
|
+
import { DisposableSandboxLifecycle, EmptySandboxInitialSource, GitSandboxInitialSource, PersistentSandboxLifecycle, SandboxCommandInput, SandboxCommandResult, SandboxInitialSource, SandboxLifecycle, SandboxPreviewUrl, SandboxResources, SandboxSnapshotRetention, SandboxState, SnapshotSandboxInitialSource, TarballSandboxInitialSource, VercelSandboxState } from "./model.mjs";
|
|
3
|
+
import { backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand } from "./lifecycle.mjs";
|
|
4
|
+
import { Sandbox } from "./service.mjs";
|
|
5
|
+
import { makeVercelSandboxName } from "./name.mjs";
|
|
6
|
+
import { SandboxStateStore } from "./state-store.mjs";
|
|
7
|
+
export { DisposableSandboxLifecycle, EmptySandboxInitialSource, GitSandboxInitialSource, PersistentSandboxLifecycle, Sandbox, SandboxCommandInput, SandboxCommandResult, SandboxConfigError, SandboxExpiredError, SandboxInitialSource, SandboxInputError, SandboxInputErrorCause, SandboxLifecycle, SandboxPreviewUrl, SandboxProviderError, SandboxResources, SandboxSnapshotRetention, SandboxState, SandboxStateError, SandboxStateStore, SandboxStateStoreError, SnapshotSandboxInitialSource, TarballSandboxInitialSource, VercelSandboxState, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, makeVercelSandboxName, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { SandboxInputError } from "./errors.mjs";
|
|
2
|
+
import { DisposableSandboxLifecycle, EmptySandboxInitialSource, SandboxInitialSource, SandboxLifecycle, SandboxState, VercelSandboxState } from "./model.mjs";
|
|
3
|
+
import { Effect, Option } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/lifecycle.d.ts
|
|
6
|
+
declare const defaultSandboxIdleTtlMs: number;
|
|
7
|
+
declare const defaultSandboxMaxLifetimeMs: number;
|
|
8
|
+
declare const defaultSandboxCommandTimeoutMs = 120000;
|
|
9
|
+
declare const maxSandboxCommandTimeoutMs = 600000;
|
|
10
|
+
declare const backgroundSandboxProbeMs = 2000;
|
|
11
|
+
declare const sandboxToolOutputLimit = 50000;
|
|
12
|
+
declare const defaultSandboxPorts: ReadonlyArray<number>;
|
|
13
|
+
declare const defaultSandboxWorkspaceRoot = "/vercel/sandbox";
|
|
14
|
+
declare const defaultSandboxLifecycle: DisposableSandboxLifecycle;
|
|
15
|
+
declare const defaultSandboxInitialSource: EmptySandboxInitialSource;
|
|
16
|
+
type SandboxRecreateReason = 'idle_expired' | 'max_expired' | 'name_mismatch';
|
|
17
|
+
type SandboxStateDecision = {
|
|
18
|
+
readonly _tag: 'UseExisting';
|
|
19
|
+
readonly state: SandboxState;
|
|
20
|
+
} | {
|
|
21
|
+
readonly _tag: 'Create';
|
|
22
|
+
readonly workspaceReset: boolean;
|
|
23
|
+
readonly reason?: SandboxRecreateReason;
|
|
24
|
+
};
|
|
25
|
+
declare const sandboxLifecycleOrDefault: (lifecycle?: SandboxLifecycle) => SandboxLifecycle;
|
|
26
|
+
declare const sandboxSourceOrDefault: (source?: SandboxInitialSource) => SandboxInitialSource;
|
|
27
|
+
declare const sandboxCommandTimeoutMs: (timeoutMs?: number) => number;
|
|
28
|
+
declare const validateSandboxCommand: (command: string) => Effect.Effect<never, SandboxInputError, never> | Effect.Effect<string, never, never>;
|
|
29
|
+
declare const normalizeWorkspaceCwd: (cwd?: string | null) => Effect.Effect<string, SandboxInputError>;
|
|
30
|
+
declare const absoluteSandboxCwd: (workspaceRoot: string, normalizedCwd: string) => string;
|
|
31
|
+
declare const initialSandboxState: (input: {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly nowMs: number;
|
|
34
|
+
readonly lifecycle: SandboxLifecycle;
|
|
35
|
+
}) => VercelSandboxState;
|
|
36
|
+
declare const touchSandboxState: (input: {
|
|
37
|
+
readonly state: SandboxState;
|
|
38
|
+
readonly nowMs: number;
|
|
39
|
+
readonly lifecycle: SandboxLifecycle;
|
|
40
|
+
}) => VercelSandboxState;
|
|
41
|
+
declare const sandboxTimeoutExtendDeltaMs: (input: {
|
|
42
|
+
readonly before: SandboxState;
|
|
43
|
+
readonly after: SandboxState;
|
|
44
|
+
}) => number;
|
|
45
|
+
declare const sandboxStateDecision: (input: {
|
|
46
|
+
readonly state: Option.Option<SandboxState>;
|
|
47
|
+
readonly name: string;
|
|
48
|
+
readonly nowMs: number;
|
|
49
|
+
}) => SandboxStateDecision;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { SandboxRecreateReason, SandboxStateDecision, absoluteSandboxCwd, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, initialSandboxState, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
|
52
|
+
//# sourceMappingURL=lifecycle.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.mts","names":[],"sources":["../src/lifecycle.ts"],"mappings":";;;;;cAWa,uBAAA;AAAA,cACA,2BAAA;AAAA,cACA,8BAAA;AAAA,cACA,0BAAA;AAAA,cACA,wBAAA;AAAA,cACA,sBAAA;AAAA,cACA,mBAAA,EAAqB,aAAa;AAAA,cAClC,2BAAA;AAAA,cAEA,uBAAA,EAAuB,0BAGlC;AAAA,cAEW,2BAAA,EAA2B,yBAAqC;AAAA,KAEjE,qBAAA;AAAA,KAEA,oBAAA;EAAA,SAEG,IAAA;EAAA,SACA,KAAA,EAAO,YAAA;AAAA;EAAA,SAGP,IAAA;EAAA,SACA,cAAA;EAAA,SACA,MAAA,GAAS,qBAAqB;AAAA;AAAA,cAMhC,yBAAA,GAA6B,SAAA,GAAY,gBAAA,KAAmB,gBACnC;AAAA,cAEzB,sBAAA,GAA0B,MAAA,GAAS,oBAAA,KAAuB,oBAChC;AAAA,cAE1B,uBAAA,GAA2B,SAAkB;AAAA,cAG7C,sBAAA,GAA0B,OAAA,aAAe,MAAA,CAAA,MAAA,QAAA,iBAAA,WAAA,MAAA,CAAA,MAAA;AAAA,cAazC,qBAAA,GAAyB,GAAA,qBAAsB,MAAA,CAAO,MAAM,SAAS,iBAAA;AAAA,cA0CrE,kBAAA,GAAsB,aAAA,UAAuB,aAAqB;AAAA,cAGlE,mBAAA,GAAuB,KAAA;EAAA,SACzB,IAAA;EAAA,SACA,KAAA;EAAA,SACA,SAAA,EAAW,gBAAA;AAAA,MACrB,kBAmBA;AAAA,cAEY,iBAAA,GAAqB,KAAA;EAAA,SACvB,KAAA,EAAO,YAAA;EAAA,SACP,KAAA;EAAA,SACA,SAAA,EAAW,gBAAA;AAAA,MACrB,kBAAA;AAAA,cAiBY,2BAAA,GAA+B,KAAA;EAAA,SACjC,MAAA,EAAQ,YAAA;EAAA,SACR,KAAA,EAAO,YAAY;AAAA;AAAA,cAGjB,oBAAA,GAAwB,KAAA;EAAA,SAC1B,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,YAAA;EAAA,SACrB,IAAA;EAAA,SACA,KAAA;AAAA,MACP,oBAAA"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { SandboxInputError } from "./errors.mjs";
|
|
2
|
+
import { DisposableSandboxLifecycle, EmptySandboxInitialSource, VercelSandboxState } from "./model.mjs";
|
|
3
|
+
import { Effect, Option } from "effect";
|
|
4
|
+
//#region src/lifecycle.ts
|
|
5
|
+
const defaultSandboxIdleTtlMs = 30 * 6e4;
|
|
6
|
+
const defaultSandboxMaxLifetimeMs = 45 * 6e4;
|
|
7
|
+
const defaultSandboxCommandTimeoutMs = 12e4;
|
|
8
|
+
const maxSandboxCommandTimeoutMs = 6e5;
|
|
9
|
+
const backgroundSandboxProbeMs = 2e3;
|
|
10
|
+
const sandboxToolOutputLimit = 5e4;
|
|
11
|
+
const defaultSandboxPorts = [
|
|
12
|
+
3e3,
|
|
13
|
+
5173,
|
|
14
|
+
4321,
|
|
15
|
+
8e3
|
|
16
|
+
];
|
|
17
|
+
const defaultSandboxWorkspaceRoot = "/vercel/sandbox";
|
|
18
|
+
const defaultSandboxLifecycle = DisposableSandboxLifecycle.make({
|
|
19
|
+
idleTtlMs: defaultSandboxIdleTtlMs,
|
|
20
|
+
maxLifetimeMs: defaultSandboxMaxLifetimeMs
|
|
21
|
+
});
|
|
22
|
+
const defaultSandboxInitialSource = EmptySandboxInitialSource.make({});
|
|
23
|
+
const positiveOr = (value, fallback) => value === void 0 || !Number.isFinite(value) || value <= 0 ? fallback : Math.floor(value);
|
|
24
|
+
const sandboxLifecycleOrDefault = (lifecycle) => lifecycle ?? defaultSandboxLifecycle;
|
|
25
|
+
const sandboxSourceOrDefault = (source) => source ?? defaultSandboxInitialSource;
|
|
26
|
+
const sandboxCommandTimeoutMs = (timeoutMs) => Math.min(maxSandboxCommandTimeoutMs, positiveOr(timeoutMs, defaultSandboxCommandTimeoutMs));
|
|
27
|
+
const validateSandboxCommand = (command) => {
|
|
28
|
+
if (command.trim().length === 0) return Effect.fail(new SandboxInputError({
|
|
29
|
+
cause: "empty_command",
|
|
30
|
+
message: "Sandbox command must not be empty"
|
|
31
|
+
}));
|
|
32
|
+
return Effect.succeed(command);
|
|
33
|
+
};
|
|
34
|
+
const normalizeWorkspaceCwd = (cwd) => {
|
|
35
|
+
if (cwd === void 0 || cwd === null || cwd.trim().length === 0) return Effect.succeed(".");
|
|
36
|
+
const trimmed = cwd.trim();
|
|
37
|
+
if (trimmed.startsWith("/") || trimmed.includes("\0")) return Effect.fail(new SandboxInputError({
|
|
38
|
+
cause: "invalid_cwd",
|
|
39
|
+
message: "cwd must be workspace-relative"
|
|
40
|
+
}));
|
|
41
|
+
const parts = [];
|
|
42
|
+
for (const segment of trimmed.split("/")) {
|
|
43
|
+
if (segment.length === 0 || segment === ".") continue;
|
|
44
|
+
if (segment === "..") {
|
|
45
|
+
if (parts.pop() === void 0) return Effect.fail(new SandboxInputError({
|
|
46
|
+
cause: "invalid_cwd",
|
|
47
|
+
message: "cwd must not escape the workspace"
|
|
48
|
+
}));
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
parts.push(segment);
|
|
52
|
+
}
|
|
53
|
+
return Effect.succeed(parts.length === 0 ? "." : parts.join("/"));
|
|
54
|
+
};
|
|
55
|
+
const absoluteSandboxCwd = (workspaceRoot, normalizedCwd) => normalizedCwd === "." ? workspaceRoot : `${workspaceRoot}/${normalizedCwd}`;
|
|
56
|
+
const initialSandboxState = (input) => {
|
|
57
|
+
switch (input.lifecycle._tag) {
|
|
58
|
+
case "Disposable": return VercelSandboxState.make({
|
|
59
|
+
name: input.name,
|
|
60
|
+
createdAtMs: input.nowMs,
|
|
61
|
+
lastUsedAtMs: input.nowMs,
|
|
62
|
+
expiresAtMs: input.nowMs + input.lifecycle.idleTtlMs,
|
|
63
|
+
maxExpiresAtMs: input.nowMs + input.lifecycle.maxLifetimeMs
|
|
64
|
+
});
|
|
65
|
+
case "Persistent": return VercelSandboxState.make({
|
|
66
|
+
name: input.name,
|
|
67
|
+
createdAtMs: input.nowMs,
|
|
68
|
+
lastUsedAtMs: input.nowMs,
|
|
69
|
+
expiresAtMs: input.nowMs + input.lifecycle.idleTtlMs,
|
|
70
|
+
maxExpiresAtMs: Number.MAX_SAFE_INTEGER
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const touchSandboxState = (input) => {
|
|
75
|
+
switch (input.lifecycle._tag) {
|
|
76
|
+
case "Disposable": return VercelSandboxState.make({
|
|
77
|
+
...input.state,
|
|
78
|
+
lastUsedAtMs: input.nowMs,
|
|
79
|
+
expiresAtMs: Math.min(input.nowMs + input.lifecycle.idleTtlMs, input.state.maxExpiresAtMs)
|
|
80
|
+
});
|
|
81
|
+
case "Persistent": return VercelSandboxState.make({
|
|
82
|
+
...input.state,
|
|
83
|
+
lastUsedAtMs: input.nowMs,
|
|
84
|
+
expiresAtMs: input.nowMs + input.lifecycle.idleTtlMs
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const sandboxTimeoutExtendDeltaMs = (input) => Math.max(0, input.after.expiresAtMs - input.before.expiresAtMs);
|
|
89
|
+
const sandboxStateDecision = (input) => {
|
|
90
|
+
if (Option.isNone(input.state)) return {
|
|
91
|
+
_tag: "Create",
|
|
92
|
+
workspaceReset: false
|
|
93
|
+
};
|
|
94
|
+
const state = input.state.value;
|
|
95
|
+
if (state.name !== input.name) return {
|
|
96
|
+
_tag: "Create",
|
|
97
|
+
workspaceReset: true,
|
|
98
|
+
reason: "name_mismatch"
|
|
99
|
+
};
|
|
100
|
+
if (input.nowMs >= state.maxExpiresAtMs) return {
|
|
101
|
+
_tag: "Create",
|
|
102
|
+
workspaceReset: true,
|
|
103
|
+
reason: "max_expired"
|
|
104
|
+
};
|
|
105
|
+
if (input.nowMs >= state.expiresAtMs) return {
|
|
106
|
+
_tag: "Create",
|
|
107
|
+
workspaceReset: true,
|
|
108
|
+
reason: "idle_expired"
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
_tag: "UseExisting",
|
|
112
|
+
state
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
//#endregion
|
|
116
|
+
export { absoluteSandboxCwd, backgroundSandboxProbeMs, defaultSandboxCommandTimeoutMs, defaultSandboxIdleTtlMs, defaultSandboxInitialSource, defaultSandboxLifecycle, defaultSandboxMaxLifetimeMs, defaultSandboxPorts, defaultSandboxWorkspaceRoot, initialSandboxState, maxSandboxCommandTimeoutMs, normalizeWorkspaceCwd, sandboxCommandTimeoutMs, sandboxLifecycleOrDefault, sandboxSourceOrDefault, sandboxStateDecision, sandboxTimeoutExtendDeltaMs, sandboxToolOutputLimit, touchSandboxState, validateSandboxCommand };
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=lifecycle.mjs.map
|