@isarai/maestro 0.1.2 → 0.1.3
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 +3 -0
- package/dist/index.js +125 -1
- package/dist/index.js.map +2 -2
- package/dist/server.js +11 -318
- package/dist/server.js.map +2 -2
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -22,108 +22,6 @@ function resolveBinaryPath(binary) {
|
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
function runNsjailSelfTest(binaryPath) {
|
|
26
|
-
const args = [
|
|
27
|
-
"--mode",
|
|
28
|
-
"o",
|
|
29
|
-
"--chroot",
|
|
30
|
-
"/",
|
|
31
|
-
"--user",
|
|
32
|
-
"0",
|
|
33
|
-
"--group",
|
|
34
|
-
"0",
|
|
35
|
-
"--disable_clone_newuser",
|
|
36
|
-
"--disable_clone_newnet",
|
|
37
|
-
"--cwd",
|
|
38
|
-
"/",
|
|
39
|
-
"--bindmount_ro",
|
|
40
|
-
"/usr:/usr",
|
|
41
|
-
"--bindmount_ro",
|
|
42
|
-
"/bin:/bin",
|
|
43
|
-
"--bindmount_ro",
|
|
44
|
-
"/lib:/lib",
|
|
45
|
-
"--bindmount_ro",
|
|
46
|
-
"/sbin:/sbin",
|
|
47
|
-
"--bindmount_ro",
|
|
48
|
-
"/etc:/etc",
|
|
49
|
-
"--bindmount",
|
|
50
|
-
"/dev:/dev",
|
|
51
|
-
"--tmpfsmount",
|
|
52
|
-
"/tmp"
|
|
53
|
-
];
|
|
54
|
-
if (fs.existsSync("/lib64")) {
|
|
55
|
-
args.push("--bindmount_ro", "/lib64:/lib64");
|
|
56
|
-
}
|
|
57
|
-
args.push("--", "/bin/true");
|
|
58
|
-
try {
|
|
59
|
-
execFileSync(binaryPath, args, {
|
|
60
|
-
stdio: ["ignore", "ignore", "pipe"]
|
|
61
|
-
});
|
|
62
|
-
return { ok: true, reason: null };
|
|
63
|
-
} catch (error) {
|
|
64
|
-
return {
|
|
65
|
-
ok: false,
|
|
66
|
-
reason: formatNsjailSelfTestError(error)
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
function formatNsjailSelfTestError(error) {
|
|
71
|
-
const appArmorProfile = getCurrentAppArmorProfile();
|
|
72
|
-
if (error && typeof error === "object" && "stderr" in error && (typeof error.stderr === "string" || Buffer.isBuffer(error.stderr))) {
|
|
73
|
-
const stderr = String(error.stderr).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
74
|
-
const detail = stderr.find((line) => line.includes("Permission denied")) || stderr.find((line) => line.includes("buildMountTree()")) || stderr.find((line) => line.includes("runChild()")) || stderr.at(-1);
|
|
75
|
-
if (detail) {
|
|
76
|
-
return buildNsjailUnavailableReason(detail, appArmorProfile);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return buildNsjailUnavailableReason("nsjail runtime self-test failed", appArmorProfile);
|
|
80
|
-
}
|
|
81
|
-
function buildNsjailUnavailableReason(detail, appArmorProfile) {
|
|
82
|
-
if (detail.includes("Permission denied")) {
|
|
83
|
-
if (appArmorProfile && appArmorProfile !== "unconfined") {
|
|
84
|
-
return `${detail}. Active AppArmor profile '${appArmorProfile}' is likely blocking mount namespace setup; when running Maestro in Docker, add \`security_opt: ["seccomp=unconfined", "apparmor=unconfined"]\` to the server container or run it with \`--privileged\`.`;
|
|
85
|
-
}
|
|
86
|
-
return `${detail}. The runtime is blocking mount namespace setup required by nsjail; when running in Docker, allow unconfined AppArmor/seccomp or run with \`--privileged\`.`;
|
|
87
|
-
}
|
|
88
|
-
return detail;
|
|
89
|
-
}
|
|
90
|
-
function getCurrentAppArmorProfile() {
|
|
91
|
-
try {
|
|
92
|
-
const profile = fs.readFileSync("/proc/self/attr/current", "utf-8").trim();
|
|
93
|
-
return profile || null;
|
|
94
|
-
} catch {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
function isNsjailAvailable() {
|
|
99
|
-
if (process.platform !== "linux") {
|
|
100
|
-
nsjailUnavailableReason = `nsjail is only supported on Linux (current platform: ${process.platform})`;
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
if (nsjailPath === void 0) {
|
|
104
|
-
nsjailPath = resolveBinaryPath("nsjail");
|
|
105
|
-
}
|
|
106
|
-
if (!nsjailPath) {
|
|
107
|
-
nsjailUnavailableReason = "nsjail binary was not found in PATH";
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
if (nsjailRuntimeAvailable === void 0) {
|
|
111
|
-
const result = runNsjailSelfTest(nsjailPath);
|
|
112
|
-
nsjailRuntimeAvailable = result.ok;
|
|
113
|
-
nsjailUnavailableReason = result.reason;
|
|
114
|
-
}
|
|
115
|
-
return nsjailRuntimeAvailable;
|
|
116
|
-
}
|
|
117
|
-
function getNsjailPath() {
|
|
118
|
-
if (!isNsjailAvailable() || !nsjailPath) {
|
|
119
|
-
const reason = nsjailUnavailableReason ? `: ${nsjailUnavailableReason}` : "";
|
|
120
|
-
throw new Error(`nsjail is not available${reason}`);
|
|
121
|
-
}
|
|
122
|
-
return nsjailPath;
|
|
123
|
-
}
|
|
124
|
-
function getNsjailUnavailableReason() {
|
|
125
|
-
return isNsjailAvailable() ? null : nsjailUnavailableReason ?? null;
|
|
126
|
-
}
|
|
127
25
|
function isDockerAvailable() {
|
|
128
26
|
if (dockerPath === void 0) {
|
|
129
27
|
dockerPath = resolveBinaryPath("docker");
|
|
@@ -151,126 +49,22 @@ function getDockerPath() {
|
|
|
151
49
|
return dockerPath;
|
|
152
50
|
}
|
|
153
51
|
function normalizeSandboxProvider(value, legacyEnabled = false) {
|
|
154
|
-
if (value === "none" || value === "
|
|
52
|
+
if (value === "none" || value === "docker") {
|
|
155
53
|
return value;
|
|
156
54
|
}
|
|
157
|
-
return legacyEnabled ? "
|
|
55
|
+
return legacyEnabled ? "docker" : "none";
|
|
158
56
|
}
|
|
159
57
|
function resolveSandboxProviderAvailability(requested, availability) {
|
|
160
58
|
if (requested === "docker") {
|
|
161
59
|
return availability.dockerAvailable ? "docker" : "none";
|
|
162
60
|
}
|
|
163
|
-
if (requested === "nsjail") {
|
|
164
|
-
return availability.nsjailAvailable ? "nsjail" : "none";
|
|
165
|
-
}
|
|
166
61
|
return "none";
|
|
167
62
|
}
|
|
168
63
|
function resolveSandboxProvider(requested) {
|
|
169
64
|
return resolveSandboxProviderAvailability(requested, {
|
|
170
|
-
nsjailAvailable: isNsjailAvailable(),
|
|
171
65
|
dockerAvailable: isDockerAvailable()
|
|
172
66
|
});
|
|
173
67
|
}
|
|
174
|
-
function ensureSandboxWritable(dirPath) {
|
|
175
|
-
try {
|
|
176
|
-
execSync(`chown -R ${SANDBOX_UID}:${SANDBOX_GID} ${JSON.stringify(dirPath)}`, {
|
|
177
|
-
stdio: "ignore"
|
|
178
|
-
});
|
|
179
|
-
} catch {
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
function buildNsjailArgs(config) {
|
|
183
|
-
const home = os.homedir();
|
|
184
|
-
const sandboxHome = "/home/sandbox";
|
|
185
|
-
const mountedReadonlyRoots = [...BASE_READONLY_MOUNTS];
|
|
186
|
-
const nodeBin = getNodeBinaryDir();
|
|
187
|
-
const npmGlobalPrefix = getNpmGlobalPrefix();
|
|
188
|
-
const codexCompanionBinDir = getCliCompanionBinDir("codex");
|
|
189
|
-
const args = [
|
|
190
|
-
"--mode",
|
|
191
|
-
"o",
|
|
192
|
-
"--chroot",
|
|
193
|
-
"/",
|
|
194
|
-
"--user",
|
|
195
|
-
`${SANDBOX_UID}`,
|
|
196
|
-
"--group",
|
|
197
|
-
`${SANDBOX_GID}`,
|
|
198
|
-
"--disable_clone_newuser",
|
|
199
|
-
"--disable_clone_newnet",
|
|
200
|
-
"--forward_signals",
|
|
201
|
-
"--cwd",
|
|
202
|
-
config.cwd,
|
|
203
|
-
"--detect_cgroupv2",
|
|
204
|
-
"--cgroup_mem_max",
|
|
205
|
-
String(config.memoryLimit ?? DEFAULT_MEMORY_LIMIT),
|
|
206
|
-
"--cgroup_pids_max",
|
|
207
|
-
String(config.maxProcesses ?? DEFAULT_MAX_PROCESSES),
|
|
208
|
-
"--rlimit_cpu",
|
|
209
|
-
"soft",
|
|
210
|
-
"--rlimit_fsize",
|
|
211
|
-
"1024",
|
|
212
|
-
"--rlimit_nproc",
|
|
213
|
-
String(config.maxProcesses ?? DEFAULT_MAX_PROCESSES),
|
|
214
|
-
"--rlimit_nofile",
|
|
215
|
-
"1024",
|
|
216
|
-
"--really_quiet"
|
|
217
|
-
];
|
|
218
|
-
for (const dir of BASE_READONLY_MOUNTS) {
|
|
219
|
-
if (fs.existsSync(dir)) {
|
|
220
|
-
args.push("--bindmount_ro", `${dir}:${dir}`);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
if (fs.existsSync("/lib64")) {
|
|
224
|
-
args.push("--bindmount_ro", "/lib64:/lib64");
|
|
225
|
-
}
|
|
226
|
-
args.push("--bindmount", "/dev:/dev");
|
|
227
|
-
args.push("--tmpfsmount", "/tmp");
|
|
228
|
-
args.push("--bindmount", `${config.cwd}:${config.cwd}`);
|
|
229
|
-
if (fs.existsSync("/nix")) {
|
|
230
|
-
args.push("--bindmount_ro", "/nix:/nix");
|
|
231
|
-
}
|
|
232
|
-
if (nodeBin && !isAlreadyMounted(nodeBin, mountedReadonlyRoots)) {
|
|
233
|
-
args.push("--bindmount_ro", `${nodeBin}:${nodeBin}`);
|
|
234
|
-
mountedReadonlyRoots.push(nodeBin);
|
|
235
|
-
}
|
|
236
|
-
if (npmGlobalPrefix && !isAlreadyMounted(npmGlobalPrefix, mountedReadonlyRoots)) {
|
|
237
|
-
args.push("--bindmount_ro", `${npmGlobalPrefix}:${npmGlobalPrefix}`);
|
|
238
|
-
mountedReadonlyRoots.push(npmGlobalPrefix);
|
|
239
|
-
}
|
|
240
|
-
if (codexCompanionBinDir && !isAlreadyMounted(codexCompanionBinDir, mountedReadonlyRoots)) {
|
|
241
|
-
args.push("--bindmount_ro", `${codexCompanionBinDir}:${codexCompanionBinDir}`);
|
|
242
|
-
mountedReadonlyRoots.push(codexCompanionBinDir);
|
|
243
|
-
}
|
|
244
|
-
mountSharedAgentPaths(args, home);
|
|
245
|
-
if (config.readonlyMounts) {
|
|
246
|
-
for (const mountPath of config.readonlyMounts) {
|
|
247
|
-
if (fs.existsSync(mountPath)) {
|
|
248
|
-
args.push("--bindmount_ro", `${mountPath}:${mountPath}`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
if (config.writableMounts) {
|
|
253
|
-
for (const mountPath of config.writableMounts) {
|
|
254
|
-
if (fs.existsSync(mountPath)) {
|
|
255
|
-
args.push("--bindmount", `${mountPath}:${mountPath}`);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
args.push("--bindmount", `${sandboxHome}:${sandboxHome}`);
|
|
260
|
-
for (const [key, value] of Object.entries(config.env)) {
|
|
261
|
-
args.push("--env", `${key}=${value}`);
|
|
262
|
-
}
|
|
263
|
-
const sandboxPath = buildSandboxPath({
|
|
264
|
-
nodeBin,
|
|
265
|
-
npmGlobalPrefix,
|
|
266
|
-
companionBinDirs: [codexCompanionBinDir]
|
|
267
|
-
});
|
|
268
|
-
args.push("--env", `PATH=${sandboxPath}`);
|
|
269
|
-
args.push("--env", `HOME=${sandboxHome}`);
|
|
270
|
-
args.push("--env", "USER=sandbox");
|
|
271
|
-
args.push("--env", "TERM=xterm-256color");
|
|
272
|
-
return args;
|
|
273
|
-
}
|
|
274
68
|
function buildDockerRunArgs(config, command, image = DEFAULT_DOCKER_IMAGE) {
|
|
275
69
|
const args = [
|
|
276
70
|
"run",
|
|
@@ -475,15 +269,6 @@ function getSharedAgentPaths(home) {
|
|
|
475
269
|
readonly: [gitconfig].filter(fs.existsSync)
|
|
476
270
|
};
|
|
477
271
|
}
|
|
478
|
-
function mountSharedAgentPaths(args, home) {
|
|
479
|
-
const sharedPaths = getSharedAgentPaths(home);
|
|
480
|
-
for (const dir of sharedPaths.readwrite) {
|
|
481
|
-
args.push("--bindmount", `${dir}:${dir}`);
|
|
482
|
-
}
|
|
483
|
-
for (const dir of sharedPaths.readonly) {
|
|
484
|
-
args.push("--bindmount_ro", `${dir}:${dir}`);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
272
|
function resolveDockerSandboxDockerfile() {
|
|
488
273
|
const localDir = path.dirname(fileURLToPath(import.meta.url));
|
|
489
274
|
const installRoot = process.env.MAESTRO_INSTALL_ROOT?.trim();
|
|
@@ -504,65 +289,10 @@ function isPathWithin(requestedPath, basePath) {
|
|
|
504
289
|
if (!requestedPath.startsWith(basePath)) return false;
|
|
505
290
|
return requestedPath.charAt(basePath.length) === path.sep;
|
|
506
291
|
}
|
|
507
|
-
|
|
508
|
-
const pathParts = [...BASE_PATH_DIRS];
|
|
509
|
-
if (options.nodeBin && !pathParts.includes(options.nodeBin)) {
|
|
510
|
-
pathParts.unshift(options.nodeBin);
|
|
511
|
-
}
|
|
512
|
-
const globalBin = options.npmGlobalPrefix ? path.join(options.npmGlobalPrefix, "bin") : null;
|
|
513
|
-
if (globalBin && !pathParts.includes(globalBin)) {
|
|
514
|
-
pathParts.unshift(globalBin);
|
|
515
|
-
}
|
|
516
|
-
for (const dir of options.companionBinDirs) {
|
|
517
|
-
if (dir && !pathParts.includes(dir)) {
|
|
518
|
-
pathParts.unshift(dir);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
return pathParts.join(":");
|
|
522
|
-
}
|
|
523
|
-
function getNodeBinaryDir() {
|
|
524
|
-
try {
|
|
525
|
-
const nodePath = execSync("which node", { encoding: "utf-8" }).trim();
|
|
526
|
-
return nodePath ? path.dirname(nodePath) : null;
|
|
527
|
-
} catch {
|
|
528
|
-
return null;
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
function getNpmGlobalPrefix() {
|
|
532
|
-
try {
|
|
533
|
-
const prefix = execSync("npm prefix -g", { encoding: "utf-8" }).trim();
|
|
534
|
-
return prefix || null;
|
|
535
|
-
} catch {
|
|
536
|
-
return null;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
function getCliCompanionBinDir(cliName) {
|
|
540
|
-
try {
|
|
541
|
-
const cliPath = execSync(`which ${cliName}`, { encoding: "utf-8" }).trim();
|
|
542
|
-
if (!cliPath) return null;
|
|
543
|
-
return path.dirname(fs.realpathSync(cliPath));
|
|
544
|
-
} catch {
|
|
545
|
-
return null;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
function isAlreadyMounted(targetPath, mountRoots) {
|
|
549
|
-
return mountRoots.some((root) => isPathWithin(targetPath, root));
|
|
550
|
-
}
|
|
551
|
-
var SANDBOX_UID, SANDBOX_GID, BASE_READONLY_MOUNTS, BASE_PATH_DIRS, DEFAULT_DOCKER_IMAGE, DEFAULT_MEMORY_LIMIT, DEFAULT_MAX_PROCESSES, nsjailPath, nsjailRuntimeAvailable, nsjailUnavailableReason, dockerPath, dockerServerReachable, dockerImageReadyFor, cachedSelfMounts, runningInsideContainer;
|
|
292
|
+
var DEFAULT_DOCKER_IMAGE, DEFAULT_MEMORY_LIMIT, DEFAULT_MAX_PROCESSES, dockerPath, dockerServerReachable, dockerImageReadyFor, cachedSelfMounts, runningInsideContainer;
|
|
552
293
|
var init_sandbox = __esm({
|
|
553
294
|
"../server/src/agents/sandbox.ts"() {
|
|
554
295
|
"use strict";
|
|
555
|
-
SANDBOX_UID = 1500;
|
|
556
|
-
SANDBOX_GID = 1500;
|
|
557
|
-
BASE_READONLY_MOUNTS = ["/usr", "/bin", "/lib", "/sbin", "/etc"];
|
|
558
|
-
BASE_PATH_DIRS = [
|
|
559
|
-
"/usr/local/sbin",
|
|
560
|
-
"/usr/local/bin",
|
|
561
|
-
"/usr/sbin",
|
|
562
|
-
"/usr/bin",
|
|
563
|
-
"/sbin",
|
|
564
|
-
"/bin"
|
|
565
|
-
];
|
|
566
296
|
DEFAULT_DOCKER_IMAGE = process.env.MAESTRO_DOCKER_SANDBOX_IMAGE || "maestro-sandbox:latest";
|
|
567
297
|
DEFAULT_MEMORY_LIMIT = 512 * 1024 * 1024;
|
|
568
298
|
DEFAULT_MAX_PROCESSES = 64;
|
|
@@ -636,38 +366,12 @@ function spawnPty(options) {
|
|
|
636
366
|
ensureSpawnHelperExecutable();
|
|
637
367
|
const shell = getShellPath(options.env);
|
|
638
368
|
const cwd = options.cwd || os2.homedir();
|
|
639
|
-
const requestedSandboxProvider = options.sandboxProvider ?? (options.sandbox ? "
|
|
369
|
+
const requestedSandboxProvider = options.sandboxProvider ?? (options.sandbox ? "docker" : "none");
|
|
640
370
|
const sandboxProvider = resolveSandboxProvider(requestedSandboxProvider);
|
|
641
371
|
let actualSandboxProvider = sandboxProvider;
|
|
642
372
|
const fullEnv = buildChildEnv(options.env);
|
|
643
373
|
let ptyProcess;
|
|
644
|
-
if (sandboxProvider === "
|
|
645
|
-
ensureSandboxWritable(cwd);
|
|
646
|
-
const sandboxConfig = {
|
|
647
|
-
cwd,
|
|
648
|
-
homeDir: options.homeDir,
|
|
649
|
-
env: fullEnv,
|
|
650
|
-
readonlyMounts: options.readonlyMounts,
|
|
651
|
-
writableMounts: options.writableMounts,
|
|
652
|
-
memoryLimit: options.memoryLimit
|
|
653
|
-
};
|
|
654
|
-
const nsjailArgs = [
|
|
655
|
-
...buildNsjailArgs(sandboxConfig),
|
|
656
|
-
"--",
|
|
657
|
-
shell,
|
|
658
|
-
"-l"
|
|
659
|
-
];
|
|
660
|
-
ptyProcess = pty.spawn(getNsjailPath(), nsjailArgs, {
|
|
661
|
-
name: "xterm-256color",
|
|
662
|
-
cols: options.cols ?? 120,
|
|
663
|
-
rows: options.rows ?? 30,
|
|
664
|
-
cwd,
|
|
665
|
-
// nsjail manages env vars via --env flags, but node-pty still needs
|
|
666
|
-
// a minimal env for the PTY master side
|
|
667
|
-
env: { TERM: "xterm-256color" }
|
|
668
|
-
});
|
|
669
|
-
console.log(`Spawned sandboxed PTY for terminal ${options.terminalId}`);
|
|
670
|
-
} else if (sandboxProvider === "docker") {
|
|
374
|
+
if (sandboxProvider === "docker") {
|
|
671
375
|
const sandboxConfig = {
|
|
672
376
|
cwd,
|
|
673
377
|
homeDir: options.homeDir,
|
|
@@ -691,12 +395,6 @@ function spawnPty(options) {
|
|
|
691
395
|
});
|
|
692
396
|
console.log(`Spawned docker-sandboxed PTY for terminal ${options.terminalId}`);
|
|
693
397
|
} else {
|
|
694
|
-
if (requestedSandboxProvider === "nsjail" && !isNsjailAvailable()) {
|
|
695
|
-
const reason = getNsjailUnavailableReason();
|
|
696
|
-
throw new Error(
|
|
697
|
-
`Sandbox requested for terminal ${options.terminalId} but nsjail is not available (platform: ${process.platform}${reason ? `, reason: ${reason}` : ""}).`
|
|
698
|
-
);
|
|
699
|
-
}
|
|
700
398
|
if (requestedSandboxProvider === "docker" && !isDockerAvailable()) {
|
|
701
399
|
throw new Error(
|
|
702
400
|
`Sandbox requested for terminal ${options.terminalId} but docker is not available.`
|
|
@@ -2516,11 +2214,7 @@ function getSettings() {
|
|
|
2516
2214
|
const agentDefaultDisableSandbox = getSetting("agentDefaultDisableSandbox");
|
|
2517
2215
|
const agentDefaultSkipPermissions = getSetting("agentDefaultSkipPermissions");
|
|
2518
2216
|
const agentDefaultWorktreeMode = getSetting("agentDefaultWorktreeMode");
|
|
2519
|
-
const
|
|
2520
|
-
sandboxProvider,
|
|
2521
|
-
sandbox === "true"
|
|
2522
|
-
);
|
|
2523
|
-
const resolvedSandboxProvider = storedSandboxProvider === "nsjail" ? "docker" : storedSandboxProvider;
|
|
2217
|
+
const resolvedSandboxProvider = normalizeSandboxProvider(sandboxProvider, sandbox === "true");
|
|
2524
2218
|
return {
|
|
2525
2219
|
autoUpdateEnabled: enabled !== null ? enabled === "true" : DEFAULTS.autoUpdateEnabled,
|
|
2526
2220
|
autoUpdateIntervalHours: interval !== null ? Number(interval) : DEFAULTS.autoUpdateIntervalHours,
|
|
@@ -2555,9 +2249,8 @@ function updateSettings(patch) {
|
|
|
2555
2249
|
}
|
|
2556
2250
|
}
|
|
2557
2251
|
if (patch.sandboxProvider !== void 0) {
|
|
2558
|
-
|
|
2559
|
-
setSetting("
|
|
2560
|
-
setSetting("sandboxEnabled", String(provider !== "none"));
|
|
2252
|
+
setSetting("sandboxProvider", patch.sandboxProvider);
|
|
2253
|
+
setSetting("sandboxEnabled", String(patch.sandboxProvider !== "none"));
|
|
2561
2254
|
}
|
|
2562
2255
|
if (patch.deepgramApiKey !== void 0) {
|
|
2563
2256
|
setSetting("deepgramApiKey", patch.deepgramApiKey);
|
|
@@ -4620,7 +4313,7 @@ import { z as z2 } from "zod";
|
|
|
4620
4313
|
import { z } from "zod";
|
|
4621
4314
|
var AutoSpawnAgentProviderSchema = z.enum(["claude", "codex"]);
|
|
4622
4315
|
var AutoSpawnAgentWorktreeModeSchema = z.enum(["none", "new"]);
|
|
4623
|
-
var SandboxProviderSchema = z.enum(["none", "
|
|
4316
|
+
var SandboxProviderSchema = z.enum(["none", "docker"]);
|
|
4624
4317
|
var SettingsSchema = z.object({
|
|
4625
4318
|
autoUpdateEnabled: z.boolean().default(false),
|
|
4626
4319
|
autoUpdateIntervalHours: z.number().min(1).max(168).default(24),
|
|
@@ -6959,7 +6652,7 @@ function stopAutoUpdater() {
|
|
|
6959
6652
|
}
|
|
6960
6653
|
|
|
6961
6654
|
// ../server/src/services/ollama.ts
|
|
6962
|
-
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync5, readFileSync as
|
|
6655
|
+
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync5, readFileSync as readFileSync5, existsSync as existsSync15 } from "node:fs";
|
|
6963
6656
|
import { join as join16 } from "node:path";
|
|
6964
6657
|
import { homedir as homedir9 } from "node:os";
|
|
6965
6658
|
var OLLAMA_HOST = process.env.OLLAMA_HOST || "http://localhost:11434";
|
|
@@ -7058,7 +6751,7 @@ function writePiModelsConfig(modelId) {
|
|
|
7058
6751
|
let existing = {};
|
|
7059
6752
|
if (existsSync15(PI_MODELS_PATH)) {
|
|
7060
6753
|
try {
|
|
7061
|
-
existing = JSON.parse(
|
|
6754
|
+
existing = JSON.parse(readFileSync5(PI_MODELS_PATH, "utf-8"));
|
|
7062
6755
|
} catch {
|
|
7063
6756
|
}
|
|
7064
6757
|
}
|