isol8 0.4.2 → 0.5.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 +5 -2
- package/dist/cli.js +104 -23
- package/dist/cli.js.map +11 -10
- package/dist/index.js +67 -17
- package/dist/index.js.map +10 -9
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/engine/docker.d.ts +1 -0
- package/dist/src/engine/docker.d.ts.map +1 -1
- package/dist/src/engine/pool.d.ts.map +1 -1
- package/dist/src/runtime/adapter.d.ts +4 -1
- package/dist/src/runtime/adapter.d.ts.map +1 -1
- package/dist/src/types.d.ts +17 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/logger.d.ts +32 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/sshcrypto-0209sx47.node +0 -0
- package/package.json +1 -1
- package/schema/isol8.config.schema.json +5 -0
package/README.md
CHANGED
|
@@ -11,8 +11,9 @@ Secure code execution engine for AI agents. Run untrusted Python, Node.js, Bun,
|
|
|
11
11
|
- **Security first** — read-only rootfs, `no-new-privileges`, PID/memory/CPU limits
|
|
12
12
|
- **Network control** — `none` (default), `host`, or `filtered` (HTTP/HTTPS proxy with regex whitelist/blacklist)
|
|
13
13
|
- **File I/O** — upload files into and download files from sandboxes
|
|
14
|
-
-
|
|
15
|
-
-
|
|
14
|
+
- **Runtime packages** — install pip/npm/bun packages on-the-fly (`--install`)
|
|
15
|
+
- **Modern Node.js** — defaults to ESM (`.mjs`), supports CommonJS (`.cjs`)
|
|
16
|
+
- **Secret masking** — environment variables are scrubbed from output
|
|
16
17
|
- **Output truncation** — prevents runaway stdout (default 1MB cap)
|
|
17
18
|
- **Remote mode** — run an HTTP server and execute from anywhere
|
|
18
19
|
- **Embeddable** — use as a TypeScript library in your own project
|
|
@@ -103,6 +104,8 @@ isol8 run script.py --host http://server:3000 --key my-api-key
|
|
|
103
104
|
| `--out <file>` | Write stdout to file | — |
|
|
104
105
|
| `--no-stream` | Disable real-time output streaming | `false` |
|
|
105
106
|
| `--persistent` | Keep container alive between runs | `false` |
|
|
107
|
+
| `--persist` | Keep container after execution for inspection/debugging | `false` |
|
|
108
|
+
| `--debug` | Enable debug logging for internal engine operations | `false` |
|
|
106
109
|
| `--timeout <ms>` | Execution timeout in milliseconds | `30000` |
|
|
107
110
|
| `--memory <limit>` | Memory limit (e.g. `512m`, `1g`) | `512m` |
|
|
108
111
|
| `--cpu <limit>` | CPU limit as fraction (e.g. `0.5`, `2.0`) | `1.0` |
|
package/dist/cli.js
CHANGED
|
@@ -6929,6 +6929,11 @@ var require_utils2 = __commonJS((exports, module) => {
|
|
|
6929
6929
|
};
|
|
6930
6930
|
});
|
|
6931
6931
|
|
|
6932
|
+
// node_modules/ssh2/lib/protocol/crypto/build/Release/sshcrypto.node
|
|
6933
|
+
var require_sshcrypto = __commonJS((exports, module) => {
|
|
6934
|
+
module.exports = __require("./sshcrypto-0209sx47.node");
|
|
6935
|
+
});
|
|
6936
|
+
|
|
6932
6937
|
// node_modules/ssh2/lib/protocol/crypto/poly1305.js
|
|
6933
6938
|
var require_poly1305 = __commonJS((exports, module) => {
|
|
6934
6939
|
var __dirname = "/home/runner/work/isol8/isol8/node_modules/ssh2/lib/protocol/crypto", __filename = "/home/runner/work/isol8/isol8/node_modules/ssh2/lib/protocol/crypto/poly1305.js";
|
|
@@ -7415,7 +7420,7 @@ var require_crypto = __commonJS((exports, module) => {
|
|
|
7415
7420
|
var ChaChaPolyDecipher;
|
|
7416
7421
|
var GenericDecipher;
|
|
7417
7422
|
try {
|
|
7418
|
-
binding = (
|
|
7423
|
+
binding = require_sshcrypto();
|
|
7419
7424
|
({
|
|
7420
7425
|
AESGCMCipher,
|
|
7421
7426
|
ChaChaPolyCipher,
|
|
@@ -54793,7 +54798,8 @@ function mergeConfig(defaults, overrides) {
|
|
|
54793
54798
|
dependencies: {
|
|
54794
54799
|
...defaults.dependencies,
|
|
54795
54800
|
...overrides.dependencies
|
|
54796
|
-
}
|
|
54801
|
+
},
|
|
54802
|
+
debug: overrides.debug ?? defaults.debug
|
|
54797
54803
|
};
|
|
54798
54804
|
}
|
|
54799
54805
|
var DEFAULT_CONFIG;
|
|
@@ -54816,7 +54822,8 @@ var init_config = __esm(() => {
|
|
|
54816
54822
|
autoPrune: true,
|
|
54817
54823
|
maxContainerAgeMs: 3600000
|
|
54818
54824
|
},
|
|
54819
|
-
dependencies: {}
|
|
54825
|
+
dependencies: {},
|
|
54826
|
+
debug: false
|
|
54820
54827
|
};
|
|
54821
54828
|
});
|
|
54822
54829
|
|
|
@@ -54826,9 +54833,12 @@ var init_adapter = __esm(() => {
|
|
|
54826
54833
|
adapters = new Map;
|
|
54827
54834
|
extensionMap = new Map;
|
|
54828
54835
|
RuntimeRegistry = {
|
|
54829
|
-
register(adapter) {
|
|
54836
|
+
register(adapter, aliases = []) {
|
|
54830
54837
|
adapters.set(adapter.name, adapter);
|
|
54831
54838
|
extensionMap.set(adapter.getFileExtension(), adapter);
|
|
54839
|
+
for (const ext of aliases) {
|
|
54840
|
+
extensionMap.set(ext, adapter);
|
|
54841
|
+
}
|
|
54832
54842
|
},
|
|
54833
54843
|
get(name) {
|
|
54834
54844
|
const adapter = adapters.get(name);
|
|
@@ -54926,7 +54936,7 @@ var init_node = __esm(() => {
|
|
|
54926
54936
|
return ["node", "-e", code];
|
|
54927
54937
|
},
|
|
54928
54938
|
getFileExtension() {
|
|
54929
|
-
return ".
|
|
54939
|
+
return ".mjs";
|
|
54930
54940
|
}
|
|
54931
54941
|
};
|
|
54932
54942
|
});
|
|
@@ -54964,12 +54974,43 @@ var init_runtime = __esm(() => {
|
|
|
54964
54974
|
init_node();
|
|
54965
54975
|
init_python();
|
|
54966
54976
|
RuntimeRegistry.register(PythonAdapter);
|
|
54967
|
-
RuntimeRegistry.register(NodeAdapter);
|
|
54977
|
+
RuntimeRegistry.register(NodeAdapter, [".js", ".cjs"]);
|
|
54968
54978
|
RuntimeRegistry.register(BunAdapter);
|
|
54969
54979
|
RuntimeRegistry.register(bashAdapter);
|
|
54970
54980
|
RuntimeRegistry.register(DenoAdapter);
|
|
54971
54981
|
});
|
|
54972
54982
|
|
|
54983
|
+
// src/utils/logger.ts
|
|
54984
|
+
var exports_logger = {};
|
|
54985
|
+
__export(exports_logger, {
|
|
54986
|
+
logger: () => logger
|
|
54987
|
+
});
|
|
54988
|
+
|
|
54989
|
+
class Logger {
|
|
54990
|
+
debugMode = false;
|
|
54991
|
+
setDebug(enabled) {
|
|
54992
|
+
this.debugMode = enabled;
|
|
54993
|
+
}
|
|
54994
|
+
debug(...args) {
|
|
54995
|
+
if (this.debugMode) {
|
|
54996
|
+
console.log("[DEBUG]", ...args);
|
|
54997
|
+
}
|
|
54998
|
+
}
|
|
54999
|
+
info(...args) {
|
|
55000
|
+
console.log(...args);
|
|
55001
|
+
}
|
|
55002
|
+
warn(...args) {
|
|
55003
|
+
console.warn("[WARN]", ...args);
|
|
55004
|
+
}
|
|
55005
|
+
error(...args) {
|
|
55006
|
+
console.error("[ERROR]", ...args);
|
|
55007
|
+
}
|
|
55008
|
+
}
|
|
55009
|
+
var logger;
|
|
55010
|
+
var init_logger = __esm(() => {
|
|
55011
|
+
logger = new Logger;
|
|
55012
|
+
});
|
|
55013
|
+
|
|
54973
55014
|
// src/engine/concurrency.ts
|
|
54974
55015
|
class Semaphore {
|
|
54975
55016
|
max;
|
|
@@ -55078,26 +55119,32 @@ class ContainerPool {
|
|
|
55078
55119
|
...this.createOptions,
|
|
55079
55120
|
Image: image
|
|
55080
55121
|
});
|
|
55122
|
+
logger.debug(`[Pool] Container ${container.id} created for image: ${image}`);
|
|
55081
55123
|
await container.start();
|
|
55124
|
+
logger.debug(`[Pool] Container ${container.id} started`);
|
|
55082
55125
|
return container;
|
|
55083
55126
|
}
|
|
55084
55127
|
replenish(image) {
|
|
55085
55128
|
if (this.replenishing.has(image)) {
|
|
55129
|
+
logger.debug(`[Pool] Replenishment for ${image} already in progress`);
|
|
55086
55130
|
return;
|
|
55087
55131
|
}
|
|
55088
55132
|
this.replenishing.add(image);
|
|
55133
|
+
logger.debug(`[Pool] Starting background replenishment for image: ${image}`);
|
|
55089
55134
|
const promise = this.createContainer(image).then((container) => {
|
|
55090
55135
|
const pool = this.pools.get(image) ?? [];
|
|
55091
55136
|
if (pool.length < this.poolSize) {
|
|
55092
55137
|
pool.push({ container, createdAt: Date.now() });
|
|
55093
55138
|
this.pools.set(image, pool);
|
|
55139
|
+
logger.debug(`[Pool] Replenished container ${container.id} added to pool for ${image}. Pool size: ${pool.length}`);
|
|
55094
55140
|
} else {
|
|
55141
|
+
logger.debug(`[Pool] Replenished container ${container.id} not needed (pool for ${image} is full), destroying`);
|
|
55095
55142
|
container.remove({ force: true }).catch((err) => {
|
|
55096
|
-
|
|
55143
|
+
logger.error(`[Pool] Error destroying unneeded replenished container ${container.id}:`, err);
|
|
55097
55144
|
});
|
|
55098
55145
|
}
|
|
55099
55146
|
}).catch((err) => {
|
|
55100
|
-
|
|
55147
|
+
logger.error(`[Pool] Error during replenishment for ${image}:`, err);
|
|
55101
55148
|
}).finally(() => {
|
|
55102
55149
|
this.replenishing.delete(image);
|
|
55103
55150
|
this.pendingReplenishments.delete(promise);
|
|
@@ -55105,6 +55152,9 @@ class ContainerPool {
|
|
|
55105
55152
|
this.pendingReplenishments.add(promise);
|
|
55106
55153
|
}
|
|
55107
55154
|
}
|
|
55155
|
+
var init_pool = __esm(() => {
|
|
55156
|
+
init_logger();
|
|
55157
|
+
});
|
|
55108
55158
|
|
|
55109
55159
|
// src/engine/utils.ts
|
|
55110
55160
|
var exports_utils = {};
|
|
@@ -55301,7 +55351,7 @@ function getInstallCommand(runtime, packages) {
|
|
|
55301
55351
|
}
|
|
55302
55352
|
async function installPackages(container, runtime, packages) {
|
|
55303
55353
|
const cmd = getInstallCommand(runtime, packages);
|
|
55304
|
-
|
|
55354
|
+
logger.debug(`Installing packages: ${JSON.stringify(cmd)}`);
|
|
55305
55355
|
const env2 = [
|
|
55306
55356
|
"PATH=/sandbox/.local/bin:/sandbox/.npm-global/bin:/sandbox/.bun-global/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
|
|
55307
55357
|
];
|
|
@@ -55365,6 +55415,7 @@ class DockerIsol8 {
|
|
|
55365
55415
|
semaphore;
|
|
55366
55416
|
sandboxSize;
|
|
55367
55417
|
tmpSize;
|
|
55418
|
+
persist;
|
|
55368
55419
|
container = null;
|
|
55369
55420
|
persistentRuntime = null;
|
|
55370
55421
|
pool = null;
|
|
@@ -55384,6 +55435,10 @@ class DockerIsol8 {
|
|
|
55384
55435
|
this.semaphore = new Semaphore(maxConcurrent);
|
|
55385
55436
|
this.sandboxSize = options.sandboxSize ?? "512m";
|
|
55386
55437
|
this.tmpSize = options.tmpSize ?? "256m";
|
|
55438
|
+
this.persist = options.persist ?? false;
|
|
55439
|
+
if (options.debug) {
|
|
55440
|
+
logger.setDebug(true);
|
|
55441
|
+
}
|
|
55387
55442
|
}
|
|
55388
55443
|
async start() {}
|
|
55389
55444
|
async stop() {
|
|
@@ -55459,7 +55514,8 @@ class DockerIsol8 {
|
|
|
55459
55514
|
if (this.network === "filtered") {
|
|
55460
55515
|
await startProxy(container, this.networkFilter);
|
|
55461
55516
|
}
|
|
55462
|
-
const
|
|
55517
|
+
const ext = req.fileExtension ?? adapter.getFileExtension();
|
|
55518
|
+
const filePath = `${SANDBOX_WORKDIR}/main${ext}`;
|
|
55463
55519
|
await writeFileViaExec(container, filePath, req.code);
|
|
55464
55520
|
if (req.installPackages?.length) {
|
|
55465
55521
|
await installPackages(container, req.runtime, req.installPackages);
|
|
@@ -55490,9 +55546,13 @@ class DockerIsol8 {
|
|
|
55490
55546
|
const execStream = await exec.start({ Tty: false });
|
|
55491
55547
|
yield* this.streamExecOutput(execStream, exec, container, timeoutMs);
|
|
55492
55548
|
} finally {
|
|
55493
|
-
|
|
55494
|
-
|
|
55495
|
-
}
|
|
55549
|
+
if (this.persist) {
|
|
55550
|
+
logger.debug(`[Persist] Leaving container running for inspection: ${container.id}`);
|
|
55551
|
+
} else {
|
|
55552
|
+
try {
|
|
55553
|
+
await container.remove({ force: true });
|
|
55554
|
+
} catch {}
|
|
55555
|
+
}
|
|
55496
55556
|
}
|
|
55497
55557
|
} finally {
|
|
55498
55558
|
this.semaphore.release();
|
|
@@ -55533,7 +55593,8 @@ class DockerIsol8 {
|
|
|
55533
55593
|
if (this.network === "filtered") {
|
|
55534
55594
|
await startProxy(container, this.networkFilter);
|
|
55535
55595
|
}
|
|
55536
|
-
const
|
|
55596
|
+
const ext = req.fileExtension ?? adapter.getFileExtension();
|
|
55597
|
+
const filePath = `${SANDBOX_WORKDIR}/main${ext}`;
|
|
55537
55598
|
await writeFileViaExec(container, filePath, req.code);
|
|
55538
55599
|
if (req.installPackages?.length) {
|
|
55539
55600
|
await installPackages(container, req.runtime, req.installPackages);
|
|
@@ -55579,7 +55640,11 @@ class DockerIsol8 {
|
|
|
55579
55640
|
...req.outputPaths ? { files: await this.retrieveFiles(container, req.outputPaths) } : {}
|
|
55580
55641
|
};
|
|
55581
55642
|
} finally {
|
|
55582
|
-
|
|
55643
|
+
if (this.persist) {
|
|
55644
|
+
logger.debug(`[Persist] Leaving container running for inspection: ${container.id}`);
|
|
55645
|
+
} else {
|
|
55646
|
+
await this.pool.release(container, image);
|
|
55647
|
+
}
|
|
55583
55648
|
}
|
|
55584
55649
|
}
|
|
55585
55650
|
async executePersistent(req) {
|
|
@@ -55590,7 +55655,8 @@ class DockerIsol8 {
|
|
|
55590
55655
|
} else if (this.persistentRuntime?.name !== adapter.name) {
|
|
55591
55656
|
throw new Error(`Cannot switch runtime from "${this.persistentRuntime?.name}" to "${adapter.name}". Each persistent container supports a single runtime. Create a new Isol8 instance for a different runtime.`);
|
|
55592
55657
|
}
|
|
55593
|
-
const
|
|
55658
|
+
const ext = req.fileExtension ?? adapter.getFileExtension();
|
|
55659
|
+
const filePath = `${SANDBOX_WORKDIR}/exec_${Date.now()}${ext}`;
|
|
55594
55660
|
if (this.readonlyRootFs) {
|
|
55595
55661
|
await writeFileViaExec(this.container, filePath, req.code);
|
|
55596
55662
|
} else {
|
|
@@ -55878,6 +55944,8 @@ class DockerIsol8 {
|
|
|
55878
55944
|
var import_dockerode, SANDBOX_WORKDIR = "/sandbox", MAX_OUTPUT_BYTES, PROXY_PORT = 8118, PROXY_STARTUP_TIMEOUT_MS = 5000, PROXY_POLL_INTERVAL_MS = 100;
|
|
55879
55945
|
var init_docker = __esm(() => {
|
|
55880
55946
|
init_runtime();
|
|
55947
|
+
init_logger();
|
|
55948
|
+
init_pool();
|
|
55881
55949
|
import_dockerode = __toESM(require_docker(), 1);
|
|
55882
55950
|
MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
55883
55951
|
});
|
|
@@ -61220,8 +61288,8 @@ program2.command("setup").description("Check Docker and build isol8 images").opt
|
|
|
61220
61288
|
console.log(`
|
|
61221
61289
|
[DONE] Setup complete!`);
|
|
61222
61290
|
});
|
|
61223
|
-
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").action(async (file, opts) => {
|
|
61224
|
-
const { code, runtime, engineOptions, engine, stdinData } = await resolveRunInput(file, opts);
|
|
61291
|
+
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) => {
|
|
61292
|
+
const { code, runtime, engineOptions, engine, stdinData, fileExtension } = await resolveRunInput(file, opts);
|
|
61225
61293
|
const cleanup = async () => {
|
|
61226
61294
|
await engine.stop();
|
|
61227
61295
|
process.exit(0);
|
|
@@ -61238,7 +61306,8 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61238
61306
|
runtime,
|
|
61239
61307
|
timeoutMs: engineOptions.timeoutMs,
|
|
61240
61308
|
...stdinData ? { stdin: stdinData } : {},
|
|
61241
|
-
...opts.install.length > 0 ? { installPackages: opts.install } : {}
|
|
61309
|
+
...opts.install.length > 0 ? { installPackages: opts.install } : {},
|
|
61310
|
+
fileExtension
|
|
61242
61311
|
};
|
|
61243
61312
|
if (opts.stream !== false) {
|
|
61244
61313
|
spinner.stop();
|
|
@@ -61480,9 +61549,21 @@ async function resolveRunInput(file, opts) {
|
|
|
61480
61549
|
...opts.pidsLimit ? { pidsLimit: Number.parseInt(opts.pidsLimit, 10) } : {},
|
|
61481
61550
|
...opts.writable ? { readonlyRootFs: false } : {},
|
|
61482
61551
|
...opts.maxOutput ? { maxOutputSize: Number.parseInt(opts.maxOutput, 10) } : {},
|
|
61483
|
-
...opts.
|
|
61484
|
-
|
|
61552
|
+
...opts.tmpSize ? { tmpSize: opts.tmpSize } : {},
|
|
61553
|
+
debug: opts.debug ?? config.debug,
|
|
61554
|
+
persist: opts.persist ?? false
|
|
61485
61555
|
};
|
|
61556
|
+
if (engineOptions.debug) {
|
|
61557
|
+
const { logger: logger2 } = await Promise.resolve().then(() => (init_logger(), exports_logger));
|
|
61558
|
+
logger2.setDebug(true);
|
|
61559
|
+
}
|
|
61560
|
+
let fileExtension;
|
|
61561
|
+
if (file) {
|
|
61562
|
+
const ext = file.substring(file.lastIndexOf("."));
|
|
61563
|
+
if (ext) {
|
|
61564
|
+
fileExtension = ext;
|
|
61565
|
+
}
|
|
61566
|
+
}
|
|
61486
61567
|
const secrets = {};
|
|
61487
61568
|
for (const s of opts.secret ?? []) {
|
|
61488
61569
|
const idx = s.indexOf("=");
|
|
@@ -61505,7 +61586,7 @@ async function resolveRunInput(file, opts) {
|
|
|
61505
61586
|
} else {
|
|
61506
61587
|
engine = new DockerIsol8(engineOptions, config.maxConcurrent);
|
|
61507
61588
|
}
|
|
61508
|
-
return { code, runtime, engineOptions, engine, stdinData };
|
|
61589
|
+
return { code, runtime, engineOptions, engine, stdinData, fileExtension };
|
|
61509
61590
|
}
|
|
61510
61591
|
function collect(value, previous) {
|
|
61511
61592
|
return previous.concat([value]);
|
|
@@ -61516,4 +61597,4 @@ if (!process.argv.slice(2).length) {
|
|
|
61516
61597
|
}
|
|
61517
61598
|
program2.parse();
|
|
61518
61599
|
|
|
61519
|
-
//# debugId=
|
|
61600
|
+
//# debugId=9AD6B80BEBAE034064756E2164756E21
|