@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 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
- endSession(session.id, exitResult.exit_code ?? 0, status);
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
- endSession(session.id, 1, "failed");
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("0.1.0");
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
- endSession(session.id, execResult.exit_code, execResult.exit_code === 0 ? "completed" : "failed");
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
  });
@@ -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,CAKjE;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAO9C"}
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":"AAKA,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"}
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,2 @@
1
+ export declare function getPackageVersion(): string;
2
+ //# sourceMappingURL=version.d.ts.map
@@ -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
- endSession(session.id, exitResult.exit_code ?? 0, status);
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
- endSession(session.id, 1, "failed");
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: "0.1.0"
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
- endSession(session.id, r.exit_code ?? 0);
5950
+ finalizeSessionExit(session.id, r.exit_code ?? 0);
5932
5951
  }).catch(() => {
5933
- endSession(session.id, 1);
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
- endSession(session.id, execResult.exit_code);
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
- const project = ensureProject(params.name, params.path);
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
  }
@@ -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: "0.1.0" });
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
- return error(err.message, 500);
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
- endSession(session.id, result.exit_code);
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
- return error(err.message, 500);
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
  }
@@ -1,2 +1,3 @@
1
+ export declare function handleRequest(req: Request): Promise<Response>;
1
2
  export declare function startServer(port: number): void;
2
3
  //# sourceMappingURL=serve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAyVA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAO9C"}
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.9",
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",