isol8 0.6.1 → 0.7.0
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 +23 -16
- package/dist/cli.js +201 -34
- package/dist/docker/Dockerfile +4 -2
- package/dist/docker/seccomp-profile.json +67 -0
- package/dist/index.js +106 -10
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/engine/docker.d.ts +3 -0
- package/dist/src/engine/docker.d.ts.map +1 -1
- package/dist/src/engine/pool.d.ts +3 -2
- package/dist/src/engine/pool.d.ts.map +1 -1
- package/dist/src/server/index.d.ts +2 -0
- package/dist/src/server/index.d.ts.map +1 -1
- package/dist/src/types.d.ts +20 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/schema/isol8.config.schema.json +20 -0
package/dist/cli.js
CHANGED
|
@@ -54799,6 +54799,10 @@ function mergeConfig(defaults, overrides) {
|
|
|
54799
54799
|
...defaults.dependencies,
|
|
54800
54800
|
...overrides.dependencies
|
|
54801
54801
|
},
|
|
54802
|
+
security: {
|
|
54803
|
+
seccomp: overrides.security?.seccomp ?? defaults.security.seccomp,
|
|
54804
|
+
customProfilePath: overrides.security?.customProfilePath ?? defaults.security.customProfilePath
|
|
54805
|
+
},
|
|
54802
54806
|
debug: overrides.debug ?? defaults.debug
|
|
54803
54807
|
};
|
|
54804
54808
|
}
|
|
@@ -54823,6 +54827,9 @@ var init_config = __esm(() => {
|
|
|
54823
54827
|
maxContainerAgeMs: 3600000
|
|
54824
54828
|
},
|
|
54825
54829
|
dependencies: {},
|
|
54830
|
+
security: {
|
|
54831
|
+
seccomp: "strict"
|
|
54832
|
+
},
|
|
54826
54833
|
debug: false
|
|
54827
54834
|
};
|
|
54828
54835
|
});
|
|
@@ -54990,11 +54997,6 @@ var init_runtime = __esm(() => {
|
|
|
54990
54997
|
});
|
|
54991
54998
|
|
|
54992
54999
|
// src/utils/logger.ts
|
|
54993
|
-
var exports_logger = {};
|
|
54994
|
-
__export(exports_logger, {
|
|
54995
|
-
logger: () => logger
|
|
54996
|
-
});
|
|
54997
|
-
|
|
54998
55000
|
class Logger {
|
|
54999
55001
|
debugMode = false;
|
|
55000
55002
|
setDebug(enabled) {
|
|
@@ -55085,6 +55087,15 @@ class ContainerPool {
|
|
|
55085
55087
|
return;
|
|
55086
55088
|
}
|
|
55087
55089
|
try {
|
|
55090
|
+
const killExec = await container.exec({
|
|
55091
|
+
Cmd: ["sh", "-c", "pkill -9 -u sandbox 2>/dev/null; true"]
|
|
55092
|
+
});
|
|
55093
|
+
await killExec.start({ Detach: true });
|
|
55094
|
+
let killInfo = await killExec.inspect();
|
|
55095
|
+
while (killInfo.Running) {
|
|
55096
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
55097
|
+
killInfo = await killExec.inspect();
|
|
55098
|
+
}
|
|
55088
55099
|
const cleanExec = await container.exec({
|
|
55089
55100
|
Cmd: ["sh", "-c", "rm -rf /sandbox/* /sandbox/.[!.]* 2>/dev/null; true"]
|
|
55090
55101
|
});
|
|
@@ -55269,12 +55280,14 @@ __export(exports_docker, {
|
|
|
55269
55280
|
DockerIsol8: () => DockerIsol8
|
|
55270
55281
|
});
|
|
55271
55282
|
import { randomUUID } from "node:crypto";
|
|
55283
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
55272
55284
|
import { PassThrough } from "node:stream";
|
|
55273
55285
|
async function writeFileViaExec(container, filePath, content) {
|
|
55274
55286
|
const data = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
|
|
55275
55287
|
const b64 = data.toString("base64");
|
|
55276
55288
|
const exec = await container.exec({
|
|
55277
|
-
Cmd: ["sh", "-c", `printf '%s' '${b64}' | base64 -d > ${filePath}`]
|
|
55289
|
+
Cmd: ["sh", "-c", `printf '%s' '${b64}' | base64 -d > ${filePath}`],
|
|
55290
|
+
User: "sandbox"
|
|
55278
55291
|
});
|
|
55279
55292
|
await exec.start({ Detach: true });
|
|
55280
55293
|
let info2 = await exec.inspect();
|
|
@@ -55290,7 +55303,8 @@ async function readFileViaExec(container, filePath) {
|
|
|
55290
55303
|
const exec = await container.exec({
|
|
55291
55304
|
Cmd: ["base64", filePath],
|
|
55292
55305
|
AttachStdout: true,
|
|
55293
|
-
AttachStderr: true
|
|
55306
|
+
AttachStderr: true,
|
|
55307
|
+
User: "sandbox"
|
|
55294
55308
|
});
|
|
55295
55309
|
const stream = await exec.start({ Tty: false });
|
|
55296
55310
|
const chunks = [];
|
|
@@ -55385,7 +55399,8 @@ async function installPackages(container, runtime, packages) {
|
|
|
55385
55399
|
Cmd: cmd,
|
|
55386
55400
|
AttachStdout: true,
|
|
55387
55401
|
AttachStderr: true,
|
|
55388
|
-
Env: env2
|
|
55402
|
+
Env: env2,
|
|
55403
|
+
User: runtime === "bash" ? "root" : "sandbox"
|
|
55389
55404
|
});
|
|
55390
55405
|
const stream = await exec.start({ Detach: false, Tty: false });
|
|
55391
55406
|
return new Promise((resolve2, reject) => {
|
|
@@ -55428,6 +55443,7 @@ class DockerIsol8 {
|
|
|
55428
55443
|
semaphore;
|
|
55429
55444
|
sandboxSize;
|
|
55430
55445
|
tmpSize;
|
|
55446
|
+
security;
|
|
55431
55447
|
persist;
|
|
55432
55448
|
container = null;
|
|
55433
55449
|
persistentRuntime = null;
|
|
@@ -55449,6 +55465,7 @@ class DockerIsol8 {
|
|
|
55449
55465
|
this.sandboxSize = options.sandboxSize ?? "512m";
|
|
55450
55466
|
this.tmpSize = options.tmpSize ?? "256m";
|
|
55451
55467
|
this.persist = options.persist ?? false;
|
|
55468
|
+
this.security = options.security ?? { seccomp: "strict" };
|
|
55452
55469
|
if (options.debug) {
|
|
55453
55470
|
logger.setDebug(true);
|
|
55454
55471
|
}
|
|
@@ -55554,7 +55571,8 @@ class DockerIsol8 {
|
|
|
55554
55571
|
Env: this.buildEnv(req.env),
|
|
55555
55572
|
AttachStdout: true,
|
|
55556
55573
|
AttachStderr: true,
|
|
55557
|
-
WorkingDir: SANDBOX_WORKDIR
|
|
55574
|
+
WorkingDir: SANDBOX_WORKDIR,
|
|
55575
|
+
User: "sandbox"
|
|
55558
55576
|
});
|
|
55559
55577
|
const execStream = await exec.start({ Tty: false });
|
|
55560
55578
|
yield* this.streamExecOutput(execStream, exec, container, timeoutMs);
|
|
@@ -55633,7 +55651,8 @@ class DockerIsol8 {
|
|
|
55633
55651
|
Env: this.buildEnv(req.env),
|
|
55634
55652
|
AttachStdout: true,
|
|
55635
55653
|
AttachStderr: true,
|
|
55636
|
-
WorkingDir: SANDBOX_WORKDIR
|
|
55654
|
+
WorkingDir: SANDBOX_WORKDIR,
|
|
55655
|
+
User: "sandbox"
|
|
55637
55656
|
});
|
|
55638
55657
|
const start = performance.now();
|
|
55639
55658
|
const execStream = await exec.start({ Tty: false });
|
|
@@ -55706,7 +55725,8 @@ class DockerIsol8 {
|
|
|
55706
55725
|
Env: execEnv,
|
|
55707
55726
|
AttachStdout: true,
|
|
55708
55727
|
AttachStderr: true,
|
|
55709
|
-
WorkingDir: SANDBOX_WORKDIR
|
|
55728
|
+
WorkingDir: SANDBOX_WORKDIR,
|
|
55729
|
+
User: "sandbox"
|
|
55710
55730
|
});
|
|
55711
55731
|
const start = performance.now();
|
|
55712
55732
|
const execStream = await exec.start({ Tty: false });
|
|
@@ -55776,9 +55796,9 @@ class DockerIsol8 {
|
|
|
55776
55796
|
ReadonlyRootfs: this.readonlyRootFs,
|
|
55777
55797
|
Tmpfs: {
|
|
55778
55798
|
"/tmp": `rw,noexec,nosuid,nodev,size=${this.tmpSize}`,
|
|
55779
|
-
[SANDBOX_WORKDIR]: `rw,exec,nosuid,nodev,size=${this.sandboxSize}`
|
|
55799
|
+
[SANDBOX_WORKDIR]: `rw,exec,nosuid,nodev,size=${this.sandboxSize},uid=100,gid=101`
|
|
55780
55800
|
},
|
|
55781
|
-
SecurityOpt:
|
|
55801
|
+
SecurityOpt: this.buildSecurityOpts()
|
|
55782
55802
|
};
|
|
55783
55803
|
if (this.network === "filtered") {
|
|
55784
55804
|
config.NetworkMode = "bridge";
|
|
@@ -55787,6 +55807,43 @@ class DockerIsol8 {
|
|
|
55787
55807
|
}
|
|
55788
55808
|
return config;
|
|
55789
55809
|
}
|
|
55810
|
+
buildSecurityOpts() {
|
|
55811
|
+
const opts = ["no-new-privileges"];
|
|
55812
|
+
if (this.security.seccomp === "unconfined") {
|
|
55813
|
+
opts.push("seccomp=unconfined");
|
|
55814
|
+
return opts;
|
|
55815
|
+
}
|
|
55816
|
+
if (this.security.seccomp === "custom" && this.security.customProfilePath) {
|
|
55817
|
+
try {
|
|
55818
|
+
const profile = readFileSync2(this.security.customProfilePath, "utf-8");
|
|
55819
|
+
opts.push(`seccomp=${profile}`);
|
|
55820
|
+
} catch (e) {
|
|
55821
|
+
logger.error(`Failed to load custom seccomp profile: ${e}`);
|
|
55822
|
+
}
|
|
55823
|
+
return opts;
|
|
55824
|
+
}
|
|
55825
|
+
try {
|
|
55826
|
+
const profile = this.loadDefaultSeccompProfile();
|
|
55827
|
+
if (profile) {
|
|
55828
|
+
opts.push(`seccomp=${profile}`);
|
|
55829
|
+
}
|
|
55830
|
+
} catch (e) {
|
|
55831
|
+
logger.error(`Failed to load default seccomp profile: ${e}`);
|
|
55832
|
+
}
|
|
55833
|
+
return opts;
|
|
55834
|
+
}
|
|
55835
|
+
loadDefaultSeccompProfile() {
|
|
55836
|
+
const devPath = new URL("../../docker/seccomp-profile.json", import.meta.url);
|
|
55837
|
+
if (existsSync2(devPath)) {
|
|
55838
|
+
return readFileSync2(devPath, "utf-8");
|
|
55839
|
+
}
|
|
55840
|
+
const prodPath = new URL("./docker/seccomp-profile.json", import.meta.url);
|
|
55841
|
+
if (existsSync2(prodPath)) {
|
|
55842
|
+
return readFileSync2(prodPath, "utf-8");
|
|
55843
|
+
}
|
|
55844
|
+
logger.warn("Could not locate default seccomp profile. Running without seccomp filter.");
|
|
55845
|
+
return null;
|
|
55846
|
+
}
|
|
55790
55847
|
buildEnv(extra) {
|
|
55791
55848
|
const env2 = [
|
|
55792
55849
|
"PYTHONUNBUFFERED=1",
|
|
@@ -55968,7 +56025,7 @@ var package_default;
|
|
|
55968
56025
|
var init_package = __esm(() => {
|
|
55969
56026
|
package_default = {
|
|
55970
56027
|
name: "isol8",
|
|
55971
|
-
version: "0.6.
|
|
56028
|
+
version: "0.6.2",
|
|
55972
56029
|
description: "Secure code execution engine for AI agents",
|
|
55973
56030
|
author: "Illusion47586",
|
|
55974
56031
|
license: "MIT",
|
|
@@ -56030,6 +56087,7 @@ var init_package = __esm(() => {
|
|
|
56030
56087
|
devDependencies: {
|
|
56031
56088
|
"@biomejs/biome": "^2.3.15",
|
|
56032
56089
|
"@semantic-release/changelog": "^6.0.3",
|
|
56090
|
+
"@semantic-release/exec": "^7.1.0",
|
|
56033
56091
|
"@semantic-release/git": "^10.0.1",
|
|
56034
56092
|
"@semantic-release/github": "^12.0.6",
|
|
56035
56093
|
"@semantic-release/npm": "^13.1.4",
|
|
@@ -57696,13 +57754,21 @@ __export(exports_server, {
|
|
|
57696
57754
|
async function createServer(options) {
|
|
57697
57755
|
const { DockerIsol8: DockerIsol82 } = await Promise.resolve().then(() => (init_docker(), exports_docker));
|
|
57698
57756
|
await Promise.resolve().then(() => (init_runtime(), exports_runtime));
|
|
57757
|
+
if (options.debug) {
|
|
57758
|
+
logger.setDebug(true);
|
|
57759
|
+
}
|
|
57699
57760
|
const config = loadConfig();
|
|
57761
|
+
logger.debug("[Server] Config loaded");
|
|
57762
|
+
logger.debug(`[Server] Max concurrent: ${config.maxConcurrent}`);
|
|
57763
|
+
logger.debug(`[Server] Auto-prune: ${config.cleanup.autoPrune}`);
|
|
57700
57764
|
const app = new Hono2;
|
|
57701
57765
|
const globalSemaphore = new Semaphore(config.maxConcurrent);
|
|
57702
57766
|
app.use("*", authMiddleware(options.apiKey));
|
|
57703
57767
|
app.get("/health", (c) => c.json({ status: "ok", version: VERSION }));
|
|
57704
57768
|
app.post("/execute", async (c) => {
|
|
57705
57769
|
const body = await c.req.json();
|
|
57770
|
+
logger.debug(`[Server] POST /execute runtime=${body.request.runtime} sessionId=${body.sessionId ?? "ephemeral"}`);
|
|
57771
|
+
logger.debug(`[Server] Code length: ${body.request.code.length} chars`);
|
|
57706
57772
|
const engineOptions = {
|
|
57707
57773
|
network: config.defaults.network,
|
|
57708
57774
|
memoryLimit: config.defaults.memoryLimit,
|
|
@@ -57717,36 +57783,45 @@ async function createServer(options) {
|
|
|
57717
57783
|
if (body.sessionId) {
|
|
57718
57784
|
const session = sessions.get(body.sessionId);
|
|
57719
57785
|
if (session) {
|
|
57786
|
+
logger.debug(`[Server] Reusing existing session: ${body.sessionId}`);
|
|
57720
57787
|
engine = session.engine;
|
|
57721
57788
|
session.lastAccessedAt = Date.now();
|
|
57722
57789
|
} else {
|
|
57790
|
+
logger.debug(`[Server] Creating new session: ${body.sessionId}`);
|
|
57723
57791
|
engine = new DockerIsol82(engineOptions, config.maxConcurrent);
|
|
57724
57792
|
await engine.start();
|
|
57725
57793
|
sessions.set(body.sessionId, { engine, lastAccessedAt: Date.now() });
|
|
57726
57794
|
}
|
|
57727
57795
|
} else {
|
|
57796
|
+
logger.debug("[Server] Creating ephemeral engine");
|
|
57728
57797
|
engine = new DockerIsol82(engineOptions, config.maxConcurrent);
|
|
57729
57798
|
await engine.start();
|
|
57730
57799
|
}
|
|
57731
57800
|
try {
|
|
57801
|
+
logger.debug("[Server] Acquiring semaphore for /execute");
|
|
57732
57802
|
await globalSemaphore.acquire();
|
|
57733
57803
|
try {
|
|
57734
57804
|
const result = await engine.execute(body.request);
|
|
57805
|
+
logger.debug(`[Server] Execution completed: exitCode=${result.exitCode} duration=${result.durationMs}ms`);
|
|
57735
57806
|
return c.json(result);
|
|
57736
57807
|
} finally {
|
|
57737
57808
|
globalSemaphore.release();
|
|
57738
57809
|
}
|
|
57739
57810
|
} catch (err) {
|
|
57740
57811
|
const message = err instanceof Error ? err.message : String(err);
|
|
57812
|
+
logger.debug(`[Server] Execution error: ${message}`);
|
|
57741
57813
|
return c.json({ error: message }, 500);
|
|
57742
57814
|
} finally {
|
|
57743
57815
|
if (!body.sessionId) {
|
|
57816
|
+
logger.debug("[Server] Cleaning up ephemeral engine");
|
|
57744
57817
|
await engine.stop();
|
|
57745
57818
|
}
|
|
57746
57819
|
}
|
|
57747
57820
|
});
|
|
57748
57821
|
app.post("/execute/stream", async (c) => {
|
|
57749
57822
|
const body = await c.req.json();
|
|
57823
|
+
logger.debug(`[Server] POST /execute/stream runtime=${body.request.runtime}`);
|
|
57824
|
+
logger.debug(`[Server] Code length: ${body.request.code.length} chars`);
|
|
57750
57825
|
const engineOptions = {
|
|
57751
57826
|
network: config.defaults.network,
|
|
57752
57827
|
memoryLimit: config.defaults.memoryLimit,
|
|
@@ -57763,6 +57838,7 @@ async function createServer(options) {
|
|
|
57763
57838
|
const stream = new ReadableStream({
|
|
57764
57839
|
async start(controller) {
|
|
57765
57840
|
try {
|
|
57841
|
+
logger.debug("[Server] Acquiring semaphore for /execute/stream");
|
|
57766
57842
|
await globalSemaphore.acquire();
|
|
57767
57843
|
try {
|
|
57768
57844
|
for await (const event of engine.executeStream(body.request)) {
|
|
@@ -57771,16 +57847,19 @@ async function createServer(options) {
|
|
|
57771
57847
|
`;
|
|
57772
57848
|
controller.enqueue(encoder.encode(line));
|
|
57773
57849
|
}
|
|
57850
|
+
logger.debug("[Server] Stream completed");
|
|
57774
57851
|
} finally {
|
|
57775
57852
|
globalSemaphore.release();
|
|
57776
57853
|
}
|
|
57777
57854
|
} catch (err) {
|
|
57778
57855
|
const message = err instanceof Error ? err.message : String(err);
|
|
57856
|
+
logger.debug(`[Server] Stream error: ${message}`);
|
|
57779
57857
|
const errorEvent = `data: ${JSON.stringify({ type: "error", data: message })}
|
|
57780
57858
|
|
|
57781
57859
|
`;
|
|
57782
57860
|
controller.enqueue(encoder.encode(errorEvent));
|
|
57783
57861
|
} finally {
|
|
57862
|
+
logger.debug("[Server] Cleaning up stream engine");
|
|
57784
57863
|
await engine.stop();
|
|
57785
57864
|
controller.close();
|
|
57786
57865
|
}
|
|
@@ -57796,35 +57875,45 @@ async function createServer(options) {
|
|
|
57796
57875
|
});
|
|
57797
57876
|
app.post("/file", async (c) => {
|
|
57798
57877
|
const body = await c.req.json();
|
|
57878
|
+
logger.debug(`[Server] POST /file sessionId=${body.sessionId} path=${body.path}`);
|
|
57799
57879
|
const session = sessions.get(body.sessionId);
|
|
57800
57880
|
if (!session) {
|
|
57881
|
+
logger.debug(`[Server] Session not found: ${body.sessionId}`);
|
|
57801
57882
|
return c.json({ error: "Session not found" }, 404);
|
|
57802
57883
|
}
|
|
57803
57884
|
session.lastAccessedAt = Date.now();
|
|
57804
57885
|
const content = Buffer.from(body.content, "base64");
|
|
57805
57886
|
await session.engine.putFile(body.path, content);
|
|
57887
|
+
logger.debug(`[Server] File uploaded: ${body.path} (${content.length} bytes)`);
|
|
57806
57888
|
return c.json({ ok: true });
|
|
57807
57889
|
});
|
|
57808
57890
|
app.get("/file", async (c) => {
|
|
57809
57891
|
const sessionId = c.req.query("sessionId");
|
|
57810
57892
|
const path = c.req.query("path");
|
|
57893
|
+
logger.debug(`[Server] GET /file sessionId=${sessionId} path=${path}`);
|
|
57811
57894
|
if (!(sessionId && path)) {
|
|
57812
57895
|
return c.json({ error: "Missing sessionId or path" }, 400);
|
|
57813
57896
|
}
|
|
57814
57897
|
const session = sessions.get(sessionId);
|
|
57815
57898
|
if (!session) {
|
|
57899
|
+
logger.debug(`[Server] Session not found: ${sessionId}`);
|
|
57816
57900
|
return c.json({ error: "Session not found" }, 404);
|
|
57817
57901
|
}
|
|
57818
57902
|
session.lastAccessedAt = Date.now();
|
|
57819
57903
|
const content = await session.engine.getFile(path);
|
|
57904
|
+
logger.debug(`[Server] File downloaded: ${path} (${content.length} bytes)`);
|
|
57820
57905
|
return c.json({ content: content.toString("base64") });
|
|
57821
57906
|
});
|
|
57822
57907
|
app.delete("/session/:id", async (c) => {
|
|
57823
57908
|
const id = c.req.param("id");
|
|
57909
|
+
logger.debug(`[Server] DELETE /session/${id}`);
|
|
57824
57910
|
const session = sessions.get(id);
|
|
57825
57911
|
if (session) {
|
|
57826
57912
|
await session.engine.stop();
|
|
57827
57913
|
sessions.delete(id);
|
|
57914
|
+
logger.debug(`[Server] Session destroyed: ${id}`);
|
|
57915
|
+
} else {
|
|
57916
|
+
logger.debug(`[Server] Session not found (already cleaned up): ${id}`);
|
|
57828
57917
|
}
|
|
57829
57918
|
return c.json({ ok: true });
|
|
57830
57919
|
});
|
|
@@ -57834,6 +57923,7 @@ async function createServer(options) {
|
|
|
57834
57923
|
const now = Date.now();
|
|
57835
57924
|
for (const [id, session] of sessions) {
|
|
57836
57925
|
if (now - session.lastAccessedAt > maxAge) {
|
|
57926
|
+
logger.debug(`[Server] Auto-pruning stale session: ${id}`);
|
|
57837
57927
|
await session.engine.stop();
|
|
57838
57928
|
sessions.delete(id);
|
|
57839
57929
|
}
|
|
@@ -57850,6 +57940,7 @@ var sessions;
|
|
|
57850
57940
|
var init_server = __esm(() => {
|
|
57851
57941
|
init_dist();
|
|
57852
57942
|
init_config();
|
|
57943
|
+
init_logger();
|
|
57853
57944
|
init_version();
|
|
57854
57945
|
sessions = new Map;
|
|
57855
57946
|
});
|
|
@@ -57857,9 +57948,9 @@ var init_server = __esm(() => {
|
|
|
57857
57948
|
// src/cli.ts
|
|
57858
57949
|
import {
|
|
57859
57950
|
chmodSync,
|
|
57860
|
-
existsSync as
|
|
57951
|
+
existsSync as existsSync4,
|
|
57861
57952
|
mkdirSync,
|
|
57862
|
-
readFileSync as
|
|
57953
|
+
readFileSync as readFileSync3,
|
|
57863
57954
|
renameSync,
|
|
57864
57955
|
unlinkSync,
|
|
57865
57956
|
writeFileSync
|
|
@@ -58462,7 +58553,7 @@ onetime.callCount = (function_) => {
|
|
|
58462
58553
|
};
|
|
58463
58554
|
var onetime_default = onetime;
|
|
58464
58555
|
|
|
58465
|
-
// node_modules/
|
|
58556
|
+
// node_modules/signal-exit/dist/mjs/signals.js
|
|
58466
58557
|
var signals = [];
|
|
58467
58558
|
signals.push("SIGHUP", "SIGINT", "SIGTERM");
|
|
58468
58559
|
if (process.platform !== "win32") {
|
|
@@ -58472,7 +58563,7 @@ if (process.platform === "linux") {
|
|
|
58472
58563
|
signals.push("SIGIO", "SIGPOLL", "SIGPWR", "SIGSTKFLT");
|
|
58473
58564
|
}
|
|
58474
58565
|
|
|
58475
|
-
// node_modules/
|
|
58566
|
+
// node_modules/signal-exit/dist/mjs/index.js
|
|
58476
58567
|
var processOk = (process3) => !!process3 && typeof process3 === "object" && typeof process3.removeListener === "function" && typeof process3.emit === "function" && typeof process3.reallyExit === "function" && typeof process3.listeners === "function" && typeof process3.kill === "function" && typeof process3.pid === "number" && typeof process3.on === "function";
|
|
58477
58568
|
var kExitEmitter = Symbol.for("signal-exit emitter");
|
|
58478
58569
|
var global2 = globalThis;
|
|
@@ -61259,10 +61350,10 @@ init_docker();
|
|
|
61259
61350
|
|
|
61260
61351
|
// src/engine/image-builder.ts
|
|
61261
61352
|
init_runtime();
|
|
61262
|
-
import { existsSync as
|
|
61353
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
61263
61354
|
function resolveDockerDir() {
|
|
61264
61355
|
const fromBundled = new URL("../docker", import.meta.url).pathname;
|
|
61265
|
-
if (
|
|
61356
|
+
if (existsSync3(fromBundled)) {
|
|
61266
61357
|
return fromBundled;
|
|
61267
61358
|
}
|
|
61268
61359
|
return new URL("../../docker", import.meta.url).pathname;
|
|
@@ -61362,15 +61453,26 @@ ${installCmd}
|
|
|
61362
61453
|
|
|
61363
61454
|
// src/cli.ts
|
|
61364
61455
|
init_runtime();
|
|
61456
|
+
init_logger();
|
|
61365
61457
|
init_version();
|
|
61366
61458
|
var program2 = new Command;
|
|
61367
|
-
program2.name("isol8").description("Secure code execution engine").version(VERSION)
|
|
61459
|
+
program2.name("isol8").description("Secure code execution engine").version(VERSION).option("--debug", "Enable debug logging").hook("preAction", (thisCommand) => {
|
|
61460
|
+
const opts = thisCommand.optsWithGlobals();
|
|
61461
|
+
if (opts.debug) {
|
|
61462
|
+
logger.setDebug(true);
|
|
61463
|
+
}
|
|
61464
|
+
logger.debug(`[CLI] Command: ${thisCommand.args?.[0] ?? thisCommand.name()}`);
|
|
61465
|
+
logger.debug(`[CLI] Version: ${VERSION}`);
|
|
61466
|
+
logger.debug(`[CLI] Platform: ${platform()} ${arch()}`);
|
|
61467
|
+
});
|
|
61368
61468
|
program2.command("setup").description("Check Docker and build isol8 images").option("--python <packages>", "Additional Python packages (comma-separated)").option("--node <packages>", "Additional Node.js packages (comma-separated)").option("--bun <packages>", "Additional Bun packages (comma-separated)").option("--deno <packages>", "Additional Deno packages (comma-separated)").option("--bash <packages>", "Additional Bash packages (comma-separated)").action(async (opts) => {
|
|
61369
61469
|
const docker = new import_dockerode2.default;
|
|
61470
|
+
logger.debug("[Setup] Connecting to Docker daemon");
|
|
61370
61471
|
const spinner = ora("Checking Docker...").start();
|
|
61371
61472
|
try {
|
|
61372
61473
|
await docker.ping();
|
|
61373
61474
|
spinner.stopAndPersist({ symbol: "[OK]", text: "Docker is running" });
|
|
61475
|
+
logger.debug("[Setup] Docker ping successful");
|
|
61374
61476
|
} catch {
|
|
61375
61477
|
spinner.stopAndPersist({ symbol: "[ERR]", text: "Docker is not running or not installed." });
|
|
61376
61478
|
console.error(" Install Docker: https://docs.docker.com/get-docker/");
|
|
@@ -61378,11 +61480,14 @@ program2.command("setup").description("Check Docker and build isol8 images").opt
|
|
|
61378
61480
|
process.exit(1);
|
|
61379
61481
|
}
|
|
61380
61482
|
spinner.start("Building isol8 images...");
|
|
61483
|
+
logger.debug("[Setup] Building base images");
|
|
61381
61484
|
await buildBaseImages(docker, (progress) => {
|
|
61382
61485
|
const status = progress.status === "error" ? "[ERR]" : progress.status === "done" ? "[OK]" : "[..]";
|
|
61383
61486
|
if (progress.status === "building") {
|
|
61384
61487
|
spinner.text = `Building ${progress.runtime}...`;
|
|
61488
|
+
logger.debug(`[Setup] Building base image for ${progress.runtime}`);
|
|
61385
61489
|
} else if (progress.status === "done" || progress.status === "error") {
|
|
61490
|
+
logger.debug(`[Setup] Base image ${progress.runtime}: ${progress.status}${progress.message ? ` (${progress.message})` : ""}`);
|
|
61386
61491
|
spinner.stopAndPersist({
|
|
61387
61492
|
symbol: status,
|
|
61388
61493
|
text: `${progress.runtime}${progress.message ? `: ${progress.message}` : ""}`
|
|
@@ -61396,32 +61501,41 @@ program2.command("setup").description("Check Docker and build isol8 images").opt
|
|
|
61396
61501
|
spinner.stop();
|
|
61397
61502
|
}
|
|
61398
61503
|
const config = loadConfig();
|
|
61504
|
+
logger.debug("[Setup] Config loaded");
|
|
61399
61505
|
if (opts.python) {
|
|
61506
|
+
logger.debug(`[Setup] Adding Python packages from CLI: ${opts.python}`);
|
|
61400
61507
|
config.dependencies.python = [
|
|
61401
61508
|
...config.dependencies.python ?? [],
|
|
61402
61509
|
...opts.python.split(",")
|
|
61403
61510
|
];
|
|
61404
61511
|
}
|
|
61405
61512
|
if (opts.node) {
|
|
61513
|
+
logger.debug(`[Setup] Adding Node.js packages from CLI: ${opts.node}`);
|
|
61406
61514
|
config.dependencies.node = [...config.dependencies.node ?? [], ...opts.node.split(",")];
|
|
61407
61515
|
}
|
|
61408
61516
|
if (opts.bun) {
|
|
61517
|
+
logger.debug(`[Setup] Adding Bun packages from CLI: ${opts.bun}`);
|
|
61409
61518
|
config.dependencies.bun = [...config.dependencies.bun ?? [], ...opts.bun.split(",")];
|
|
61410
61519
|
}
|
|
61411
61520
|
if (opts.deno) {
|
|
61521
|
+
logger.debug(`[Setup] Adding Deno packages from CLI: ${opts.deno}`);
|
|
61412
61522
|
config.dependencies.deno = [...config.dependencies.deno ?? [], ...opts.deno.split(",")];
|
|
61413
61523
|
}
|
|
61414
61524
|
if (opts.bash) {
|
|
61525
|
+
logger.debug(`[Setup] Adding Bash packages from CLI: ${opts.bash}`);
|
|
61415
61526
|
config.dependencies.bash = [...config.dependencies.bash ?? [], ...opts.bash.split(",")];
|
|
61416
61527
|
}
|
|
61417
61528
|
const hasDeps = Object.values(config.dependencies).some((pkgs) => pkgs && pkgs.length > 0);
|
|
61418
61529
|
if (hasDeps) {
|
|
61530
|
+
logger.debug("[Setup] Building custom images with dependencies:", JSON.stringify(config.dependencies));
|
|
61419
61531
|
spinner.start("Building custom images with dependencies...");
|
|
61420
61532
|
await buildCustomImages(docker, config, (progress) => {
|
|
61421
61533
|
const status = progress.status === "error" ? "[ERR]" : progress.status === "done" ? "[OK]" : "[..]";
|
|
61422
61534
|
if (progress.status === "building") {
|
|
61423
61535
|
spinner.text = `Building custom ${progress.runtime}...`;
|
|
61536
|
+
logger.debug(`[Setup] Building custom image for ${progress.runtime}`);
|
|
61424
61537
|
} else if (progress.status === "done" || progress.status === "error") {
|
|
61538
|
+
logger.debug(`[Setup] Custom image ${progress.runtime}: ${progress.status}${progress.message ? ` (${progress.message})` : ""}`);
|
|
61425
61539
|
spinner.stopAndPersist({
|
|
61426
61540
|
symbol: status,
|
|
61427
61541
|
text: `${progress.runtime}${progress.message ? ` (${progress.message})` : ""}`
|
|
@@ -61440,6 +61554,22 @@ program2.command("setup").description("Check Docker and build isol8 images").opt
|
|
|
61440
61554
|
});
|
|
61441
61555
|
program2.command("run").description("Execute code in isol8").argument("[file]", "Script file to execute").option("-e, --eval <code>", "Execute inline code string").option("-r, --runtime <name>", "Force runtime (python, node, bun, deno, bash)").option("--net <mode>", "Network mode: none, host, filtered", "none").option("--allow <regex>", "Whitelist regex for filtered mode (repeatable)", collect, []).option("--deny <regex>", "Blacklist regex for filtered mode (repeatable)", collect, []).option("--out <file>", "Write output to file").option("--persistent", "Use persistent container").option("--timeout <ms>", "Execution timeout in milliseconds").option("--memory <limit>", "Memory limit (e.g. 512m, 1g)").option("--cpu <limit>", "CPU limit as fraction (e.g. 0.5, 2.0)").option("--image <name>", "Override Docker image").option("--pids-limit <n>", "Maximum number of processes").option("--writable", "Disable read-only root filesystem").option("--max-output <bytes>", "Maximum output size in bytes").option("--secret <KEY=VALUE>", "Secret env var (repeatable, values masked)", collect, []).option("--sandbox-size <size>", "Sandbox tmpfs size (e.g. 128m)").option("--tmp-size <size>", "Tmp tmpfs size (e.g. 256m, 512m)").option("--stdin <data>", "Data to pipe to stdin").option("--install <package>", "Install package for runtime (repeatable)", collect, []).option("--host <url>", "Execute on remote server").option("--key <key>", "API key for remote server").option("--no-stream", "Disable real-time output streaming").option("--debug", "Enable debug logging").option("--persist", "Keep container running after execution for inspection").action(async (file, opts) => {
|
|
61442
61556
|
const { code, runtime, engineOptions, engine, stdinData, fileExtension } = await resolveRunInput(file, opts);
|
|
61557
|
+
logger.debug(`[Run] Runtime: ${runtime}, mode: ${engineOptions.mode}`);
|
|
61558
|
+
logger.debug(`[Run] Network: ${engineOptions.network}, timeout: ${engineOptions.timeoutMs}ms`);
|
|
61559
|
+
logger.debug(`[Run] Memory: ${engineOptions.memoryLimit}, CPU: ${engineOptions.cpuLimit}`);
|
|
61560
|
+
logger.debug(`[Run] Code length: ${code.length} chars`);
|
|
61561
|
+
if (stdinData) {
|
|
61562
|
+
logger.debug(`[Run] Stdin data provided (${stdinData.length} chars)`);
|
|
61563
|
+
}
|
|
61564
|
+
if (opts.install?.length > 0) {
|
|
61565
|
+
logger.debug(`[Run] Packages to install: ${opts.install.join(", ")}`);
|
|
61566
|
+
}
|
|
61567
|
+
if (opts.host) {
|
|
61568
|
+
logger.debug(`[Run] Remote execution on ${opts.host}`);
|
|
61569
|
+
}
|
|
61570
|
+
if (engineOptions.persist) {
|
|
61571
|
+
logger.debug("[Run] Persist mode enabled");
|
|
61572
|
+
}
|
|
61443
61573
|
const cleanup = async () => {
|
|
61444
61574
|
await engine.stop();
|
|
61445
61575
|
process.exit(0);
|
|
@@ -61450,6 +61580,7 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61450
61580
|
let exitCode = 0;
|
|
61451
61581
|
try {
|
|
61452
61582
|
await engine.start();
|
|
61583
|
+
logger.debug("[Run] Engine started");
|
|
61453
61584
|
spinner.text = "Running code...";
|
|
61454
61585
|
const req = {
|
|
61455
61586
|
code,
|
|
@@ -61460,6 +61591,7 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61460
61591
|
fileExtension
|
|
61461
61592
|
};
|
|
61462
61593
|
if (opts.stream !== false) {
|
|
61594
|
+
logger.debug("[Run] Using streaming mode");
|
|
61463
61595
|
spinner.stop();
|
|
61464
61596
|
const stream = engine.executeStream(req);
|
|
61465
61597
|
for await (const event of stream) {
|
|
@@ -61477,7 +61609,9 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61477
61609
|
}
|
|
61478
61610
|
}
|
|
61479
61611
|
} else {
|
|
61612
|
+
logger.debug("[Run] Using non-streaming mode");
|
|
61480
61613
|
const result = await engine.execute(req);
|
|
61614
|
+
logger.debug(`[Run] Execution completed: exitCode=${result.exitCode}, duration=${result.durationMs}ms, truncated=${result.truncated}`);
|
|
61481
61615
|
spinner.stop();
|
|
61482
61616
|
if (result.stdout) {
|
|
61483
61617
|
console.log(result.stdout);
|
|
@@ -61500,6 +61634,7 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61500
61634
|
spinner.stop();
|
|
61501
61635
|
throw err;
|
|
61502
61636
|
} finally {
|
|
61637
|
+
logger.debug("[Run] Stopping engine");
|
|
61503
61638
|
const cleanupPromise = engine.stop();
|
|
61504
61639
|
const timeoutPromise = new Promise((resolve3) => setTimeout(resolve3, 5000));
|
|
61505
61640
|
await Promise.race([cleanupPromise, timeoutPromise]);
|
|
@@ -61508,24 +61643,33 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61508
61643
|
process.exit(exitCode);
|
|
61509
61644
|
}
|
|
61510
61645
|
});
|
|
61511
|
-
program2.command("serve").description("Start the isol8 remote server").option("-p, --port <port>", "Port to listen on", "3000").option("-k, --key <key>", "API key for authentication").option("--update", "Force re-download the server binary").action(async (opts) => {
|
|
61646
|
+
program2.command("serve").description("Start the isol8 remote server").option("-p, --port <port>", "Port to listen on", "3000").option("-k, --key <key>", "API key for authentication").option("--update", "Force re-download the server binary").option("--debug", "Enable debug logging").action(async (opts) => {
|
|
61512
61647
|
const apiKey = opts.key ?? process.env.ISOL8_API_KEY;
|
|
61513
61648
|
if (!apiKey) {
|
|
61514
61649
|
console.error("[ERR] API key required. Use --key or ISOL8_API_KEY env var.");
|
|
61515
61650
|
process.exit(1);
|
|
61516
61651
|
}
|
|
61517
61652
|
const port = Number.parseInt(opts.port, 10);
|
|
61653
|
+
logger.debug(`[Serve] Port: ${port}`);
|
|
61654
|
+
logger.debug(`[Serve] API key: ${"*".repeat(apiKey.length)}`);
|
|
61518
61655
|
if (typeof globalThis.Bun !== "undefined") {
|
|
61656
|
+
logger.debug("[Serve] Running under Bun, starting server in-process");
|
|
61519
61657
|
const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), exports_server));
|
|
61520
|
-
const server = await createServer2({ port, apiKey });
|
|
61658
|
+
const server = await createServer2({ port, apiKey, debug: opts.debug ?? false });
|
|
61521
61659
|
console.log(`[INFO] isol8 server v${VERSION} listening on http://localhost:${port}`);
|
|
61522
61660
|
console.log(" Auth: Bearer token required");
|
|
61523
61661
|
Bun.serve({ fetch: server.app.fetch, port });
|
|
61524
61662
|
return;
|
|
61525
61663
|
}
|
|
61664
|
+
logger.debug("[Serve] Running under Node.js, launching standalone binary");
|
|
61526
61665
|
const binaryPath = await ensureServerBinary(opts.update ?? false);
|
|
61666
|
+
logger.debug(`[Serve] Binary path: ${binaryPath}`);
|
|
61527
61667
|
const { spawn: spawnChild } = await import("node:child_process");
|
|
61528
|
-
const
|
|
61668
|
+
const binaryArgs = ["--port", String(port), "--key", apiKey];
|
|
61669
|
+
if (opts.debug) {
|
|
61670
|
+
binaryArgs.push("--debug");
|
|
61671
|
+
}
|
|
61672
|
+
const child = spawnChild(binaryPath, binaryArgs, {
|
|
61529
61673
|
stdio: "inherit"
|
|
61530
61674
|
});
|
|
61531
61675
|
const forwardSignal = (signal) => {
|
|
@@ -61540,6 +61684,7 @@ program2.command("serve").description("Start the isol8 remote server").option("-
|
|
|
61540
61684
|
function getServerBinaryName() {
|
|
61541
61685
|
const os2 = platform();
|
|
61542
61686
|
const cpu = arch();
|
|
61687
|
+
logger.debug(`[Serve] Resolving binary name for ${os2}-${cpu}`);
|
|
61543
61688
|
const osMap = {
|
|
61544
61689
|
darwin: "darwin",
|
|
61545
61690
|
linux: "linux",
|
|
@@ -61560,7 +61705,8 @@ function getServerBinaryName() {
|
|
|
61560
61705
|
return `isol8-server-${resolvedOs}-${resolvedArch}`;
|
|
61561
61706
|
}
|
|
61562
61707
|
async function getServerBinaryVersion(binaryPath) {
|
|
61563
|
-
if (!
|
|
61708
|
+
if (!existsSync4(binaryPath)) {
|
|
61709
|
+
logger.debug(`[Serve] No binary found at ${binaryPath}`);
|
|
61564
61710
|
return null;
|
|
61565
61711
|
}
|
|
61566
61712
|
try {
|
|
@@ -61569,14 +61715,17 @@ async function getServerBinaryVersion(binaryPath) {
|
|
|
61569
61715
|
encoding: "utf-8",
|
|
61570
61716
|
timeout: 5000
|
|
61571
61717
|
});
|
|
61718
|
+
logger.debug(`[Serve] Existing binary version: ${output.trim()}`);
|
|
61572
61719
|
return output.trim();
|
|
61573
61720
|
} catch {
|
|
61721
|
+
logger.debug("[Serve] Failed to get binary version");
|
|
61574
61722
|
return null;
|
|
61575
61723
|
}
|
|
61576
61724
|
}
|
|
61577
61725
|
async function downloadServerBinary(binaryPath) {
|
|
61578
61726
|
const binaryName = getServerBinaryName();
|
|
61579
61727
|
const url = `https://github.com/Illusion47586/isol8/releases/download/v${VERSION}/${binaryName}`;
|
|
61728
|
+
logger.debug(`[Serve] Download URL: ${url}`);
|
|
61580
61729
|
const spinner = ora(`Downloading isol8 server v${VERSION}...`).start();
|
|
61581
61730
|
try {
|
|
61582
61731
|
const response = await fetch(url, { redirect: "follow" });
|
|
@@ -61596,11 +61745,12 @@ async function downloadServerBinary(binaryPath) {
|
|
|
61596
61745
|
writeFileSync(tmpPath, buffer);
|
|
61597
61746
|
chmodSync(tmpPath, 493);
|
|
61598
61747
|
renameSync(tmpPath, binaryPath);
|
|
61748
|
+
logger.debug(`[Serve] Binary saved to ${binaryPath} (${buffer.length} bytes)`);
|
|
61599
61749
|
spinner.succeed(`Downloaded isol8 server v${VERSION}`);
|
|
61600
61750
|
} catch (err) {
|
|
61601
61751
|
spinner.fail("Failed to download server binary");
|
|
61602
61752
|
const tmpPath = `${binaryPath}.tmp`;
|
|
61603
|
-
if (
|
|
61753
|
+
if (existsSync4(tmpPath)) {
|
|
61604
61754
|
unlinkSync(tmpPath);
|
|
61605
61755
|
}
|
|
61606
61756
|
throw err;
|
|
@@ -61622,18 +61772,23 @@ async function promptYesNo(question) {
|
|
|
61622
61772
|
async function ensureServerBinary(forceUpdate) {
|
|
61623
61773
|
const binDir = join2(homedir2(), ".isol8", "bin");
|
|
61624
61774
|
const binaryPath = join2(binDir, "isol8-server");
|
|
61775
|
+
logger.debug(`[Serve] Binary path: ${binaryPath}, forceUpdate: ${forceUpdate}`);
|
|
61625
61776
|
if (forceUpdate) {
|
|
61777
|
+
logger.debug("[Serve] Force update requested");
|
|
61626
61778
|
await downloadServerBinary(binaryPath);
|
|
61627
61779
|
return binaryPath;
|
|
61628
61780
|
}
|
|
61629
61781
|
const existingVersion = await getServerBinaryVersion(binaryPath);
|
|
61630
61782
|
if (existingVersion === null) {
|
|
61783
|
+
logger.debug("[Serve] No existing binary, downloading");
|
|
61631
61784
|
await downloadServerBinary(binaryPath);
|
|
61632
61785
|
return binaryPath;
|
|
61633
61786
|
}
|
|
61634
61787
|
if (existingVersion === VERSION) {
|
|
61788
|
+
logger.debug(`[Serve] Binary version ${existingVersion} matches CLI`);
|
|
61635
61789
|
return binaryPath;
|
|
61636
61790
|
}
|
|
61791
|
+
logger.debug(`[Serve] Version mismatch: binary=${existingVersion}, CLI=${VERSION}`);
|
|
61637
61792
|
console.log(`Server binary v${existingVersion} found, but CLI is v${VERSION}.`);
|
|
61638
61793
|
const shouldUpdate = await promptYesNo("Download updated binary? [Y/n] ");
|
|
61639
61794
|
if (shouldUpdate) {
|
|
@@ -61649,7 +61804,9 @@ program2.command("config").description("Show the resolved isol8 configuration").
|
|
|
61649
61804
|
join2(resolve2(process.cwd()), "isol8.config.json"),
|
|
61650
61805
|
join2(homedir2(), ".isol8", "config.json")
|
|
61651
61806
|
];
|
|
61652
|
-
const loadedFrom = searchPaths.find((p) =>
|
|
61807
|
+
const loadedFrom = searchPaths.find((p) => existsSync4(p));
|
|
61808
|
+
logger.debug(`[Config] Config source: ${loadedFrom ?? "defaults"}`);
|
|
61809
|
+
logger.debug(`[Config] Resolved config: ${JSON.stringify(config)}`);
|
|
61653
61810
|
if (opts.json) {
|
|
61654
61811
|
console.log(JSON.stringify(config, null, 2));
|
|
61655
61812
|
return;
|
|
@@ -61713,10 +61870,12 @@ Isol8 Configuration
|
|
|
61713
61870
|
});
|
|
61714
61871
|
program2.command("cleanup").description("Remove orphaned isol8 containers").option("--force", "Skip confirmation prompt").action(async (opts) => {
|
|
61715
61872
|
const docker = new import_dockerode2.default;
|
|
61873
|
+
logger.debug("[Cleanup] Connecting to Docker daemon");
|
|
61716
61874
|
const spinner = ora("Checking Docker...").start();
|
|
61717
61875
|
try {
|
|
61718
61876
|
await docker.ping();
|
|
61719
61877
|
spinner.succeed("Docker is running");
|
|
61878
|
+
logger.debug("[Cleanup] Docker ping successful");
|
|
61720
61879
|
} catch {
|
|
61721
61880
|
spinner.fail("Docker is not running or not installed.");
|
|
61722
61881
|
process.exit(1);
|
|
@@ -61724,6 +61883,7 @@ program2.command("cleanup").description("Remove orphaned isol8 containers").opti
|
|
|
61724
61883
|
spinner.start("Finding isol8 containers...");
|
|
61725
61884
|
const containers = await docker.listContainers({ all: true });
|
|
61726
61885
|
const isol8Containers = containers.filter((c) => c.Image.startsWith("isol8:") || c.Image.startsWith("isol8-custom:"));
|
|
61886
|
+
logger.debug(`[Cleanup] Found ${containers.length} total containers, ${isol8Containers.length} isol8 containers`);
|
|
61727
61887
|
if (isol8Containers.length === 0) {
|
|
61728
61888
|
spinner.info("No isol8 containers found");
|
|
61729
61889
|
return;
|
|
@@ -61752,7 +61912,9 @@ program2.command("cleanup").description("Remove orphaned isol8 containers").opti
|
|
|
61752
61912
|
}
|
|
61753
61913
|
}
|
|
61754
61914
|
spinner.start("Removing containers...");
|
|
61915
|
+
logger.debug("[Cleanup] Removing containers");
|
|
61755
61916
|
const result = await DockerIsol8.cleanup(docker);
|
|
61917
|
+
logger.debug(`[Cleanup] Removed: ${result.removed}, failed: ${result.failed}`);
|
|
61756
61918
|
if (result.errors.length > 0) {
|
|
61757
61919
|
console.log("");
|
|
61758
61920
|
for (const err of result.errors) {
|
|
@@ -61767,29 +61929,35 @@ program2.command("cleanup").description("Remove orphaned isol8 containers").opti
|
|
|
61767
61929
|
});
|
|
61768
61930
|
async function resolveRunInput(file, opts) {
|
|
61769
61931
|
const config = loadConfig();
|
|
61932
|
+
logger.debug("[Run] Config loaded");
|
|
61770
61933
|
let code;
|
|
61771
61934
|
let runtime;
|
|
61772
61935
|
if (opts.eval) {
|
|
61773
61936
|
code = opts.eval;
|
|
61774
61937
|
runtime = opts.runtime ?? "python";
|
|
61938
|
+
logger.debug(`[Run] Inline eval, runtime: ${runtime}`);
|
|
61775
61939
|
} else if (file) {
|
|
61776
61940
|
const filePath = resolve2(file);
|
|
61777
|
-
|
|
61941
|
+
logger.debug(`[Run] Reading file: ${filePath}`);
|
|
61942
|
+
if (!existsSync4(filePath)) {
|
|
61778
61943
|
console.error(`[ERR] File not found: ${file}`);
|
|
61779
61944
|
process.exit(1);
|
|
61780
61945
|
}
|
|
61781
|
-
code =
|
|
61946
|
+
code = readFileSync3(filePath, "utf-8");
|
|
61782
61947
|
if (opts.runtime) {
|
|
61783
61948
|
runtime = opts.runtime;
|
|
61949
|
+
logger.debug(`[Run] Runtime specified: ${runtime}`);
|
|
61784
61950
|
} else {
|
|
61785
61951
|
try {
|
|
61786
61952
|
runtime = RuntimeRegistry.detect(file).name;
|
|
61953
|
+
logger.debug(`[Run] Auto-detected runtime: ${runtime}`);
|
|
61787
61954
|
} catch {
|
|
61788
61955
|
console.error(`[ERR] Cannot detect runtime for ${file}. Use --runtime to specify.`);
|
|
61789
61956
|
process.exit(1);
|
|
61790
61957
|
}
|
|
61791
61958
|
}
|
|
61792
61959
|
} else {
|
|
61960
|
+
logger.debug("[Run] Reading code from stdin");
|
|
61793
61961
|
const chunks = [];
|
|
61794
61962
|
for await (const chunk of process.stdin) {
|
|
61795
61963
|
chunks.push(chunk);
|
|
@@ -61815,10 +61983,7 @@ async function resolveRunInput(file, opts) {
|
|
|
61815
61983
|
debug: opts.debug ?? config.debug,
|
|
61816
61984
|
persist: opts.persist ?? false
|
|
61817
61985
|
};
|
|
61818
|
-
|
|
61819
|
-
const { logger: logger2 } = await Promise.resolve().then(() => (init_logger(), exports_logger));
|
|
61820
|
-
logger2.setDebug(true);
|
|
61821
|
-
}
|
|
61986
|
+
logger.debug(`[Run] Engine options: mode=${engineOptions.mode}, network=${engineOptions.network}`);
|
|
61822
61987
|
let fileExtension;
|
|
61823
61988
|
if (file) {
|
|
61824
61989
|
const ext = file.substring(file.lastIndexOf("."));
|
|
@@ -61839,6 +62004,7 @@ async function resolveRunInput(file, opts) {
|
|
|
61839
62004
|
const stdinData = opts.stdin ?? undefined;
|
|
61840
62005
|
let engine;
|
|
61841
62006
|
if (opts.host) {
|
|
62007
|
+
logger.debug(`[Run] Using remote engine: ${opts.host}`);
|
|
61842
62008
|
const apiKey = opts.key ?? process.env.ISOL8_API_KEY;
|
|
61843
62009
|
if (!apiKey) {
|
|
61844
62010
|
console.error("[ERR] API key required. Use --key or ISOL8_API_KEY env var.");
|
|
@@ -61846,6 +62012,7 @@ async function resolveRunInput(file, opts) {
|
|
|
61846
62012
|
}
|
|
61847
62013
|
engine = new RemoteIsol8({ host: opts.host, apiKey, sessionId: opts.persistent ? `cli-${Date.now()}` : undefined }, engineOptions);
|
|
61848
62014
|
} else {
|
|
62015
|
+
logger.debug("[Run] Using local Docker engine");
|
|
61849
62016
|
engine = new DockerIsol8(engineOptions, config.maxConcurrent);
|
|
61850
62017
|
}
|
|
61851
62018
|
return { code, runtime, engineOptions, engine, stdinData, fileExtension };
|
|
@@ -61859,4 +62026,4 @@ if (!process.argv.slice(2).length) {
|
|
|
61859
62026
|
}
|
|
61860
62027
|
program2.parse();
|
|
61861
62028
|
|
|
61862
|
-
//# debugId=
|
|
62029
|
+
//# debugId=F86C7DBAE803AC0664756E2164756E21
|