isol8 0.11.2 → 0.11.3

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/README.md CHANGED
@@ -105,7 +105,7 @@ isol8 run script.py --host http://server:3000 --key my-api-key
105
105
  |------|-------------|---------|
106
106
  | `-e, --eval <code>` | Execute inline code | — |
107
107
  | `-r, --runtime <rt>` | Force runtime: `python`, `node`, `bun`, `deno`, `bash` | auto-detect |
108
- | `--net <mode>` | Network mode: `none`, `host`, `filtered` | `none` |
108
+ | `--net <mode>` | Network mode: `none`, `host`, `filtered` | `none` (unless `--install` is used without explicit `--net`, then auto `filtered`) |
109
109
  | `--allow <regex>` | Whitelist regex (repeatable, for `filtered`) | — |
110
110
  | `--deny <regex>` | Blacklist regex (repeatable, for `filtered`) | — |
111
111
  | `--out <file>` | Write stdout to file | — |
@@ -113,7 +113,7 @@ isol8 run script.py --host http://server:3000 --key my-api-key
113
113
  | `--persistent` | Keep container alive between runs | `false` |
114
114
  | `--persist` | Keep container after execution for inspection/debugging | `false` |
115
115
  | `--debug` | Enable debug logging for internal engine operations | `false` |
116
- | `--timeout <ms>` | Execution timeout in milliseconds | `30000` |
116
+ | `--timeout <ms>` | Timeout in milliseconds for package install + execution phases | `30000` |
117
117
  | `--memory <limit>` | Memory limit (e.g. `512m`, `1g`) | `512m` |
118
118
  | `--cpu <limit>` | CPU limit as fraction (e.g. `0.5`, `2.0`) | `1.0` |
119
119
  | `--image <name>` | Override Docker image | — |
@@ -124,7 +124,7 @@ isol8 run script.py --host http://server:3000 --key my-api-key
124
124
  | `--sandbox-size <size>` | Sandbox tmpfs size (e.g. `512m`, `1g`) | `512m` |
125
125
  | `--tmp-size <size>` | Tmp tmpfs size (e.g. `256m`, `512m`) | `256m` |
126
126
  | `--stdin <data>` | Data to pipe to stdin | — |
127
- | `--install <pkg>` | Install package for runtime (repeatable) | — |
127
+ | `--install <pkg>` | Install package for runtime (repeatable) | — (auto-adds default runtime registry allowlist in `filtered` mode) |
128
128
  | `--url <url>` | Fetch code from URL (requires `remoteCode.enabled=true`) | — |
129
129
  | `--github <owner/repo/ref/path>` | GitHub shorthand for raw source | — |
130
130
  | `--gist <gistId/file.ext>` | Gist shorthand for raw source | — |
@@ -176,6 +176,8 @@ isol8 serve --update # Force re-download the server binary
176
176
 
177
177
  If the selected port is already in use, `isol8 serve` now prompts to enter another port or auto-select an available one. In non-interactive environments, it auto-falls back to a free port.
178
178
 
179
+ On graceful shutdown (`SIGINT`/`SIGTERM`), the server now cleans up tracked sessions, isol8 containers, and isol8 images before exiting.
180
+
179
181
  ### `isol8 config`
180
182
 
181
183
  Display the resolved configuration (merged defaults + config file). Shows the source file, defaults, network rules, cleanup policy, and dependencies.
@@ -377,7 +379,7 @@ Add the `$schema` property to get autocompletion, validation, and inline documen
377
379
  "node": ["lodash"]
378
380
  },
379
381
  "security": {
380
- "seccomp": "safety"
382
+ "seccomp": "strict"
381
383
  }
382
384
  }
383
385
  ```
@@ -441,7 +443,7 @@ bun run bench:detailed # Phase breakdown
441
443
  | **Network** | Disabled by default; optional proxy-based filtering |
442
444
  | **Output** | Truncated at 1MB; secrets masked from stdout/stderr |
443
445
  | **Isolation** | Each execution in its own container (ephemeral) or exec (persistent) |
444
- | **Seccomp** | Default "safety" profile blocks dangerous syscalls (mount, swap, ptrace) but allows others for compatibility; configurable via `security.seccomp` |
446
+ | **Seccomp** | Default `strict` mode applies the built-in profile that blocks dangerous syscalls (mount, swap, ptrace). In standalone server binaries, an embedded copy is used when profile files are not present. If strict/custom profile loading fails, execution fails. |
445
447
 
446
448
  ### Container Filesystem
447
449
 
@@ -470,6 +472,7 @@ When running `isol8 serve`, these endpoints are available:
470
472
  | `POST` | `/file` | Upload file (base64) |
471
473
  | `GET` | `/file?sessionId=&path=` | Download file (base64) |
472
474
  | `DELETE` | `/session/:id` | Destroy persistent session |
475
+ | `POST` | `/cleanup` | Run server-side cleanup for sessions/containers (and images by default) |
473
476
 
474
477
  All endpoints (except `/health`) require `Authorization: Bearer <key>`.
475
478
 
package/dist/cli.js CHANGED
@@ -6318,7 +6318,7 @@ var require_bcrypt_pbkdf = __commonJS((exports, module) => {
6318
6318
 
6319
6319
  // node_modules/cpu-features/build/Release/cpufeatures.node
6320
6320
  var require_cpufeatures = __commonJS((exports, module) => {
6321
- module.exports = __require("./cpufeatures-tjjrgpt7.node");
6321
+ module.exports = __require("./cpufeatures-1yrn0vtw.node");
6322
6322
  });
6323
6323
 
6324
6324
  // node_modules/cpu-features/lib/index.js
@@ -55412,6 +55412,73 @@ class Semaphore {
55412
55412
  }
55413
55413
  }
55414
55414
 
55415
+ // src/engine/default-seccomp-profile.ts
55416
+ var EMBEDDED_DEFAULT_SECCOMP_PROFILE;
55417
+ var init_default_seccomp_profile = __esm(() => {
55418
+ EMBEDDED_DEFAULT_SECCOMP_PROFILE = JSON.stringify({
55419
+ defaultAction: "SCMP_ACT_ALLOW",
55420
+ architectures: ["SCMP_ARCH_X86_64", "SCMP_ARCH_X86", "SCMP_ARCH_X32", "SCMP_ARCH_AARCH64"],
55421
+ syscalls: [
55422
+ {
55423
+ names: [
55424
+ "acct",
55425
+ "add_key",
55426
+ "bpf",
55427
+ "clock_adjtime",
55428
+ "clock_settime",
55429
+ "create_module",
55430
+ "delete_module",
55431
+ "finit_module",
55432
+ "get_mempolicy",
55433
+ "init_module",
55434
+ "ioperm",
55435
+ "iopl",
55436
+ "kcmp",
55437
+ "kexec_file_load",
55438
+ "kexec_load",
55439
+ "keyctl",
55440
+ "lookup_dcookie",
55441
+ "mbind",
55442
+ "mount",
55443
+ "move_pages",
55444
+ "name_to_handle_at",
55445
+ "open_by_handle_at",
55446
+ "perf_event_open",
55447
+ "pivot_root",
55448
+ "process_vm_readv",
55449
+ "process_vm_writev",
55450
+ "ptrace",
55451
+ "query_module",
55452
+ "quotactl",
55453
+ "reboot",
55454
+ "request_key",
55455
+ "set_mempolicy",
55456
+ "setns",
55457
+ "settimeofday",
55458
+ "stime",
55459
+ "swapon",
55460
+ "swapoff",
55461
+ "sysfs",
55462
+ "syslog",
55463
+ "umount",
55464
+ "umount2",
55465
+ "unshare",
55466
+ "uselib",
55467
+ "userfaultfd",
55468
+ "ustat",
55469
+ "vm86",
55470
+ "vm86old"
55471
+ ],
55472
+ action: "SCMP_ACT_ERRNO",
55473
+ args: [],
55474
+ comment: "",
55475
+ includes: {},
55476
+ excludes: {}
55477
+ }
55478
+ ]
55479
+ });
55480
+ });
55481
+
55415
55482
  // src/engine/utils.ts
55416
55483
  var exports_utils = {};
55417
55484
  __export(exports_utils, {
@@ -56155,7 +56222,19 @@ function wrapWithTimeout(cmd, timeoutSec) {
56155
56222
  function getInstallCommand(runtime, packages) {
56156
56223
  switch (runtime) {
56157
56224
  case "python":
56158
- return ["pip", "install", "--user", "--no-cache-dir", "--break-system-packages", ...packages];
56225
+ return [
56226
+ "pip",
56227
+ "install",
56228
+ "--user",
56229
+ "--no-cache-dir",
56230
+ "--break-system-packages",
56231
+ "--disable-pip-version-check",
56232
+ "--retries",
56233
+ "0",
56234
+ "--timeout",
56235
+ "15",
56236
+ ...packages
56237
+ ];
56159
56238
  case "node":
56160
56239
  return ["npm", "install", "--prefix", "/sandbox", ...packages];
56161
56240
  case "bun":
@@ -56168,8 +56247,9 @@ function getInstallCommand(runtime, packages) {
56168
56247
  throw new Error(`Unknown runtime for package install: ${runtime}`);
56169
56248
  }
56170
56249
  }
56171
- async function installPackages(container, runtime, packages) {
56172
- const cmd = getInstallCommand(runtime, packages);
56250
+ async function installPackages(container, runtime, packages, timeoutMs) {
56251
+ const timeoutSec = Math.max(1, Math.ceil(timeoutMs / 1000));
56252
+ const cmd = wrapWithTimeout(getInstallCommand(runtime, packages), timeoutSec);
56173
56253
  logger.debug(`Installing packages: ${JSON.stringify(cmd)}`);
56174
56254
  const env2 = [
56175
56255
  "PATH=/sandbox/.local/bin:/sandbox/.npm-global/bin:/sandbox/.bun-global/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
@@ -56180,6 +56260,12 @@ async function installPackages(container, runtime, packages) {
56180
56260
  env2.push("NPM_CONFIG_PREFIX=/sandbox/.npm-global");
56181
56261
  env2.push("NPM_CONFIG_CACHE=/sandbox/.npm-cache");
56182
56262
  env2.push("npm_config_cache=/sandbox/.npm-cache");
56263
+ env2.push("NPM_CONFIG_FETCH_RETRIES=0");
56264
+ env2.push("npm_config_fetch_retries=0");
56265
+ env2.push("NPM_CONFIG_FETCH_RETRY_MINTIMEOUT=1000");
56266
+ env2.push("npm_config_fetch_retry_mintimeout=1000");
56267
+ env2.push("NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT=2000");
56268
+ env2.push("npm_config_fetch_retry_maxtimeout=2000");
56183
56269
  } else if (runtime === "bun") {
56184
56270
  env2.push("BUN_INSTALL_GLOBAL_DIR=/sandbox/.bun-global");
56185
56271
  env2.push("BUN_INSTALL_CACHE_DIR=/sandbox/.bun-cache");
@@ -56201,7 +56287,13 @@ async function installPackages(container, runtime, packages) {
56201
56287
  const stderrStream = new PassThrough;
56202
56288
  container.modem.demuxStream(stream, stdoutStream, stderrStream);
56203
56289
  stderrStream.on("data", (chunk) => {
56204
- stderr += chunk.toString();
56290
+ const text = chunk.toString();
56291
+ stderr += text;
56292
+ logger.debug(`[install:${runtime}:stderr] ${text.trimEnd()}`);
56293
+ });
56294
+ stdoutStream.on("data", (chunk) => {
56295
+ const text = chunk.toString();
56296
+ logger.debug(`[install:${runtime}:stdout] ${text.trimEnd()}`);
56205
56297
  });
56206
56298
  stream.on("end", async () => {
56207
56299
  try {
@@ -56531,7 +56623,7 @@ class DockerIsol8 {
56531
56623
  const filePath = `${SANDBOX_WORKDIR}/main${ext}`;
56532
56624
  await writeFileViaExec(container, filePath, request.code);
56533
56625
  if (request.installPackages?.length) {
56534
- await installPackages(container, request.runtime, request.installPackages);
56626
+ await installPackages(container, request.runtime, request.installPackages, timeoutMs);
56535
56627
  }
56536
56628
  if (request.files) {
56537
56629
  for (const [fPath, fContent] of Object.entries(request.files)) {
@@ -56660,7 +56752,7 @@ class DockerIsol8 {
56660
56752
  rawCmd = adapter.getCommand(req.code, filePath);
56661
56753
  }
56662
56754
  if (req.installPackages?.length) {
56663
- await installPackages(container, req.runtime, req.installPackages);
56755
+ await installPackages(container, req.runtime, req.installPackages, timeoutMs);
56664
56756
  }
56665
56757
  const timeoutSec = Math.ceil(timeoutMs / 1000);
56666
56758
  let cmd;
@@ -56768,7 +56860,7 @@ class DockerIsol8 {
56768
56860
  const rawCmd = adapter.getCommand(req.code, filePath);
56769
56861
  const timeoutSec = Math.ceil(timeoutMs / 1000);
56770
56862
  if (req.installPackages?.length) {
56771
- await installPackages(this.container, req.runtime, req.installPackages);
56863
+ await installPackages(this.container, req.runtime, req.installPackages, timeoutMs);
56772
56864
  }
56773
56865
  let cmd;
56774
56866
  if (req.stdin) {
@@ -56911,17 +57003,15 @@ class DockerIsol8 {
56911
57003
  const profile = readFileSync3(this.security.customProfilePath, "utf-8");
56912
57004
  opts.push(`seccomp=${profile}`);
56913
57005
  } catch (e) {
56914
- logger.error(`Failed to load custom seccomp profile: ${e}`);
57006
+ throw new Error(`Failed to load custom seccomp profile at ${this.security.customProfilePath}: ${e}`);
56915
57007
  }
56916
57008
  return opts;
56917
57009
  }
56918
57010
  try {
56919
57011
  const profile = this.loadDefaultSeccompProfile();
56920
- if (profile) {
56921
- opts.push(`seccomp=${profile}`);
56922
- }
57012
+ opts.push(`seccomp=${profile}`);
56923
57013
  } catch (e) {
56924
- logger.error(`Failed to load default seccomp profile: ${e}`);
57014
+ throw new Error(`Failed to load default seccomp profile: ${e}`);
56925
57015
  }
56926
57016
  return opts;
56927
57017
  }
@@ -56934,8 +57024,11 @@ class DockerIsol8 {
56934
57024
  if (existsSync4(prodPath)) {
56935
57025
  return readFileSync3(prodPath, "utf-8");
56936
57026
  }
56937
- logger.warn("Could not locate default seccomp profile. Running without seccomp filter.");
56938
- return null;
57027
+ if (EMBEDDED_DEFAULT_SECCOMP_PROFILE.length > 0) {
57028
+ logger.debug(`Default seccomp profile file not found. Using embedded profile. Tried: ${devPath.pathname}, ${prodPath.pathname}`);
57029
+ return EMBEDDED_DEFAULT_SECCOMP_PROFILE;
57030
+ }
57031
+ throw new Error("Embedded default seccomp profile is unavailable");
56939
57032
  }
56940
57033
  buildEnv(extra) {
56941
57034
  const env2 = [
@@ -57160,6 +57253,7 @@ var init_docker = __esm(() => {
57160
57253
  init_logger();
57161
57254
  init_audit();
57162
57255
  init_code_fetcher();
57256
+ init_default_seccomp_profile();
57163
57257
  init_image_builder();
57164
57258
  init_pool();
57165
57259
  import_dockerode = __toESM(require_docker(), 1);
@@ -57171,7 +57265,7 @@ var package_default;
57171
57265
  var init_package = __esm(() => {
57172
57266
  package_default = {
57173
57267
  name: "isol8",
57174
- version: "0.11.1",
57268
+ version: "0.11.2",
57175
57269
  description: "Secure code execution engine for AI agents",
57176
57270
  author: "Illusion47586",
57177
57271
  license: "MIT",
@@ -58919,6 +59013,50 @@ async function createServer(options) {
58919
59013
  logger.debug(`[Server] Auto-prune: ${config.cleanup.autoPrune}`);
58920
59014
  const app = new Hono2;
58921
59015
  const globalSemaphore = new Semaphore(config.maxConcurrent);
59016
+ let pruneInterval;
59017
+ let cleanupInFlight = null;
59018
+ const cleanupSessions = async () => {
59019
+ let removed = 0;
59020
+ let failed = 0;
59021
+ const errors = [];
59022
+ for (const [id, session] of sessions) {
59023
+ try {
59024
+ await session.engine.stop();
59025
+ removed++;
59026
+ } catch (err) {
59027
+ failed++;
59028
+ const errorMsg = err instanceof Error ? err.message : String(err);
59029
+ errors.push(`${id}: ${errorMsg}`);
59030
+ } finally {
59031
+ sessions.delete(id);
59032
+ }
59033
+ }
59034
+ return { removed, failed, errors };
59035
+ };
59036
+ const runCleanup = async (includeImages) => {
59037
+ if (cleanupInFlight) {
59038
+ return cleanupInFlight;
59039
+ }
59040
+ cleanupInFlight = (async () => {
59041
+ logger.info(`[Server] Starting cleanup (sessions=true containers=true images=${includeImages})`);
59042
+ const sessionsResult = await cleanupSessions();
59043
+ const containersResult = await DockerIsol82.cleanup();
59044
+ const result = {
59045
+ sessions: sessionsResult,
59046
+ containers: containersResult
59047
+ };
59048
+ if (includeImages) {
59049
+ result.images = await DockerIsol82.cleanupImages();
59050
+ }
59051
+ logger.info(`[Server] Cleanup complete: sessions=${result.sessions.removed}/${result.sessions.failed} containers=${result.containers.removed}/${result.containers.failed}${result.images ? ` images=${result.images.removed}/${result.images.failed}` : ""}`);
59052
+ return result;
59053
+ })();
59054
+ try {
59055
+ return await cleanupInFlight;
59056
+ } finally {
59057
+ cleanupInFlight = null;
59058
+ }
59059
+ };
58922
59060
  app.use("*", authMiddleware(options.apiKey));
58923
59061
  app.get("/health", (c) => c.json({ status: "ok", version: VERSION }));
58924
59062
  app.post("/execute", async (c) => {
@@ -59099,8 +59237,21 @@ async function createServer(options) {
59099
59237
  }
59100
59238
  return c.json({ ok: true });
59101
59239
  });
59240
+ app.post("/cleanup", async (c) => {
59241
+ const body = await c.req.json().catch(() => ({}));
59242
+ const includeImages = body.images ?? true;
59243
+ logger.debug(`[Server] POST /cleanup images=${includeImages}`);
59244
+ try {
59245
+ const result = await runCleanup(includeImages);
59246
+ return c.json({ ok: true, ...result });
59247
+ } catch (err) {
59248
+ const message = err instanceof Error ? err.message : String(err);
59249
+ logger.error(`[Server] Cleanup failed: ${message}`);
59250
+ return c.json({ error: message }, 500);
59251
+ }
59252
+ });
59102
59253
  if (config.cleanup.autoPrune) {
59103
- setInterval(async () => {
59254
+ pruneInterval = setInterval(async () => {
59104
59255
  const maxAge = config.cleanup.maxContainerAgeMs;
59105
59256
  const now = Date.now();
59106
59257
  for (const [id, session] of sessions) {
@@ -59118,7 +59269,15 @@ async function createServer(options) {
59118
59269
  return {
59119
59270
  app,
59120
59271
  fetch: app.fetch,
59121
- port: options.port
59272
+ port: options.port,
59273
+ cleanup: async (includeImages = true) => runCleanup(includeImages),
59274
+ shutdown: async (includeImages = true) => {
59275
+ if (pruneInterval) {
59276
+ clearInterval(pruneInterval);
59277
+ pruneInterval = undefined;
59278
+ }
59279
+ await runCleanup(includeImages);
59280
+ }
59122
59281
  };
59123
59282
  }
59124
59283
  var sessions;
@@ -62762,9 +62921,39 @@ program2.command("serve").description("Start the isol8 remote server").option("-
62762
62921
  logger.debug("[Serve] Running under Bun, starting server in-process");
62763
62922
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), exports_server));
62764
62923
  const server = await createServer2({ port, apiKey, debug: opts.debug ?? false });
62924
+ let shuttingDown = false;
62925
+ const bunServer = Bun.serve({ fetch: server.app.fetch, port });
62926
+ const shutdown = async () => {
62927
+ if (shuttingDown) {
62928
+ return;
62929
+ }
62930
+ shuttingDown = true;
62931
+ logger.info("[Serve] Shutting down server and cleaning up resources...");
62932
+ bunServer.stop();
62933
+ try {
62934
+ await server.shutdown();
62935
+ logger.info("[Serve] Cleanup complete");
62936
+ process.exit(0);
62937
+ } catch (err) {
62938
+ const message = err instanceof Error ? err.message : String(err);
62939
+ logger.error(`[Serve] Cleanup failed: ${message}`);
62940
+ process.exit(1);
62941
+ }
62942
+ };
62943
+ process.on("SIGINT", () => {
62944
+ shutdown().catch((err) => {
62945
+ const message = err instanceof Error ? err.message : String(err);
62946
+ logger.error(`[Serve] Shutdown handler failed: ${message}`);
62947
+ });
62948
+ });
62949
+ process.on("SIGTERM", () => {
62950
+ shutdown().catch((err) => {
62951
+ const message = err instanceof Error ? err.message : String(err);
62952
+ logger.error(`[Serve] Shutdown handler failed: ${message}`);
62953
+ });
62954
+ });
62765
62955
  console.log(`[INFO] isol8 server v${VERSION} listening on http://localhost:${port}`);
62766
62956
  console.log(" Auth: Bearer token required");
62767
- Bun.serve({ fetch: server.app.fetch, port });
62768
62957
  return;
62769
62958
  }
62770
62959
  logger.debug("[Serve] Running under Node.js, launching standalone binary");
@@ -63185,6 +63374,7 @@ program2.command("cleanup").description("Remove orphaned isol8 containers (and o
63185
63374
  async function resolveRunInput(file, opts) {
63186
63375
  const config = loadConfig();
63187
63376
  logger.debug("[Run] Config loaded");
63377
+ const hasExplicitNetFlag = process.argv.some((arg) => arg === "--net");
63188
63378
  let code;
63189
63379
  let codeUrl;
63190
63380
  let codeHash;
@@ -63258,6 +63448,20 @@ async function resolveRunInput(file, opts) {
63258
63448
  dependencies: config.dependencies,
63259
63449
  remoteCode: config.remoteCode
63260
63450
  };
63451
+ if (opts.install.length > 0 && !hasExplicitNetFlag) {
63452
+ engineOptions.network = "filtered";
63453
+ logger.debug("[Run] --install detected without explicit --net; using filtered network mode automatically");
63454
+ }
63455
+ if (opts.install.length > 0 && engineOptions.network === "filtered") {
63456
+ const runtimeRegistryAllowlist = getDefaultRegistryAllowPatterns(runtime);
63457
+ if (runtimeRegistryAllowlist.length > 0) {
63458
+ engineOptions.networkFilter = {
63459
+ whitelist: Array.from(new Set([...engineOptions.networkFilter?.whitelist ?? [], ...runtimeRegistryAllowlist])),
63460
+ blacklist: engineOptions.networkFilter?.blacklist ?? []
63461
+ };
63462
+ logger.debug(`[Run] Added default package registries for ${runtime}: ${runtimeRegistryAllowlist.join(", ")}`);
63463
+ }
63464
+ }
63261
63465
  logger.debug(`[Run] Engine options: mode=${engineOptions.mode}, network=${engineOptions.network}`);
63262
63466
  let fileExtension;
63263
63467
  if (file) {
@@ -63333,6 +63537,19 @@ function detectRuntimeFromPath(pathValue) {
63333
63537
  return;
63334
63538
  }
63335
63539
  }
63540
+ function getDefaultRegistryAllowPatterns(runtime) {
63541
+ switch (runtime) {
63542
+ case "python":
63543
+ return ["^pypi\\.org$", "^files\\.pythonhosted\\.org$"];
63544
+ case "node":
63545
+ case "bun":
63546
+ return ["^registry\\.npmjs\\.org$"];
63547
+ case "bash":
63548
+ return ["^dl-cdn\\.alpinelinux\\.org$"];
63549
+ default:
63550
+ return [];
63551
+ }
63552
+ }
63336
63553
  function collect(value, previous) {
63337
63554
  return previous.concat([value]);
63338
63555
  }
@@ -63342,4 +63559,4 @@ if (!process.argv.slice(2).length) {
63342
63559
  }
63343
63560
  program2.parse();
63344
63561
 
63345
- //# debugId=33A00A6A263B687D64756E2164756E21
63562
+ //# debugId=DC4F72D2D8660BF264756E2164756E21
package/dist/index.js CHANGED
@@ -546,6 +546,73 @@ class Semaphore {
546
546
  }
547
547
  }
548
548
 
549
+ // src/engine/default-seccomp-profile.ts
550
+ var EMBEDDED_DEFAULT_SECCOMP_PROFILE;
551
+ var init_default_seccomp_profile = __esm(() => {
552
+ EMBEDDED_DEFAULT_SECCOMP_PROFILE = JSON.stringify({
553
+ defaultAction: "SCMP_ACT_ALLOW",
554
+ architectures: ["SCMP_ARCH_X86_64", "SCMP_ARCH_X86", "SCMP_ARCH_X32", "SCMP_ARCH_AARCH64"],
555
+ syscalls: [
556
+ {
557
+ names: [
558
+ "acct",
559
+ "add_key",
560
+ "bpf",
561
+ "clock_adjtime",
562
+ "clock_settime",
563
+ "create_module",
564
+ "delete_module",
565
+ "finit_module",
566
+ "get_mempolicy",
567
+ "init_module",
568
+ "ioperm",
569
+ "iopl",
570
+ "kcmp",
571
+ "kexec_file_load",
572
+ "kexec_load",
573
+ "keyctl",
574
+ "lookup_dcookie",
575
+ "mbind",
576
+ "mount",
577
+ "move_pages",
578
+ "name_to_handle_at",
579
+ "open_by_handle_at",
580
+ "perf_event_open",
581
+ "pivot_root",
582
+ "process_vm_readv",
583
+ "process_vm_writev",
584
+ "ptrace",
585
+ "query_module",
586
+ "quotactl",
587
+ "reboot",
588
+ "request_key",
589
+ "set_mempolicy",
590
+ "setns",
591
+ "settimeofday",
592
+ "stime",
593
+ "swapon",
594
+ "swapoff",
595
+ "sysfs",
596
+ "syslog",
597
+ "umount",
598
+ "umount2",
599
+ "unshare",
600
+ "uselib",
601
+ "userfaultfd",
602
+ "ustat",
603
+ "vm86",
604
+ "vm86old"
605
+ ],
606
+ action: "SCMP_ACT_ERRNO",
607
+ args: [],
608
+ comment: "",
609
+ includes: {},
610
+ excludes: {}
611
+ }
612
+ ]
613
+ });
614
+ });
615
+
549
616
  // src/engine/image-builder.ts
550
617
  import { createHash as createHash2 } from "node:crypto";
551
618
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
@@ -1087,7 +1154,19 @@ function wrapWithTimeout(cmd, timeoutSec) {
1087
1154
  function getInstallCommand(runtime, packages) {
1088
1155
  switch (runtime) {
1089
1156
  case "python":
1090
- return ["pip", "install", "--user", "--no-cache-dir", "--break-system-packages", ...packages];
1157
+ return [
1158
+ "pip",
1159
+ "install",
1160
+ "--user",
1161
+ "--no-cache-dir",
1162
+ "--break-system-packages",
1163
+ "--disable-pip-version-check",
1164
+ "--retries",
1165
+ "0",
1166
+ "--timeout",
1167
+ "15",
1168
+ ...packages
1169
+ ];
1091
1170
  case "node":
1092
1171
  return ["npm", "install", "--prefix", "/sandbox", ...packages];
1093
1172
  case "bun":
@@ -1100,8 +1179,9 @@ function getInstallCommand(runtime, packages) {
1100
1179
  throw new Error(`Unknown runtime for package install: ${runtime}`);
1101
1180
  }
1102
1181
  }
1103
- async function installPackages(container, runtime, packages) {
1104
- const cmd = getInstallCommand(runtime, packages);
1182
+ async function installPackages(container, runtime, packages, timeoutMs) {
1183
+ const timeoutSec = Math.max(1, Math.ceil(timeoutMs / 1000));
1184
+ const cmd = wrapWithTimeout(getInstallCommand(runtime, packages), timeoutSec);
1105
1185
  logger.debug(`Installing packages: ${JSON.stringify(cmd)}`);
1106
1186
  const env = [
1107
1187
  "PATH=/sandbox/.local/bin:/sandbox/.npm-global/bin:/sandbox/.bun-global/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
@@ -1112,6 +1192,12 @@ async function installPackages(container, runtime, packages) {
1112
1192
  env.push("NPM_CONFIG_PREFIX=/sandbox/.npm-global");
1113
1193
  env.push("NPM_CONFIG_CACHE=/sandbox/.npm-cache");
1114
1194
  env.push("npm_config_cache=/sandbox/.npm-cache");
1195
+ env.push("NPM_CONFIG_FETCH_RETRIES=0");
1196
+ env.push("npm_config_fetch_retries=0");
1197
+ env.push("NPM_CONFIG_FETCH_RETRY_MINTIMEOUT=1000");
1198
+ env.push("npm_config_fetch_retry_mintimeout=1000");
1199
+ env.push("NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT=2000");
1200
+ env.push("npm_config_fetch_retry_maxtimeout=2000");
1115
1201
  } else if (runtime === "bun") {
1116
1202
  env.push("BUN_INSTALL_GLOBAL_DIR=/sandbox/.bun-global");
1117
1203
  env.push("BUN_INSTALL_CACHE_DIR=/sandbox/.bun-cache");
@@ -1133,7 +1219,13 @@ async function installPackages(container, runtime, packages) {
1133
1219
  const stderrStream = new PassThrough;
1134
1220
  container.modem.demuxStream(stream, stdoutStream, stderrStream);
1135
1221
  stderrStream.on("data", (chunk) => {
1136
- stderr += chunk.toString();
1222
+ const text = chunk.toString();
1223
+ stderr += text;
1224
+ logger.debug(`[install:${runtime}:stderr] ${text.trimEnd()}`);
1225
+ });
1226
+ stdoutStream.on("data", (chunk) => {
1227
+ const text = chunk.toString();
1228
+ logger.debug(`[install:${runtime}:stdout] ${text.trimEnd()}`);
1137
1229
  });
1138
1230
  stream.on("end", async () => {
1139
1231
  try {
@@ -1463,7 +1555,7 @@ class DockerIsol8 {
1463
1555
  const filePath = `${SANDBOX_WORKDIR}/main${ext}`;
1464
1556
  await writeFileViaExec(container, filePath, request.code);
1465
1557
  if (request.installPackages?.length) {
1466
- await installPackages(container, request.runtime, request.installPackages);
1558
+ await installPackages(container, request.runtime, request.installPackages, timeoutMs);
1467
1559
  }
1468
1560
  if (request.files) {
1469
1561
  for (const [fPath, fContent] of Object.entries(request.files)) {
@@ -1592,7 +1684,7 @@ class DockerIsol8 {
1592
1684
  rawCmd = adapter.getCommand(req.code, filePath);
1593
1685
  }
1594
1686
  if (req.installPackages?.length) {
1595
- await installPackages(container, req.runtime, req.installPackages);
1687
+ await installPackages(container, req.runtime, req.installPackages, timeoutMs);
1596
1688
  }
1597
1689
  const timeoutSec = Math.ceil(timeoutMs / 1000);
1598
1690
  let cmd;
@@ -1700,7 +1792,7 @@ class DockerIsol8 {
1700
1792
  const rawCmd = adapter.getCommand(req.code, filePath);
1701
1793
  const timeoutSec = Math.ceil(timeoutMs / 1000);
1702
1794
  if (req.installPackages?.length) {
1703
- await installPackages(this.container, req.runtime, req.installPackages);
1795
+ await installPackages(this.container, req.runtime, req.installPackages, timeoutMs);
1704
1796
  }
1705
1797
  let cmd;
1706
1798
  if (req.stdin) {
@@ -1843,17 +1935,15 @@ class DockerIsol8 {
1843
1935
  const profile = readFileSync3(this.security.customProfilePath, "utf-8");
1844
1936
  opts.push(`seccomp=${profile}`);
1845
1937
  } catch (e) {
1846
- logger.error(`Failed to load custom seccomp profile: ${e}`);
1938
+ throw new Error(`Failed to load custom seccomp profile at ${this.security.customProfilePath}: ${e}`);
1847
1939
  }
1848
1940
  return opts;
1849
1941
  }
1850
1942
  try {
1851
1943
  const profile = this.loadDefaultSeccompProfile();
1852
- if (profile) {
1853
- opts.push(`seccomp=${profile}`);
1854
- }
1944
+ opts.push(`seccomp=${profile}`);
1855
1945
  } catch (e) {
1856
- logger.error(`Failed to load default seccomp profile: ${e}`);
1946
+ throw new Error(`Failed to load default seccomp profile: ${e}`);
1857
1947
  }
1858
1948
  return opts;
1859
1949
  }
@@ -1866,8 +1956,11 @@ class DockerIsol8 {
1866
1956
  if (existsSync4(prodPath)) {
1867
1957
  return readFileSync3(prodPath, "utf-8");
1868
1958
  }
1869
- logger.warn("Could not locate default seccomp profile. Running without seccomp filter.");
1870
- return null;
1959
+ if (EMBEDDED_DEFAULT_SECCOMP_PROFILE.length > 0) {
1960
+ logger.debug(`Default seccomp profile file not found. Using embedded profile. Tried: ${devPath.pathname}, ${prodPath.pathname}`);
1961
+ return EMBEDDED_DEFAULT_SECCOMP_PROFILE;
1962
+ }
1963
+ throw new Error("Embedded default seccomp profile is unavailable");
1871
1964
  }
1872
1965
  buildEnv(extra) {
1873
1966
  const env = [
@@ -2092,6 +2185,7 @@ var init_docker = __esm(() => {
2092
2185
  init_logger();
2093
2186
  init_audit();
2094
2187
  init_code_fetcher();
2188
+ init_default_seccomp_profile();
2095
2189
  init_image_builder();
2096
2190
  init_pool();
2097
2191
  MAX_OUTPUT_BYTES = 1024 * 1024;
@@ -2349,7 +2443,7 @@ init_logger();
2349
2443
  // package.json
2350
2444
  var package_default = {
2351
2445
  name: "isol8",
2352
- version: "0.11.1",
2446
+ version: "0.11.2",
2353
2447
  description: "Secure code execution engine for AI agents",
2354
2448
  author: "Illusion47586",
2355
2449
  license: "MIT",
@@ -2501,6 +2595,50 @@ async function createServer(options) {
2501
2595
  logger.debug(`[Server] Auto-prune: ${config.cleanup.autoPrune}`);
2502
2596
  const app = new Hono;
2503
2597
  const globalSemaphore = new Semaphore(config.maxConcurrent);
2598
+ let pruneInterval;
2599
+ let cleanupInFlight = null;
2600
+ const cleanupSessions = async () => {
2601
+ let removed = 0;
2602
+ let failed = 0;
2603
+ const errors = [];
2604
+ for (const [id, session] of sessions) {
2605
+ try {
2606
+ await session.engine.stop();
2607
+ removed++;
2608
+ } catch (err) {
2609
+ failed++;
2610
+ const errorMsg = err instanceof Error ? err.message : String(err);
2611
+ errors.push(`${id}: ${errorMsg}`);
2612
+ } finally {
2613
+ sessions.delete(id);
2614
+ }
2615
+ }
2616
+ return { removed, failed, errors };
2617
+ };
2618
+ const runCleanup = async (includeImages) => {
2619
+ if (cleanupInFlight) {
2620
+ return cleanupInFlight;
2621
+ }
2622
+ cleanupInFlight = (async () => {
2623
+ logger.info(`[Server] Starting cleanup (sessions=true containers=true images=${includeImages})`);
2624
+ const sessionsResult = await cleanupSessions();
2625
+ const containersResult = await DockerIsol82.cleanup();
2626
+ const result = {
2627
+ sessions: sessionsResult,
2628
+ containers: containersResult
2629
+ };
2630
+ if (includeImages) {
2631
+ result.images = await DockerIsol82.cleanupImages();
2632
+ }
2633
+ logger.info(`[Server] Cleanup complete: sessions=${result.sessions.removed}/${result.sessions.failed} containers=${result.containers.removed}/${result.containers.failed}${result.images ? ` images=${result.images.removed}/${result.images.failed}` : ""}`);
2634
+ return result;
2635
+ })();
2636
+ try {
2637
+ return await cleanupInFlight;
2638
+ } finally {
2639
+ cleanupInFlight = null;
2640
+ }
2641
+ };
2504
2642
  app.use("*", authMiddleware(options.apiKey));
2505
2643
  app.get("/health", (c) => c.json({ status: "ok", version: VERSION }));
2506
2644
  app.post("/execute", async (c) => {
@@ -2681,8 +2819,21 @@ async function createServer(options) {
2681
2819
  }
2682
2820
  return c.json({ ok: true });
2683
2821
  });
2822
+ app.post("/cleanup", async (c) => {
2823
+ const body = await c.req.json().catch(() => ({}));
2824
+ const includeImages = body.images ?? true;
2825
+ logger.debug(`[Server] POST /cleanup images=${includeImages}`);
2826
+ try {
2827
+ const result = await runCleanup(includeImages);
2828
+ return c.json({ ok: true, ...result });
2829
+ } catch (err) {
2830
+ const message = err instanceof Error ? err.message : String(err);
2831
+ logger.error(`[Server] Cleanup failed: ${message}`);
2832
+ return c.json({ error: message }, 500);
2833
+ }
2834
+ });
2684
2835
  if (config.cleanup.autoPrune) {
2685
- setInterval(async () => {
2836
+ pruneInterval = setInterval(async () => {
2686
2837
  const maxAge = config.cleanup.maxContainerAgeMs;
2687
2838
  const now = Date.now();
2688
2839
  for (const [id, session] of sessions) {
@@ -2700,7 +2851,15 @@ async function createServer(options) {
2700
2851
  return {
2701
2852
  app,
2702
2853
  fetch: app.fetch,
2703
- port: options.port
2854
+ port: options.port,
2855
+ cleanup: async (includeImages = true) => runCleanup(includeImages),
2856
+ shutdown: async (includeImages = true) => {
2857
+ if (pruneInterval) {
2858
+ clearInterval(pruneInterval);
2859
+ pruneInterval = undefined;
2860
+ }
2861
+ await runCleanup(includeImages);
2862
+ }
2704
2863
  };
2705
2864
  }
2706
2865
  export {
@@ -2717,4 +2876,4 @@ export {
2717
2876
  BunAdapter
2718
2877
  };
2719
2878
 
2720
- //# debugId=E6910E46B07952A064756E2164756E21
2879
+ //# debugId=C10FBC887CAF691764756E2164756E21
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Embedded default seccomp profile.
3
+ *
4
+ * This keeps strict seccomp available in standalone compiled binaries where
5
+ * docker/seccomp-profile.json may not be present on disk.
6
+ */
7
+ export declare const EMBEDDED_DEFAULT_SECCOMP_PROFILE: string;
8
+ //# sourceMappingURL=default-seccomp-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-seccomp-profile.d.ts","sourceRoot":"","sources":["../../../src/engine/default-seccomp-profile.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,QA6D3C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../../src/engine/docker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,MAAM,MAAM,WAAW,CAAC;AAG/B,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAEf,WAAW,EAEX,YAAY,EAKZ,YAAY,EACZ,WAAW,EACZ,MAAM,UAAU,CAAC;AA2UlB,2HAA2H;AAC3H,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,WAAY,YAAW,WAAW;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAsB;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;IACrE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IAEpD,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,IAAI,CAA8B;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;YAE1C,uBAAuB;IA6BrC;;;OAGG;gBACS,OAAO,GAAE,kBAAuB,EAAE,aAAa,SAAK;IA4ChE;;;;;OAKG;IACG,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCtD,kFAAkF;IAC5E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB3B;;;OAGG;IACG,OAAO,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAgB9D;;OAEG;YACW,WAAW;IAoDzB;;OAEG;YACW,qBAAqB;IA8CnC;;OAEG;YACW,kBAAkB;IA+DhC;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYpE;;;;;;OAMG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmB5C,6GAA6G;IAC7G,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAE/B;IAED;;;OAGG;IACI,aAAa,CAAC,GAAG,EAAE,gBAAgB,GAAG,aAAa,CAAC,WAAW,CAAC;YAuFzD,YAAY;IA0C1B,OAAO,CAAC,UAAU;YAsBJ,gBAAgB;YAgKhB,iBAAiB;YAwIjB,aAAa;YAkBb,oBAAoB;YASpB,wBAAwB;IA4BtC,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,yBAAyB;IAyBjC,OAAO,CAAC,QAAQ;YAwCD,gBAAgB;YA8EjB,iBAAiB;IAiG/B,OAAO,CAAC,iBAAiB;IAYzB;;;;;;;;;;;;;;;;;;;;OAoBG;WACU,OAAO,CAClB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA0BjE;;;;;OAKG;WACU,aAAa,CACxB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CA2BlE"}
1
+ {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../../src/engine/docker.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,23 @@ export interface ServerOptions {
15
15
  /** Enable debug logging for internal server operations. */
16
16
  debug?: boolean;
17
17
  }
18
+ interface CleanupResult {
19
+ sessions: {
20
+ removed: number;
21
+ failed: number;
22
+ errors: string[];
23
+ };
24
+ containers: {
25
+ removed: number;
26
+ failed: number;
27
+ errors: string[];
28
+ };
29
+ images?: {
30
+ removed: number;
31
+ failed: number;
32
+ errors: string[];
33
+ };
34
+ }
18
35
  /**
19
36
  * Creates and configures the isol8 HTTP server.
20
37
  *
@@ -36,5 +53,8 @@ export declare function createServer(options: ServerOptions): Promise<{
36
53
  app: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
37
54
  fetch: (request: Request, Env?: unknown, executionCtx?: import("hono").ExecutionContext) => Response | Promise<Response>;
38
55
  port: number;
56
+ cleanup: (includeImages?: boolean) => Promise<CleanupResult>;
57
+ shutdown: (includeImages?: boolean) => Promise<void>;
39
58
  }>;
59
+ export {};
40
60
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,aAAa;;;;GAmRxD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAaD,UAAU,aAAa;IACrB,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAChE,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAClE,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAChE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,aAAa;;;;;;GAyWxD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isol8",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
4
4
  "description": "Secure code execution engine for AI agents",
5
5
  "author": "Illusion47586",
6
6
  "license": "MIT",