svamp-cli 0.1.29 → 0.1.30
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/dist/cli.mjs +7 -7
- package/dist/{commands-CgT3AgJ0.mjs → commands-B2xQb9u7.mjs} +1 -1
- package/dist/{commands-CKTIJoV0.mjs → commands-C5pW2VmI.mjs} +286 -60
- package/dist/{commands-DDB3y1L1.mjs → commands-TZkNivgV.mjs} +295 -44
- package/dist/index.mjs +1 -1
- package/dist/{run-DZmxHj-e.mjs → run-CtCTd6if.mjs} +234 -50
- package/dist/{run-CuN6K7pN.mjs → run-Cxdc5Zmw.mjs} +316 -164
- package/dist/{run-DMD0N00A.mjs → run-dBWhjQRf.mjs} +316 -76
- package/package.json +1 -1
- package/dist/agent-cli.mjs +0 -453
- package/dist/commands-1CYZC6Xh.mjs +0 -481
- package/dist/commands-B1DcpgLW.mjs +0 -481
- package/dist/commands-BGmdgMAC.mjs +0 -485
- package/dist/commands-BOeSil-P.mjs +0 -459
- package/dist/commands-BU4GZQuH.mjs +0 -481
- package/dist/commands-Ba66PxtQ.mjs +0 -481
- package/dist/commands-C0-xqIIc.mjs +0 -481
- package/dist/commands-C7Qy5n6d.mjs +0 -481
- package/dist/commands-CKpC8R9T.mjs +0 -481
- package/dist/commands-CNqOjR1y.mjs +0 -481
- package/dist/commands-CVKh1tWr.mjs +0 -485
- package/dist/commands-CYBblX73.mjs +0 -485
- package/dist/commands-CZBYmj16.mjs +0 -485
- package/dist/commands-CcWIvCA4.mjs +0 -481
- package/dist/commands-Cfwf-cQG.mjs +0 -481
- package/dist/commands-DCNO2m66.mjs +0 -471
- package/dist/commands-DRIFvhmC.mjs +0 -481
- package/dist/commands-DXmw2dzy.mjs +0 -481
- package/dist/commands-DkSvlKFF.mjs +0 -485
- package/dist/commands-DnDd4Sew.mjs +0 -481
- package/dist/commands-DnpnAFQW.mjs +0 -485
- package/dist/commands-Do-TVYFm.mjs +0 -481
- package/dist/commands-GEXri0yz.mjs +0 -484
- package/dist/commands-Kzm0_XNH.mjs +0 -481
- package/dist/commands-MQvNbIid.mjs +0 -481
- package/dist/commands-_uCC3U1U.mjs +0 -481
- package/dist/commands-y2WG29W9.mjs +0 -485
- package/dist/hyphaClient-DLkclazm.mjs +0 -39
- package/dist/package-ASJ9pMHk.mjs +0 -60
- package/dist/package-B2FOzHaM.mjs +0 -57
- package/dist/package-Bk_PFVA0.mjs +0 -57
- package/dist/package-Bnij-ZtR.mjs +0 -57
- package/dist/package-BtRbHfjz.mjs +0 -57
- package/dist/package-C5B0twb8.mjs +0 -57
- package/dist/package-CC5d8_0L.mjs +0 -57
- package/dist/package-CCJ045H0.mjs +0 -60
- package/dist/package-CS219SXn.mjs +0 -57
- package/dist/package-Cd-9ktpd.mjs +0 -60
- package/dist/package-CgBD49cA.mjs +0 -57
- package/dist/package-CvnNnsm7.mjs +0 -60
- package/dist/package-DPXkSwHu.mjs +0 -57
- package/dist/package-DpqWz9Cr.mjs +0 -60
- package/dist/package-JqEt5Ib4.mjs +0 -57
- package/dist/package-k18Su1iE.mjs +0 -58
- package/dist/package-nzkXV1aM.mjs +0 -57
- package/dist/package-pNo6GC3a.mjs +0 -60
- package/dist/package-pZp14zKI.mjs +0 -57
- package/dist/run-4fyJcaRE.mjs +0 -3856
- package/dist/run-B6oqR83K.mjs +0 -4631
- package/dist/run-BI32lPRK.mjs +0 -3870
- package/dist/run-BQHneHfW.mjs +0 -3834
- package/dist/run-Bb4fyIWZ.mjs +0 -3812
- package/dist/run-BglwnB-A.mjs +0 -3889
- package/dist/run-BjVWuitO.mjs +0 -3919
- package/dist/run-BzUE-JUT.mjs +0 -3708
- package/dist/run-BzqS97Sx.mjs +0 -3666
- package/dist/run-C6snRxyh.mjs +0 -3826
- package/dist/run-C8CI8Ujj.mjs +0 -3693
- package/dist/run-CL-FS4Yc.mjs +0 -3933
- package/dist/run-CS1Z4GcM.mjs +0 -3786
- package/dist/run-CT7uizQo.mjs +0 -4492
- package/dist/run-CUIj4xbE.mjs +0 -4880
- package/dist/run-CW26vPqj.mjs +0 -3919
- package/dist/run-CkTufc0D.mjs +0 -3875
- package/dist/run-Cmostc0S.mjs +0 -3902
- package/dist/run-Cp3kKdzm.mjs +0 -3865
- package/dist/run-D0bCTY72.mjs +0 -3816
- package/dist/run-D4N6FQON.mjs +0 -4673
- package/dist/run-D4dlA0jo.mjs +0 -4813
- package/dist/run-DMW8ibIw.mjs +0 -3958
- package/dist/run-DO52unxE.mjs +0 -3950
- package/dist/run-DQ5FOQ_c.mjs +0 -4788
- package/dist/run-DT7FgL8L.mjs +0 -4339
- package/dist/run-DYhBROuo.mjs +0 -3934
- package/dist/run-DjfPjgOb.mjs +0 -3904
- package/dist/run-DlL4JALM.mjs +0 -4719
- package/dist/run-Dp2JPkGI.mjs +0 -3913
- package/dist/run-Dptna3Je.mjs +0 -3867
- package/dist/run-DwK3dfHd.mjs +0 -3875
- package/dist/run-M_SMt96j.mjs +0 -3913
- package/dist/run-MlpxQUPN.mjs +0 -3869
- package/dist/run-PuTIelbv.mjs +0 -3706
- package/dist/run-h37iSCUB.mjs +0 -3934
- package/dist/run-lpV0oguG.mjs +0 -3897
- package/dist/run-oHmTMcv8.mjs +0 -4721
|
@@ -10,12 +10,12 @@ import { existsSync, readFileSync, mkdirSync, appendFileSync, writeFileSync } fr
|
|
|
10
10
|
import { join } from 'node:path';
|
|
11
11
|
import { spawn, execSync, execFile } from 'node:child_process';
|
|
12
12
|
import { ndJsonStream, ClientSideConnection } from '@agentclientprotocol/sdk';
|
|
13
|
+
import { homedir, tmpdir } from 'node:os';
|
|
13
14
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
14
15
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
15
16
|
import { ElicitRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
16
17
|
import { z } from 'zod';
|
|
17
18
|
import { mkdir, access, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
18
|
-
import { homedir } from 'node:os';
|
|
19
19
|
import { promisify } from 'node:util';
|
|
20
20
|
|
|
21
21
|
let connectToServerFn = null;
|
|
@@ -153,6 +153,12 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
153
153
|
// Spawn a new session
|
|
154
154
|
spawnSession: async (options, context) => {
|
|
155
155
|
authorizeRequest(context, currentMetadata.sharing, "interact");
|
|
156
|
+
if (options.sharing?.enabled && !options.sharing.owner && context?.user?.email) {
|
|
157
|
+
options = {
|
|
158
|
+
...options,
|
|
159
|
+
sharing: { ...options.sharing, owner: context.user.email }
|
|
160
|
+
};
|
|
161
|
+
}
|
|
156
162
|
const result = await handlers.spawnSession({
|
|
157
163
|
...options,
|
|
158
164
|
machineId
|
|
@@ -419,6 +425,8 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
419
425
|
data.uuid = randomUUID();
|
|
420
426
|
}
|
|
421
427
|
wrappedContent = { role: "agent", content: { type: "output", data } };
|
|
428
|
+
} else if (role === "event") {
|
|
429
|
+
wrappedContent = { role: "agent", content: { type: "event", data: content } };
|
|
422
430
|
} else if (role === "session") {
|
|
423
431
|
wrappedContent = { role: "session", content: { type: "session", data: content } };
|
|
424
432
|
} else {
|
|
@@ -661,6 +669,9 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
661
669
|
if (metadata.sharing && context?.user?.email && context.user.email !== metadata.sharing.owner) {
|
|
662
670
|
throw new Error("Only the session owner can update sharing settings");
|
|
663
671
|
}
|
|
672
|
+
if (newSharing.enabled && !newSharing.owner && context?.user?.email) {
|
|
673
|
+
newSharing = { ...newSharing, owner: context.user.email };
|
|
674
|
+
}
|
|
664
675
|
metadata = { ...metadata, sharing: newSharing };
|
|
665
676
|
metadataVersion++;
|
|
666
677
|
notifyListeners({
|
|
@@ -1188,6 +1199,106 @@ var DefaultTransport$1 = /*#__PURE__*/Object.freeze({
|
|
|
1188
1199
|
DefaultTransport: DefaultTransport
|
|
1189
1200
|
});
|
|
1190
1201
|
|
|
1202
|
+
const SVAMP_TOOLS_DIR$1 = join(homedir(), ".svamp", "tools");
|
|
1203
|
+
const SVAMP_TOOLS_BIN$1 = join(SVAMP_TOOLS_DIR$1, "node_modules", ".bin");
|
|
1204
|
+
const SVAMP_TOOLS_RG_BIN$1 = join(SVAMP_TOOLS_DIR$1, "node_modules", "@vscode", "ripgrep", "bin");
|
|
1205
|
+
function wrapWithIsolation(originalCommand, originalArgs, config) {
|
|
1206
|
+
switch (config.method) {
|
|
1207
|
+
case "srt":
|
|
1208
|
+
return wrapWithSrt(originalCommand, originalArgs, config);
|
|
1209
|
+
case "bwrap":
|
|
1210
|
+
return wrapWithBwrap(originalCommand, originalArgs, config);
|
|
1211
|
+
case "docker":
|
|
1212
|
+
return wrapWithContainer("docker", originalCommand, originalArgs, config);
|
|
1213
|
+
case "podman":
|
|
1214
|
+
return wrapWithContainer("podman", originalCommand, originalArgs, config);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
function wrapWithSrt(command, args, config) {
|
|
1218
|
+
const settings = {
|
|
1219
|
+
filesystem: {
|
|
1220
|
+
denyRead: config.srtConfig?.filesystem?.denyRead ?? [],
|
|
1221
|
+
allowWrite: config.srtConfig?.filesystem?.allowWrite ?? [config.workspacePath],
|
|
1222
|
+
denyWrite: config.srtConfig?.filesystem?.denyWrite ?? []
|
|
1223
|
+
},
|
|
1224
|
+
network: {
|
|
1225
|
+
allowedDomains: config.srtConfig?.network?.allowedDomains ?? [],
|
|
1226
|
+
deniedDomains: config.srtConfig?.network?.deniedDomains ?? []
|
|
1227
|
+
}
|
|
1228
|
+
};
|
|
1229
|
+
const settingsPath = join(tmpdir(), `srt-settings-${process.pid}-${Date.now()}.json`);
|
|
1230
|
+
writeFileSync(settingsPath, JSON.stringify(settings));
|
|
1231
|
+
const pathParts = [SVAMP_TOOLS_BIN$1, SVAMP_TOOLS_RG_BIN$1];
|
|
1232
|
+
if (process.env.PATH) pathParts.push(process.env.PATH);
|
|
1233
|
+
return {
|
|
1234
|
+
command: config.binaryPath,
|
|
1235
|
+
args: ["--settings", settingsPath, command, ...args],
|
|
1236
|
+
env: { PATH: pathParts.join(":") },
|
|
1237
|
+
cleanupFiles: [settingsPath]
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
function wrapWithBwrap(command, args, config) {
|
|
1241
|
+
const bwrapArgs = [
|
|
1242
|
+
// Mount root filesystem read-only
|
|
1243
|
+
"--ro-bind",
|
|
1244
|
+
"/",
|
|
1245
|
+
"/",
|
|
1246
|
+
// Mount workspace read-write
|
|
1247
|
+
"--bind",
|
|
1248
|
+
config.workspacePath,
|
|
1249
|
+
config.workspacePath,
|
|
1250
|
+
// Mount /tmp read-write (many tools need it)
|
|
1251
|
+
"--bind",
|
|
1252
|
+
"/tmp",
|
|
1253
|
+
"/tmp",
|
|
1254
|
+
// Mount /dev read-write
|
|
1255
|
+
"--dev",
|
|
1256
|
+
"/dev",
|
|
1257
|
+
// Mount /proc
|
|
1258
|
+
"--proc",
|
|
1259
|
+
"/proc",
|
|
1260
|
+
// Unshare network — no network access inside sandbox
|
|
1261
|
+
"--unshare-net",
|
|
1262
|
+
// Unshare PID namespace
|
|
1263
|
+
"--unshare-pid",
|
|
1264
|
+
// Die when parent dies
|
|
1265
|
+
"--die-with-parent",
|
|
1266
|
+
// The actual command
|
|
1267
|
+
"--",
|
|
1268
|
+
command,
|
|
1269
|
+
...args
|
|
1270
|
+
];
|
|
1271
|
+
return {
|
|
1272
|
+
command: config.binaryPath,
|
|
1273
|
+
args: bwrapArgs
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
function wrapWithContainer(runtime, command, args, config) {
|
|
1277
|
+
const image = config.containerConfig?.image || "node:lts-slim";
|
|
1278
|
+
const networkMode = config.containerConfig?.networkMode || "none";
|
|
1279
|
+
const containerArgs = [
|
|
1280
|
+
"run",
|
|
1281
|
+
"--rm",
|
|
1282
|
+
"-i",
|
|
1283
|
+
// interactive (for stdin/stdout piping)
|
|
1284
|
+
`--network=${networkMode}`,
|
|
1285
|
+
"-v",
|
|
1286
|
+
`${config.workspacePath}:${config.workspacePath}`,
|
|
1287
|
+
"-w",
|
|
1288
|
+
config.workspacePath
|
|
1289
|
+
];
|
|
1290
|
+
if (config.containerConfig?.extraMounts) {
|
|
1291
|
+
for (const mount of config.containerConfig.extraMounts) {
|
|
1292
|
+
containerArgs.push("-v", mount);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
containerArgs.push(image, command, ...args);
|
|
1296
|
+
return {
|
|
1297
|
+
command: config.binaryPath,
|
|
1298
|
+
args: containerArgs
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1191
1302
|
const DEFAULT_IDLE_TIMEOUT_MS = 500;
|
|
1192
1303
|
const DEFAULT_TOOL_CALL_TIMEOUT_MS = 12e4;
|
|
1193
1304
|
function parseArgsFromContent(content) {
|
|
@@ -1506,21 +1617,41 @@ class AcpBackend {
|
|
|
1506
1617
|
let startupStatusErrorEmitted = false;
|
|
1507
1618
|
try {
|
|
1508
1619
|
const args = this.options.args || [];
|
|
1620
|
+
let spawnCommand = this.options.command;
|
|
1621
|
+
let spawnArgs = args;
|
|
1622
|
+
let isoEnv = {};
|
|
1623
|
+
let isoCleanupFiles = [];
|
|
1624
|
+
if (this.options.isolationConfig) {
|
|
1625
|
+
const wrapped = wrapWithIsolation(spawnCommand, spawnArgs, this.options.isolationConfig);
|
|
1626
|
+
spawnCommand = wrapped.command;
|
|
1627
|
+
spawnArgs = wrapped.args;
|
|
1628
|
+
if (wrapped.env) isoEnv = wrapped.env;
|
|
1629
|
+
if (wrapped.cleanupFiles) isoCleanupFiles = wrapped.cleanupFiles;
|
|
1630
|
+
this.log(`[ACP] Isolation: ${this.options.isolationConfig.method}`);
|
|
1631
|
+
}
|
|
1632
|
+
const spawnEnv = { ...process.env, ...this.options.env, ...isoEnv };
|
|
1509
1633
|
if (process.platform === "win32") {
|
|
1510
|
-
const fullCommand = [
|
|
1634
|
+
const fullCommand = [spawnCommand, ...spawnArgs].join(" ");
|
|
1511
1635
|
this.process = spawn("cmd.exe", ["/c", fullCommand], {
|
|
1512
1636
|
cwd: this.options.cwd,
|
|
1513
|
-
env:
|
|
1637
|
+
env: spawnEnv,
|
|
1514
1638
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1515
1639
|
windowsHide: true
|
|
1516
1640
|
});
|
|
1517
1641
|
} else {
|
|
1518
|
-
this.process = spawn(
|
|
1642
|
+
this.process = spawn(spawnCommand, spawnArgs, {
|
|
1519
1643
|
cwd: this.options.cwd,
|
|
1520
|
-
env:
|
|
1644
|
+
env: spawnEnv,
|
|
1521
1645
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1522
1646
|
});
|
|
1523
1647
|
}
|
|
1648
|
+
if (isoCleanupFiles.length > 0) {
|
|
1649
|
+
this.process.on("exit", async () => {
|
|
1650
|
+
const { rm } = await import('node:fs/promises');
|
|
1651
|
+
for (const f of isoCleanupFiles) rm(f, { force: true }).catch(() => {
|
|
1652
|
+
});
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1524
1655
|
if (!this.process.stdin || !this.process.stdout || !this.process.stderr) {
|
|
1525
1656
|
throw new Error("Failed to create stdio pipes");
|
|
1526
1657
|
}
|
|
@@ -2133,15 +2264,15 @@ function bridgeAcpToSession(backend, sessionService, getMetadata, setMetadata, l
|
|
|
2133
2264
|
setMetadata((m) => ({ ...m, lifecycleState: "running" }));
|
|
2134
2265
|
} else if (msg.status === "error") {
|
|
2135
2266
|
flushText();
|
|
2136
|
-
sessionService.pushMessage(
|
|
2137
|
-
type: "
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
sessionService.
|
|
2267
|
+
sessionService.pushMessage(
|
|
2268
|
+
{ type: "message", message: `Agent process exited unexpectedly: ${msg.detail || "Unknown error"}` },
|
|
2269
|
+
"event"
|
|
2270
|
+
);
|
|
2271
|
+
sessionService.sendSessionEnd();
|
|
2141
2272
|
setMetadata((m) => ({ ...m, lifecycleState: "error" }));
|
|
2142
2273
|
} else if (msg.status === "stopped") {
|
|
2143
2274
|
flushText();
|
|
2144
|
-
sessionService.
|
|
2275
|
+
sessionService.sendSessionEnd();
|
|
2145
2276
|
setMetadata((m) => ({ ...m, lifecycleState: "stopped" }));
|
|
2146
2277
|
}
|
|
2147
2278
|
break;
|
|
@@ -2296,6 +2427,8 @@ class CodexMcpBackend {
|
|
|
2296
2427
|
connected = false;
|
|
2297
2428
|
// Pending elicitation approvals
|
|
2298
2429
|
pendingApprovals = /* @__PURE__ */ new Map();
|
|
2430
|
+
// Temp files from isolation wrapping (cleaned up on disconnect)
|
|
2431
|
+
_isolationCleanupFiles = [];
|
|
2299
2432
|
constructor(options) {
|
|
2300
2433
|
this.options = options;
|
|
2301
2434
|
this.log = options.log || (() => {
|
|
@@ -2438,9 +2571,21 @@ class CodexMcpBackend {
|
|
|
2438
2571
|
} else if (!existingRustLog.includes("codex_core::rollout::list=")) {
|
|
2439
2572
|
env.RUST_LOG = `${existingRustLog},${rolloutFilter}`;
|
|
2440
2573
|
}
|
|
2574
|
+
let transportCommand = "codex";
|
|
2575
|
+
let transportArgs = [mcpCommand];
|
|
2576
|
+
if (this.options.isolationConfig) {
|
|
2577
|
+
const wrapped = wrapWithIsolation(transportCommand, transportArgs, this.options.isolationConfig);
|
|
2578
|
+
transportCommand = wrapped.command;
|
|
2579
|
+
transportArgs = wrapped.args;
|
|
2580
|
+
if (wrapped.env) Object.assign(env, wrapped.env);
|
|
2581
|
+
if (wrapped.cleanupFiles) {
|
|
2582
|
+
this._isolationCleanupFiles = wrapped.cleanupFiles;
|
|
2583
|
+
}
|
|
2584
|
+
this.log(`[Codex] Isolation: ${this.options.isolationConfig.method}`);
|
|
2585
|
+
}
|
|
2441
2586
|
this.transport = new StdioClientTransport({
|
|
2442
|
-
command:
|
|
2443
|
-
args:
|
|
2587
|
+
command: transportCommand,
|
|
2588
|
+
args: transportArgs,
|
|
2444
2589
|
env
|
|
2445
2590
|
});
|
|
2446
2591
|
this.registerPermissionHandlers();
|
|
@@ -2477,6 +2622,12 @@ class CodexMcpBackend {
|
|
|
2477
2622
|
}
|
|
2478
2623
|
this.transport = null;
|
|
2479
2624
|
this.connected = false;
|
|
2625
|
+
if (this._isolationCleanupFiles.length > 0) {
|
|
2626
|
+
const { rm } = await import('node:fs/promises');
|
|
2627
|
+
for (const f of this._isolationCleanupFiles) rm(f, { force: true }).catch(() => {
|
|
2628
|
+
});
|
|
2629
|
+
this._isolationCleanupFiles = [];
|
|
2630
|
+
}
|
|
2480
2631
|
}
|
|
2481
2632
|
// ── Permission handling ────────────────────────────────────────────
|
|
2482
2633
|
registerPermissionHandlers() {
|
|
@@ -3536,8 +3687,19 @@ async function startDaemon() {
|
|
|
3536
3687
|
proc.kill(signal);
|
|
3537
3688
|
}
|
|
3538
3689
|
});
|
|
3690
|
+
}, buildIsolationConfig2 = function(dir) {
|
|
3691
|
+
if (!sessionMetadata.sharing?.enabled) return null;
|
|
3692
|
+
const method = isolationCapabilities.preferred;
|
|
3693
|
+
if (!method) return null;
|
|
3694
|
+
const detail = isolationCapabilities.details[method];
|
|
3695
|
+
if (!detail.found || detail.verified === false) return null;
|
|
3696
|
+
return {
|
|
3697
|
+
method,
|
|
3698
|
+
binaryPath: detail.path || method,
|
|
3699
|
+
workspacePath: dir
|
|
3700
|
+
};
|
|
3539
3701
|
};
|
|
3540
|
-
var parseBashPermission = parseBashPermission2, shouldAutoAllow = shouldAutoAllow2, killAndWaitForExit = killAndWaitForExit2;
|
|
3702
|
+
var parseBashPermission = parseBashPermission2, shouldAutoAllow = shouldAutoAllow2, killAndWaitForExit = killAndWaitForExit2, buildIsolationConfig = buildIsolationConfig2;
|
|
3541
3703
|
let sessionMetadata = {
|
|
3542
3704
|
path: directory,
|
|
3543
3705
|
host: os.hostname(),
|
|
@@ -3590,6 +3752,7 @@ async function startDaemon() {
|
|
|
3590
3752
|
"auto-approve-all": "bypassPermissions"
|
|
3591
3753
|
};
|
|
3592
3754
|
const toClaudePermissionMode = (mode) => CLAUDE_PERMISSION_MODE_MAP[mode] || mode;
|
|
3755
|
+
let isolationCleanupFiles = [];
|
|
3593
3756
|
const spawnClaude = (initialMessage, meta) => {
|
|
3594
3757
|
const rawPermissionMode = meta?.permissionMode || agentConfig.default_permission_mode || currentPermissionMode;
|
|
3595
3758
|
const permissionMode = toClaudePermissionMode(rawPermissionMode);
|
|
@@ -3610,10 +3773,26 @@ async function startDaemon() {
|
|
|
3610
3773
|
if (model) args.push("--model", model);
|
|
3611
3774
|
if (appendSystemPrompt) args.push("--append-system-prompt", appendSystemPrompt);
|
|
3612
3775
|
if (claudeResumeId) args.push("--resume", claudeResumeId);
|
|
3613
|
-
|
|
3614
|
-
|
|
3776
|
+
let spawnCommand = "claude";
|
|
3777
|
+
let spawnArgs = args;
|
|
3778
|
+
let extraEnv = {};
|
|
3779
|
+
isolationCleanupFiles = [];
|
|
3780
|
+
const isoConfig = buildIsolationConfig2(directory);
|
|
3781
|
+
if (isoConfig) {
|
|
3782
|
+
const wrapped = wrapWithIsolation(spawnCommand, spawnArgs, isoConfig);
|
|
3783
|
+
spawnCommand = wrapped.command;
|
|
3784
|
+
spawnArgs = wrapped.args;
|
|
3785
|
+
if (wrapped.env) extraEnv = wrapped.env;
|
|
3786
|
+
if (wrapped.cleanupFiles) isolationCleanupFiles = wrapped.cleanupFiles;
|
|
3787
|
+
sessionMetadata = { ...sessionMetadata, isolationMethod: isoConfig.method };
|
|
3788
|
+
logger.log(`[Session ${sessionId}] Isolation: ${isoConfig.method} (binary: ${isoConfig.binaryPath})`);
|
|
3789
|
+
} else {
|
|
3790
|
+
sessionMetadata = { ...sessionMetadata, isolationMethod: void 0 };
|
|
3791
|
+
}
|
|
3792
|
+
logger.log(`[Session ${sessionId}] Spawning Claude: ${spawnCommand} ${spawnArgs.join(" ")} (cwd: ${directory})`);
|
|
3793
|
+
const spawnEnv = { ...process.env, ...extraEnv };
|
|
3615
3794
|
delete spawnEnv.CLAUDECODE;
|
|
3616
|
-
const child = spawn$1(
|
|
3795
|
+
const child = spawn$1(spawnCommand, spawnArgs, {
|
|
3617
3796
|
cwd: directory,
|
|
3618
3797
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3619
3798
|
env: spawnEnv,
|
|
@@ -3623,17 +3802,11 @@ async function startDaemon() {
|
|
|
3623
3802
|
logger.log(`[Session ${sessionId}] Claude PID: ${child.pid}, stdin: ${!!child.stdin}, stdout: ${!!child.stdout}, stderr: ${!!child.stderr}`);
|
|
3624
3803
|
child.on("error", (err) => {
|
|
3625
3804
|
logger.log(`[Session ${sessionId}] Claude process error: ${err.message}`);
|
|
3626
|
-
sessionService.pushMessage(
|
|
3627
|
-
type: "
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
Please ensure Claude Code CLI is installed on this machine. You can install it with:
|
|
3633
|
-
\`npm install -g @anthropic-ai/claude-code\``
|
|
3634
|
-
}]
|
|
3635
|
-
}, "agent");
|
|
3636
|
-
sessionService.sendKeepAlive(false);
|
|
3805
|
+
sessionService.pushMessage(
|
|
3806
|
+
{ type: "message", message: `Agent process exited unexpectedly: ${err.message}. Please ensure Claude Code CLI is installed.` },
|
|
3807
|
+
"event"
|
|
3808
|
+
);
|
|
3809
|
+
sessionService.sendSessionEnd();
|
|
3637
3810
|
});
|
|
3638
3811
|
let stdoutBuffer = "";
|
|
3639
3812
|
let lastErrorMessagePushed = false;
|
|
@@ -3827,25 +4000,25 @@ Please ensure Claude Code CLI is installed on this machine. You can install it w
|
|
|
3827
4000
|
child.on("exit", (code, signal) => {
|
|
3828
4001
|
logger.log(`[Session ${sessionId}] Claude exited: code=${code}, signal=${signal}`);
|
|
3829
4002
|
claudeProcess = null;
|
|
4003
|
+
for (const f of isolationCleanupFiles) {
|
|
4004
|
+
fs.rm(f, { force: true }).catch(() => {
|
|
4005
|
+
});
|
|
4006
|
+
}
|
|
4007
|
+
isolationCleanupFiles = [];
|
|
3830
4008
|
for (const [id, pending] of pendingPermissions) {
|
|
3831
4009
|
pending.resolve({ behavior: "deny", message: "Claude process exited" });
|
|
3832
4010
|
}
|
|
3833
4011
|
pendingPermissions.clear();
|
|
3834
4012
|
if (code !== 0 && code !== null && !lastErrorMessagePushed) {
|
|
3835
|
-
sessionService.pushMessage(
|
|
3836
|
-
type: "
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
text: `Error: Claude process exited with code ${code}${signal ? ` (signal: ${signal})` : ""}.
|
|
3840
|
-
|
|
3841
|
-
This may indicate that Claude Code CLI is not properly installed or configured.`
|
|
3842
|
-
}]
|
|
3843
|
-
}, "agent");
|
|
4013
|
+
sessionService.pushMessage(
|
|
4014
|
+
{ type: "message", message: `Agent process exited unexpectedly (code ${code}${signal ? `, signal: ${signal}` : ""})` },
|
|
4015
|
+
"event"
|
|
4016
|
+
);
|
|
3844
4017
|
}
|
|
3845
4018
|
lastErrorMessagePushed = false;
|
|
3846
4019
|
sessionMetadata = { ...sessionMetadata, lifecycleState: claudeResumeId ? "idle" : "stopped" };
|
|
3847
4020
|
sessionService.updateMetadata(sessionMetadata);
|
|
3848
|
-
sessionService.
|
|
4021
|
+
sessionService.sendSessionEnd();
|
|
3849
4022
|
if (claudeResumeId && !trackedSession.stopped) {
|
|
3850
4023
|
saveSession({
|
|
3851
4024
|
sessionId,
|
|
@@ -4337,12 +4510,27 @@ This may indicate that Claude Code CLI is not properly installed or configured.`
|
|
|
4337
4510
|
logger
|
|
4338
4511
|
);
|
|
4339
4512
|
const permissionHandler = new HyphaPermissionHandler(shouldAutoAllow2, logger.log);
|
|
4513
|
+
let agentIsoConfig;
|
|
4514
|
+
if (sessionMetadata.sharing?.enabled && isolationCapabilities.preferred) {
|
|
4515
|
+
const method = isolationCapabilities.preferred;
|
|
4516
|
+
const detail = isolationCapabilities.details[method];
|
|
4517
|
+
if (detail.found && detail.verified !== false) {
|
|
4518
|
+
agentIsoConfig = {
|
|
4519
|
+
method,
|
|
4520
|
+
binaryPath: detail.path || method,
|
|
4521
|
+
workspacePath: directory
|
|
4522
|
+
};
|
|
4523
|
+
sessionMetadata = { ...sessionMetadata, isolationMethod: method };
|
|
4524
|
+
logger.log(`[Agent Session ${sessionId}] Isolation: ${method}`);
|
|
4525
|
+
}
|
|
4526
|
+
}
|
|
4340
4527
|
let agentBackend;
|
|
4341
4528
|
if (KNOWN_MCP_AGENTS[agentName]) {
|
|
4342
4529
|
agentBackend = new CodexMcpBackend({
|
|
4343
4530
|
cwd: directory,
|
|
4344
4531
|
env: options.environmentVariables,
|
|
4345
|
-
log: logger.log
|
|
4532
|
+
log: logger.log,
|
|
4533
|
+
isolationConfig: agentIsoConfig
|
|
4346
4534
|
});
|
|
4347
4535
|
} else {
|
|
4348
4536
|
const transportHandler = agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(agentName);
|
|
@@ -4355,7 +4543,8 @@ This may indicate that Claude Code CLI is not properly installed or configured.`
|
|
|
4355
4543
|
env: options.environmentVariables,
|
|
4356
4544
|
permissionHandler,
|
|
4357
4545
|
transportHandler,
|
|
4358
|
-
log: logger.log
|
|
4546
|
+
log: logger.log,
|
|
4547
|
+
isolationConfig: agentIsoConfig
|
|
4359
4548
|
});
|
|
4360
4549
|
}
|
|
4361
4550
|
bridgeAcpToSession(
|
|
@@ -4387,16 +4576,11 @@ This may indicate that Claude Code CLI is not properly installed or configured.`
|
|
|
4387
4576
|
logger.log(`[Agent Session ${sessionId}] ${agentName} backend started, waiting for first message`);
|
|
4388
4577
|
}).catch((err) => {
|
|
4389
4578
|
logger.error(`[Agent Session ${sessionId}] Failed to start ${agentName}:`, err);
|
|
4390
|
-
sessionService.pushMessage(
|
|
4391
|
-
type: "
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
Please ensure the ${agentName} CLI is installed.`
|
|
4397
|
-
}]
|
|
4398
|
-
}, "agent");
|
|
4399
|
-
sessionService.sendKeepAlive(false);
|
|
4579
|
+
sessionService.pushMessage(
|
|
4580
|
+
{ type: "message", message: `Agent process exited unexpectedly: ${err.message}. Please ensure the ${agentName} CLI is installed.` },
|
|
4581
|
+
"event"
|
|
4582
|
+
);
|
|
4583
|
+
sessionService.sendSessionEnd();
|
|
4400
4584
|
});
|
|
4401
4585
|
return {
|
|
4402
4586
|
type: "success",
|