@rlemaigre/sbx 0.1.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -0
  3. package/dist/api.d.ts +91 -0
  4. package/dist/api.d.ts.map +1 -0
  5. package/dist/api.js +216 -0
  6. package/dist/api.js.map +1 -0
  7. package/dist/cli.d.ts +2 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +144 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/commands/deploy.d.ts +6 -0
  12. package/dist/commands/deploy.d.ts.map +1 -0
  13. package/dist/commands/deploy.js +49 -0
  14. package/dist/commands/deploy.js.map +1 -0
  15. package/dist/commands/init.d.ts +6 -0
  16. package/dist/commands/init.d.ts.map +1 -0
  17. package/dist/commands/init.js +21 -0
  18. package/dist/commands/init.js.map +1 -0
  19. package/dist/commands/run.d.ts +9 -0
  20. package/dist/commands/run.d.ts.map +1 -0
  21. package/dist/commands/run.js +49 -0
  22. package/dist/commands/run.js.map +1 -0
  23. package/dist/commands/undeploy.d.ts +6 -0
  24. package/dist/commands/undeploy.d.ts.map +1 -0
  25. package/dist/commands/undeploy.js +28 -0
  26. package/dist/commands/undeploy.js.map +1 -0
  27. package/dist/config.d.ts +99 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +165 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/lib/config.d.ts +51 -0
  32. package/dist/lib/config.d.ts.map +1 -0
  33. package/dist/lib/config.js +47 -0
  34. package/dist/lib/config.js.map +1 -0
  35. package/dist/lib/network.d.ts +18 -0
  36. package/dist/lib/network.d.ts.map +1 -0
  37. package/dist/lib/network.js +31 -0
  38. package/dist/lib/network.js.map +1 -0
  39. package/dist/lib/paths.d.ts +12 -0
  40. package/dist/lib/paths.d.ts.map +1 -0
  41. package/dist/lib/paths.js +21 -0
  42. package/dist/lib/paths.js.map +1 -0
  43. package/dist/lib/vfs.d.ts +15 -0
  44. package/dist/lib/vfs.d.ts.map +1 -0
  45. package/dist/lib/vfs.js +44 -0
  46. package/dist/lib/vfs.js.map +1 -0
  47. package/dist/templates/config.template.yaml +47 -0
  48. package/dist/templates/shim.template.cmd +2 -0
  49. package/dist/templates/shim.template.sh +2 -0
  50. package/package.json +43 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 earendil-works
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # sbx
2
+
3
+ Sandboxed AI Agents — TypeScript API and CLI for [Gondolin](https://github.com/earendil-works/gondolin) micro-VMs.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g sbx
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### CLI
14
+
15
+ ```bash
16
+ # Generate a config file at ~/.config/sbx/<name>.yaml
17
+ sbx init pi
18
+
19
+ # Deploy shim scripts for named configs
20
+ sbx deploy pi
21
+
22
+ # Run a command inside the sandbox
23
+ sbx run pi -- echo hello
24
+ ```
25
+
26
+ ### API
27
+
28
+ ```typescript
29
+ import { Sandbox, SandboxConfig } from "sbx";
30
+
31
+ const config = SandboxConfig.load("~/.config/sbx/pi.yaml");
32
+ const sandbox = await Sandbox.create(config, "~/.cache/sbx/pi");
33
+
34
+ const result = await (await sandbox.exec("pi --help")).exit;
35
+ console.log(result.stdout);
36
+
37
+ await sandbox.shutdown();
38
+ ```
39
+
40
+ Or use `execAndAttach()` for PTY mode with stream passthrough:
41
+
42
+ ```typescript
43
+ const exitCode = await sandbox.execAndAttach("pi");
44
+ ```
45
+
46
+ ## Config
47
+
48
+ Configs live in `~/.config/sbx/<name>.yaml`. Run `sbx init <name>` to scaffold one.
49
+
50
+ ```yaml
51
+ cmd: pi
52
+
53
+ setup:
54
+ - apk add --no-cache nodejs npm git ripgrep
55
+
56
+ network:
57
+ allowedHosts:
58
+ - api.anthropic.com
59
+ - "*.github.com"
60
+ allowedInternalHosts: []
61
+
62
+ mounts:
63
+ - hostPath: "/home/user/project"
64
+ guestPath: "/workspace"
65
+ readOnly: false
66
+
67
+ shadow:
68
+ - ".env"
69
+ - ".npmrc"
70
+
71
+ env:
72
+ NODE_ENV: production
73
+
74
+ secrets:
75
+ ANTHROPIC_API_KEY:
76
+ hosts:
77
+ - api.anthropic.com
78
+ ```
79
+
80
+ ## License
81
+
82
+ MIT
package/dist/api.d.ts ADDED
@@ -0,0 +1,91 @@
1
+ import { VM } from "@earendil-works/gondolin";
2
+ import { SandboxConfig } from "./config";
3
+ export { loadConfig, SandboxConfig } from "./config";
4
+ export type { INetworkPolicy, IMount, ISecretConfig, } from "./config";
5
+ /**
6
+ * Options for sandbox process execution.
7
+ * stdout/stderr default to "pipe" (buffered in ExecResult).
8
+ */
9
+ export interface IExecOptions {
10
+ pty?: boolean;
11
+ stdin?: boolean;
12
+ stdout?: "pipe" | "inherit";
13
+ stderr?: "pipe" | "inherit";
14
+ }
15
+ /**
16
+ * Async process handle returned by sandbox.exec().
17
+ * Use attach() for PTY/streaming mode, or await exit for buffered results.
18
+ */
19
+ export interface IProcess {
20
+ attach(stdin: NodeJS.ReadStream, stdout: NodeJS.WriteStream, stderr?: NodeJS.WriteStream): Promise<void>;
21
+ exit: Promise<IExecResult>;
22
+ }
23
+ /**
24
+ * Result of a sandbox process execution.
25
+ */
26
+ export interface IExecResult {
27
+ exitCode: number;
28
+ /**
29
+ * Extension: captured stdout (not in SPECS §4.2).
30
+ */
31
+ stdout: string;
32
+ /**
33
+ * Extension: captured stderr (not in SPECS §4.2).
34
+ */
35
+ stderr: string;
36
+ }
37
+ /**
38
+ * Sandbox handle — wraps the underlying Gondolin VM.
39
+ * The guest disk is disposable: modifications via `exec()` are never persisted.
40
+ * The checkpoint (post-setup snapshot) is managed automatically by `Sandbox.create()`.
41
+ * To persist data, write through `mounts` backed by `RealFSProvider`.
42
+ */
43
+ export declare class Sandbox {
44
+ /**
45
+ * The sandbox configuration used at creation time.
46
+ */
47
+ readonly config: SandboxConfig;
48
+ private readonly vm;
49
+ constructor(vm: VM, config: SandboxConfig);
50
+ /**
51
+ * Create a sandboxed agent VM.
52
+ *
53
+ * On first run: fresh boot → run `setup` → save disk snapshot + manifest into `cacheDir`.
54
+ * On subsequent runs: if `setup` matches the saved manifest, restore the snapshot;
55
+ * otherwise re-run setup from scratch and save a new snapshot.
56
+ * Mounts, network, and secrets are always rebuilt from the caller-supplied config.
57
+ * User modifications via `exec()` are never persisted.
58
+ */
59
+ static create(config: SandboxConfig, cacheDir?: string): Promise<Sandbox>;
60
+ /**
61
+ * Run each setup command from the config inside an existing sandbox.
62
+ */
63
+ private static runSetup;
64
+ /**
65
+ * Execute a command inside the sandbox.
66
+ * Returns a process handle — use `exit` for buffered results or `attach()` for PTY streaming.
67
+ */
68
+ exec(cmd: string, options?: IExecOptions): Promise<IProcess>;
69
+ /**
70
+ * Build Gondolin ExecOptions from user-facing IExecOptions.
71
+ */
72
+ private static buildExecOptions;
73
+ /**
74
+ * Build the exit result promise — buffered or PTY mode.
75
+ */
76
+ private static buildExitPromise;
77
+ /**
78
+ * Execute a command inside the sandbox, attach to the current process streams,
79
+ * and return the exit code.
80
+ */
81
+ execAndAttach(cmd: string): Promise<number>;
82
+ /**
83
+ * Tear down the VM. Does not save state — shutdown is destructive.
84
+ */
85
+ shutdown(): Promise<void>;
86
+ /**
87
+ * Checkpoint the current VM state to a path on disk.
88
+ */
89
+ save(path: string): Promise<void>;
90
+ }
91
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAkC,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAc,aAAa,EAAE,MAAM,UAAU,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAErD,YAAY,EACV,cAAc,EACd,MAAM,EACN,aAAa,GACd,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,MAAM,CACJ,KAAK,EAAE,MAAM,CAAC,UAAU,EACxB,MAAM,EAAE,MAAM,CAAC,WAAW,EAC1B,MAAM,CAAC,EAAE,MAAM,CAAC,WAAW,GAC1B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,qBAAa,OAAO;IAClB;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAK;gBAEZ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa;IAKzC;;;;;;;;OAQG;WACU,MAAM,CACjB,MAAM,EAAE,aAAa,EACrB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAwBnB;;OAEG;mBACkB,QAAQ;IAS7B;;;OAGG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC;IAWlE;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAO/B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAgB/B;;;OAGG;IACG,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMjD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B;;OAEG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAIxC"}
package/dist/api.js ADDED
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Sandbox = exports.SandboxConfig = exports.loadConfig = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const gondolin_1 = require("@earendil-works/gondolin");
7
+ var config_1 = require("./config");
8
+ Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
9
+ Object.defineProperty(exports, "SandboxConfig", { enumerable: true, get: function () { return config_1.SandboxConfig; } });
10
+ /**
11
+ * Sandbox handle — wraps the underlying Gondolin VM.
12
+ * The guest disk is disposable: modifications via `exec()` are never persisted.
13
+ * The checkpoint (post-setup snapshot) is managed automatically by `Sandbox.create()`.
14
+ * To persist data, write through `mounts` backed by `RealFSProvider`.
15
+ */
16
+ class Sandbox {
17
+ /**
18
+ * The sandbox configuration used at creation time.
19
+ */
20
+ config;
21
+ vm;
22
+ constructor(vm, config) {
23
+ this.vm = vm;
24
+ this.config = config;
25
+ }
26
+ /**
27
+ * Create a sandboxed agent VM.
28
+ *
29
+ * On first run: fresh boot → run `setup` → save disk snapshot + manifest into `cacheDir`.
30
+ * On subsequent runs: if `setup` matches the saved manifest, restore the snapshot;
31
+ * otherwise re-run setup from scratch and save a new snapshot.
32
+ * Mounts, network, and secrets are always rebuilt from the caller-supplied config.
33
+ * User modifications via `exec()` are never persisted.
34
+ */
35
+ static async create(config, cacheDir) {
36
+ const vmOptions = buildVmOptions(config);
37
+ const cache = cacheDir ? new CacheDir(cacheDir) : null;
38
+ // Restore from cache if manifest matches
39
+ if (cache?.matches(config)) {
40
+ return cache.restore(config);
41
+ }
42
+ // Fresh boot — run setup
43
+ const setupVm = await gondolin_1.VM.create(vmOptions);
44
+ const sandbox = new Sandbox(setupVm, config);
45
+ await Sandbox.runSetup(sandbox, config);
46
+ // If caching, checkpoint and resume from snapshot
47
+ if (cache) {
48
+ await cache.save(setupVm, config);
49
+ await setupVm.close();
50
+ return cache.restore(config);
51
+ }
52
+ return sandbox;
53
+ }
54
+ /**
55
+ * Run each setup command from the config inside an existing sandbox.
56
+ */
57
+ static async runSetup(sandbox, config) {
58
+ for (const cmd of config.setup ?? []) {
59
+ await (await sandbox.exec(cmd)).exit;
60
+ }
61
+ }
62
+ /**
63
+ * Execute a command inside the sandbox.
64
+ * Returns a process handle — use `exit` for buffered results or `attach()` for PTY streaming.
65
+ */
66
+ async exec(cmd, options) {
67
+ await this.vm.start();
68
+ const useBuffer = !options?.pty;
69
+ const proc = this.vm.exec(cmd, Sandbox.buildExecOptions(options));
70
+ return {
71
+ attach: (stdin, stdout, stderr) => Promise.resolve(proc.attach(stdin, stdout, stderr)),
72
+ exit: Sandbox.buildExitPromise(proc, useBuffer),
73
+ };
74
+ }
75
+ /**
76
+ * Build Gondolin ExecOptions from user-facing IExecOptions.
77
+ */
78
+ static buildExecOptions(options) {
79
+ const useBuffer = !options?.pty;
80
+ return useBuffer
81
+ ? { ...options, buffer: true }
82
+ : { pty: options?.pty, stdin: options?.stdin, buffer: false, stdout: "inherit", stderr: "inherit" };
83
+ }
84
+ /**
85
+ * Build the exit result promise — buffered or PTY mode.
86
+ */
87
+ static buildExitPromise(proc, useBuffer) {
88
+ if (useBuffer) {
89
+ return (async () => {
90
+ const r = await proc;
91
+ return { exitCode: r.exitCode, stdout: r.stdout, stderr: r.stderr };
92
+ })();
93
+ }
94
+ return (async () => {
95
+ const r = await proc.result;
96
+ return { exitCode: r.exitCode, stdout: "", stderr: "" };
97
+ })();
98
+ }
99
+ /**
100
+ * Execute a command inside the sandbox, attach to the current process streams,
101
+ * and return the exit code.
102
+ */
103
+ async execAndAttach(cmd) {
104
+ const proc = await this.exec(cmd, { pty: true, stdin: true });
105
+ await proc.attach(process.stdin, process.stdout, process.stderr);
106
+ return (await proc.exit).exitCode;
107
+ }
108
+ /**
109
+ * Tear down the VM. Does not save state — shutdown is destructive.
110
+ */
111
+ async shutdown() {
112
+ return this.vm.close();
113
+ }
114
+ /**
115
+ * Checkpoint the current VM state to a path on disk.
116
+ */
117
+ async save(path) {
118
+ const cache = new CacheDir(path);
119
+ await cache.save(this.vm, this.config);
120
+ }
121
+ }
122
+ exports.Sandbox = Sandbox;
123
+ /**
124
+ * Cache directory handle — manages checkpoint save/restore and manifest validation.
125
+ */
126
+ class CacheDir {
127
+ path;
128
+ constructor(path) {
129
+ this.path = path;
130
+ }
131
+ /**
132
+ * Load the cached manifest (verbatim setup commands).
133
+ * Returns undefined if manifest.txt is missing.
134
+ */
135
+ loadManifest() {
136
+ const path = (0, node_path_1.join)(this.path, "manifest.txt");
137
+ if (!(0, node_fs_1.existsSync)(path))
138
+ return undefined;
139
+ try {
140
+ return (0, node_fs_1.readFileSync)(path, "utf-8").split("\n").filter(Boolean);
141
+ }
142
+ catch {
143
+ return undefined;
144
+ }
145
+ }
146
+ /**
147
+ * Load a cached disk checkpoint.
148
+ * Returns undefined if the file is missing or corrupt.
149
+ */
150
+ async loadCheckpoint() {
151
+ const path = (0, node_path_1.join)(this.path, "disk.qcow2");
152
+ if (!(0, node_fs_1.existsSync)(path))
153
+ return undefined;
154
+ try {
155
+ return await gondolin_1.VmCheckpoint.load(path);
156
+ }
157
+ catch {
158
+ return undefined;
159
+ }
160
+ }
161
+ /**
162
+ * Returns true if the cached manifest matches the config setup commands.
163
+ */
164
+ matches(config) {
165
+ const manifest = this.loadManifest();
166
+ if (!manifest)
167
+ return false;
168
+ const setup = config.setup ?? [];
169
+ if (manifest.length !== setup.length)
170
+ return false;
171
+ return manifest.every((cmd, i) => cmd === setup[i]);
172
+ }
173
+ /**
174
+ * Restore a sandbox from the cached checkpoint.
175
+ * Throws if the manifest does not match the config.
176
+ */
177
+ async restore(config) {
178
+ if (!this.matches(config)) {
179
+ throw new Error("checkpoint manifest mismatch");
180
+ }
181
+ const checkpoint = await this.loadCheckpoint();
182
+ if (!checkpoint)
183
+ throw new Error("checkpoint not found");
184
+ const vmOptions = buildVmOptions(config);
185
+ const vm = await checkpoint.resume(vmOptions);
186
+ return new Sandbox(vm, config);
187
+ }
188
+ /**
189
+ * Save the current VM disk and manifest into the cache directory.
190
+ */
191
+ async save(vm, config) {
192
+ (0, node_fs_1.mkdirSync)(this.path, { recursive: true });
193
+ try {
194
+ await vm.checkpoint((0, node_path_1.join)(this.path, "disk.qcow2"));
195
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(this.path, "manifest.txt"), (config.setup ?? []).join("\n"));
196
+ }
197
+ catch {
198
+ // checkpoint failed — VM still runs
199
+ }
200
+ }
201
+ }
202
+ /**
203
+ * Build VM options from a sandbox config.
204
+ * Derives network hooks, VFS mounts, merged env, and DNS mode.
205
+ */
206
+ function buildVmOptions(config) {
207
+ const { httpHooks, env } = config.buildHttpHooks();
208
+ const mounts = config.buildVFSProviders();
209
+ return {
210
+ httpHooks,
211
+ env: { ...env, ...config.env },
212
+ dns: { mode: "synthetic" },
213
+ vfs: { mounts },
214
+ };
215
+ }
216
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const commander_1 = require("commander");
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
10
+ const config_1 = require("./config");
11
+ const api_1 = require("./api");
12
+ // ─── Path constants (SPECS §3.2) ────────────────────────────────────────────
13
+ const home = process.env.HOME;
14
+ (0, tiny_invariant_1.default)(home, "HOME environment variable not set");
15
+ const CONFIG_DIR = (0, node_path_1.resolve)((0, node_path_1.join)(home, ".config", "sbx"));
16
+ const SHIM_DIR = process.platform === "win32"
17
+ ? (0, node_path_1.resolve)((0, node_path_1.join)(home, "AppData", "Roaming", "bin"))
18
+ : (0, node_path_1.resolve)((0, node_path_1.join)(home, ".local", "bin"));
19
+ const CACHE_DIR = (0, node_path_1.resolve)((0, node_path_1.join)(home, ".cache", "sbx"));
20
+ /**
21
+ * Commander program instance with registered sub-commands.
22
+ */
23
+ const program = new commander_1.Command();
24
+ program
25
+ .name("sbx")
26
+ .description("Sandboxed AI Agents — CLI for Gondolin micro-VMs")
27
+ .version("0.1.0");
28
+ program
29
+ .command("init")
30
+ .description("Generate a config file at ~/.config/sbx/<name>.yaml")
31
+ .argument("<name>", "shim name (e.g. pi)")
32
+ .action(handleInit);
33
+ program
34
+ .command("deploy")
35
+ .description("Install shim scripts for named configs")
36
+ .argument("<names...>", "config names to deploy")
37
+ .action(handleDeploy);
38
+ program
39
+ .command("undeploy")
40
+ .description("Remove shim scripts")
41
+ .argument("<names...>", "shim names to remove")
42
+ .action(handleUndeploy);
43
+ program
44
+ .command("run")
45
+ .description("Execute agent inside sandboxed VM (internal — invoked by shims)")
46
+ .argument("[args...]", "arguments to pass to the agent command")
47
+ .option("--shim-name <name>", "shim name (resolves config)")
48
+ .allowUnknownOption(true)
49
+ .action(handleRun);
50
+ program.parse(process.argv);
51
+ // ─── Handlers ────────────────────────────────────────────────────────────────
52
+ /**
53
+ * Generate a template config file at ~/.config/sbx/<name>.yaml.
54
+ */
55
+ function handleInit(name) {
56
+ const target = (0, node_path_1.join)(CONFIG_DIR, `${name}.yaml`);
57
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(target), { recursive: true });
58
+ (0, node_fs_1.copyFileSync)((0, node_path_1.resolve)(__dirname, "templates", "config.template.yaml"), target);
59
+ console.log(`Created ${target}`);
60
+ console.log(`Edit it, then run: sbx deploy ${name}`);
61
+ }
62
+ /**
63
+ * Write shim scripts to SHIM_DIR.
64
+ */
65
+ function handleDeploy(names) {
66
+ (0, node_fs_1.mkdirSync)(SHIM_DIR, { recursive: true });
67
+ for (const name of names) {
68
+ writeShim(name);
69
+ }
70
+ }
71
+ /**
72
+ * Write a single shim script for the given name.
73
+ * The config file is resolved at runtime, not at deploy time.
74
+ */
75
+ function writeShim(name) {
76
+ const shimPath = resolveShimPath(name);
77
+ (0, node_fs_1.writeFileSync)(shimPath, generateShimContent(name));
78
+ if (process.platform !== "win32") {
79
+ (0, node_fs_1.chmodSync)(shimPath, 0o755);
80
+ }
81
+ console.log(`Deployed ${shimPath}`);
82
+ }
83
+ /**
84
+ * Remove shim scripts for the given names.
85
+ */
86
+ function handleUndeploy(names) {
87
+ for (const name of names) {
88
+ removeShim(name);
89
+ }
90
+ }
91
+ /**
92
+ * Remove a single shim script for the given name.
93
+ */
94
+ function removeShim(name) {
95
+ const shimPath = resolveShimPath(name);
96
+ if ((0, node_fs_1.existsSync)(shimPath)) {
97
+ (0, node_fs_1.unlinkSync)(shimPath);
98
+ console.log(`Removed ${shimPath}`);
99
+ }
100
+ else {
101
+ console.error(`Shim not found: ${shimPath}`);
102
+ }
103
+ }
104
+ /**
105
+ * Execute the agent command inside a sandboxed VM (invoked by shims).
106
+ */
107
+ async function handleRun(args, opts) {
108
+ const shimName = opts.shimName;
109
+ (0, tiny_invariant_1.default)(shimName, "Missing --shim-name");
110
+ const config = config_1.SandboxConfig.load((0, node_path_1.join)(CONFIG_DIR, `${shimName}.yaml`));
111
+ (0, tiny_invariant_1.default)(config.cmd, `Config for ${shimName} must specify cmd`);
112
+ const sandbox = await api_1.Sandbox.create(config, (0, node_path_1.join)(CACHE_DIR, shimName));
113
+ const cmd = buildCommand(config.cmd, args);
114
+ try {
115
+ const exitCode = await sandbox.execAndAttach(cmd);
116
+ process.exit(exitCode);
117
+ }
118
+ finally {
119
+ await sandbox.shutdown();
120
+ }
121
+ }
122
+ /**
123
+ * Build a shell command string from a base command and positional arguments.
124
+ */
125
+ function buildCommand(cmd, args) {
126
+ if (args.length === 0)
127
+ return cmd;
128
+ return `${cmd} ${args.map((a) => `'${a}'`).join(" ")}`;
129
+ }
130
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
131
+ /**
132
+ * Resolve the platform-specific shim path for a given name.
133
+ */
134
+ function resolveShimPath(name) {
135
+ return (0, node_path_1.join)(SHIM_DIR, process.platform === "win32" ? `${name}.cmd` : name);
136
+ }
137
+ /**
138
+ * Generate platform-specific shim content that forwards to `sbx run --shim-name <name>`.
139
+ */
140
+ function generateShimContent(name) {
141
+ const template = process.platform === "win32" ? "shim.template.cmd" : "shim.template.sh";
142
+ return (0, node_fs_1.readFileSync)((0, node_path_1.resolve)(__dirname, "templates", template), "utf-8").replace("{{NAME}}", name);
143
+ }
144
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Deploy command — install shim scripts.
3
+ */
4
+ import { Command } from "commander";
5
+ export declare const deployCommand: Command;
6
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,eAAO,MAAM,aAAa,SA0CtB,CAAC"}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ /**
3
+ * Deploy command — install shim scripts.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.deployCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const node_fs_1 = require("node:fs");
9
+ const node_path_1 = require("node:path");
10
+ const paths_1 = require("../lib/paths");
11
+ function getLinuxShim(name) {
12
+ return `#!/usr/bin/env bash\nexec sbx run "$@" --shim-name ${name}\n`;
13
+ }
14
+ function getWindowsShim(name) {
15
+ return `@echo off\nwsl sbx run %* --shim-name ${name}\n`;
16
+ }
17
+ exports.deployCommand = new commander_1.Command("deploy")
18
+ .description("Install shim scripts for named configs")
19
+ .argument("[names...]", "config names to deploy (default: all)")
20
+ .action((names) => {
21
+ const configNames = names?.length
22
+ ? names
23
+ : (0, node_fs_1.readdirSync)(paths_1.CONFIG_DIR)
24
+ .filter((f) => f.endsWith(".yaml"))
25
+ .map((f) => f.replace(/\.yaml$/, ""));
26
+ (0, node_fs_1.mkdirSync)(paths_1.SHIM_DIR, { recursive: true });
27
+ for (const name of configNames) {
28
+ const configPath = (0, node_path_1.join)(paths_1.CONFIG_DIR, `${name}.yaml`);
29
+ if (!(0, node_fs_1.existsSync)(configPath)) {
30
+ console.error(`Config not found for: ${name}`);
31
+ continue;
32
+ }
33
+ const shimPath = process.platform === "win32"
34
+ ? (0, node_path_1.join)(paths_1.SHIM_DIR, `${name}.cmd`)
35
+ : (0, node_path_1.join)(paths_1.SHIM_DIR, name);
36
+ const content = process.platform === "win32"
37
+ ? getWindowsShim(name)
38
+ : getLinuxShim(name);
39
+ (0, node_fs_1.writeFileSync)(shimPath, content);
40
+ if (process.platform !== "win32") {
41
+ (0, node_fs_1.chmodSync)(shimPath, 0o755);
42
+ }
43
+ console.log(`Deployed ${shimPath}`);
44
+ }
45
+ if (process.platform === "win32") {
46
+ console.log(`\nIf ${paths_1.SHIM_DIR} is not on your PATH, run:\n setx PATH "%PATH%;${paths_1.SHIM_DIR}"`);
47
+ }
48
+ });
49
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,yCAAoC;AACpC,qCAAuF;AACvF,yCAAiC;AACjC,wCAAoD;AAEpD,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,sDAAsD,IAAI,IAAI,CAAC;AACxE,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,yCAAyC,IAAI,IAAI,CAAC;AAC3D,CAAC;AAEY,QAAA,aAAa,GAAG,IAAI,mBAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,wCAAwC,CAAC;KACrD,QAAQ,CAAC,YAAY,EAAE,uCAAuC,CAAC;KAC/D,MAAM,CAAC,CAAC,KAAgB,EAAE,EAAE;IAC3B,MAAM,WAAW,GACf,KAAK,EAAE,MAAM;QACX,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAA,qBAAW,EAAC,kBAAU,CAAC;aAClB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;aAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;IAEhD,IAAA,mBAAS,EAAC,gBAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,IAAA,gBAAI,EAAC,kBAAU,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;QACpD,IAAI,CAAC,IAAA,oBAAU,EAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;YAC/C,SAAS;QACX,CAAC;QAED,MAAM,QAAQ,GACZ,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC1B,CAAC,CAAC,IAAA,gBAAI,EAAC,gBAAQ,EAAE,GAAG,IAAI,MAAM,CAAC;YAC/B,CAAC,CAAC,IAAA,gBAAI,EAAC,gBAAQ,EAAE,IAAI,CAAC,CAAC;QAE3B,MAAM,OAAO,GACX,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC1B,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC;YACtB,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAEzB,IAAA,uBAAa,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACjC,IAAA,mBAAS,EAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,YAAY,QAAQ,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CACT,QAAQ,gBAAQ,mDAAmD,gBAAQ,GAAG,CAC/E,CAAC;IACJ,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Init command — copy template config to user config directory.
3
+ */
4
+ import { Command } from "commander";
5
+ export declare const initCommand: Command;
6
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,WAAW,SASpB,CAAC"}