svamp-cli 0.2.68 → 0.2.71
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/{agentCommands-QnPGJFY-.mjs → agentCommands-COEbsMuw.mjs} +2 -2
- package/dist/cli.mjs +127 -68
- package/dist/{commands-D5kCHCfX.mjs → commands-B0zqVia0.mjs} +374 -46
- package/dist/{commands-Cxb6tsha.mjs → commands-Cc8AE2jl.mjs} +3 -3
- package/dist/{commands-tUjBdy54.mjs → commands-Kztc20Nx.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{package-DhOTD1Ln.mjs → package-CDSBvCp_.mjs} +2 -2
- package/dist/{run-BvcwFt_g.mjs → run-B_bKTQ8M.mjs} +3 -3
- package/dist/{run-HuBXfVSz.mjs → run-h-QVSVFd.mjs} +211 -49
- package/dist/{serveCommands-DDlHXpPe.mjs → serveCommands-CM17DByZ.mjs} +5 -5
- package/dist/{serveManager-DWQtF8NK.mjs → serveManager-Bzjw2bO6.mjs} +1 -1
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import os from 'node:os';
|
|
5
|
-
import { n as normalizeAllowedUser, l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha, i as buildSessionShareUrl, j as buildMachineShareUrl } from './run-
|
|
5
|
+
import { n as normalizeAllowedUser, l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha, i as buildSessionShareUrl, j as buildMachineShareUrl } from './run-h-QVSVFd.mjs';
|
|
6
6
|
import 'os';
|
|
7
7
|
import 'fs/promises';
|
|
8
8
|
import 'fs';
|
|
@@ -73,7 +73,10 @@ function formatJson(data) {
|
|
|
73
73
|
|
|
74
74
|
const SESSION_RPC_PARAMS = {
|
|
75
75
|
getMessages: ["afterSeq", "limit"],
|
|
76
|
+
getMessageCount: [],
|
|
77
|
+
getLatestMessages: ["beforeSeq", "limit"],
|
|
76
78
|
sendMessage: ["content", "localId", "meta"],
|
|
79
|
+
btw: ["question"],
|
|
77
80
|
getMetadata: [],
|
|
78
81
|
updateMetadata: ["newMetadata", "expectedVersion"],
|
|
79
82
|
updateConfig: ["patch"],
|
|
@@ -83,7 +86,7 @@ const SESSION_RPC_PARAMS = {
|
|
|
83
86
|
permissionResponse: ["params"],
|
|
84
87
|
switchMode: ["mode"],
|
|
85
88
|
restartClaude: [],
|
|
86
|
-
|
|
89
|
+
archiveSession: [],
|
|
87
90
|
keepAlive: ["thinking", "mode"],
|
|
88
91
|
sessionEnd: [],
|
|
89
92
|
getActivityState: [],
|
|
@@ -1002,10 +1005,10 @@ async function sessionSpawn(agent, directory, machineId, opts) {
|
|
|
1002
1005
|
if (result.type === "success") {
|
|
1003
1006
|
console.log(`Session started: ${result.sessionId}`);
|
|
1004
1007
|
if (result.message) console.log(` ${result.message}`);
|
|
1005
|
-
const
|
|
1006
|
-
if (
|
|
1007
|
-
console.log(`\x1B[33m\u26A0 Permission mode: ${
|
|
1008
|
-
console.log(`\x1B[33m Use
|
|
1008
|
+
const explicitPermMode = opts?.permissionMode;
|
|
1009
|
+
if (explicitPermMode && explicitPermMode !== "bypassPermissions") {
|
|
1010
|
+
console.log(`\x1B[33m\u26A0 Permission mode: ${explicitPermMode}. Agent will pause for tool approval.\x1B[0m`);
|
|
1011
|
+
console.log(`\x1B[33m Use \`svamp session approve <id>\` to unblock, or drop the flag to run autonomously.\x1B[0m`);
|
|
1009
1012
|
}
|
|
1010
1013
|
if (opts?.message && result.sessionId) {
|
|
1011
1014
|
const svc = getSessionProxy(machine, result.sessionId);
|
|
@@ -1034,14 +1037,42 @@ async function sessionSpawn(agent, directory, machineId, opts) {
|
|
|
1034
1037
|
await server.disconnect();
|
|
1035
1038
|
}
|
|
1036
1039
|
}
|
|
1037
|
-
async function
|
|
1040
|
+
async function sessionArchive(sessionId, machineId) {
|
|
1038
1041
|
const { server, machine, fullId } = await connectAndResolveSession(sessionId, machineId);
|
|
1039
1042
|
try {
|
|
1040
|
-
const success = await machine.
|
|
1043
|
+
const success = await machine.archiveSession(fullId);
|
|
1041
1044
|
if (success) {
|
|
1042
|
-
console.log(`Session ${fullId.slice(0, 8)}
|
|
1045
|
+
console.log(`Session ${fullId.slice(0, 8)} archived. Run \`svamp session resume ${fullId.slice(0, 8)}\` to bring it back.`);
|
|
1043
1046
|
} else {
|
|
1044
|
-
console.error("Failed to
|
|
1047
|
+
console.error("Failed to archive session (not found on daemon).");
|
|
1048
|
+
process.exit(1);
|
|
1049
|
+
}
|
|
1050
|
+
} finally {
|
|
1051
|
+
await server.disconnect();
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
async function sessionResume(sessionId, machineId) {
|
|
1055
|
+
const { server, machine, fullId } = await connectAndResolveSession(sessionId, machineId);
|
|
1056
|
+
try {
|
|
1057
|
+
const result = await machine.resumeSession(fullId);
|
|
1058
|
+
if (result?.success) {
|
|
1059
|
+
console.log(`Session ${fullId.slice(0, 8)} resumed.`);
|
|
1060
|
+
} else {
|
|
1061
|
+
console.error(`Failed to resume session: ${result?.message || "unknown error"}`);
|
|
1062
|
+
process.exit(1);
|
|
1063
|
+
}
|
|
1064
|
+
} finally {
|
|
1065
|
+
await server.disconnect();
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
async function sessionDelete(sessionId, machineId) {
|
|
1069
|
+
const { server, machine, fullId } = await connectAndResolveSession(sessionId, machineId);
|
|
1070
|
+
try {
|
|
1071
|
+
const success = await machine.deleteSession(fullId);
|
|
1072
|
+
if (success) {
|
|
1073
|
+
console.log(`Session ${fullId.slice(0, 8)} deleted.`);
|
|
1074
|
+
} else {
|
|
1075
|
+
console.error("Failed to delete session.");
|
|
1045
1076
|
process.exit(1);
|
|
1046
1077
|
}
|
|
1047
1078
|
} finally {
|
|
@@ -1285,12 +1316,12 @@ async function sessionAttach(sessionId, machineId) {
|
|
|
1285
1316
|
process.stdout.write("> ");
|
|
1286
1317
|
return;
|
|
1287
1318
|
}
|
|
1288
|
-
if (trimmed === "/
|
|
1319
|
+
if (trimmed === "/archive") {
|
|
1289
1320
|
try {
|
|
1290
|
-
await svc.
|
|
1291
|
-
console.log("Session
|
|
1321
|
+
await svc.archiveSession();
|
|
1322
|
+
console.log("Session archived. Run `svamp session resume <id>` to bring it back.");
|
|
1292
1323
|
} catch (err) {
|
|
1293
|
-
console.error(`
|
|
1324
|
+
console.error(`Archive failed: ${err.message}`);
|
|
1294
1325
|
}
|
|
1295
1326
|
rl.close();
|
|
1296
1327
|
await server.disconnect();
|
|
@@ -1330,66 +1361,361 @@ async function sessionAttach(sessionId, machineId) {
|
|
|
1330
1361
|
process.exit(0);
|
|
1331
1362
|
});
|
|
1332
1363
|
}
|
|
1364
|
+
async function snapshotLatestSeq(machine, fullId) {
|
|
1365
|
+
try {
|
|
1366
|
+
const r = await machine.sessionRPC(fullId, "getMessageCount", {});
|
|
1367
|
+
return Math.max(0, Number(r?.latestSeq ?? 0));
|
|
1368
|
+
} catch {
|
|
1369
|
+
try {
|
|
1370
|
+
const r = await machine.sessionRPC(fullId, "getLatestMessages", { limit: 1 });
|
|
1371
|
+
const msgs = r?.messages || [];
|
|
1372
|
+
return msgs.length > 0 ? Number(msgs[msgs.length - 1].seq || 0) : 0;
|
|
1373
|
+
} catch {
|
|
1374
|
+
return 0;
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
async function collectAssistantResponse(machine, fullId, afterSeq) {
|
|
1379
|
+
const pageLimit = 500;
|
|
1380
|
+
let cursor = afterSeq;
|
|
1381
|
+
const collected = [];
|
|
1382
|
+
const seqs = [];
|
|
1383
|
+
for (let i = 0; i < 20; i++) {
|
|
1384
|
+
const { messages, hasMore } = await machine.sessionRPC(
|
|
1385
|
+
fullId,
|
|
1386
|
+
"getMessages",
|
|
1387
|
+
{ afterSeq: cursor, limit: pageLimit }
|
|
1388
|
+
);
|
|
1389
|
+
if (!messages || messages.length === 0) break;
|
|
1390
|
+
for (const msg of messages) {
|
|
1391
|
+
const role = msg?.content?.role;
|
|
1392
|
+
if (role === "agent" || role === "assistant") {
|
|
1393
|
+
const data = msg.content?.content?.data || msg.content?.content;
|
|
1394
|
+
if (!data) continue;
|
|
1395
|
+
let blocks = null;
|
|
1396
|
+
if (data.type === "assistant") {
|
|
1397
|
+
const b = data.message?.content || data.content;
|
|
1398
|
+
blocks = Array.isArray(b) ? b : null;
|
|
1399
|
+
} else if (data.type === "output" && data.data?.type === "assistant") {
|
|
1400
|
+
const b = data.data.message?.content || data.data.content;
|
|
1401
|
+
blocks = Array.isArray(b) ? b : null;
|
|
1402
|
+
}
|
|
1403
|
+
if (blocks) {
|
|
1404
|
+
for (const block of blocks) {
|
|
1405
|
+
if (block.type === "text" && typeof block.text === "string" && block.text) {
|
|
1406
|
+
collected.push(block.text);
|
|
1407
|
+
if (!seqs.includes(msg.seq)) seqs.push(msg.seq);
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
} else if (data.type === "result" && typeof data.result === "string" && data.result) {
|
|
1411
|
+
collected.push(data.result);
|
|
1412
|
+
if (!seqs.includes(msg.seq)) seqs.push(msg.seq);
|
|
1413
|
+
} else if (data.type === "output" && data.data?.type === "result" && typeof data.data.result === "string" && data.data.result) {
|
|
1414
|
+
collected.push(data.data.result);
|
|
1415
|
+
if (!seqs.includes(msg.seq)) seqs.push(msg.seq);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
cursor = Math.max(cursor, Number(msg.seq || 0));
|
|
1419
|
+
}
|
|
1420
|
+
if (!hasMore) break;
|
|
1421
|
+
}
|
|
1422
|
+
return { text: collected.join("\n").trim(), messageSeqs: seqs };
|
|
1423
|
+
}
|
|
1424
|
+
function validateSendOptions(opts) {
|
|
1425
|
+
if (!opts?.btw) return [];
|
|
1426
|
+
const incompatible = [];
|
|
1427
|
+
if (opts.subject) incompatible.push("--subject");
|
|
1428
|
+
if (opts.urgency) incompatible.push("--urgency");
|
|
1429
|
+
if (opts.wait) incompatible.push("--wait");
|
|
1430
|
+
if (opts.response) incompatible.push("--response");
|
|
1431
|
+
return incompatible;
|
|
1432
|
+
}
|
|
1433
|
+
async function sendCore(machine, fullId, message, opts) {
|
|
1434
|
+
if (opts?.btw) {
|
|
1435
|
+
const btwResult = await machine.sessionRPC(fullId, "btw", { question: message });
|
|
1436
|
+
if (!btwResult?.success) {
|
|
1437
|
+
return {
|
|
1438
|
+
sessionId: fullId,
|
|
1439
|
+
mode: "btw",
|
|
1440
|
+
sent: false,
|
|
1441
|
+
waited: false,
|
|
1442
|
+
status: "error",
|
|
1443
|
+
error: btwResult?.error || "btw failed"
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
return {
|
|
1447
|
+
sessionId: fullId,
|
|
1448
|
+
mode: "btw",
|
|
1449
|
+
sent: true,
|
|
1450
|
+
waited: true,
|
|
1451
|
+
status: "idle",
|
|
1452
|
+
response: String(btwResult.answer || "")
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
const wantResponse = !!opts?.response;
|
|
1456
|
+
const shouldWait = !!opts?.wait || wantResponse;
|
|
1457
|
+
let bypassEnsured = false;
|
|
1458
|
+
if (shouldWait && !opts?.requireApproval) {
|
|
1459
|
+
try {
|
|
1460
|
+
await machine.sessionRPC(fullId, "switchMode", { mode: "bypassPermissions" });
|
|
1461
|
+
bypassEnsured = true;
|
|
1462
|
+
} catch {
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
const preSeq = wantResponse ? await snapshotLatestSeq(machine, fullId) : 0;
|
|
1466
|
+
const { randomUUID } = await import('node:crypto');
|
|
1467
|
+
const callerSessionId = process.env.SVAMP_SESSION_ID;
|
|
1468
|
+
const inboxMessage = {
|
|
1469
|
+
messageId: randomUUID(),
|
|
1470
|
+
body: message,
|
|
1471
|
+
timestamp: Date.now(),
|
|
1472
|
+
read: false,
|
|
1473
|
+
from: callerSessionId ? `agent:${callerSessionId}` : `cli:${os.userInfo().username}`,
|
|
1474
|
+
...callerSessionId ? { fromSession: callerSessionId } : {},
|
|
1475
|
+
to: fullId,
|
|
1476
|
+
subject: opts?.subject,
|
|
1477
|
+
urgency: opts?.urgency || "urgent"
|
|
1478
|
+
};
|
|
1479
|
+
const result = await machine.sessionRPC(fullId, "sendInboxMessage", { message: inboxMessage });
|
|
1480
|
+
let waitResult;
|
|
1481
|
+
if (shouldWait) {
|
|
1482
|
+
const timeoutMs = (opts?.timeout || 300) * 1e3;
|
|
1483
|
+
waitResult = await waitForBusyThenIdle(machine, fullId, timeoutMs);
|
|
1484
|
+
}
|
|
1485
|
+
if (waitResult?.pendingPermissions?.length) {
|
|
1486
|
+
return {
|
|
1487
|
+
sessionId: fullId,
|
|
1488
|
+
mode: "send",
|
|
1489
|
+
sent: true,
|
|
1490
|
+
messageId: result.messageId,
|
|
1491
|
+
waited: true,
|
|
1492
|
+
status: "permission-pending",
|
|
1493
|
+
pendingPermissions: waitResult.pendingPermissions,
|
|
1494
|
+
bypassEnsured
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
let response;
|
|
1498
|
+
if (wantResponse) {
|
|
1499
|
+
response = await collectAssistantResponse(machine, fullId, preSeq);
|
|
1500
|
+
}
|
|
1501
|
+
return {
|
|
1502
|
+
sessionId: fullId,
|
|
1503
|
+
mode: "send",
|
|
1504
|
+
sent: true,
|
|
1505
|
+
messageId: result.messageId,
|
|
1506
|
+
waited: shouldWait,
|
|
1507
|
+
status: shouldWait ? "idle" : "sent",
|
|
1508
|
+
bypassEnsured,
|
|
1509
|
+
...wantResponse && response ? { response: response.text, responseSeqs: response.messageSeqs } : {}
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1333
1512
|
async function sessionSend(sessionId, message, machineId, opts) {
|
|
1513
|
+
const incompatible = validateSendOptions(opts);
|
|
1514
|
+
if (incompatible.length) {
|
|
1515
|
+
console.error(`Error: --btw is incompatible with: ${incompatible.join(", ")}`);
|
|
1516
|
+
console.error(" --btw runs as a one-shot forked query that returns the answer directly.");
|
|
1517
|
+
process.exit(1);
|
|
1518
|
+
}
|
|
1334
1519
|
const { server, machine, fullId } = await connectAndResolveSession(sessionId, machineId);
|
|
1335
1520
|
try {
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1521
|
+
const r = await sendCore(machine, fullId, message, opts);
|
|
1522
|
+
if (r.mode === "btw") {
|
|
1523
|
+
if (r.status === "error") {
|
|
1524
|
+
if (opts?.json) {
|
|
1525
|
+
console.log(formatJson({
|
|
1526
|
+
sessionId: r.sessionId,
|
|
1527
|
+
mode: "btw",
|
|
1528
|
+
message,
|
|
1529
|
+
success: false,
|
|
1530
|
+
error: r.error
|
|
1531
|
+
}));
|
|
1532
|
+
} else {
|
|
1533
|
+
console.error(`btw failed: ${r.error || "unknown error"}`);
|
|
1534
|
+
}
|
|
1535
|
+
process.exitCode = 1;
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
if (opts?.json) {
|
|
1539
|
+
console.log(formatJson({
|
|
1540
|
+
sessionId: r.sessionId,
|
|
1541
|
+
mode: "btw",
|
|
1542
|
+
message,
|
|
1543
|
+
success: true,
|
|
1544
|
+
response: r.response || ""
|
|
1545
|
+
}));
|
|
1546
|
+
} else if (r.response) {
|
|
1547
|
+
console.log(r.response);
|
|
1548
|
+
}
|
|
1549
|
+
return;
|
|
1352
1550
|
}
|
|
1353
|
-
if (
|
|
1551
|
+
if (r.status === "permission-pending") {
|
|
1354
1552
|
if (opts?.json) {
|
|
1355
1553
|
console.log(formatJson({
|
|
1356
|
-
sessionId:
|
|
1554
|
+
sessionId: r.sessionId,
|
|
1357
1555
|
message,
|
|
1358
1556
|
sent: true,
|
|
1359
|
-
messageId:
|
|
1557
|
+
messageId: r.messageId,
|
|
1360
1558
|
status: "permission-pending",
|
|
1361
|
-
pendingPermissions:
|
|
1559
|
+
pendingPermissions: r.pendingPermissions
|
|
1362
1560
|
}));
|
|
1363
1561
|
} else {
|
|
1364
|
-
console.log(`Message sent to session ${
|
|
1562
|
+
console.log(`Message sent to session ${r.sessionId.slice(0, 8)} (id: ${(r.messageId || "").slice(0, 8)})`);
|
|
1365
1563
|
console.log("Agent is waiting for permission approval:");
|
|
1366
|
-
for (const p of
|
|
1564
|
+
for (const p of r.pendingPermissions || []) {
|
|
1367
1565
|
const argsStr = JSON.stringify(p.arguments || {}).slice(0, 120);
|
|
1368
1566
|
console.log(` [${p.id.slice(0, 8)}] ${p.tool}(${argsStr})`);
|
|
1369
1567
|
}
|
|
1370
1568
|
console.log(`
|
|
1371
|
-
Use: svamp session approve ${
|
|
1569
|
+
Use: svamp session approve ${r.sessionId.slice(0, 8)}`);
|
|
1372
1570
|
}
|
|
1373
1571
|
process.exitCode = 2;
|
|
1374
|
-
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
if (opts?.json) {
|
|
1375
1575
|
console.log(formatJson({
|
|
1376
|
-
sessionId:
|
|
1576
|
+
sessionId: r.sessionId,
|
|
1377
1577
|
message,
|
|
1378
1578
|
sent: true,
|
|
1379
|
-
messageId:
|
|
1380
|
-
waited:
|
|
1381
|
-
status:
|
|
1579
|
+
messageId: r.messageId,
|
|
1580
|
+
waited: r.waited,
|
|
1581
|
+
status: r.status,
|
|
1582
|
+
...r.bypassEnsured ? { bypassEnsured: true } : {},
|
|
1583
|
+
...opts.response ? { response: r.response || "", responseSeqs: r.responseSeqs || [] } : {}
|
|
1382
1584
|
}));
|
|
1383
1585
|
} else {
|
|
1384
|
-
console.log(`Message sent to session ${
|
|
1385
|
-
if (
|
|
1586
|
+
console.log(`Message sent to session ${r.sessionId.slice(0, 8)} (id: ${(r.messageId || "").slice(0, 8)})`);
|
|
1587
|
+
if (r.waited) {
|
|
1386
1588
|
console.log("Agent is idle.");
|
|
1387
1589
|
}
|
|
1590
|
+
if (opts?.response) {
|
|
1591
|
+
if (r.response) {
|
|
1592
|
+
console.log("");
|
|
1593
|
+
console.log(r.response);
|
|
1594
|
+
} else {
|
|
1595
|
+
console.log("(no text response captured)");
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1388
1598
|
}
|
|
1389
1599
|
} finally {
|
|
1390
1600
|
await server.disconnect();
|
|
1391
1601
|
}
|
|
1392
1602
|
}
|
|
1603
|
+
async function queryCore(machine, directory, prompt, opts) {
|
|
1604
|
+
const absDir = resolve(directory);
|
|
1605
|
+
const spawnOpts = {
|
|
1606
|
+
directory: absDir,
|
|
1607
|
+
agent: "claude",
|
|
1608
|
+
permissionMode: opts?.permissionMode || "bypassPermissions",
|
|
1609
|
+
tags: opts?.tag ? [opts.tag] : ["svamp-query"]
|
|
1610
|
+
};
|
|
1611
|
+
const spawn = await machine.spawnSession(spawnOpts);
|
|
1612
|
+
if (spawn.type !== "success" || !spawn.sessionId) {
|
|
1613
|
+
return {
|
|
1614
|
+
sessionId: "",
|
|
1615
|
+
mode: "query",
|
|
1616
|
+
sent: false,
|
|
1617
|
+
waited: false,
|
|
1618
|
+
status: "error",
|
|
1619
|
+
error: spawn.errorMessage || `spawn returned type=${spawn.type}`,
|
|
1620
|
+
directory: absDir
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
const spawnedId = spawn.sessionId;
|
|
1624
|
+
const svc = getSessionProxy(machine, spawnedId);
|
|
1625
|
+
await svc.sendMessage(
|
|
1626
|
+
JSON.stringify({
|
|
1627
|
+
role: "user",
|
|
1628
|
+
content: { type: "text", text: prompt },
|
|
1629
|
+
meta: { sentFrom: "svamp-cli-query" }
|
|
1630
|
+
})
|
|
1631
|
+
);
|
|
1632
|
+
const timeoutMs = (opts?.timeout || 300) * 1e3;
|
|
1633
|
+
const waitResult = await waitForBusyThenIdle(machine, spawnedId, timeoutMs);
|
|
1634
|
+
if (waitResult.pendingPermissions?.length) {
|
|
1635
|
+
return {
|
|
1636
|
+
sessionId: spawnedId,
|
|
1637
|
+
mode: "query",
|
|
1638
|
+
sent: true,
|
|
1639
|
+
waited: true,
|
|
1640
|
+
status: "permission-pending",
|
|
1641
|
+
pendingPermissions: waitResult.pendingPermissions,
|
|
1642
|
+
error: `Agent paused for tool approval (${waitResult.pendingPermissions.length} pending). Pass --permission-mode bypassPermissions or approve the request manually.`,
|
|
1643
|
+
directory: absDir
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
const response = await collectAssistantResponse(machine, spawnedId, 0);
|
|
1647
|
+
return {
|
|
1648
|
+
sessionId: spawnedId,
|
|
1649
|
+
mode: "query",
|
|
1650
|
+
sent: true,
|
|
1651
|
+
waited: true,
|
|
1652
|
+
status: "idle",
|
|
1653
|
+
response: response.text,
|
|
1654
|
+
responseSeqs: response.messageSeqs,
|
|
1655
|
+
directory: absDir
|
|
1656
|
+
};
|
|
1657
|
+
}
|
|
1658
|
+
async function sessionQuery(directory, prompt, machineId, opts) {
|
|
1659
|
+
const { server, machine } = await connectAndGetMachine(machineId);
|
|
1660
|
+
let spawnedId;
|
|
1661
|
+
try {
|
|
1662
|
+
const r = await queryCore(machine, directory, prompt, opts);
|
|
1663
|
+
spawnedId = r.sessionId || void 0;
|
|
1664
|
+
if (r.status === "error") {
|
|
1665
|
+
if (opts?.json) {
|
|
1666
|
+
console.log(formatJson({
|
|
1667
|
+
success: false,
|
|
1668
|
+
error: r.error,
|
|
1669
|
+
directory: r.directory
|
|
1670
|
+
}));
|
|
1671
|
+
} else {
|
|
1672
|
+
console.error(`Failed to spawn query session: ${r.error}`);
|
|
1673
|
+
}
|
|
1674
|
+
process.exitCode = 1;
|
|
1675
|
+
return;
|
|
1676
|
+
}
|
|
1677
|
+
if (r.status === "permission-pending") {
|
|
1678
|
+
if (opts?.json) {
|
|
1679
|
+
console.log(formatJson({
|
|
1680
|
+
success: false,
|
|
1681
|
+
sessionId: r.sessionId,
|
|
1682
|
+
directory: r.directory,
|
|
1683
|
+
error: r.error,
|
|
1684
|
+
pendingPermissions: r.pendingPermissions
|
|
1685
|
+
}));
|
|
1686
|
+
} else {
|
|
1687
|
+
console.error(r.error);
|
|
1688
|
+
}
|
|
1689
|
+
process.exitCode = 2;
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
if (opts?.json) {
|
|
1693
|
+
console.log(formatJson({
|
|
1694
|
+
success: true,
|
|
1695
|
+
sessionId: r.sessionId,
|
|
1696
|
+
directory: r.directory,
|
|
1697
|
+
prompt,
|
|
1698
|
+
response: r.response || "",
|
|
1699
|
+
responseSeqs: r.responseSeqs || []
|
|
1700
|
+
}));
|
|
1701
|
+
} else {
|
|
1702
|
+
if (r.response) {
|
|
1703
|
+
console.log(r.response);
|
|
1704
|
+
} else {
|
|
1705
|
+
console.log("(no text response captured)");
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
} finally {
|
|
1709
|
+
if (spawnedId && !opts?.keep) {
|
|
1710
|
+
try {
|
|
1711
|
+
await machine.deleteSession(spawnedId);
|
|
1712
|
+
} catch (err) {
|
|
1713
|
+
console.error(`Warning: failed to delete query session ${spawnedId}: ${err?.message || err}`);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
await server.disconnect();
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1393
1719
|
async function sessionWait(sessionId, machineId, opts) {
|
|
1394
1720
|
const { server, machine, fullId } = await connectAndResolveSession(sessionId, machineId);
|
|
1395
1721
|
try {
|
|
@@ -1776,12 +2102,14 @@ async function sessionInboxSend(sessionIdPartial, body, machineId, opts) {
|
|
|
1776
2102
|
const { server, machine, fullId } = await connectAndResolveSession(sessionIdPartial, machineId);
|
|
1777
2103
|
try {
|
|
1778
2104
|
const { randomUUID } = await import('node:crypto');
|
|
2105
|
+
const callerSessionId = process.env.SVAMP_SESSION_ID;
|
|
1779
2106
|
const message = {
|
|
1780
2107
|
messageId: randomUUID(),
|
|
1781
2108
|
body,
|
|
1782
2109
|
timestamp: Date.now(),
|
|
1783
2110
|
read: false,
|
|
1784
|
-
from: `cli:${os.userInfo().username}`,
|
|
2111
|
+
from: callerSessionId ? `agent:${callerSessionId}` : `cli:${os.userInfo().username}`,
|
|
2112
|
+
...callerSessionId ? { fromSession: callerSessionId } : {},
|
|
1785
2113
|
to: fullId,
|
|
1786
2114
|
subject: opts?.subject,
|
|
1787
2115
|
urgency: opts?.urgency || "normal",
|
|
@@ -1897,4 +2225,4 @@ async function sessionInboxClear(sessionIdPartial, machineId, opts) {
|
|
|
1897
2225
|
}
|
|
1898
2226
|
}
|
|
1899
2227
|
|
|
1900
|
-
export { connectAndGetMachine, connectAndResolveSession, createWorktree, generateWorktreeName, machineExec, machineInfo, machineLs, machineShare, parseShareArg, renderMessage, resolveSessionId, sessionApprove, sessionAttach, sessionDeny, sessionInboxClear, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxSend, sessionInfo, sessionList, sessionMachines, sessionMessages, sessionRalphCancel, sessionRalphStart, sessionRalphStatus, sessionSend, sessionShare, sessionSpawn,
|
|
2228
|
+
export { collectAssistantResponse, connectAndGetMachine, connectAndResolveSession, createWorktree, generateWorktreeName, machineExec, machineInfo, machineLs, machineShare, parseShareArg, queryCore, renderMessage, resolveSessionId, sendCore, sessionApprove, sessionArchive, sessionAttach, sessionDelete, sessionDeny, sessionInboxClear, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxSend, sessionInfo, sessionList, sessionMachines, sessionMessages, sessionQuery, sessionRalphCancel, sessionRalphStart, sessionRalphStatus, sessionResume, sessionSend, sessionShare, sessionSpawn, sessionWait, snapshotLatestSeq, validateSendOptions };
|
|
@@ -68,7 +68,7 @@ async function serviceExpose(args) {
|
|
|
68
68
|
});
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
71
|
+
const { connectAndGetMachine } = await import('./commands-B0zqVia0.mjs');
|
|
72
72
|
const { server, machine } = await connectAndGetMachine();
|
|
73
73
|
try {
|
|
74
74
|
const status = await machine.tunnelStart({
|
|
@@ -132,7 +132,7 @@ async function serviceServe(args) {
|
|
|
132
132
|
}
|
|
133
133
|
async function serviceList(_args) {
|
|
134
134
|
try {
|
|
135
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
135
|
+
const { connectAndGetMachine } = await import('./commands-B0zqVia0.mjs');
|
|
136
136
|
const { server, machine } = await connectAndGetMachine();
|
|
137
137
|
try {
|
|
138
138
|
const tunnels = await machine.tunnelList({});
|
|
@@ -161,7 +161,7 @@ async function serviceDelete(args) {
|
|
|
161
161
|
process.exit(1);
|
|
162
162
|
}
|
|
163
163
|
try {
|
|
164
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
164
|
+
const { connectAndGetMachine } = await import('./commands-B0zqVia0.mjs');
|
|
165
165
|
const { server, machine } = await connectAndGetMachine();
|
|
166
166
|
try {
|
|
167
167
|
await machine.tunnelStop({ name });
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { writeFileSync, readFileSync } from 'fs';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
|
-
import { connectAndGetMachine } from './commands-
|
|
3
|
+
import { connectAndGetMachine } from './commands-B0zqVia0.mjs';
|
|
4
4
|
import 'node:fs';
|
|
5
5
|
import 'node:child_process';
|
|
6
6
|
import 'node:path';
|
|
7
7
|
import 'node:os';
|
|
8
|
-
import './run-
|
|
8
|
+
import './run-h-QVSVFd.mjs';
|
|
9
9
|
import 'os';
|
|
10
10
|
import 'fs/promises';
|
|
11
11
|
import 'url';
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { c as connectToHypha, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, a as registerSessionService, s as startDaemon, b as stopDaemon } from './run-
|
|
1
|
+
export { c as connectToHypha, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, a as registerSessionService, s as startDaemon, b as stopDaemon } from './run-h-QVSVFd.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
var name = "svamp-cli";
|
|
2
|
-
var version = "0.2.
|
|
2
|
+
var version = "0.2.71";
|
|
3
3
|
var description = "Svamp CLI — AI workspace daemon on Hypha Cloud";
|
|
4
4
|
var author = "Amun AI AB";
|
|
5
5
|
var license = "SEE LICENSE IN LICENSE";
|
|
@@ -19,7 +19,7 @@ var exports$1 = {
|
|
|
19
19
|
var scripts = {
|
|
20
20
|
build: "rm -rf dist bin/skills && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && tsc --noEmit && pkgroll",
|
|
21
21
|
typecheck: "tsc --noEmit",
|
|
22
|
-
test: "npx tsx test/test-context-window.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only",
|
|
22
|
+
test: "npx tsx test/test-context-window.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only",
|
|
23
23
|
"test:hypha": "node --no-warnings test/test-hypha-service.mjs",
|
|
24
24
|
dev: "tsx src/cli.ts",
|
|
25
25
|
"dev:daemon": "tsx src/cli.ts daemon start-sync",
|
|
@@ -2,7 +2,7 @@ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(im
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import { existsSync, readFileSync, watch } from 'node:fs';
|
|
5
|
-
import { c as connectToHypha, a as registerSessionService, k as generateHookSettings } from './run-
|
|
5
|
+
import { c as connectToHypha, a as registerSessionService, k as generateHookSettings } from './run-h-QVSVFd.mjs';
|
|
6
6
|
import { createServer } from 'node:http';
|
|
7
7
|
import { spawn } from 'node:child_process';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
@@ -684,8 +684,8 @@ async function runInteractive(options) {
|
|
|
684
684
|
log("[hypha] Restart requested");
|
|
685
685
|
return { success: false, message: "Restart not supported in interactive mode" };
|
|
686
686
|
},
|
|
687
|
-
|
|
688
|
-
log("[hypha]
|
|
687
|
+
onArchiveSession: async () => {
|
|
688
|
+
log("[hypha] Archive requested");
|
|
689
689
|
await cleanup();
|
|
690
690
|
process.exit(0);
|
|
691
691
|
},
|