@hasna/sandboxes 0.1.9 → 0.1.11
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/dist/cli/index.js +48 -4
- package/dist/db/projects.d.ts +1 -1
- package/dist/db/projects.d.ts.map +1 -1
- package/dist/index.js +2 -17
- package/dist/lib/agent-runner.d.ts.map +1 -1
- package/dist/lib/runtime-state.d.ts +5 -0
- package/dist/lib/runtime-state.d.ts.map +1 -0
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/mcp/index.js +56 -25
- package/dist/server/index.js +41 -22
- package/dist/server/serve.d.ts +1 -0
- package/dist/server/serve.d.ts.map +1 -1
- package/package.json +1 -2
package/dist/cli/index.js
CHANGED
|
@@ -3364,6 +3364,25 @@ var init_stream = __esm(() => {
|
|
|
3364
3364
|
listeners = new Map;
|
|
3365
3365
|
});
|
|
3366
3366
|
|
|
3367
|
+
// src/lib/runtime-state.ts
|
|
3368
|
+
function getErrorMessage(error) {
|
|
3369
|
+
return error instanceof Error ? error.message : String(error);
|
|
3370
|
+
}
|
|
3371
|
+
function finalizeSessionExit(sessionId, exitCode) {
|
|
3372
|
+
endSession(sessionId, exitCode, exitCode === 0 ? "completed" : "failed");
|
|
3373
|
+
}
|
|
3374
|
+
function finalizeSessionFailure(sessionId, _error, exitCode = 1) {
|
|
3375
|
+
endSession(sessionId, exitCode, "failed");
|
|
3376
|
+
}
|
|
3377
|
+
function finalizeSandboxProvisionFailure(sandboxId, error) {
|
|
3378
|
+
updateSandbox(sandboxId, { status: "error" });
|
|
3379
|
+
return getErrorMessage(error);
|
|
3380
|
+
}
|
|
3381
|
+
var init_runtime_state = __esm(() => {
|
|
3382
|
+
init_sessions();
|
|
3383
|
+
init_sandboxes();
|
|
3384
|
+
});
|
|
3385
|
+
|
|
3367
3386
|
// src/lib/agents/claude.ts
|
|
3368
3387
|
class ClaudeDriver {
|
|
3369
3388
|
name = "claude";
|
|
@@ -3543,7 +3562,7 @@ async function runAgent(sandboxId, opts) {
|
|
|
3543
3562
|
}).then((result) => {
|
|
3544
3563
|
const exitResult = result;
|
|
3545
3564
|
const status = exitResult.exit_code === 0 ? "completed" : "failed";
|
|
3546
|
-
|
|
3565
|
+
finalizeSessionExit(session.id, exitResult.exit_code ?? 0);
|
|
3547
3566
|
emitLifecycleEvent(sandbox.id, `Agent ${opts.agentType} finished with exit code ${exitResult.exit_code}`);
|
|
3548
3567
|
if (opts.webhookUrl && webhookEvents.includes("complete")) {
|
|
3549
3568
|
fireWebhook(opts.webhookUrl, {
|
|
@@ -3558,7 +3577,7 @@ async function runAgent(sandboxId, opts) {
|
|
|
3558
3577
|
});
|
|
3559
3578
|
}
|
|
3560
3579
|
}).catch((err) => {
|
|
3561
|
-
|
|
3580
|
+
finalizeSessionFailure(session.id, err);
|
|
3562
3581
|
emitLifecycleEvent(sandbox.id, `Agent ${opts.agentType} failed: ${err.message}`);
|
|
3563
3582
|
if (opts.webhookUrl && webhookEvents.includes("error")) {
|
|
3564
3583
|
fireWebhook(opts.webhookUrl, {
|
|
@@ -3590,6 +3609,7 @@ var init_agent_runner = __esm(() => {
|
|
|
3590
3609
|
init_providers();
|
|
3591
3610
|
init_stream();
|
|
3592
3611
|
init_agents();
|
|
3612
|
+
init_runtime_state();
|
|
3593
3613
|
});
|
|
3594
3614
|
|
|
3595
3615
|
// node_modules/commander/esm.mjs
|
|
@@ -3669,6 +3689,20 @@ function listAgents() {
|
|
|
3669
3689
|
init_providers();
|
|
3670
3690
|
init_config();
|
|
3671
3691
|
init_stream();
|
|
3692
|
+
init_runtime_state();
|
|
3693
|
+
|
|
3694
|
+
// src/lib/version.ts
|
|
3695
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
3696
|
+
var cachedVersion;
|
|
3697
|
+
function getPackageVersion() {
|
|
3698
|
+
if (cachedVersion)
|
|
3699
|
+
return cachedVersion;
|
|
3700
|
+
const packageJson = JSON.parse(readFileSync2(new URL("../../package.json", import.meta.url), "utf8"));
|
|
3701
|
+
cachedVersion = packageJson.version ?? "0.0.0";
|
|
3702
|
+
return cachedVersion;
|
|
3703
|
+
}
|
|
3704
|
+
|
|
3705
|
+
// src/cli/index.tsx
|
|
3672
3706
|
function printTable(headers, rows) {
|
|
3673
3707
|
const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] || "").length)));
|
|
3674
3708
|
const headerLine = headers.map((h, i) => chalk.bold(h.padEnd(widths[i]))).join(" ");
|
|
@@ -3720,11 +3754,12 @@ function parseEnvVars(envArgs) {
|
|
|
3720
3754
|
}
|
|
3721
3755
|
return vars;
|
|
3722
3756
|
}
|
|
3723
|
-
var program2 = new Command().name("sandboxes").description("Universal cloud sandbox manager for AI coding agents").version(
|
|
3757
|
+
var program2 = new Command().name("sandboxes").description("Universal cloud sandbox manager for AI coding agents").version(getPackageVersion());
|
|
3724
3758
|
program2.command("create").description("Create a new sandbox").option("-p, --provider <provider>", "Provider (e2b, daytona, modal)").option("-i, --image <image>", "Container image").option("-t, --timeout <seconds>", "Timeout in seconds").option("-n, --name <name>", "Sandbox name").option("-e, --env <KEY=VAL...>", "Environment variables", (val, acc) => {
|
|
3725
3759
|
acc.push(val);
|
|
3726
3760
|
return acc;
|
|
3727
3761
|
}, []).action(async (opts) => {
|
|
3762
|
+
let sandboxId;
|
|
3728
3763
|
try {
|
|
3729
3764
|
const provider = opts.provider || getDefaultProvider();
|
|
3730
3765
|
const timeout = opts.timeout ? parseInt(opts.timeout, 10) : getDefaultTimeout();
|
|
@@ -3737,6 +3772,7 @@ program2.command("create").description("Create a new sandbox").option("-p, --pro
|
|
|
3737
3772
|
timeout,
|
|
3738
3773
|
env_vars: envVars
|
|
3739
3774
|
});
|
|
3775
|
+
sandboxId = sandbox.id;
|
|
3740
3776
|
console.log(chalk.dim("Creating sandbox..."));
|
|
3741
3777
|
const p = await getProvider(provider);
|
|
3742
3778
|
const result = await p.create({
|
|
@@ -3756,6 +3792,9 @@ program2.command("create").description("Create a new sandbox").option("-p, --pro
|
|
|
3756
3792
|
console.log(` ${chalk.bold("Name:")} ${updated.name}`);
|
|
3757
3793
|
}
|
|
3758
3794
|
} catch (err) {
|
|
3795
|
+
if (sandboxId) {
|
|
3796
|
+
finalizeSandboxProvisionFailure(sandboxId, err);
|
|
3797
|
+
}
|
|
3759
3798
|
handleError(err);
|
|
3760
3799
|
}
|
|
3761
3800
|
});
|
|
@@ -3812,6 +3851,7 @@ program2.command("show <id>").description("Show sandbox details").action((id) =>
|
|
|
3812
3851
|
}
|
|
3813
3852
|
});
|
|
3814
3853
|
program2.command("exec <id> <command...>").description("Execute a command in a sandbox").action(async (id, commandParts) => {
|
|
3854
|
+
let sessionId;
|
|
3815
3855
|
try {
|
|
3816
3856
|
const sandbox = getSandbox(id);
|
|
3817
3857
|
if (!sandbox.provider_sandbox_id) {
|
|
@@ -3823,6 +3863,7 @@ program2.command("exec <id> <command...>").description("Execute a command in a s
|
|
|
3823
3863
|
sandbox_id: sandbox.id,
|
|
3824
3864
|
command: cmd
|
|
3825
3865
|
});
|
|
3866
|
+
sessionId = session.id;
|
|
3826
3867
|
const collector = createStreamCollector(sandbox.id, session.id);
|
|
3827
3868
|
const p = await getProvider(sandbox.provider);
|
|
3828
3869
|
const result = await p.exec(sandbox.provider_sandbox_id, cmd, {
|
|
@@ -3836,9 +3877,12 @@ program2.command("exec <id> <command...>").description("Execute a command in a s
|
|
|
3836
3877
|
}
|
|
3837
3878
|
});
|
|
3838
3879
|
const execResult = "exit_code" in result ? result : await result.wait();
|
|
3839
|
-
|
|
3880
|
+
finalizeSessionExit(session.id, execResult.exit_code);
|
|
3840
3881
|
process.exit(execResult.exit_code);
|
|
3841
3882
|
} catch (err) {
|
|
3883
|
+
if (sessionId) {
|
|
3884
|
+
finalizeSessionFailure(sessionId, err);
|
|
3885
|
+
}
|
|
3842
3886
|
handleError(err);
|
|
3843
3887
|
}
|
|
3844
3888
|
});
|
package/dist/db/projects.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ export declare function createProject(input: CreateProjectInput): Project;
|
|
|
4
4
|
export declare function getProject(id: string): Project;
|
|
5
5
|
export declare function getProjectByPath(path: string): Project | null;
|
|
6
6
|
export declare function listProjects(): Project[];
|
|
7
|
-
export declare function ensureProject(name: string, path: string): Project;
|
|
7
|
+
export declare function ensureProject(name: string, path: string, description?: string): Project;
|
|
8
8
|
export declare function deleteProject(id: string): void;
|
|
9
9
|
//# sourceMappingURL=projects.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/db/projects.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAKlE,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CASlD;AAID,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAYhE;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAY9C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAS7D;AAED,wBAAgB,YAAY,IAAI,OAAO,EAAE,CAQxC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/db/projects.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAKlE,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CASlD;AAID,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAYhE;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAY9C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAS7D;AAED,wBAAgB,YAAY,IAAI,OAAO,EAAE,CAQxC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAKvF;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAO9C"}
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
2
|
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
3
|
var __export = (target, all) => {
|
|
19
4
|
for (var name in all)
|
|
20
5
|
__defProp(target, name, {
|
|
@@ -1308,11 +1293,11 @@ function listProjects() {
|
|
|
1308
1293
|
const rows = db2.query("SELECT * FROM projects ORDER BY created_at DESC").all();
|
|
1309
1294
|
return rows.map(rowToProject);
|
|
1310
1295
|
}
|
|
1311
|
-
function ensureProject(name, path) {
|
|
1296
|
+
function ensureProject(name, path, description) {
|
|
1312
1297
|
const existing = getProjectByPath(path);
|
|
1313
1298
|
if (existing)
|
|
1314
1299
|
return existing;
|
|
1315
|
-
return createProject({ name, path });
|
|
1300
|
+
return createProject({ name, path, description });
|
|
1316
1301
|
}
|
|
1317
1302
|
function deleteProject(id) {
|
|
1318
1303
|
const db2 = getDatabase();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-runner.d.ts","sourceRoot":"","sources":["../../src/lib/agent-runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-runner.d.ts","sourceRoot":"","sources":["../../src/lib/agent-runner.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAc,MAAM,mBAAmB,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC,EAAE,CAAC;CACpD;AAcD,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,cAAc,CAAC,CAyGzB;AAED,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhE"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function getErrorMessage(error: unknown): string;
|
|
2
|
+
export declare function finalizeSessionExit(sessionId: string, exitCode: number): void;
|
|
3
|
+
export declare function finalizeSessionFailure(sessionId: string, _error?: unknown, exitCode?: number): void;
|
|
4
|
+
export declare function finalizeSandboxProvisionFailure(sandboxId: string, error?: unknown): string;
|
|
5
|
+
//# sourceMappingURL=runtime-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-state.d.ts","sourceRoot":"","sources":["../../src/lib/runtime-state.ts"],"names":[],"mappings":"AAGA,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEtD;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE7E;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,SAAI,GAAG,IAAI,CAG9F;AAED,wBAAgB,+BAA+B,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAI1F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/lib/version.ts"],"names":[],"mappings":"AAIA,wBAAgB,iBAAiB,IAAI,MAAM,CAS1C"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var __create = Object.create;
|
|
4
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
5
3
|
var __defProp = Object.defineProperty;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
-
for (let key of __getOwnPropNames(mod))
|
|
12
|
-
if (!__hasOwnProp.call(to, key))
|
|
13
|
-
__defProp(to, key, {
|
|
14
|
-
get: () => mod[key],
|
|
15
|
-
enumerable: true
|
|
16
|
-
});
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
4
|
var __export = (target, all) => {
|
|
20
5
|
for (var name in all)
|
|
21
6
|
__defProp(target, name, {
|
|
@@ -5203,11 +5188,11 @@ function listProjects() {
|
|
|
5203
5188
|
const rows = db2.query("SELECT * FROM projects ORDER BY created_at DESC").all();
|
|
5204
5189
|
return rows.map(rowToProject);
|
|
5205
5190
|
}
|
|
5206
|
-
function ensureProject(name, path) {
|
|
5191
|
+
function ensureProject(name, path, description) {
|
|
5207
5192
|
const existing = getProjectByPath(path);
|
|
5208
5193
|
if (existing)
|
|
5209
5194
|
return existing;
|
|
5210
|
-
return createProject({ name, path });
|
|
5195
|
+
return createProject({ name, path, description });
|
|
5211
5196
|
}
|
|
5212
5197
|
|
|
5213
5198
|
// src/db/templates.ts
|
|
@@ -5538,6 +5523,21 @@ function getAgentDriver(name) {
|
|
|
5538
5523
|
return DRIVER_MAP.get(name);
|
|
5539
5524
|
}
|
|
5540
5525
|
|
|
5526
|
+
// src/lib/runtime-state.ts
|
|
5527
|
+
function getErrorMessage(error) {
|
|
5528
|
+
return error instanceof Error ? error.message : String(error);
|
|
5529
|
+
}
|
|
5530
|
+
function finalizeSessionExit(sessionId, exitCode) {
|
|
5531
|
+
endSession(sessionId, exitCode, exitCode === 0 ? "completed" : "failed");
|
|
5532
|
+
}
|
|
5533
|
+
function finalizeSessionFailure(sessionId, _error, exitCode = 1) {
|
|
5534
|
+
endSession(sessionId, exitCode, "failed");
|
|
5535
|
+
}
|
|
5536
|
+
function finalizeSandboxProvisionFailure(sandboxId, error) {
|
|
5537
|
+
updateSandbox(sandboxId, { status: "error" });
|
|
5538
|
+
return getErrorMessage(error);
|
|
5539
|
+
}
|
|
5540
|
+
|
|
5541
5541
|
// src/lib/agent-runner.ts
|
|
5542
5542
|
async function fireWebhook(url, payload) {
|
|
5543
5543
|
try {
|
|
@@ -5600,7 +5600,7 @@ async function runAgent(sandboxId, opts) {
|
|
|
5600
5600
|
}).then((result) => {
|
|
5601
5601
|
const exitResult = result;
|
|
5602
5602
|
const status = exitResult.exit_code === 0 ? "completed" : "failed";
|
|
5603
|
-
|
|
5603
|
+
finalizeSessionExit(session.id, exitResult.exit_code ?? 0);
|
|
5604
5604
|
emitLifecycleEvent(sandbox.id, `Agent ${opts.agentType} finished with exit code ${exitResult.exit_code}`);
|
|
5605
5605
|
if (opts.webhookUrl && webhookEvents.includes("complete")) {
|
|
5606
5606
|
fireWebhook(opts.webhookUrl, {
|
|
@@ -5615,7 +5615,7 @@ async function runAgent(sandboxId, opts) {
|
|
|
5615
5615
|
});
|
|
5616
5616
|
}
|
|
5617
5617
|
}).catch((err) => {
|
|
5618
|
-
|
|
5618
|
+
finalizeSessionFailure(session.id, err);
|
|
5619
5619
|
emitLifecycleEvent(sandbox.id, `Agent ${opts.agentType} failed: ${err.message}`);
|
|
5620
5620
|
if (opts.webhookUrl && webhookEvents.includes("error")) {
|
|
5621
5621
|
fireWebhook(opts.webhookUrl, {
|
|
@@ -5684,6 +5684,17 @@ function getBuiltinImageSetupScript(image) {
|
|
|
5684
5684
|
return BUILTIN_IMAGES[image]?.setup_script;
|
|
5685
5685
|
}
|
|
5686
5686
|
|
|
5687
|
+
// src/lib/version.ts
|
|
5688
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
5689
|
+
var cachedVersion;
|
|
5690
|
+
function getPackageVersion() {
|
|
5691
|
+
if (cachedVersion)
|
|
5692
|
+
return cachedVersion;
|
|
5693
|
+
const packageJson = JSON.parse(readFileSync2(new URL("../../package.json", import.meta.url), "utf8"));
|
|
5694
|
+
cachedVersion = packageJson.version ?? "0.0.0";
|
|
5695
|
+
return cachedVersion;
|
|
5696
|
+
}
|
|
5697
|
+
|
|
5687
5698
|
// src/mcp/index.ts
|
|
5688
5699
|
var E2B_COST_PER_SECOND = 0.000014;
|
|
5689
5700
|
var DAYTONA_COST_PER_SECOND = 0.00001;
|
|
@@ -5718,6 +5729,7 @@ var TOOL_CATALOG = [
|
|
|
5718
5729
|
{ name: "read_file", description: "Read a file from a sandbox" },
|
|
5719
5730
|
{ name: "write_file", description: "Write a file to a sandbox" },
|
|
5720
5731
|
{ name: "list_files", description: "List files in a sandbox directory" },
|
|
5732
|
+
{ name: "get_session", description: "Get session details and exit code (useful for background commands)" },
|
|
5721
5733
|
{ name: "get_logs", description: "Get sandbox/session event logs" },
|
|
5722
5734
|
{ name: "register_agent", description: "Register an agent" },
|
|
5723
5735
|
{ name: "list_agents", description: "List all registered agents" },
|
|
@@ -5744,7 +5756,7 @@ var TOOL_CATALOG = [
|
|
|
5744
5756
|
];
|
|
5745
5757
|
var server = new McpServer({
|
|
5746
5758
|
name: "sandboxes",
|
|
5747
|
-
version:
|
|
5759
|
+
version: getPackageVersion()
|
|
5748
5760
|
});
|
|
5749
5761
|
server.tool("create_sandbox", "Create a new sandbox", {
|
|
5750
5762
|
provider: exports_external.string().optional().describe("Provider name (e2b, daytona, modal)"),
|
|
@@ -5760,6 +5772,7 @@ server.tool("create_sandbox", "Create a new sandbox", {
|
|
|
5760
5772
|
budget_limit_usd: exports_external.number().optional().describe("Auto-terminate sandbox if compute cost exceeds this USD amount"),
|
|
5761
5773
|
on_budget_exceeded: exports_external.enum(["terminate", "pause", "notify"]).optional().describe("Action when budget limit is reached (default: terminate)")
|
|
5762
5774
|
}, async (params) => {
|
|
5775
|
+
let sandboxId;
|
|
5763
5776
|
try {
|
|
5764
5777
|
const providerName = params.provider ?? getDefaultProvider();
|
|
5765
5778
|
const timeout = params.timeout ?? getDefaultTimeout();
|
|
@@ -5787,6 +5800,7 @@ server.tool("create_sandbox", "Create a new sandbox", {
|
|
|
5787
5800
|
budget_limit_usd: params.budget_limit_usd,
|
|
5788
5801
|
on_budget_exceeded: params.on_budget_exceeded
|
|
5789
5802
|
});
|
|
5803
|
+
sandboxId = sandbox.id;
|
|
5790
5804
|
const provider = await getProvider(providerName);
|
|
5791
5805
|
if (params.snapshot_id) {
|
|
5792
5806
|
const snapshot = getSnapshot(params.snapshot_id);
|
|
@@ -5823,6 +5837,9 @@ server.tool("create_sandbox", "Create a new sandbox", {
|
|
|
5823
5837
|
}
|
|
5824
5838
|
return ok(updated);
|
|
5825
5839
|
} catch (e) {
|
|
5840
|
+
if (sandboxId) {
|
|
5841
|
+
finalizeSandboxProvisionFailure(sandboxId, e);
|
|
5842
|
+
}
|
|
5826
5843
|
return err(e);
|
|
5827
5844
|
}
|
|
5828
5845
|
});
|
|
@@ -5907,6 +5924,7 @@ server.tool("exec_command", "Execute a command in a sandbox", {
|
|
|
5907
5924
|
stdin: exports_external.string().optional().describe("String to pipe as stdin to the command"),
|
|
5908
5925
|
tty: exports_external.boolean().optional().describe("Allocate a TTY for the session (best-effort)")
|
|
5909
5926
|
}, async (params) => {
|
|
5927
|
+
let sessionId;
|
|
5910
5928
|
try {
|
|
5911
5929
|
const sandbox = getSandbox(params.sandbox_id);
|
|
5912
5930
|
if (!sandbox.provider_sandbox_id)
|
|
@@ -5915,6 +5933,7 @@ server.tool("exec_command", "Execute a command in a sandbox", {
|
|
|
5915
5933
|
sandbox_id: sandbox.id,
|
|
5916
5934
|
command: params.command
|
|
5917
5935
|
});
|
|
5936
|
+
sessionId = session.id;
|
|
5918
5937
|
const collector = createStreamCollector(sandbox.id, session.id);
|
|
5919
5938
|
const provider = await getProvider(sandbox.provider);
|
|
5920
5939
|
const callEnv = { ...sandbox.env_vars, ...params.env_vars };
|
|
@@ -5928,9 +5947,9 @@ server.tool("exec_command", "Execute a command in a sandbox", {
|
|
|
5928
5947
|
tty: params.tty
|
|
5929
5948
|
}).then((res) => {
|
|
5930
5949
|
const r = res;
|
|
5931
|
-
|
|
5950
|
+
finalizeSessionExit(session.id, r.exit_code ?? 0);
|
|
5932
5951
|
}).catch(() => {
|
|
5933
|
-
|
|
5952
|
+
finalizeSessionFailure(session.id);
|
|
5934
5953
|
});
|
|
5935
5954
|
return ok({ session_id: session.id, background: true });
|
|
5936
5955
|
}
|
|
@@ -5942,7 +5961,7 @@ server.tool("exec_command", "Execute a command in a sandbox", {
|
|
|
5942
5961
|
tty: params.tty
|
|
5943
5962
|
});
|
|
5944
5963
|
const execResult = result;
|
|
5945
|
-
|
|
5964
|
+
finalizeSessionExit(session.id, execResult.exit_code);
|
|
5946
5965
|
return ok({
|
|
5947
5966
|
session_id: session.id,
|
|
5948
5967
|
exit_code: execResult.exit_code,
|
|
@@ -5950,6 +5969,9 @@ server.tool("exec_command", "Execute a command in a sandbox", {
|
|
|
5950
5969
|
stderr: execResult.stderr
|
|
5951
5970
|
});
|
|
5952
5971
|
} catch (e) {
|
|
5972
|
+
if (sessionId) {
|
|
5973
|
+
finalizeSessionFailure(sessionId, e);
|
|
5974
|
+
}
|
|
5953
5975
|
return err(e);
|
|
5954
5976
|
}
|
|
5955
5977
|
});
|
|
@@ -6011,6 +6033,16 @@ server.tool("list_files", "List files in a sandbox directory", {
|
|
|
6011
6033
|
return err(e);
|
|
6012
6034
|
}
|
|
6013
6035
|
});
|
|
6036
|
+
server.tool("get_session", "Get session details and exit code (useful for polling background command results)", {
|
|
6037
|
+
session_id: exports_external.string().describe("Session ID")
|
|
6038
|
+
}, async (params) => {
|
|
6039
|
+
try {
|
|
6040
|
+
const session = getSession(params.session_id);
|
|
6041
|
+
return ok(session);
|
|
6042
|
+
} catch (e) {
|
|
6043
|
+
return err(e);
|
|
6044
|
+
}
|
|
6045
|
+
});
|
|
6014
6046
|
server.tool("get_logs", "Get sandbox/session event logs", {
|
|
6015
6047
|
sandbox_id: exports_external.string().optional().describe("Filter by sandbox ID"),
|
|
6016
6048
|
session_id: exports_external.string().optional().describe("Filter by session ID"),
|
|
@@ -6049,8 +6081,7 @@ server.tool("register_project", "Register a project", {
|
|
|
6049
6081
|
description: exports_external.string().optional().describe("Project description")
|
|
6050
6082
|
}, async (params) => {
|
|
6051
6083
|
try {
|
|
6052
|
-
|
|
6053
|
-
return ok(project);
|
|
6084
|
+
return ok(ensureProject(params.name, params.path, params.description));
|
|
6054
6085
|
} catch (e) {
|
|
6055
6086
|
return err(e);
|
|
6056
6087
|
}
|
package/dist/server/index.js
CHANGED
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var __create = Object.create;
|
|
4
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
5
3
|
var __defProp = Object.defineProperty;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
-
for (let key of __getOwnPropNames(mod))
|
|
12
|
-
if (!__hasOwnProp.call(to, key))
|
|
13
|
-
__defProp(to, key, {
|
|
14
|
-
get: () => mod[key],
|
|
15
|
-
enumerable: true
|
|
16
|
-
});
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
4
|
var __export = (target, all) => {
|
|
20
5
|
for (var name in all)
|
|
21
6
|
__defProp(target, name, {
|
|
@@ -1245,11 +1230,11 @@ function listProjects() {
|
|
|
1245
1230
|
const rows = db2.query("SELECT * FROM projects ORDER BY created_at DESC").all();
|
|
1246
1231
|
return rows.map(rowToProject);
|
|
1247
1232
|
}
|
|
1248
|
-
function ensureProject(name, path) {
|
|
1233
|
+
function ensureProject(name, path, description) {
|
|
1249
1234
|
const existing = getProjectByPath(path);
|
|
1250
1235
|
if (existing)
|
|
1251
1236
|
return existing;
|
|
1252
|
-
return createProject({ name, path });
|
|
1237
|
+
return createProject({ name, path, description });
|
|
1253
1238
|
}
|
|
1254
1239
|
|
|
1255
1240
|
// src/db/webhooks.ts
|
|
@@ -1443,6 +1428,32 @@ function emitLifecycleEvent(sandboxId, message) {
|
|
|
1443
1428
|
notifyListeners(sandboxId, "lifecycle", message);
|
|
1444
1429
|
}
|
|
1445
1430
|
|
|
1431
|
+
// src/lib/runtime-state.ts
|
|
1432
|
+
function getErrorMessage(error) {
|
|
1433
|
+
return error instanceof Error ? error.message : String(error);
|
|
1434
|
+
}
|
|
1435
|
+
function finalizeSessionExit(sessionId, exitCode) {
|
|
1436
|
+
endSession(sessionId, exitCode, exitCode === 0 ? "completed" : "failed");
|
|
1437
|
+
}
|
|
1438
|
+
function finalizeSessionFailure(sessionId, _error, exitCode = 1) {
|
|
1439
|
+
endSession(sessionId, exitCode, "failed");
|
|
1440
|
+
}
|
|
1441
|
+
function finalizeSandboxProvisionFailure(sandboxId, error) {
|
|
1442
|
+
updateSandbox(sandboxId, { status: "error" });
|
|
1443
|
+
return getErrorMessage(error);
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
// src/lib/version.ts
|
|
1447
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
1448
|
+
var cachedVersion;
|
|
1449
|
+
function getPackageVersion() {
|
|
1450
|
+
if (cachedVersion)
|
|
1451
|
+
return cachedVersion;
|
|
1452
|
+
const packageJson = JSON.parse(readFileSync2(new URL("../../package.json", import.meta.url), "utf8"));
|
|
1453
|
+
cachedVersion = packageJson.version ?? "0.0.0";
|
|
1454
|
+
return cachedVersion;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1446
1457
|
// src/server/serve.ts
|
|
1447
1458
|
function json(data, status = 200) {
|
|
1448
1459
|
return new Response(JSON.stringify(data), {
|
|
@@ -1488,7 +1499,7 @@ async function handleRequest(req) {
|
|
|
1488
1499
|
return json({ ok: true });
|
|
1489
1500
|
}
|
|
1490
1501
|
if (pathname === "/api/health" && method === "GET") {
|
|
1491
|
-
return json({ status: "ok", version:
|
|
1502
|
+
return json({ status: "ok", version: getPackageVersion() });
|
|
1492
1503
|
}
|
|
1493
1504
|
if (pathname === "/api/sandboxes" && method === "GET") {
|
|
1494
1505
|
const status = url.searchParams.get("status") || undefined;
|
|
@@ -1500,11 +1511,13 @@ async function handleRequest(req) {
|
|
|
1500
1511
|
return json(result);
|
|
1501
1512
|
}
|
|
1502
1513
|
if (pathname === "/api/sandboxes" && method === "POST") {
|
|
1514
|
+
let sandboxId;
|
|
1503
1515
|
try {
|
|
1504
1516
|
const input = await body(req);
|
|
1505
1517
|
const providerName = input.provider || getDefaultProvider();
|
|
1506
1518
|
const timeout = input.timeout || getDefaultTimeout();
|
|
1507
1519
|
const sandbox = createSandbox({ ...input, provider: providerName, timeout });
|
|
1520
|
+
sandboxId = sandbox.id;
|
|
1508
1521
|
const provider = await getProvider(providerName);
|
|
1509
1522
|
const providerSandbox = await provider.create({
|
|
1510
1523
|
image: input.image,
|
|
@@ -1518,7 +1531,8 @@ async function handleRequest(req) {
|
|
|
1518
1531
|
emitLifecycleEvent(sandbox.id, `Sandbox created with provider ${providerName}`);
|
|
1519
1532
|
return json(updated, 201);
|
|
1520
1533
|
} catch (err) {
|
|
1521
|
-
|
|
1534
|
+
const message = sandboxId ? finalizeSandboxProvisionFailure(sandboxId, err) : getErrorMessage(err);
|
|
1535
|
+
return error(message, 500);
|
|
1522
1536
|
}
|
|
1523
1537
|
}
|
|
1524
1538
|
let params = matchRoute(pathname, method, "/api/sandboxes/:id", "GET");
|
|
@@ -1561,6 +1575,7 @@ async function handleRequest(req) {
|
|
|
1561
1575
|
}
|
|
1562
1576
|
params = matchRoute(pathname, method, "/api/sandboxes/:id/exec", "POST");
|
|
1563
1577
|
if (params) {
|
|
1578
|
+
let sessionId;
|
|
1564
1579
|
try {
|
|
1565
1580
|
const sandbox = getSandbox(params["id"]);
|
|
1566
1581
|
if (!sandbox.provider_sandbox_id) {
|
|
@@ -1568,6 +1583,7 @@ async function handleRequest(req) {
|
|
|
1568
1583
|
}
|
|
1569
1584
|
const { command } = await body(req);
|
|
1570
1585
|
const session = createSession({ sandbox_id: sandbox.id, command });
|
|
1586
|
+
sessionId = session.id;
|
|
1571
1587
|
const collector = createStreamCollector(sandbox.id, session.id);
|
|
1572
1588
|
const provider = await getProvider(sandbox.provider);
|
|
1573
1589
|
const result = await provider.exec(sandbox.provider_sandbox_id, command, {
|
|
@@ -1575,12 +1591,15 @@ async function handleRequest(req) {
|
|
|
1575
1591
|
onStderr: collector.onStderr
|
|
1576
1592
|
});
|
|
1577
1593
|
if ("exit_code" in result) {
|
|
1578
|
-
|
|
1594
|
+
finalizeSessionExit(session.id, result.exit_code);
|
|
1579
1595
|
return json({ session_id: session.id, ...result });
|
|
1580
1596
|
}
|
|
1581
1597
|
return json({ session_id: session.id, status: "running" });
|
|
1582
1598
|
} catch (err) {
|
|
1583
|
-
|
|
1599
|
+
if (sessionId) {
|
|
1600
|
+
finalizeSessionFailure(sessionId, err);
|
|
1601
|
+
}
|
|
1602
|
+
return error(getErrorMessage(err), 500);
|
|
1584
1603
|
}
|
|
1585
1604
|
}
|
|
1586
1605
|
params = matchRoute(pathname, method, "/api/sandboxes/:id/keep-alive", "POST");
|
|
@@ -1645,7 +1664,7 @@ async function handleRequest(req) {
|
|
|
1645
1664
|
if (pathname === "/api/projects" && method === "POST") {
|
|
1646
1665
|
try {
|
|
1647
1666
|
const input = await body(req);
|
|
1648
|
-
return json(ensureProject(input.name, input.path), 201);
|
|
1667
|
+
return json(ensureProject(input.name, input.path, input.description), 201);
|
|
1649
1668
|
} catch (err) {
|
|
1650
1669
|
return error(err.message, 500);
|
|
1651
1670
|
}
|
package/dist/server/serve.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAuEA,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CA+RnE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAO9C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/sandboxes",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"author": "Andrei Hasna <andrei@hasna.com>",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@daytonaio/sdk": "^0.18.0",
|
|
12
12
|
"@e2b/code-interpreter": "^1.5.0",
|
|
13
|
-
"@hasna/sandboxes": "^0.1.8",
|
|
14
13
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
15
14
|
"chalk": "^5.4.1",
|
|
16
15
|
"commander": "^13.1.0",
|