@bike4mind/cli 0.2.64-worktree-refactor-extract-search-query-builders.21815 → 0.2.64

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 (85) hide show
  1. package/bin/bike4mind-cli.mjs +6 -6
  2. package/dist/BubblewrapRuntime-BHbtqvLx.mjs +72 -0
  3. package/dist/ConfigStore-CllM6jOf.mjs +8614 -0
  4. package/dist/ImageStore-DaKT_Ew8.mjs +202 -0
  5. package/dist/ProxyManager-Dl2nFk-A.mjs +259 -0
  6. package/dist/ProxyManager-kiOD1X8-.mjs +3 -0
  7. package/dist/SandboxOrchestrator-BEW3rqYi.mjs +159 -0
  8. package/dist/SandboxOrchestrator-CHZgSR3P.mjs +3 -0
  9. package/dist/SandboxRuntimeAdapter-C1B4t20N.mjs +57 -0
  10. package/dist/SandboxRuntimeAdapter-D7UAG13n.mjs +3 -0
  11. package/dist/SeatbeltRuntime-D4m0VOcD.mjs +116 -0
  12. package/dist/StderrViolationParser-D0afQ3-1.mjs +70 -0
  13. package/dist/ViolationLogStore-CZl35HcA.mjs +96 -0
  14. package/dist/bashExecute-BTkdqlSs-5foM20Lb.mjs +466 -0
  15. package/dist/commands/doctorCommand.mjs +101 -0
  16. package/dist/commands/headlessCommand.mjs +319 -0
  17. package/dist/commands/mcpCommand.mjs +218 -0
  18. package/dist/commands/updateCommand.mjs +40 -0
  19. package/dist/createFile-yQfh8uvk-I-yM5DxC.mjs +63 -0
  20. package/dist/deleteFile-DKHfnyny-G3b1Kj2T.mjs +66 -0
  21. package/dist/globFiles-D1en6joM-8jekiXdX.mjs +100 -0
  22. package/dist/grepSearch-aMamoBn_-DCJcY8JS.mjs +173 -0
  23. package/dist/index.mjs +6722 -0
  24. package/dist/pathValidation-Cgjh5WQO-DiCZTcq6.mjs +63 -0
  25. package/dist/store-Dw1nZX2Y.mjs +128 -0
  26. package/dist/store-nZExNOWX.mjs +3 -0
  27. package/dist/terminalSetup-rmr1P8KF.mjs +254 -0
  28. package/dist/tools-C6M5aW8W.mjs +20907 -0
  29. package/dist/treeSitterEngine-DCSXcm_3.mjs +309 -0
  30. package/dist/types-DBEjF9YS.mjs +59 -0
  31. package/dist/types-DK3P88Px.mjs +3 -0
  32. package/dist/updateChecker-Cu9dkHxV.mjs +120 -0
  33. package/package.json +10 -10
  34. package/dist/BubblewrapRuntime-PMIOLWKR.js +0 -71
  35. package/dist/HydrationEngine-YL2HWJ3V.js +0 -9
  36. package/dist/ImageStore-MMUOUPI2.js +0 -224
  37. package/dist/ProxyManager-HEB4TLVX.js +0 -7
  38. package/dist/SandboxOrchestrator-UIJ5GYBB.js +0 -8
  39. package/dist/SandboxRuntimeAdapter-FQ56MAB2.js +0 -13
  40. package/dist/SeatbeltRuntime-EE3TTLEP.js +0 -98
  41. package/dist/StderrViolationParser-7OYPM2DJ.js +0 -59
  42. package/dist/ViolationLogStore-RIIUVURH.js +0 -104
  43. package/dist/artifactExtractor-R7DIP2XO.js +0 -180
  44. package/dist/bashExecute-GLGLD3JD.js +0 -379
  45. package/dist/chunk-4BIBE3J7.js +0 -48
  46. package/dist/chunk-5LZS5CVJ.js +0 -161
  47. package/dist/chunk-BDQBOLYG.js +0 -120
  48. package/dist/chunk-BPFEGDC7.js +0 -192
  49. package/dist/chunk-EPIYC3LA.js +0 -13770
  50. package/dist/chunk-G4ZGEQFT.js +0 -250
  51. package/dist/chunk-GQGOWACU.js +0 -770
  52. package/dist/chunk-J6ZBI6TI.js +0 -1079
  53. package/dist/chunk-JW3JRHH7.js +0 -12433
  54. package/dist/chunk-KQAMBXAW.js +0 -163
  55. package/dist/chunk-KUVV2NAB.js +0 -19125
  56. package/dist/chunk-LTLJRF6I.js +0 -44
  57. package/dist/chunk-PFBYGCOW.js +0 -449
  58. package/dist/chunk-QWB6ZYY4.js +0 -48
  59. package/dist/chunk-SGPRXN4C.js +0 -245
  60. package/dist/chunk-UZUHPHZC.js +0 -95
  61. package/dist/chunk-WBE7SQUB.js +0 -241
  62. package/dist/chunk-Y4WOJJM3.js +0 -147
  63. package/dist/commands/doctorCommand.js +0 -87
  64. package/dist/commands/headlessCommand.js +0 -380
  65. package/dist/commands/mcpCommand.js +0 -203
  66. package/dist/commands/updateCommand.js +0 -42
  67. package/dist/create-C4VEEEYR.js +0 -12
  68. package/dist/createFile-6PSPLW6R.js +0 -71
  69. package/dist/deleteFile-AUSRLWIK.js +0 -73
  70. package/dist/formatConverter-5QEJDW24.js +0 -7
  71. package/dist/globFiles-TSRN64N2.js +0 -120
  72. package/dist/grepSearch-634XWZOJ.js +0 -216
  73. package/dist/index.js +0 -6779
  74. package/dist/llmMarkdownGenerator-Z6NB26TT.js +0 -371
  75. package/dist/markdownGenerator-SK2ZQQL4.js +0 -269
  76. package/dist/mementoService-N4IM6QAC.js +0 -12
  77. package/dist/notificationDeduplicator-HUC53NEW.js +0 -9
  78. package/dist/src-F4KZCAA2.js +0 -319
  79. package/dist/src-ISX322I7.js +0 -1101
  80. package/dist/store-CAB6BV3P.js +0 -11
  81. package/dist/subtractCredits-D4KEM6VU.js +0 -12
  82. package/dist/terminalSetup-C5FHMLC3.js +0 -214
  83. package/dist/treeSitterEngine-4SGFQDY3.js +0 -330
  84. package/dist/types-KB5NP6T4.js +0 -7
  85. package/dist/utils-JCHWDM4Z.js +0 -31
@@ -0,0 +1,202 @@
1
+ #!/usr/bin/env node
2
+ import { createHash } from "crypto";
3
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
4
+ import { homedir } from "os";
5
+ import { extname, join, resolve } from "path";
6
+ import Database from "better-sqlite3";
7
+ import sharp from "sharp";
8
+ //#region src/storage/ImageStore.ts
9
+ /**
10
+ * Local image cache for CLI
11
+ * Stores pasted/dropped images before upload to S3
12
+ */
13
+ var ImageStore = class ImageStore {
14
+ static {
15
+ this.BASE_DIR = join(homedir(), ".bike4mind", "cli");
16
+ }
17
+ static {
18
+ this.IMAGES_DIR = join(ImageStore.BASE_DIR, "images");
19
+ }
20
+ static {
21
+ this.DB_PATH = join(ImageStore.BASE_DIR, "images.db");
22
+ }
23
+ static {
24
+ this.RETENTION_DAYS = 7;
25
+ }
26
+ static {
27
+ this.MAX_RAW_SIZE = 750 * 1024;
28
+ }
29
+ static {
30
+ this.MAX_PRECOMPRESS_SIZE = 50 * 1024 * 1024;
31
+ }
32
+ constructor() {
33
+ this.ensureDirectories();
34
+ this.db = new Database(ImageStore.DB_PATH);
35
+ this.initDatabase();
36
+ try {
37
+ this.cleanupOldImages();
38
+ } catch (err) {
39
+ console.warn("Failed to cleanup old images:", err);
40
+ }
41
+ }
42
+ ensureDirectories() {
43
+ mkdirSync(ImageStore.BASE_DIR, { recursive: true });
44
+ mkdirSync(ImageStore.IMAGES_DIR, { recursive: true });
45
+ }
46
+ initDatabase() {
47
+ this.db.exec(`
48
+ CREATE TABLE IF NOT EXISTS images (
49
+ hash TEXT PRIMARY KEY,
50
+ format TEXT NOT NULL,
51
+ size INTEGER NOT NULL,
52
+ timestamp INTEGER NOT NULL,
53
+ uploaded INTEGER NOT NULL DEFAULT 0,
54
+ s3_url TEXT,
55
+ original_filename TEXT
56
+ )
57
+ `);
58
+ }
59
+ /**
60
+ * Store an image locally with content-based hashing for deduplication
61
+ */
62
+ async store(imageData, originalFilename) {
63
+ const { buffer: processedData, format: processedFormat } = await this.processImage(imageData, originalFilename);
64
+ const hash = this.generateHash(processedData);
65
+ const format = processedFormat;
66
+ const ext = format.toLowerCase();
67
+ const localPath = join(ImageStore.IMAGES_DIR, `${hash}.${ext}`);
68
+ const existing = this.getMetadata(hash);
69
+ if (existing) return {
70
+ hash,
71
+ placeholder: "",
72
+ localPath,
73
+ metadata: existing
74
+ };
75
+ writeFileSync(localPath, processedData);
76
+ const metadata = {
77
+ hash,
78
+ format,
79
+ size: processedData.length,
80
+ timestamp: Date.now(),
81
+ uploaded: false,
82
+ originalFilename
83
+ };
84
+ this.db.prepare(`INSERT INTO images (hash, format, size, timestamp, uploaded, original_filename)
85
+ VALUES (?, ?, ?, ?, ?, ?)`).run(hash, format, metadata.size, metadata.timestamp, 0, originalFilename || null);
86
+ return {
87
+ hash,
88
+ placeholder: "",
89
+ localPath,
90
+ metadata
91
+ };
92
+ }
93
+ /**
94
+ * Get image metadata by hash
95
+ */
96
+ getMetadata(hash) {
97
+ const row = this.db.prepare("SELECT * FROM images WHERE hash = ?").get(hash);
98
+ if (!row) return null;
99
+ return {
100
+ hash: row.hash,
101
+ format: row.format,
102
+ size: row.size,
103
+ timestamp: row.timestamp,
104
+ uploaded: Boolean(row.uploaded),
105
+ s3Url: row.s3_url,
106
+ originalFilename: row.original_filename
107
+ };
108
+ }
109
+ /**
110
+ * Read image data from local cache
111
+ */
112
+ readImage(hash) {
113
+ const metadata = this.getMetadata(hash);
114
+ if (!metadata) return null;
115
+ const localPath = join(ImageStore.IMAGES_DIR, `${hash}.${metadata.format.toLowerCase()}`);
116
+ if (!resolve(localPath).startsWith(resolve(ImageStore.IMAGES_DIR))) throw new Error("Invalid image path");
117
+ if (!existsSync(localPath)) return null;
118
+ return readFileSync(localPath);
119
+ }
120
+ /**
121
+ * Generate content hash for deduplication
122
+ */
123
+ generateHash(data) {
124
+ return createHash("sha256").update(data).digest("hex").substring(0, 16);
125
+ }
126
+ /**
127
+ * Process image: compress if needed to stay under size limit
128
+ */
129
+ async processImage(data, originalFilename) {
130
+ if (data.length > ImageStore.MAX_PRECOMPRESS_SIZE) throw new Error(`Image too large to process (${Math.round(data.length / 1024 / 1024)}MB). Maximum size is ${ImageStore.MAX_PRECOMPRESS_SIZE / 1024 / 1024}MB.`);
131
+ const originalFormat = this.detectFormat(data, originalFilename);
132
+ if (data.length <= ImageStore.MAX_RAW_SIZE) return {
133
+ buffer: data,
134
+ format: originalFormat
135
+ };
136
+ let image = sharp(data);
137
+ const metadata = await image.metadata();
138
+ if (!metadata.width || !metadata.height) throw new Error("Unable to read image dimensions");
139
+ const maxDimension = 2048;
140
+ let width = metadata.width;
141
+ let height = metadata.height;
142
+ if (width > maxDimension || height > maxDimension) if (width > height) {
143
+ height = Math.round(height * maxDimension / width);
144
+ width = maxDimension;
145
+ } else {
146
+ width = Math.round(width * maxDimension / height);
147
+ height = maxDimension;
148
+ }
149
+ image = image.resize(width, height);
150
+ let quality = 85;
151
+ let buffer = await image.jpeg({ quality }).toBuffer();
152
+ while (buffer.length > ImageStore.MAX_RAW_SIZE && quality > 30) {
153
+ quality -= 10;
154
+ buffer = await image.jpeg({ quality }).toBuffer();
155
+ }
156
+ if (buffer.length > ImageStore.MAX_RAW_SIZE) throw new Error(`Unable to compress image below ${ImageStore.MAX_RAW_SIZE / 1024}KB limit`);
157
+ return {
158
+ buffer,
159
+ format: "jpg"
160
+ };
161
+ }
162
+ /**
163
+ * Detect image format from buffer or filename
164
+ */
165
+ detectFormat(data, filename) {
166
+ if (data[0] === 137 && data[1] === 80 && data[2] === 78 && data[3] === 71) return "png";
167
+ if (data[0] === 255 && data[1] === 216 && data[2] === 255) return "jpg";
168
+ if (data[0] === 71 && data[1] === 73 && data[2] === 70) return "gif";
169
+ if (data[0] === 82 && data[1] === 73 && data[2] === 70 && data[3] === 70) return "webp";
170
+ if (filename) {
171
+ const ext = extname(filename).substring(1).toLowerCase();
172
+ if ([
173
+ "png",
174
+ "jpg",
175
+ "jpeg",
176
+ "gif",
177
+ "webp"
178
+ ].includes(ext)) return ext === "jpeg" ? "jpg" : ext;
179
+ }
180
+ return "png";
181
+ }
182
+ /**
183
+ * Clean up images older than retention period
184
+ */
185
+ cleanupOldImages() {
186
+ const cutoffTime = Date.now() - ImageStore.RETENTION_DAYS * 24 * 60 * 60 * 1e3;
187
+ const oldImages = this.db.prepare("SELECT hash, format FROM images WHERE timestamp < ?").all(cutoffTime);
188
+ for (const { hash, format } of oldImages) {
189
+ const localPath = join(ImageStore.IMAGES_DIR, `${hash}.${format.toLowerCase()}`);
190
+ if (existsSync(localPath)) unlinkSync(localPath);
191
+ }
192
+ this.db.prepare("DELETE FROM images WHERE timestamp < ?").run(cutoffTime);
193
+ }
194
+ /**
195
+ * Close database connection
196
+ */
197
+ close() {
198
+ this.db.close();
199
+ }
200
+ };
201
+ //#endregion
202
+ export { ImageStore };
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env node
2
+ import { EventEmitter } from "events";
3
+ import http from "http";
4
+ import net from "net";
5
+ //#region src/sandbox/proxy/domainMatcher.ts
6
+ /**
7
+ * Domain matching utilities for the network proxy allowlist.
8
+ * Pure functions, zero dependencies.
9
+ */
10
+ /**
11
+ * Normalize a domain for comparison: lowercase, strip port, strip trailing dot.
12
+ */
13
+ function normalizeDomain(domain) {
14
+ let d = domain.toLowerCase().trim();
15
+ const colonIdx = d.lastIndexOf(":");
16
+ if (colonIdx > 0) {
17
+ const afterColon = d.slice(colonIdx + 1);
18
+ if (/^\d+$/.test(afterColon)) d = d.slice(0, colonIdx);
19
+ }
20
+ if (d.endsWith(".")) d = d.slice(0, -1);
21
+ return d;
22
+ }
23
+ /**
24
+ * Check if a domain matches a pattern.
25
+ * - Exact match: "github.com" matches "github.com"
26
+ * - Wildcard: "*.github.com" matches "api.github.com" but NOT "github.com"
27
+ */
28
+ function matchesDomain(domain, pattern) {
29
+ const d = normalizeDomain(domain);
30
+ const p = normalizeDomain(pattern);
31
+ if (d === p) return true;
32
+ if (p.startsWith("*.")) {
33
+ const suffix = p.slice(1);
34
+ return d.endsWith(suffix) && d.length > suffix.length;
35
+ }
36
+ return false;
37
+ }
38
+ /**
39
+ * Check if a domain is in the allowed list.
40
+ */
41
+ function isDomainAllowed(domain, allowedDomains) {
42
+ if (!domain || allowedDomains.length === 0) return false;
43
+ return allowedDomains.some((pattern) => matchesDomain(domain, pattern));
44
+ }
45
+ //#endregion
46
+ //#region src/sandbox/proxy/HttpConnectProxy.ts
47
+ /**
48
+ * HTTP CONNECT proxy for network domain filtering.
49
+ *
50
+ * Intercepts outbound HTTP/HTTPS connections from sandboxed commands
51
+ * and filters by domain allowlist. Uses only Node.js built-ins.
52
+ *
53
+ * - CONNECT handler (HTTPS): Parse domain → check allowlist → tunnel or 403
54
+ * - HTTP handler (forward proxy): Parse host → check allowlist → forward or 403
55
+ */
56
+ var HttpConnectProxy = class extends EventEmitter {
57
+ constructor(options) {
58
+ super();
59
+ this.server = null;
60
+ this.activeSockets = /* @__PURE__ */ new Set();
61
+ this.allowedDomains = [...options.allowedDomains];
62
+ this.requestedPort = options.port ?? 0;
63
+ }
64
+ async start() {
65
+ if (this.server) throw new Error("Proxy is already running");
66
+ return new Promise((resolve, reject) => {
67
+ const server = http.createServer((req, res) => {
68
+ this.handleHttpRequest(req, res);
69
+ });
70
+ server.on("connect", (req, clientSocket, head) => {
71
+ this.handleConnect(req, clientSocket, head);
72
+ });
73
+ server.on("connection", (socket) => {
74
+ this.activeSockets.add(socket);
75
+ socket.on("close", () => this.activeSockets.delete(socket));
76
+ });
77
+ server.on("error", reject);
78
+ server.listen(this.requestedPort, "127.0.0.1", () => {
79
+ const addr = server.address();
80
+ if (!addr || typeof addr === "string") {
81
+ reject(/* @__PURE__ */ new Error("Failed to get server address"));
82
+ return;
83
+ }
84
+ this.server = server;
85
+ resolve(addr.port);
86
+ });
87
+ });
88
+ }
89
+ async stop() {
90
+ if (!this.server) return;
91
+ for (const socket of this.activeSockets) socket.destroy();
92
+ this.activeSockets.clear();
93
+ return new Promise((resolve, reject) => {
94
+ this.server.close((err) => {
95
+ this.server = null;
96
+ if (err) reject(err);
97
+ else resolve();
98
+ });
99
+ });
100
+ }
101
+ updateAllowedDomains(domains) {
102
+ this.allowedDomains = [...domains];
103
+ }
104
+ getPort() {
105
+ if (!this.server) return null;
106
+ const addr = this.server.address();
107
+ if (!addr || typeof addr === "string") return null;
108
+ return addr.port;
109
+ }
110
+ isRunning() {
111
+ return this.server !== null;
112
+ }
113
+ emitEvent(type, domain, method) {
114
+ const event = {
115
+ type,
116
+ domain,
117
+ method,
118
+ timestamp: /* @__PURE__ */ new Date()
119
+ };
120
+ this.emit("proxy-event", event);
121
+ }
122
+ /**
123
+ * Handle CONNECT requests (HTTPS tunneling).
124
+ */
125
+ handleConnect(req, clientSocket, head) {
126
+ const target = req.url || "";
127
+ const [host] = target.split(":");
128
+ const port = parseInt(target.split(":")[1] || "443", 10);
129
+ if (!isDomainAllowed(host, this.allowedDomains)) {
130
+ this.emitEvent("blocked", host, "CONNECT");
131
+ clientSocket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
132
+ clientSocket.end();
133
+ return;
134
+ }
135
+ this.emitEvent("allowed", host, "CONNECT");
136
+ const serverSocket = net.connect(port, host, () => {
137
+ clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
138
+ if (head.length > 0) serverSocket.write(head);
139
+ serverSocket.pipe(clientSocket);
140
+ clientSocket.pipe(serverSocket);
141
+ });
142
+ serverSocket.setTimeout(5e3, () => {
143
+ serverSocket.destroy();
144
+ clientSocket.write("HTTP/1.1 504 Gateway Timeout\r\n\r\n");
145
+ clientSocket.end();
146
+ });
147
+ serverSocket.on("error", () => {
148
+ clientSocket.write("HTTP/1.1 502 Bad Gateway\r\n\r\n");
149
+ clientSocket.end();
150
+ });
151
+ clientSocket.on("error", () => {
152
+ serverSocket.destroy();
153
+ });
154
+ }
155
+ /**
156
+ * Handle plain HTTP forward proxy requests.
157
+ */
158
+ handleHttpRequest(req, res) {
159
+ const url = req.url || "";
160
+ let host;
161
+ try {
162
+ host = new URL(url).hostname;
163
+ } catch {
164
+ host = (req.headers.host || "").split(":")[0];
165
+ }
166
+ if (!host || !isDomainAllowed(host, this.allowedDomains)) {
167
+ this.emitEvent("blocked", host || "unknown", req.method || "GET");
168
+ res.writeHead(403, { "Content-Type": "text/plain" });
169
+ res.end("Blocked by sandbox network proxy");
170
+ return;
171
+ }
172
+ this.emitEvent("allowed", host, req.method || "GET");
173
+ const parsed = new URL(url);
174
+ const proxyReq = http.request({
175
+ hostname: parsed.hostname,
176
+ port: parsed.port || 80,
177
+ path: parsed.pathname + parsed.search,
178
+ method: req.method,
179
+ headers: req.headers
180
+ }, (proxyRes) => {
181
+ res.writeHead(proxyRes.statusCode || 502, proxyRes.headers);
182
+ proxyRes.pipe(res);
183
+ });
184
+ proxyReq.on("error", () => {
185
+ res.writeHead(502, { "Content-Type": "text/plain" });
186
+ res.end("Bad Gateway");
187
+ });
188
+ req.pipe(proxyReq);
189
+ }
190
+ };
191
+ //#endregion
192
+ //#region src/sandbox/proxy/ProxyManager.ts
193
+ var ProxyManager = class {
194
+ constructor(networkConfig) {
195
+ this.proxy = null;
196
+ this.eventHandlers = /* @__PURE__ */ new Set();
197
+ this.networkConfig = {
198
+ ...networkConfig,
199
+ allowedDomains: [...networkConfig.allowedDomains]
200
+ };
201
+ }
202
+ async start() {
203
+ if (!this.networkConfig.enabled) return;
204
+ if (this.proxy?.isRunning()) return;
205
+ this.proxy = new HttpConnectProxy({ allowedDomains: this.networkConfig.allowedDomains });
206
+ this.proxy.on("proxy-event", (event) => {
207
+ for (const handler of this.eventHandlers) handler(event);
208
+ });
209
+ await this.proxy.start();
210
+ }
211
+ async stop() {
212
+ if (!this.proxy) return;
213
+ await this.proxy.stop();
214
+ this.proxy = null;
215
+ }
216
+ /**
217
+ * Get proxy env vars for injecting into sandboxed processes.
218
+ * Returns both upper and lowercase variants for maximum compatibility.
219
+ */
220
+ getProxyEnv() {
221
+ if (!this.proxy?.isRunning()) return {};
222
+ const port = this.proxy.getPort();
223
+ if (!port) return {};
224
+ const proxyUrl = `http://127.0.0.1:${port}`;
225
+ const noProxy = "localhost,127.0.0.1,::1";
226
+ return {
227
+ HTTP_PROXY: proxyUrl,
228
+ http_proxy: proxyUrl,
229
+ HTTPS_PROXY: proxyUrl,
230
+ https_proxy: proxyUrl,
231
+ NO_PROXY: noProxy,
232
+ no_proxy: noProxy
233
+ };
234
+ }
235
+ addAllowedDomain(domain) {
236
+ if (!this.networkConfig.allowedDomains.includes(domain)) {
237
+ this.networkConfig.allowedDomains.push(domain);
238
+ this.proxy?.updateAllowedDomains(this.networkConfig.allowedDomains);
239
+ }
240
+ }
241
+ getAllowedDomains() {
242
+ return [...this.networkConfig.allowedDomains];
243
+ }
244
+ isRunning() {
245
+ return this.proxy?.isRunning() ?? false;
246
+ }
247
+ getPort() {
248
+ return this.proxy?.getPort() ?? null;
249
+ }
250
+ /**
251
+ * Subscribe to proxy events. Returns an unsubscribe function.
252
+ */
253
+ onEvent(handler) {
254
+ this.eventHandlers.add(handler);
255
+ return () => this.eventHandlers.delete(handler);
256
+ }
257
+ };
258
+ //#endregion
259
+ export { ProxyManager as t };
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { t as ProxyManager } from "./ProxyManager-Dl2nFk-A.mjs";
3
+ export { ProxyManager };
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env node
2
+ import { t as DEFAULT_SANDBOX_CONFIG } from "./types-DBEjF9YS.mjs";
3
+ //#region src/sandbox/SandboxOrchestrator.ts
4
+ var SandboxOrchestrator = class {
5
+ constructor(config, runtime, proxyManager) {
6
+ this.stats = {
7
+ sandboxed: 0,
8
+ unsandboxed: 0,
9
+ blocked: 0,
10
+ violations: 0
11
+ };
12
+ this.violationStore = null;
13
+ this.config = config ?? DEFAULT_SANDBOX_CONFIG;
14
+ this.runtime = runtime ?? null;
15
+ this.proxyManager = proxyManager ?? null;
16
+ }
17
+ /**
18
+ * Determine whether a command should be sandboxed.
19
+ *
20
+ * Decision logic:
21
+ * 1. If sandbox is disabled → unsandboxed (no permission change)
22
+ * 2. If command matches an excluded command → unsandboxed (requires permission)
23
+ * 3. If runtime is not available → unsandboxed with warning
24
+ * 4. Otherwise → sandbox the command
25
+ */
26
+ shouldSandbox(command, cwd) {
27
+ if (!this.config.enabled || this.config.mode === "disabled") return {
28
+ type: "unsandboxed",
29
+ requiresPermission: true
30
+ };
31
+ const baseCommand = this.getBaseCommand(command);
32
+ if (this.isExcludedCommand(baseCommand)) {
33
+ if (!this.config.allowUnsandboxedCommands) return {
34
+ type: "blocked",
35
+ reason: `Command '${baseCommand}' is excluded from sandboxing and unsandboxed commands are not allowed`
36
+ };
37
+ return {
38
+ type: "unsandboxed",
39
+ requiresPermission: true,
40
+ reason: `Command '${baseCommand}' is excluded from sandboxing`
41
+ };
42
+ }
43
+ if (!this.runtime) return {
44
+ type: "unsandboxed",
45
+ requiresPermission: true,
46
+ reason: "Sandbox runtime not available on this platform"
47
+ };
48
+ const proxyEnv = this.proxyManager?.getProxyEnv() ?? {};
49
+ return {
50
+ type: "sandbox",
51
+ wrappedCommand: this.runtime.wrapCommand({
52
+ command,
53
+ cwd,
54
+ filesystemConfig: this.config.filesystem,
55
+ env: proxyEnv,
56
+ ...this.runtime.platform === "linux" && this.config.platform.linux.seccompProfile && { seccompProfile: this.config.platform.linux.seccompProfile }
57
+ })
58
+ };
59
+ }
60
+ /** Get the current sandbox mode */
61
+ getMode() {
62
+ return this.config.mode;
63
+ }
64
+ /** Set the sandbox mode (does not persist — caller must save config) */
65
+ setMode(mode) {
66
+ this.config.mode = mode;
67
+ this.config.enabled = mode !== "disabled";
68
+ }
69
+ /** Check if sandbox is enabled and runtime is available */
70
+ isAvailable() {
71
+ return this.runtime !== null && this.runtime.isAvailable();
72
+ }
73
+ /** Check if sandbox is currently active (enabled + available) */
74
+ isActive() {
75
+ return this.config.enabled && this.config.mode !== "disabled" && this.isAvailable();
76
+ }
77
+ /** Get the current sandbox configuration */
78
+ getConfig() {
79
+ return this.config;
80
+ }
81
+ /** Update config (does not persist — caller must save) */
82
+ updateConfig(config) {
83
+ this.config = config;
84
+ }
85
+ /** Get the ProxyManager instance (if any) */
86
+ getProxyManager() {
87
+ return this.proxyManager;
88
+ }
89
+ /** Start the network proxy (if configured) */
90
+ async startProxy() {
91
+ await this.proxyManager?.start();
92
+ }
93
+ /** Stop the network proxy */
94
+ async stopProxy() {
95
+ await this.proxyManager?.stop();
96
+ }
97
+ /** Get full status information for display */
98
+ getStatus() {
99
+ return {
100
+ mode: this.config.mode,
101
+ enabled: this.config.enabled,
102
+ platform: this.runtime?.platform ?? null,
103
+ runtimeAvailable: this.runtime?.isAvailable() ?? false,
104
+ runtimeName: this.runtime?.name ?? null,
105
+ proxyRunning: this.proxyManager?.isRunning() ?? false,
106
+ proxyPort: this.proxyManager?.getPort() ?? null,
107
+ config: this.config,
108
+ stats: { ...this.stats }
109
+ };
110
+ }
111
+ recordSandboxed() {
112
+ this.stats.sandboxed++;
113
+ }
114
+ recordUnsandboxed() {
115
+ this.stats.unsandboxed++;
116
+ }
117
+ recordBlocked() {
118
+ this.stats.blocked++;
119
+ }
120
+ recordViolations(count = 1) {
121
+ this.stats.violations += count;
122
+ }
123
+ getStats() {
124
+ return { ...this.stats };
125
+ }
126
+ resetStats() {
127
+ this.stats = {
128
+ sandboxed: 0,
129
+ unsandboxed: 0,
130
+ blocked: 0,
131
+ violations: 0
132
+ };
133
+ }
134
+ setViolationStore(store) {
135
+ this.violationStore = store;
136
+ }
137
+ getViolationStore() {
138
+ return this.violationStore;
139
+ }
140
+ /** Record a violation to store and increment stats */
141
+ async recordViolation(violation) {
142
+ this.stats.violations++;
143
+ await this.violationStore?.record(violation).catch(() => {});
144
+ }
145
+ /**
146
+ * Extract the base command name from a full command string.
147
+ * e.g., "docker compose up -d" → "docker"
148
+ */
149
+ getBaseCommand(command) {
150
+ const first = command.trim().replace(/^(\w+=\S+\s+)*/, "").split(/\s+/)[0] || "";
151
+ return first.split("/").pop() || first;
152
+ }
153
+ /** Check if a command is in the excluded list */
154
+ isExcludedCommand(baseCommand) {
155
+ return this.config.excludedCommands.some((excluded) => baseCommand === excluded);
156
+ }
157
+ };
158
+ //#endregion
159
+ export { SandboxOrchestrator as t };
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { t as SandboxOrchestrator } from "./SandboxOrchestrator-BEW3rqYi.mjs";
3
+ export { SandboxOrchestrator };
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+ import { accessSync, constants } from "fs";
3
+ import os from "os";
4
+ import path from "path";
5
+ //#region src/sandbox/runtime/SandboxRuntimeAdapter.ts
6
+ /**
7
+ * Abstract sandbox runtime adapter with platform detection and factory.
8
+ */
9
+ /**
10
+ * Detect the current platform.
11
+ * Returns null if the platform is not supported for sandboxing.
12
+ */
13
+ function detectPlatform() {
14
+ const platform = os.platform();
15
+ if (platform === "darwin") return "darwin";
16
+ if (platform === "linux") return "linux";
17
+ return null;
18
+ }
19
+ /**
20
+ * Check if a binary exists on the system PATH.
21
+ * Uses pure filesystem checks instead of shell execution to avoid command injection.
22
+ */
23
+ function isBinaryAvailable(binary) {
24
+ const pathDirs = (process.env.PATH || "").split(path.delimiter);
25
+ for (const dir of pathDirs) try {
26
+ accessSync(path.join(dir, binary), constants.X_OK);
27
+ return true;
28
+ } catch {}
29
+ return false;
30
+ }
31
+ /**
32
+ * Expand environment variables ($HOME, $USER) in a path string.
33
+ */
34
+ function expandPath(pathStr) {
35
+ return pathStr.replace(/\$HOME/g, os.homedir()).replace(/\$USER/g, os.userInfo().username).replace(/~\//g, `${os.homedir()}/`);
36
+ }
37
+ /**
38
+ * Factory function to create the appropriate sandbox runtime for the current platform.
39
+ * Returns null if the platform is unsupported or the runtime binary is not available.
40
+ */
41
+ async function createSandboxRuntime() {
42
+ const platform = detectPlatform();
43
+ if (!platform) return null;
44
+ if (platform === "darwin") {
45
+ const { SeatbeltRuntime } = await import("./SeatbeltRuntime-D4m0VOcD.mjs");
46
+ const runtime = new SeatbeltRuntime();
47
+ return runtime.isAvailable() ? runtime : null;
48
+ }
49
+ if (platform === "linux") {
50
+ const { BubblewrapRuntime } = await import("./BubblewrapRuntime-BHbtqvLx.mjs");
51
+ const runtime = new BubblewrapRuntime();
52
+ return runtime.isAvailable() ? runtime : null;
53
+ }
54
+ return null;
55
+ }
56
+ //#endregion
57
+ export { isBinaryAvailable as i, detectPlatform as n, expandPath as r, createSandboxRuntime as t };
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { i as isBinaryAvailable, n as detectPlatform, r as expandPath, t as createSandboxRuntime } from "./SandboxRuntimeAdapter-C1B4t20N.mjs";
3
+ export { createSandboxRuntime, detectPlatform, expandPath, isBinaryAvailable };