svamp-cli 0.1.67 → 0.1.69
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 +18 -62
- package/dist/{commands-CdQ8qr6l.mjs → commands-CNWZF0B9.mjs} +2 -2
- package/dist/{commands-Dpc6QK0m.mjs → commands-CgWkG45c.mjs} +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{package-BeHXZuag.mjs → package-D2QVDgm_.mjs} +1 -1
- package/dist/{run-ez-QlRKy.mjs → run-DqPEyYsf.mjs} +1 -1
- package/dist/{run-BDmLH9T8.mjs → run-DxmtlxnM.mjs} +75 -1
- package/package.json +2 -2
- package/dist/storageCommands-CKhntx1P.mjs +0 -154
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-
|
|
1
|
+
import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-DxmtlxnM.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -109,7 +109,7 @@ async function main() {
|
|
|
109
109
|
const { handleServiceCommand } = await import('./commands-CF32XIau.mjs');
|
|
110
110
|
await handleServiceCommand();
|
|
111
111
|
} else if (subcommand === "process" || subcommand === "proc") {
|
|
112
|
-
const { processCommand } = await import('./commands-
|
|
112
|
+
const { processCommand } = await import('./commands-CNWZF0B9.mjs');
|
|
113
113
|
let machineId;
|
|
114
114
|
const processArgs = args.slice(1);
|
|
115
115
|
const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
|
|
@@ -127,7 +127,7 @@ async function main() {
|
|
|
127
127
|
} else if (!subcommand || subcommand === "start") {
|
|
128
128
|
await handleInteractiveCommand();
|
|
129
129
|
} else if (subcommand === "--version" || subcommand === "-v") {
|
|
130
|
-
const pkg = await import('./package-
|
|
130
|
+
const pkg = await import('./package-D2QVDgm_.mjs').catch(() => ({ default: { version: "unknown" } }));
|
|
131
131
|
console.log(`svamp version: ${pkg.default.version}`);
|
|
132
132
|
} else {
|
|
133
133
|
console.error(`Unknown command: ${subcommand}`);
|
|
@@ -136,7 +136,7 @@ async function main() {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
async function handleInteractiveCommand() {
|
|
139
|
-
const { runInteractive } = await import('./run-
|
|
139
|
+
const { runInteractive } = await import('./run-DqPEyYsf.mjs');
|
|
140
140
|
const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
|
|
141
141
|
let directory = process.cwd();
|
|
142
142
|
let resumeSessionId;
|
|
@@ -181,7 +181,7 @@ async function handleAgentCommand() {
|
|
|
181
181
|
return;
|
|
182
182
|
}
|
|
183
183
|
if (agentArgs[0] === "list") {
|
|
184
|
-
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-
|
|
184
|
+
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-DxmtlxnM.mjs').then(function (n) { return n.i; });
|
|
185
185
|
console.log("Known agents:");
|
|
186
186
|
for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
|
|
187
187
|
console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
|
|
@@ -193,7 +193,7 @@ async function handleAgentCommand() {
|
|
|
193
193
|
console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
|
|
194
194
|
return;
|
|
195
195
|
}
|
|
196
|
-
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-
|
|
196
|
+
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-DxmtlxnM.mjs').then(function (n) { return n.i; });
|
|
197
197
|
let cwd = process.cwd();
|
|
198
198
|
const filteredArgs = [];
|
|
199
199
|
for (let i = 0; i < agentArgs.length; i++) {
|
|
@@ -217,12 +217,12 @@ async function handleAgentCommand() {
|
|
|
217
217
|
console.log(`Starting ${config.agentName} agent in ${cwd}...`);
|
|
218
218
|
let backend;
|
|
219
219
|
if (KNOWN_MCP_AGENTS[config.agentName]) {
|
|
220
|
-
const { CodexMcpBackend } = await import('./run-
|
|
220
|
+
const { CodexMcpBackend } = await import('./run-DxmtlxnM.mjs').then(function (n) { return n.j; });
|
|
221
221
|
backend = new CodexMcpBackend({ cwd, log: logFn });
|
|
222
222
|
} else {
|
|
223
|
-
const { AcpBackend } = await import('./run-
|
|
224
|
-
const { GeminiTransport } = await import('./run-
|
|
225
|
-
const { DefaultTransport } = await import('./run-
|
|
223
|
+
const { AcpBackend } = await import('./run-DxmtlxnM.mjs').then(function (n) { return n.h; });
|
|
224
|
+
const { GeminiTransport } = await import('./run-DxmtlxnM.mjs').then(function (n) { return n.G; });
|
|
225
|
+
const { DefaultTransport } = await import('./run-DxmtlxnM.mjs').then(function (n) { return n.D; });
|
|
226
226
|
const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
|
|
227
227
|
backend = new AcpBackend({
|
|
228
228
|
agentName: config.agentName,
|
|
@@ -340,7 +340,7 @@ async function handleSessionCommand() {
|
|
|
340
340
|
printSessionHelp();
|
|
341
341
|
return;
|
|
342
342
|
}
|
|
343
|
-
const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionQueueAdd, sessionQueueList, sessionQueueClear } = await import('./commands-
|
|
343
|
+
const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionQueueAdd, sessionQueueList, sessionQueueClear } = await import('./commands-CgWkG45c.mjs');
|
|
344
344
|
const parseFlagStr = (flag, shortFlag) => {
|
|
345
345
|
for (let i = 1; i < sessionArgs.length; i++) {
|
|
346
346
|
if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
|
|
@@ -400,7 +400,7 @@ async function handleSessionCommand() {
|
|
|
400
400
|
allowDomain.push(sessionArgs[++i]);
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
|
-
const { parseShareArg } = await import('./commands-
|
|
403
|
+
const { parseShareArg } = await import('./commands-CgWkG45c.mjs');
|
|
404
404
|
const shareEntries = share.map((s) => parseShareArg(s));
|
|
405
405
|
await sessionSpawn(agent, dir, targetMachineId, {
|
|
406
406
|
message,
|
|
@@ -484,7 +484,7 @@ async function handleSessionCommand() {
|
|
|
484
484
|
console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
|
|
485
485
|
process.exit(1);
|
|
486
486
|
}
|
|
487
|
-
const { sessionApprove } = await import('./commands-
|
|
487
|
+
const { sessionApprove } = await import('./commands-CgWkG45c.mjs');
|
|
488
488
|
const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
489
489
|
await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
|
|
490
490
|
json: hasFlag("--json")
|
|
@@ -494,7 +494,7 @@ async function handleSessionCommand() {
|
|
|
494
494
|
console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
|
|
495
495
|
process.exit(1);
|
|
496
496
|
}
|
|
497
|
-
const { sessionDeny } = await import('./commands-
|
|
497
|
+
const { sessionDeny } = await import('./commands-CgWkG45c.mjs');
|
|
498
498
|
const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
499
499
|
await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
|
|
500
500
|
json: hasFlag("--json")
|
|
@@ -597,7 +597,7 @@ async function handleMachineCommand() {
|
|
|
597
597
|
return;
|
|
598
598
|
}
|
|
599
599
|
if (machineSubcommand === "share") {
|
|
600
|
-
const { machineShare } = await import('./commands-
|
|
600
|
+
const { machineShare } = await import('./commands-CgWkG45c.mjs');
|
|
601
601
|
let machineId;
|
|
602
602
|
const shareArgs = [];
|
|
603
603
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
@@ -627,7 +627,7 @@ async function handleMachineCommand() {
|
|
|
627
627
|
}
|
|
628
628
|
await machineShare(machineId, { add, remove, list, configPath, showConfig });
|
|
629
629
|
} else if (machineSubcommand === "exec") {
|
|
630
|
-
const { machineExec } = await import('./commands-
|
|
630
|
+
const { machineExec } = await import('./commands-CgWkG45c.mjs');
|
|
631
631
|
let machineId;
|
|
632
632
|
let cwd;
|
|
633
633
|
const cmdParts = [];
|
|
@@ -647,7 +647,7 @@ async function handleMachineCommand() {
|
|
|
647
647
|
}
|
|
648
648
|
await machineExec(machineId, command, cwd);
|
|
649
649
|
} else if (machineSubcommand === "info") {
|
|
650
|
-
const { machineInfo } = await import('./commands-
|
|
650
|
+
const { machineInfo } = await import('./commands-CgWkG45c.mjs');
|
|
651
651
|
let machineId;
|
|
652
652
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
653
653
|
if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
|
|
@@ -670,7 +670,7 @@ async function handleMachineCommand() {
|
|
|
670
670
|
const { machineNotify } = await import('./agentCommands-C6iGblcL.mjs');
|
|
671
671
|
await machineNotify(message, level);
|
|
672
672
|
} else if (machineSubcommand === "ls") {
|
|
673
|
-
const { machineLs } = await import('./commands-
|
|
673
|
+
const { machineLs } = await import('./commands-CgWkG45c.mjs');
|
|
674
674
|
let machineId;
|
|
675
675
|
let showHidden = false;
|
|
676
676
|
let path;
|
|
@@ -684,43 +684,6 @@ async function handleMachineCommand() {
|
|
|
684
684
|
}
|
|
685
685
|
}
|
|
686
686
|
await machineLs(machineId, path, showHidden);
|
|
687
|
-
} else if (machineSubcommand === "storage") {
|
|
688
|
-
const { storageList, storageOrphans, storageMarkOrphan, storageUnmarkOrphan, storageDelete, printStorageHelp } = await import('./storageCommands-CKhntx1P.mjs');
|
|
689
|
-
const storageArgs = machineArgs.slice(1);
|
|
690
|
-
const storageSubcmd = storageArgs[0];
|
|
691
|
-
if (!storageSubcmd || storageSubcmd === "--help" || storageSubcmd === "-h") {
|
|
692
|
-
printStorageHelp();
|
|
693
|
-
} else if (storageSubcmd === "list") {
|
|
694
|
-
await storageList();
|
|
695
|
-
} else if (storageSubcmd === "orphans") {
|
|
696
|
-
const mark = storageArgs.includes("--mark");
|
|
697
|
-
await storageOrphans(mark);
|
|
698
|
-
} else if (storageSubcmd === "mark-orphan") {
|
|
699
|
-
const ns = storageArgs[1];
|
|
700
|
-
if (!ns) {
|
|
701
|
-
console.error("Usage: svamp machine storage mark-orphan <namespace>");
|
|
702
|
-
process.exit(1);
|
|
703
|
-
}
|
|
704
|
-
await storageMarkOrphan(ns);
|
|
705
|
-
} else if (storageSubcmd === "unmark-orphan") {
|
|
706
|
-
const ns = storageArgs[1];
|
|
707
|
-
if (!ns) {
|
|
708
|
-
console.error("Usage: svamp machine storage unmark-orphan <namespace>");
|
|
709
|
-
process.exit(1);
|
|
710
|
-
}
|
|
711
|
-
await storageUnmarkOrphan(ns);
|
|
712
|
-
} else if (storageSubcmd === "delete") {
|
|
713
|
-
const ns = storageArgs[1];
|
|
714
|
-
if (!ns) {
|
|
715
|
-
console.error("Usage: svamp machine storage delete <namespace>");
|
|
716
|
-
process.exit(1);
|
|
717
|
-
}
|
|
718
|
-
await storageDelete(ns);
|
|
719
|
-
} else {
|
|
720
|
-
console.error(`Unknown storage command: ${storageSubcmd}`);
|
|
721
|
-
printStorageHelp();
|
|
722
|
-
process.exit(1);
|
|
723
|
-
}
|
|
724
687
|
} else {
|
|
725
688
|
console.error(`Unknown machine command: ${machineSubcommand}`);
|
|
726
689
|
printMachineHelp();
|
|
@@ -1322,13 +1285,6 @@ Usage:
|
|
|
1322
1285
|
svamp machine share --config <path> Apply security context config
|
|
1323
1286
|
svamp machine share --show-config Show current security context config
|
|
1324
1287
|
|
|
1325
|
-
Storage (admin):
|
|
1326
|
-
svamp machine storage list List all user PVCs with status
|
|
1327
|
-
svamp machine storage orphans [--mark] Show PVCs with no active namespace
|
|
1328
|
-
svamp machine storage mark-orphan <namespace> Flag a PVC as orphaned
|
|
1329
|
-
svamp machine storage unmark-orphan <namespace> Remove orphan flag
|
|
1330
|
-
svamp machine storage delete <namespace> Permanently delete a PVC (double confirm)
|
|
1331
|
-
|
|
1332
1288
|
Options:
|
|
1333
1289
|
--machine <id>, -m <id> Target a specific machine (prefix match supported)
|
|
1334
1290
|
--cwd <path> Working directory for exec (default: home dir)
|
|
@@ -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-CgWkG45c.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-DxmtlxnM.mjs';
|
|
9
9
|
import 'os';
|
|
10
10
|
import 'fs/promises';
|
|
11
11
|
import 'url';
|
|
@@ -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 { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-
|
|
5
|
+
import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-DxmtlxnM.mjs';
|
|
6
6
|
import 'os';
|
|
7
7
|
import 'fs/promises';
|
|
8
8
|
import 'fs';
|
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-DxmtlxnM.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -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 { join, resolve } from 'node:path';
|
|
4
4
|
import { mkdirSync, writeFileSync, existsSync, unlinkSync, readFileSync, watch } from 'node:fs';
|
|
5
|
-
import { c as connectToHypha, a as registerSessionService } from './run-
|
|
5
|
+
import { c as connectToHypha, a as registerSessionService } from './run-DxmtlxnM.mjs';
|
|
6
6
|
import { createServer } from 'node:http';
|
|
7
7
|
import { spawn } from 'node:child_process';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
@@ -1158,6 +1158,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1158
1158
|
sessionId,
|
|
1159
1159
|
metadata: { value: metadata, version: metadataVersion }
|
|
1160
1160
|
});
|
|
1161
|
+
callbacks.onSharingUpdate?.(newSharing);
|
|
1161
1162
|
return { success: true, sharing: newSharing };
|
|
1162
1163
|
},
|
|
1163
1164
|
/** Update security context and restart the agent process with new rules */
|
|
@@ -4466,6 +4467,53 @@ async function installSkillFromMarketplace(name) {
|
|
|
4466
4467
|
writeFileSync(localPath, content, "utf-8");
|
|
4467
4468
|
}
|
|
4468
4469
|
}
|
|
4470
|
+
function preventMachineSleep(logger) {
|
|
4471
|
+
if (process.platform === "darwin") {
|
|
4472
|
+
const caff = spawn$1("caffeinate", ["-s", "-i", "-m"], { stdio: "ignore", detached: false });
|
|
4473
|
+
caff.on("error", (err) => {
|
|
4474
|
+
logger.log(`Warning: could not start caffeinate to prevent sleep: ${err.message}`);
|
|
4475
|
+
});
|
|
4476
|
+
caff.on("exit", (code) => {
|
|
4477
|
+
if (code !== null && code !== 0) {
|
|
4478
|
+
logger.log(`Warning: caffeinate exited unexpectedly (code ${code})`);
|
|
4479
|
+
}
|
|
4480
|
+
});
|
|
4481
|
+
process.on("exit", () => {
|
|
4482
|
+
try {
|
|
4483
|
+
caff.kill();
|
|
4484
|
+
} catch {
|
|
4485
|
+
}
|
|
4486
|
+
});
|
|
4487
|
+
logger.log("caffeinate started \u2014 machine will not sleep while daemon is running");
|
|
4488
|
+
return;
|
|
4489
|
+
}
|
|
4490
|
+
if (process.platform === "linux") {
|
|
4491
|
+
const inh = spawn$1(
|
|
4492
|
+
"systemd-inhibit",
|
|
4493
|
+
["--what=idle:sleep:handle-lid-switch", "--who=svamp", "--why=Svamp daemon running", "--mode=block", "sleep", "infinity"],
|
|
4494
|
+
{ stdio: "ignore", detached: false }
|
|
4495
|
+
);
|
|
4496
|
+
inh.on("error", () => {
|
|
4497
|
+
});
|
|
4498
|
+
inh.on("exit", (code) => {
|
|
4499
|
+
if (code !== null && code !== 0 && code !== 130) {
|
|
4500
|
+
logger.log(`Warning: systemd-inhibit exited with code ${code} \u2014 sleep prevention may be inactive`);
|
|
4501
|
+
}
|
|
4502
|
+
});
|
|
4503
|
+
process.on("exit", () => {
|
|
4504
|
+
try {
|
|
4505
|
+
inh.kill();
|
|
4506
|
+
} catch {
|
|
4507
|
+
}
|
|
4508
|
+
});
|
|
4509
|
+
setImmediate(() => {
|
|
4510
|
+
if (!inh.killed && inh.exitCode === null) {
|
|
4511
|
+
logger.log("systemd-inhibit started \u2014 machine will not idle-sleep while daemon is running");
|
|
4512
|
+
}
|
|
4513
|
+
});
|
|
4514
|
+
return;
|
|
4515
|
+
}
|
|
4516
|
+
}
|
|
4469
4517
|
async function ensureAutoInstalledSkills(logger) {
|
|
4470
4518
|
const tasks = [
|
|
4471
4519
|
{
|
|
@@ -5158,8 +5206,12 @@ async function startDaemon(options) {
|
|
|
5158
5206
|
// hypha-rpc connection closed message
|
|
5159
5207
|
"Client disconnected",
|
|
5160
5208
|
// Hypha client disconnect events
|
|
5161
|
-
"fetch failed"
|
|
5209
|
+
"fetch failed",
|
|
5162
5210
|
// Fetch API errors during reconnect
|
|
5211
|
+
"already exists in the cache store",
|
|
5212
|
+
// hypha-rpc: stale in-flight RPC calls after reconnect try to resolve with duplicate message keys
|
|
5213
|
+
"Failed to send the request when calling method"
|
|
5214
|
+
// hypha-rpc: RPC call failed after reconnect (often wraps the cache store error)
|
|
5163
5215
|
];
|
|
5164
5216
|
let unhandledRejectionCount = 0;
|
|
5165
5217
|
let unhandledRejectionResetTimer = null;
|
|
@@ -5254,6 +5306,7 @@ async function startDaemon(options) {
|
|
|
5254
5306
|
await supervisor.init();
|
|
5255
5307
|
ensureAutoInstalledSkills(logger).catch(() => {
|
|
5256
5308
|
});
|
|
5309
|
+
preventMachineSleep(logger);
|
|
5257
5310
|
try {
|
|
5258
5311
|
logger.log("Connecting to Hypha server...");
|
|
5259
5312
|
server = await connectToHypha({
|
|
@@ -6218,6 +6271,23 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6218
6271
|
sessionMetadata = { ...sessionMetadata, securityContext: newSecurityContext };
|
|
6219
6272
|
return await restartClaudeHandler();
|
|
6220
6273
|
},
|
|
6274
|
+
onSharingUpdate: (newSharing) => {
|
|
6275
|
+
logger.log(`[Session ${sessionId}] Sharing config updated \u2014 persisting to disk`);
|
|
6276
|
+
sessionMetadata = { ...sessionMetadata, sharing: newSharing };
|
|
6277
|
+
if (!trackedSession.stopped) {
|
|
6278
|
+
saveSession({
|
|
6279
|
+
sessionId,
|
|
6280
|
+
directory,
|
|
6281
|
+
claudeResumeId,
|
|
6282
|
+
permissionMode: currentPermissionMode,
|
|
6283
|
+
spawnMeta: lastSpawnMeta,
|
|
6284
|
+
metadata: sessionMetadata,
|
|
6285
|
+
createdAt: Date.now(),
|
|
6286
|
+
machineId,
|
|
6287
|
+
wasProcessing: sessionWasProcessing
|
|
6288
|
+
});
|
|
6289
|
+
}
|
|
6290
|
+
},
|
|
6221
6291
|
onApplySystemPrompt: async (prompt) => {
|
|
6222
6292
|
logger.log(`[Session ${sessionId}] System prompt update requested \u2014 restarting agent`);
|
|
6223
6293
|
lastSpawnMeta = { ...lastSpawnMeta, appendSystemPrompt: prompt };
|
|
@@ -6609,6 +6679,10 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6609
6679
|
sessionMetadata = { ...sessionMetadata, securityContext: newSecurityContext };
|
|
6610
6680
|
return { success: false, message: "Security context updates with restart are not yet supported for this agent type." };
|
|
6611
6681
|
},
|
|
6682
|
+
onSharingUpdate: (newSharing) => {
|
|
6683
|
+
logger.log(`[${agentName} Session ${sessionId}] Sharing config updated \u2014 persisting in-memory`);
|
|
6684
|
+
sessionMetadata = { ...sessionMetadata, sharing: newSharing };
|
|
6685
|
+
},
|
|
6612
6686
|
onApplySystemPrompt: async () => {
|
|
6613
6687
|
return { success: false, message: "System prompt updates with restart are not yet supported for this agent type." };
|
|
6614
6688
|
},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svamp-cli",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Svamp CLI
|
|
3
|
+
"version": "0.1.69",
|
|
4
|
+
"description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
|
|
5
5
|
"author": "Amun AI AB",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
7
7
|
"type": "module",
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { getSandboxEnv } from './api-BRbsyqJ4.mjs';
|
|
2
|
-
|
|
3
|
-
async function adminFetch(path, method = "GET", body) {
|
|
4
|
-
const env = getSandboxEnv();
|
|
5
|
-
if (!env.apiKey) {
|
|
6
|
-
throw new Error('No API credentials. Run "svamp login" or set SANDBOX_API_KEY.');
|
|
7
|
-
}
|
|
8
|
-
const url = `${env.apiUrl.replace(/\/+$/, "")}${path}`;
|
|
9
|
-
const res = await fetch(url, {
|
|
10
|
-
method,
|
|
11
|
-
headers: {
|
|
12
|
-
"Authorization": `Bearer ${env.apiKey}`,
|
|
13
|
-
"Content-Type": "application/json"
|
|
14
|
-
},
|
|
15
|
-
...{}
|
|
16
|
-
});
|
|
17
|
-
if (!res.ok) {
|
|
18
|
-
const text = await res.text().catch(() => "");
|
|
19
|
-
throw new Error(`HTTP ${res.status} ${method} ${path}: ${text}`);
|
|
20
|
-
}
|
|
21
|
-
return res.json();
|
|
22
|
-
}
|
|
23
|
-
function fmtAge(ts) {
|
|
24
|
-
if (!ts) return "?";
|
|
25
|
-
try {
|
|
26
|
-
const dt = /^\d+$/.test(ts) ? new Date(parseInt(ts, 10) * 1e3) : new Date(ts);
|
|
27
|
-
const secs = (Date.now() - dt.getTime()) / 1e3;
|
|
28
|
-
const d = Math.floor(secs / 86400);
|
|
29
|
-
const h = Math.floor(secs % 86400 / 3600);
|
|
30
|
-
return d > 0 ? `${d}d ${h}h ago` : `${h}h ago`;
|
|
31
|
-
} catch {
|
|
32
|
-
return ts;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function pad(s, n) {
|
|
36
|
-
return s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
37
|
-
}
|
|
38
|
-
async function storageList() {
|
|
39
|
-
const data = await adminFetch("/admin/storage/pvcs");
|
|
40
|
-
const pvcs = data.pvcs ?? [];
|
|
41
|
-
if (!pvcs.length) {
|
|
42
|
-
console.log("No managed PVCs found.");
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
console.log("");
|
|
46
|
-
console.log(`${pad("NAMESPACE", 36)}${pad("SIZE", 9)}${pad("STATUS", 9)}${pad("CREATED", 20)}ORPHANED`);
|
|
47
|
-
console.log("\u2500".repeat(90));
|
|
48
|
-
for (const p of pvcs.sort((a, b) => a.namespace.localeCompare(b.namespace))) {
|
|
49
|
-
const orphan = p.orphaned_at ? `\u26A0 ${fmtAge(p.orphaned_at)}` : "\u2014";
|
|
50
|
-
console.log(`${pad(p.namespace, 36)}${pad(p.capacity ?? "?", 9)}${pad(p.status ?? "?", 9)}${pad(fmtAge(p.created_at), 20)}${orphan}`);
|
|
51
|
-
}
|
|
52
|
-
console.log(`
|
|
53
|
-
Total: ${data.count} PVC(s)`);
|
|
54
|
-
}
|
|
55
|
-
async function storageOrphans(mark = false) {
|
|
56
|
-
const data = await adminFetch(`/admin/orphaned-pvcs?dry_run=${mark ? "false" : "true"}`);
|
|
57
|
-
const orphans = data.orphaned_pvcs ?? [];
|
|
58
|
-
if (!orphans.length) {
|
|
59
|
-
console.log("\u2705 No orphaned PVCs found.");
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
console.log(`
|
|
63
|
-
\u26A0 ${orphans.length} orphaned PVC(s) (namespace has no running pods):
|
|
64
|
-
`);
|
|
65
|
-
console.log(`${pad("NAMESPACE", 36)}${pad("SIZE", 9)}${pad("MARKED", 9)}ORPHANED FOR`);
|
|
66
|
-
console.log("\u2500".repeat(72));
|
|
67
|
-
for (const o of orphans) {
|
|
68
|
-
const age = o.orphaned_for || (o.marked ? "?" : "not marked");
|
|
69
|
-
console.log(`${pad(o.namespace, 36)}${pad(o.storage ?? "?", 9)}${pad(o.marked ? "yes" : "no", 9)}${age}`);
|
|
70
|
-
}
|
|
71
|
-
if (!mark) {
|
|
72
|
-
console.log("\nTip: pass --mark to start the retention clock on unmarked orphans.");
|
|
73
|
-
}
|
|
74
|
-
console.log("\nTo delete: svamp machine storage delete <namespace>");
|
|
75
|
-
}
|
|
76
|
-
async function storageMarkOrphan(namespace) {
|
|
77
|
-
const data = await adminFetch(`/admin/storage/mark-orphan/${namespace}`, "POST");
|
|
78
|
-
if (data.marked) {
|
|
79
|
-
console.log(`\u2705 PVC for '${namespace}' marked as orphaned.`);
|
|
80
|
-
console.log(` To delete: svamp machine storage delete ${namespace}`);
|
|
81
|
-
} else {
|
|
82
|
-
console.log(`\u2139 PVC for '${namespace}' was already marked or not found.`);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
async function storageUnmarkOrphan(namespace) {
|
|
86
|
-
const data = await adminFetch(`/admin/storage/unmark-orphan/${namespace}`, "POST");
|
|
87
|
-
if (data.unmarked) {
|
|
88
|
-
console.log(`\u2705 Orphan mark removed from '${namespace}'.`);
|
|
89
|
-
} else {
|
|
90
|
-
console.log(`\u2139 PVC for '${namespace}' was not marked or not found.`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
async function storageDelete(namespace) {
|
|
94
|
-
const readline = await import('readline');
|
|
95
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
96
|
-
const ask = (q) => new Promise((res) => rl.question(q, res));
|
|
97
|
-
try {
|
|
98
|
-
const data2 = await adminFetch("/admin/storage/pvcs");
|
|
99
|
-
const pvc = (data2.pvcs ?? []).find((p) => p.namespace === namespace);
|
|
100
|
-
if (!pvc) {
|
|
101
|
-
console.error(`No PVC found for namespace '${namespace}'.`);
|
|
102
|
-
rl.close();
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
console.log(`
|
|
106
|
-
\u26A0 Namespace: ${pvc.namespace}`);
|
|
107
|
-
console.log(` Size: ${pvc.capacity ?? "?"}`);
|
|
108
|
-
console.log(` Created: ${fmtAge(pvc.created_at)}`);
|
|
109
|
-
if (pvc.orphaned_at) console.log(` Orphaned: ${fmtAge(pvc.orphaned_at)}`);
|
|
110
|
-
} catch {
|
|
111
|
-
}
|
|
112
|
-
console.log("\n\u26A0 PERMANENTLY deleting this PVC will IRREVERSIBLY destroy all user data.\n");
|
|
113
|
-
const a1 = (await ask(`Type the namespace name to confirm: `)).trim();
|
|
114
|
-
if (a1 !== namespace) {
|
|
115
|
-
console.log("Confirmation mismatch \u2014 aborted.");
|
|
116
|
-
rl.close();
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const a2 = (await ask(`Type it again to double-confirm: `)).trim();
|
|
120
|
-
rl.close();
|
|
121
|
-
if (a2 !== namespace) {
|
|
122
|
-
console.log("Confirmation mismatch \u2014 aborted.");
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
const data = await adminFetch(`/admin/storage/pvc/${namespace}`, "DELETE");
|
|
126
|
-
if (data.deleted) {
|
|
127
|
-
console.log(`\u2705 PVC for '${namespace}' permanently deleted.`);
|
|
128
|
-
} else {
|
|
129
|
-
console.log(`\u2139 PVC for '${namespace}' was not found or already deleted.`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
function printStorageHelp() {
|
|
133
|
-
console.log(`
|
|
134
|
-
svamp machine storage \u2014 sandbox PVC lifecycle management (admin only)
|
|
135
|
-
|
|
136
|
-
Usage:
|
|
137
|
-
svamp machine storage list List all PVCs with status
|
|
138
|
-
svamp machine storage orphans [--mark] Show PVCs with no active namespace
|
|
139
|
-
svamp machine storage mark-orphan <ns> Flag a PVC as orphaned (no deletion)
|
|
140
|
-
svamp machine storage unmark-orphan <ns> Remove orphan flag
|
|
141
|
-
svamp machine storage delete <ns> Permanently delete a PVC (double confirmation)
|
|
142
|
-
|
|
143
|
-
Environment:
|
|
144
|
-
SANDBOX_API_URL Sandbox API base URL (default: https://agent-sandbox.aicell.io)
|
|
145
|
-
SANDBOX_API_KEY Admin API key (or use HYPHA_TOKEN from svamp login)
|
|
146
|
-
|
|
147
|
-
Safety rules:
|
|
148
|
-
- Automated systems NEVER delete PVCs
|
|
149
|
-
- delete requires typing the namespace name twice
|
|
150
|
-
- delete checks for running pods and refuses if any are active
|
|
151
|
-
`);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export { printStorageHelp, storageDelete, storageList, storageMarkOrphan, storageOrphans, storageUnmarkOrphan };
|