@agentick/sandbox-local 0.2.1

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 (87) hide show
  1. package/README.md +211 -0
  2. package/dist/executor/base.d.ts +15 -0
  3. package/dist/executor/base.d.ts.map +1 -0
  4. package/dist/executor/base.js +20 -0
  5. package/dist/executor/base.js.map +1 -0
  6. package/dist/executor/darwin.d.ts +16 -0
  7. package/dist/executor/darwin.d.ts.map +1 -0
  8. package/dist/executor/darwin.js +44 -0
  9. package/dist/executor/darwin.js.map +1 -0
  10. package/dist/executor/linux.d.ts +22 -0
  11. package/dist/executor/linux.d.ts.map +1 -0
  12. package/dist/executor/linux.js +50 -0
  13. package/dist/executor/linux.js.map +1 -0
  14. package/dist/executor/select.d.ts +12 -0
  15. package/dist/executor/select.d.ts.map +1 -0
  16. package/dist/executor/select.js +23 -0
  17. package/dist/executor/select.js.map +1 -0
  18. package/dist/executor/types.d.ts +29 -0
  19. package/dist/executor/types.d.ts.map +1 -0
  20. package/dist/executor/types.js +4 -0
  21. package/dist/executor/types.js.map +1 -0
  22. package/dist/index.d.ts +12 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +12 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/linux/bwrap.d.ts +11 -0
  27. package/dist/linux/bwrap.d.ts.map +1 -0
  28. package/dist/linux/bwrap.js +46 -0
  29. package/dist/linux/bwrap.js.map +1 -0
  30. package/dist/linux/cgroup.d.ts +27 -0
  31. package/dist/linux/cgroup.d.ts.map +1 -0
  32. package/dist/linux/cgroup.js +80 -0
  33. package/dist/linux/cgroup.js.map +1 -0
  34. package/dist/linux/unshare.d.ts +11 -0
  35. package/dist/linux/unshare.d.ts.map +1 -0
  36. package/dist/linux/unshare.js +22 -0
  37. package/dist/linux/unshare.js.map +1 -0
  38. package/dist/local-sandbox.d.ts +42 -0
  39. package/dist/local-sandbox.d.ts.map +1 -0
  40. package/dist/local-sandbox.js +235 -0
  41. package/dist/local-sandbox.js.map +1 -0
  42. package/dist/network/ca.d.ts +38 -0
  43. package/dist/network/ca.d.ts.map +1 -0
  44. package/dist/network/ca.js +143 -0
  45. package/dist/network/ca.js.map +1 -0
  46. package/dist/network/proxy.d.ts +46 -0
  47. package/dist/network/proxy.d.ts.map +1 -0
  48. package/dist/network/proxy.js +144 -0
  49. package/dist/network/proxy.js.map +1 -0
  50. package/dist/network/rules.d.ts +23 -0
  51. package/dist/network/rules.d.ts.map +1 -0
  52. package/dist/network/rules.js +64 -0
  53. package/dist/network/rules.js.map +1 -0
  54. package/dist/paths.d.ts +29 -0
  55. package/dist/paths.d.ts.map +1 -0
  56. package/dist/paths.js +129 -0
  57. package/dist/paths.js.map +1 -0
  58. package/dist/platform/detect.d.ts +17 -0
  59. package/dist/platform/detect.d.ts.map +1 -0
  60. package/dist/platform/detect.js +114 -0
  61. package/dist/platform/detect.js.map +1 -0
  62. package/dist/platform/types.d.ts +16 -0
  63. package/dist/platform/types.d.ts.map +1 -0
  64. package/dist/platform/types.js +4 -0
  65. package/dist/platform/types.js.map +1 -0
  66. package/dist/provider.d.ts +33 -0
  67. package/dist/provider.d.ts.map +1 -0
  68. package/dist/provider.js +137 -0
  69. package/dist/provider.js.map +1 -0
  70. package/dist/resources.d.ts +30 -0
  71. package/dist/resources.d.ts.map +1 -0
  72. package/dist/resources.js +94 -0
  73. package/dist/resources.js.map +1 -0
  74. package/dist/seatbelt/profile.d.ts +30 -0
  75. package/dist/seatbelt/profile.d.ts.map +1 -0
  76. package/dist/seatbelt/profile.js +106 -0
  77. package/dist/seatbelt/profile.js.map +1 -0
  78. package/dist/testing.d.ts +22 -0
  79. package/dist/testing.d.ts.map +1 -0
  80. package/dist/testing.js +39 -0
  81. package/dist/testing.js.map +1 -0
  82. package/dist/workspace.d.ts +30 -0
  83. package/dist/workspace.d.ts.map +1 -0
  84. package/dist/workspace.js +68 -0
  85. package/dist/workspace.js.map +1 -0
  86. package/package.json +64 -0
  87. package/src/index.ts +17 -0
package/README.md ADDED
@@ -0,0 +1,211 @@
1
+ # @agentick/sandbox-local
2
+
3
+ Local sandbox provider for Agentick. Executes commands on the host machine with OS-level security rails.
4
+
5
+ ## Quick Start
6
+
7
+ ```typescript
8
+ import { localProvider } from "@agentick/sandbox-local";
9
+
10
+ const provider = localProvider();
11
+ const sandbox = await provider.create({ workspace: true });
12
+
13
+ const result = await sandbox.exec("echo hello");
14
+ console.log(result.stdout); // "hello\n"
15
+
16
+ await sandbox.writeFile("test.txt", "content");
17
+ const content = await sandbox.readFile("test.txt");
18
+
19
+ await sandbox.destroy();
20
+ ```
21
+
22
+ ## Sandbox Strategies
23
+
24
+ The provider automatically selects the best available isolation strategy:
25
+
26
+ | Strategy | Platform | Isolation |
27
+ | ---------- | -------- | ------------------------------------------------------------- |
28
+ | `seatbelt` | macOS | Apple Sandbox (`sandbox-exec`) with SBPL profiles |
29
+ | `bwrap` | Linux | Bubblewrap with namespace isolation |
30
+ | `unshare` | Linux | `unshare` with user namespaces |
31
+ | `none` | Any | No OS sandboxing (workspace isolation + path validation only) |
32
+
33
+ ```typescript
34
+ // Auto-detect (default)
35
+ const provider = localProvider();
36
+
37
+ // Force a specific strategy
38
+ const provider = localProvider({ strategy: "seatbelt" });
39
+ const provider = localProvider({ strategy: "none" }); // For testing
40
+ ```
41
+
42
+ ## Platform Detection
43
+
44
+ ```typescript
45
+ import { detectCapabilities } from "@agentick/sandbox-local";
46
+
47
+ const caps = await detectCapabilities();
48
+ // {
49
+ // platform: "darwin",
50
+ // arch: "arm64",
51
+ // hasSandboxExec: true,
52
+ // recommended: "seatbelt",
53
+ // ...
54
+ // }
55
+ ```
56
+
57
+ ## Network Rules
58
+
59
+ Control sandbox network access with fine-grained rules.
60
+
61
+ ```typescript
62
+ const sandbox = await provider.create({
63
+ workspace: true,
64
+ permissions: {
65
+ net: [
66
+ { action: "allow", domain: "api.github.com" },
67
+ { action: "allow", domain: "*.npmjs.org" },
68
+ { action: "deny", domain: "*.evil.com" },
69
+ { action: "allow", port: 443, methods: ["GET"] },
70
+ ],
71
+ },
72
+ });
73
+ ```
74
+
75
+ Rules are evaluated in order. First match wins. Default action is **deny**.
76
+
77
+ When `NetworkRule[]` is provided, a transparent HTTP proxy is started. HTTPS connections are filtered at the CONNECT level (domain allow/block without TLS termination).
78
+
79
+ ## Permissions
80
+
81
+ ```typescript
82
+ const sandbox = await provider.create({
83
+ workspace: true,
84
+ permissions: {
85
+ fs: true, // Filesystem access (default: true)
86
+ net: false, // Network access (default: false)
87
+ childProcess: true, // Fork processes (default: true)
88
+ inheritEnv: false, // Inherit host env vars (default: false)
89
+ },
90
+ });
91
+ ```
92
+
93
+ ## Mounts
94
+
95
+ Map host directories into the sandbox.
96
+
97
+ ```typescript
98
+ const sandbox = await provider.create({
99
+ workspace: true,
100
+ mounts: [
101
+ { host: "/data/shared", sandbox: "/mnt/shared", mode: "ro" },
102
+ { host: "/data/output", sandbox: "/mnt/output", mode: "rw" },
103
+ ],
104
+ });
105
+ ```
106
+
107
+ ## Resource Limits
108
+
109
+ ```typescript
110
+ const sandbox = await provider.create({
111
+ workspace: true,
112
+ limits: {
113
+ memory: 512 * 1024 * 1024, // 512MB
114
+ cpu: 0.5, // Half a core
115
+ timeout: 30000, // 30s global timeout
116
+ disk: 100 * 1024 * 1024, // 100MB workspace
117
+ maxProcesses: 10,
118
+ },
119
+ });
120
+ ```
121
+
122
+ Resource limits use cgroups v2 on Linux. On macOS, timeout and disk limits are enforced; memory/CPU are advisory.
123
+
124
+ ## Streaming Output
125
+
126
+ ```typescript
127
+ const result = await sandbox.exec("npm install", {
128
+ onOutput: (chunk) => {
129
+ process.stdout.write(`[${chunk.stream}] ${chunk.data}`);
130
+ },
131
+ });
132
+ ```
133
+
134
+ ## With Agentick Components
135
+
136
+ ```tsx
137
+ import { Sandbox, Shell, ReadFile, WriteFile } from "@agentick/sandbox";
138
+ import { localProvider } from "@agentick/sandbox-local";
139
+
140
+ const MyAgent = () => (
141
+ <Sandbox provider={localProvider()} workspace={true}>
142
+ <Shell />
143
+ <ReadFile />
144
+ <WriteFile />
145
+ </Sandbox>
146
+ );
147
+ ```
148
+
149
+ ## Testing
150
+
151
+ ```typescript
152
+ import { createTestProvider, isDarwin } from "@agentick/sandbox-local/testing";
153
+
154
+ const provider = createTestProvider(); // strategy: "none"
155
+ const sandbox = await provider.create({ workspace: true });
156
+
157
+ // Platform-gated tests
158
+ describe.skipIf(!isDarwin)("seatbelt tests", () => { ... });
159
+ ```
160
+
161
+ ## Security Model
162
+
163
+ **Safe by default.** The sandbox denies access to sensitive resources unless explicitly allowed.
164
+
165
+ ### macOS Seatbelt (reads)
166
+
167
+ Sandboxed processes can read system libraries and executables (required for bash/node), but **cannot** read:
168
+
169
+ | Denied Path | Contains |
170
+ | ------------------------- | ------------------------------------------------------------------ |
171
+ | `/Users` | Home directories — SSH keys, `.env`, browser profiles, credentials |
172
+ | `/private/var/root` | Root's home directory |
173
+ | `/Volumes` | Mounted drives, encrypted volumes, network shares |
174
+ | `/Network` | Network-mounted resources |
175
+ | `/Library/Keychains` | System-level keychains and certificates |
176
+ | `/private/var/db/dslocal` | Local directory service (user account data) |
177
+
178
+ The workspace and any configured mounts are re-allowed via SBPL specificity rules (more-specific subpath allows override broader denies).
179
+
180
+ ### Write restrictions
181
+
182
+ All strategies restrict writes to:
183
+
184
+ - The workspace directory
185
+ - Configured read-write mounts
186
+ - `/tmp` and `/dev`
187
+
188
+ ### Additional protections
189
+
190
+ | Threat | Mitigation |
191
+ | ------------------- | -------------------------------------------------------------- |
192
+ | Path traversal | `realpath()` + bounds check |
193
+ | Symlink escape | Follow symlinks before validation |
194
+ | Null byte injection | Reject null bytes in all paths |
195
+ | Output OOM | 10MB cap per stream |
196
+ | Env var injection | Blocklist for `LD_PRELOAD`, `DYLD_*` |
197
+ | Process orphans | Kill process group (`detached` + `-pid`), SIGTERM then SIGKILL |
198
+ | Zombie sandbox | `destroyed` flag prevents use-after-destroy |
199
+ | Disk bomb | Polling monitor kills processes on exceed |
200
+
201
+ ### Platform requirements
202
+
203
+ **macOS**: `/usr/bin/sandbox-exec` (ships with macOS, no install needed).
204
+
205
+ **Linux**: One of:
206
+
207
+ - `bwrap` (bubblewrap) — install via `apt install bubblewrap` or equivalent
208
+ - `unshare` with unprivileged user namespaces enabled (`sysctl kernel.unprivileged_userns_clone=1`)
209
+ - cgroups v2 for memory/CPU/process limits (writable `/sys/fs/cgroup`)
210
+
211
+ **All platforms**: Falls back to `strategy: "none"` (workspace isolation + path validation only, no OS-level sandboxing) when no sandbox tooling is available.
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Base (unsandboxed) executor.
3
+ *
4
+ * Plain child_process.spawn — no OS-level sandboxing.
5
+ * Still benefits from workspace isolation, path validation, and timeout enforcement
6
+ * provided by LocalSandbox.
7
+ */
8
+ import type { ChildProcess } from "node:child_process";
9
+ import type { CommandExecutor, SpawnOptions } from "./types";
10
+ import type { SandboxStrategy } from "../platform/types";
11
+ export declare class BaseExecutor implements CommandExecutor {
12
+ readonly strategy: SandboxStrategy;
13
+ spawn(command: string, options: SpawnOptions): ChildProcess;
14
+ }
15
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/executor/base.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,qBAAa,YAAa,YAAW,eAAe;IAClD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAU;IAE5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,YAAY;CAQ5D"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Base (unsandboxed) executor.
3
+ *
4
+ * Plain child_process.spawn — no OS-level sandboxing.
5
+ * Still benefits from workspace isolation, path validation, and timeout enforcement
6
+ * provided by LocalSandbox.
7
+ */
8
+ import { spawn } from "node:child_process";
9
+ export class BaseExecutor {
10
+ strategy = "none";
11
+ spawn(command, options) {
12
+ return spawn("sh", ["-c", command], {
13
+ cwd: options.cwd,
14
+ env: options.env,
15
+ stdio: ["pipe", "pipe", "pipe"],
16
+ detached: true,
17
+ });
18
+ }
19
+ }
20
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/executor/base.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAK3C,MAAM,OAAO,YAAY;IACd,QAAQ,GAAoB,MAAM,CAAC;IAE5C,KAAK,CAAC,OAAe,EAAE,OAAqB;QAC1C,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;YAClC,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * macOS Seatbelt Executor
3
+ *
4
+ * Generates a seatbelt profile from SpawnOptions, writes it to a temp file,
5
+ * and spawns the command under sandbox-exec.
6
+ */
7
+ import type { ChildProcess } from "node:child_process";
8
+ import type { CommandExecutor, SpawnOptions } from "./types";
9
+ import type { SandboxStrategy } from "../platform/types";
10
+ export declare class DarwinExecutor implements CommandExecutor {
11
+ readonly strategy: SandboxStrategy;
12
+ private readonly profileDir;
13
+ constructor();
14
+ spawn(command: string, options: SpawnOptions): ChildProcess;
15
+ }
16
+ //# sourceMappingURL=darwin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"darwin.d.ts","sourceRoot":"","sources":["../../src/executor/darwin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,qBAAa,cAAe,YAAW,eAAe;IACpD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAc;IAChD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;;IAQpC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,YAAY;CAyB5D"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * macOS Seatbelt Executor
3
+ *
4
+ * Generates a seatbelt profile from SpawnOptions, writes it to a temp file,
5
+ * and spawns the command under sandbox-exec.
6
+ */
7
+ import { spawn } from "node:child_process";
8
+ import { writeFileSync, unlinkSync, mkdirSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { randomBytes } from "node:crypto";
11
+ import { tmpdir } from "node:os";
12
+ import { compileSeatbeltProfile } from "../seatbelt/profile";
13
+ export class DarwinExecutor {
14
+ strategy = "seatbelt";
15
+ profileDir;
16
+ constructor() {
17
+ // Per-instance temp dir for profile files
18
+ this.profileDir = join(tmpdir(), `agentick-seatbelt-${randomBytes(6).toString("hex")}`);
19
+ mkdirSync(this.profileDir, { recursive: true, mode: 0o700 });
20
+ }
21
+ spawn(command, options) {
22
+ const profile = compileSeatbeltProfile(options);
23
+ // Write profile to temp file with restricted permissions
24
+ const profilePath = join(this.profileDir, `profile-${randomBytes(4).toString("hex")}.sb`);
25
+ writeFileSync(profilePath, profile, { mode: 0o600 });
26
+ const child = spawn("sandbox-exec", ["-f", profilePath, "/bin/bash", "-c", command], {
27
+ cwd: options.cwd,
28
+ env: options.env,
29
+ stdio: ["pipe", "pipe", "pipe"],
30
+ detached: true,
31
+ });
32
+ // Clean up profile after process starts
33
+ child.on("exit", () => {
34
+ try {
35
+ unlinkSync(profilePath);
36
+ }
37
+ catch {
38
+ // Best-effort cleanup
39
+ }
40
+ });
41
+ return child;
42
+ }
43
+ }
44
+ //# sourceMappingURL=darwin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"darwin.js","sourceRoot":"","sources":["../../src/executor/darwin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,MAAM,OAAO,cAAc;IAChB,QAAQ,GAAoB,UAAU,CAAC;IAC/B,UAAU,CAAS;IAEpC;QACE,0CAA0C;QAC1C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,qBAAqB,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxF,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,OAAqB;QAC1C,MAAM,OAAO,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;QAEhD,yDAAyD;QACzD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1F,aAAa,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAErD,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE;YACnF,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QAEH,wCAAwC;QACxC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACpB,IAAI,CAAC;gBACH,UAAU,CAAC,WAAW,CAAC,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,sBAAsB;YACxB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Linux Executor (bubblewrap / unshare)
3
+ *
4
+ * Spawns commands under bwrap or unshare for namespace-based isolation.
5
+ */
6
+ import type { ChildProcess } from "node:child_process";
7
+ import type { CommandExecutor, SpawnOptions } from "./types";
8
+ import type { SandboxStrategy } from "../platform/types";
9
+ import type { CgroupManager } from "../linux/cgroup";
10
+ export declare class BwrapExecutor implements CommandExecutor {
11
+ readonly strategy: SandboxStrategy;
12
+ private cgroup?;
13
+ constructor(cgroup?: CgroupManager);
14
+ spawn(command: string, options: SpawnOptions): ChildProcess;
15
+ }
16
+ export declare class UnshareExecutor implements CommandExecutor {
17
+ readonly strategy: SandboxStrategy;
18
+ private cgroup?;
19
+ constructor(cgroup?: CgroupManager);
20
+ spawn(command: string, options: SpawnOptions): ChildProcess;
21
+ }
22
+ //# sourceMappingURL=linux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linux.d.ts","sourceRoot":"","sources":["../../src/executor/linux.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,qBAAa,aAAc,YAAW,eAAe;IACnD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAW;IAC7C,OAAO,CAAC,MAAM,CAAC,CAAgB;gBAEnB,MAAM,CAAC,EAAE,aAAa;IAIlC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,YAAY;CAgB5D;AAED,qBAAa,eAAgB,YAAW,eAAe;IACrD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAa;IAC/C,OAAO,CAAC,MAAM,CAAC,CAAgB;gBAEnB,MAAM,CAAC,EAAE,aAAa;IAIlC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,YAAY;CAiB5D"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Linux Executor (bubblewrap / unshare)
3
+ *
4
+ * Spawns commands under bwrap or unshare for namespace-based isolation.
5
+ */
6
+ import { spawn } from "node:child_process";
7
+ import { buildBwrapArgs } from "../linux/bwrap";
8
+ import { buildUnshareArgs } from "../linux/unshare";
9
+ export class BwrapExecutor {
10
+ strategy = "bwrap";
11
+ cgroup;
12
+ constructor(cgroup) {
13
+ this.cgroup = cgroup;
14
+ }
15
+ spawn(command, options) {
16
+ const args = buildBwrapArgs(options);
17
+ args.push("sh", "-c", command);
18
+ const child = spawn("bwrap", args, {
19
+ env: options.env,
20
+ stdio: ["pipe", "pipe", "pipe"],
21
+ detached: true,
22
+ });
23
+ if (this.cgroup && child.pid) {
24
+ this.cgroup.addProcess(child.pid).catch(() => { });
25
+ }
26
+ return child;
27
+ }
28
+ }
29
+ export class UnshareExecutor {
30
+ strategy = "unshare";
31
+ cgroup;
32
+ constructor(cgroup) {
33
+ this.cgroup = cgroup;
34
+ }
35
+ spawn(command, options) {
36
+ const args = buildUnshareArgs(options);
37
+ args.push("sh", "-c", command);
38
+ const child = spawn("unshare", args, {
39
+ cwd: options.cwd,
40
+ env: options.env,
41
+ stdio: ["pipe", "pipe", "pipe"],
42
+ detached: true,
43
+ });
44
+ if (this.cgroup && child.pid) {
45
+ this.cgroup.addProcess(child.pid).catch(() => { });
46
+ }
47
+ return child;
48
+ }
49
+ }
50
+ //# sourceMappingURL=linux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linux.js","sourceRoot":"","sources":["../../src/executor/linux.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAI3C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGpD,MAAM,OAAO,aAAa;IACf,QAAQ,GAAoB,OAAO,CAAC;IACrC,MAAM,CAAiB;IAE/B,YAAY,MAAsB;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,OAAqB;QAC1C,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAE/B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YACjC,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,MAAM,OAAO,eAAe;IACjB,QAAQ,GAAoB,SAAS,CAAC;IACvC,MAAM,CAAiB;IAE/B,YAAY,MAAsB;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,OAAqB;QAC1C,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAE/B,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE;YACnC,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Executor factory — select executor based on platform capabilities.
3
+ */
4
+ import type { SandboxStrategy } from "../platform/types";
5
+ import type { CommandExecutor } from "./types";
6
+ import type { CgroupManager } from "../linux/cgroup";
7
+ /**
8
+ * Create a CommandExecutor for the given strategy.
9
+ * Optionally accepts a CgroupManager for Linux executors.
10
+ */
11
+ export declare function selectExecutor(strategy: SandboxStrategy, cgroup?: CgroupManager): CommandExecutor;
12
+ //# sourceMappingURL=select.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/executor/select.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,eAAe,CAWjG"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Executor factory — select executor based on platform capabilities.
3
+ */
4
+ import { BaseExecutor } from "./base";
5
+ import { DarwinExecutor } from "./darwin";
6
+ import { BwrapExecutor, UnshareExecutor } from "./linux";
7
+ /**
8
+ * Create a CommandExecutor for the given strategy.
9
+ * Optionally accepts a CgroupManager for Linux executors.
10
+ */
11
+ export function selectExecutor(strategy, cgroup) {
12
+ switch (strategy) {
13
+ case "seatbelt":
14
+ return new DarwinExecutor();
15
+ case "bwrap":
16
+ return new BwrapExecutor(cgroup);
17
+ case "unshare":
18
+ return new UnshareExecutor(cgroup);
19
+ case "none":
20
+ return new BaseExecutor();
21
+ }
22
+ }
23
+ //# sourceMappingURL=select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/executor/select.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGzD;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAAyB,EAAE,MAAsB;IAC9E,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,UAAU;YACb,OAAO,IAAI,cAAc,EAAE,CAAC;QAC9B,KAAK,OAAO;YACV,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QACnC,KAAK,SAAS;YACZ,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;QACrC,KAAK,MAAM;YACT,OAAO,IAAI,YAAY,EAAE,CAAC;IAC9B,CAAC;AACH,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Command executor types.
3
+ */
4
+ import type { ChildProcess } from "node:child_process";
5
+ import type { SandboxStrategy } from "../platform/types";
6
+ import type { NetworkRule } from "@agentick/sandbox";
7
+ export interface CommandExecutor {
8
+ readonly strategy: SandboxStrategy;
9
+ spawn(command: string, options: SpawnOptions): ChildProcess;
10
+ }
11
+ export interface SpawnOptions {
12
+ cwd: string;
13
+ env: Record<string, string>;
14
+ workspacePath: string;
15
+ mounts: ResolvedMount[];
16
+ permissions: ResolvedPermissions;
17
+ }
18
+ export interface ResolvedPermissions {
19
+ readPaths: string[];
20
+ writePaths: string[];
21
+ network: boolean | NetworkRule[];
22
+ childProcess: boolean;
23
+ }
24
+ export interface ResolvedMount {
25
+ hostPath: string;
26
+ sandboxPath: string;
27
+ mode: "ro" | "rw";
28
+ }
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/executor/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,YAAY,CAAC;CAC7D;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,WAAW,EAAE,mBAAmB,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,OAAO,GAAG,WAAW,EAAE,CAAC;IACjC,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;CACnB"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Command executor types.
3
+ */
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/executor/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @agentick/sandbox-local — Local sandbox provider
3
+ *
4
+ * OS-level process isolation using macOS seatbelt and Linux bubblewrap/unshare.
5
+ */
6
+ export { localProvider } from "./provider";
7
+ export type { LocalProviderConfig } from "./provider";
8
+ export { detectCapabilities } from "./platform/detect";
9
+ export type { PlatformCapabilities, SandboxStrategy } from "./platform/types";
10
+ export { NetworkProxyServer } from "./network/proxy";
11
+ export type { ProxyServerConfig } from "./network/proxy";
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAG9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @agentick/sandbox-local — Local sandbox provider
3
+ *
4
+ * OS-level process isolation using macOS seatbelt and Linux bubblewrap/unshare.
5
+ */
6
+ // ── Provider ────────────────────────────────────────────────────────────────
7
+ export { localProvider } from "./provider";
8
+ // ── Platform Detection ──────────────────────────────────────────────────────
9
+ export { detectCapabilities } from "./platform/detect";
10
+ // ── Network Proxy ───────────────────────────────────────────────────────────
11
+ export { NetworkProxyServer } from "./network/proxy";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,+EAA+E;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C,+EAA+E;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvD,+EAA+E;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Bubblewrap argument builder.
3
+ *
4
+ * Constructs the bwrap command-line arguments from SpawnOptions.
5
+ */
6
+ import type { SpawnOptions } from "../executor/types";
7
+ /**
8
+ * Build bubblewrap argument array for a given set of spawn options.
9
+ */
10
+ export declare function buildBwrapArgs(options: SpawnOptions): string[];
11
+ //# sourceMappingURL=bwrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bwrap.d.ts","sourceRoot":"","sources":["../../src/linux/bwrap.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKtD;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,CA0C9D"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Bubblewrap argument builder.
3
+ *
4
+ * Constructs the bwrap command-line arguments from SpawnOptions.
5
+ */
6
+ /** System directories to mount read-only into the sandbox. */
7
+ const SYSTEM_RO_BINDS = ["/usr", "/lib", "/lib64", "/bin", "/sbin", "/etc"];
8
+ /**
9
+ * Build bubblewrap argument array for a given set of spawn options.
10
+ */
11
+ export function buildBwrapArgs(options) {
12
+ const args = [];
13
+ // Namespace isolation
14
+ args.push("--unshare-all");
15
+ // Re-share network if allowed
16
+ const net = options.permissions.network;
17
+ if (net === true || (Array.isArray(net) && net.length > 0)) {
18
+ args.push("--share-net");
19
+ }
20
+ // System directories (read-only)
21
+ for (const dir of SYSTEM_RO_BINDS) {
22
+ args.push("--ro-bind", dir, dir);
23
+ }
24
+ // Proc, dev, tmp
25
+ args.push("--proc", "/proc");
26
+ args.push("--dev", "/dev");
27
+ args.push("--tmpfs", "/tmp");
28
+ // Workspace (read-write)
29
+ args.push("--bind", options.workspacePath, options.workspacePath);
30
+ // User mounts
31
+ for (const mount of options.mounts) {
32
+ if (mount.mode === "ro") {
33
+ args.push("--ro-bind", mount.hostPath, mount.sandboxPath);
34
+ }
35
+ else {
36
+ args.push("--bind", mount.hostPath, mount.sandboxPath);
37
+ }
38
+ }
39
+ // Safety
40
+ args.push("--die-with-parent");
41
+ args.push("--new-session");
42
+ // Working directory
43
+ args.push("--chdir", options.cwd);
44
+ return args;
45
+ }
46
+ //# sourceMappingURL=bwrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bwrap.js","sourceRoot":"","sources":["../../src/linux/bwrap.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,8DAA8D;AAC9D,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAE5E;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,OAAqB;IAClD,MAAM,IAAI,GAAa,EAAE,CAAC;IAE1B,sBAAsB;IACtB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAE3B,8BAA8B;IAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;IACxC,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC3B,CAAC;IAED,iCAAiC;IACjC,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,iBAAiB;IACjB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAE7B,yBAAyB;IACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAElE,cAAc;IACd,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED,SAAS;IACT,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAE3B,oBAAoB;IACpB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAElC,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * cgroups v2 Resource Limit Manager
3
+ *
4
+ * Creates a cgroup under /sys/fs/cgroup/ for enforcing memory, CPU, and
5
+ * process limits. Degrades gracefully if the cgroup directory is not writable.
6
+ */
7
+ import type { ResourceLimits } from "@agentick/sandbox";
8
+ export declare class CgroupManager {
9
+ private readonly id;
10
+ private readonly cgroupPath;
11
+ private created;
12
+ constructor(id: string);
13
+ /**
14
+ * Create the cgroup directory and apply resource limits.
15
+ * No-op if cgroups v2 is not available or not writable.
16
+ */
17
+ create(limits: ResourceLimits): Promise<void>;
18
+ /**
19
+ * Add a process to this cgroup.
20
+ */
21
+ addProcess(pid: number): Promise<void>;
22
+ /**
23
+ * Destroy the cgroup directory.
24
+ */
25
+ destroy(): Promise<void>;
26
+ }
27
+ //# sourceMappingURL=cgroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cgroup.d.ts","sourceRoot":"","sources":["../../src/linux/cgroup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIxD,qBAAa,aAAa;IAIZ,OAAO,CAAC,QAAQ,CAAC,EAAE;IAH/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,OAAO,CAAS;gBAEK,EAAE,EAAE,MAAM;IAIvC;;;OAGG;IACG,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCnD;;OAEG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU5C;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAU/B"}