svamp-cli 0.1.47 → 0.1.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/cli.mjs +251 -90
  2. package/dist/commands-6EyqaoCp.mjs +507 -0
  3. package/dist/commands-BVuE0VQU.mjs +507 -0
  4. package/dist/commands-BdvvRQIo.mjs +1415 -0
  5. package/dist/commands-Bgg_dvDw.mjs +1683 -0
  6. package/dist/commands-C9TOoTCv.mjs +1395 -0
  7. package/dist/commands-C9TdN_El.mjs +1683 -0
  8. package/dist/commands-Cw2Od6mc.mjs +1683 -0
  9. package/dist/commands-D1brd9fB.mjs +1741 -0
  10. package/dist/commands-DBv6A3aJ.mjs +507 -0
  11. package/dist/commands-DHnFOhQC.mjs +1741 -0
  12. package/dist/commands-DWira-Cz.mjs +1741 -0
  13. package/dist/commands-DlPBC5p0.mjs +514 -0
  14. package/dist/commands-DwveR96q.mjs +1683 -0
  15. package/dist/commands-HrBaGV-C.mjs +1683 -0
  16. package/dist/commands-Ugz9TtRu.mjs +1420 -0
  17. package/dist/commands-Wng0OuNY.mjs +1683 -0
  18. package/dist/commands-rhHI6Wb2.mjs +1420 -0
  19. package/dist/index.mjs +1 -1
  20. package/dist/package-BYUO-39f.mjs +60 -0
  21. package/dist/package-BaGfG8vL.mjs +58 -0
  22. package/dist/package-k3XsdP9k.mjs +58 -0
  23. package/dist/run-B9ND6srh.mjs +6154 -0
  24. package/dist/run-BG3279Kg.mjs +1051 -0
  25. package/dist/run-BicITYWX.mjs +6138 -0
  26. package/dist/run-BjZ6SyFy.mjs +1051 -0
  27. package/dist/run-BxTdRjCG.mjs +1051 -0
  28. package/dist/run-ByOVDgvx.mjs +6115 -0
  29. package/dist/run-CE4H8ZiN.mjs +6273 -0
  30. package/dist/run-C_KIew8H.mjs +1051 -0
  31. package/dist/run-CcYaXgCy.mjs +6091 -0
  32. package/dist/run-Cf2Dl_ck.mjs +1051 -0
  33. package/dist/run-CtJRxaFC.mjs +1051 -0
  34. package/dist/run-CuIMdkKF.mjs +6099 -0
  35. package/dist/run-CzIY4_RE.mjs +6093 -0
  36. package/dist/run-D1PFrNZB.mjs +6273 -0
  37. package/dist/run-D3Lqxasl.mjs +1051 -0
  38. package/dist/run-DWdtp6VD.mjs +6136 -0
  39. package/dist/run-D_W5YF0D.mjs +6046 -0
  40. package/dist/run-Dd9XkswU.mjs +1051 -0
  41. package/dist/run-YFYpyThQ.mjs +1051 -0
  42. package/dist/run-coIDvBK_.mjs +6127 -0
  43. package/dist/run-wpUutZ9C.mjs +1051 -0
  44. package/dist/run-yTjJ7noq.mjs +1051 -0
  45. package/dist/tunnel-BXEroHJF.mjs +299 -0
  46. package/package.json +5 -3
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-Ckyg9-fm.mjs';
1
+ import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-CE4H8ZiN.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -105,12 +105,15 @@ async function main() {
105
105
  await handleMachineCommand();
106
106
  } else if (subcommand === "skills") {
107
107
  await handleSkillsCommand();
108
+ } else if (subcommand === "service" || subcommand === "svc") {
109
+ const { handleServiceCommand } = await import('./commands-DlPBC5p0.mjs').then(function (n) { return n.c; });
110
+ await handleServiceCommand();
108
111
  } else if (subcommand === "--help" || subcommand === "-h") {
109
112
  printHelp();
110
113
  } else if (!subcommand || subcommand === "start") {
111
114
  await handleInteractiveCommand();
112
115
  } else if (subcommand === "--version" || subcommand === "-v") {
113
- const pkg = await import('./package-DG0AkZdm.mjs').catch(() => ({ default: { version: "unknown" } }));
116
+ const pkg = await import('./package-BYUO-39f.mjs').catch(() => ({ default: { version: "unknown" } }));
114
117
  console.log(`svamp version: ${pkg.default.version}`);
115
118
  } else {
116
119
  console.error(`Unknown command: ${subcommand}`);
@@ -119,7 +122,7 @@ async function main() {
119
122
  }
120
123
  }
121
124
  async function handleInteractiveCommand() {
122
- const { runInteractive } = await import('./run-6dwQnoBL.mjs');
125
+ const { runInteractive } = await import('./run-CtJRxaFC.mjs');
123
126
  const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
124
127
  let directory = process.cwd();
125
128
  let resumeSessionId;
@@ -164,7 +167,7 @@ async function handleAgentCommand() {
164
167
  return;
165
168
  }
166
169
  if (agentArgs[0] === "list") {
167
- const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-Ckyg9-fm.mjs').then(function (n) { return n.i; });
170
+ const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-CE4H8ZiN.mjs').then(function (n) { return n.i; });
168
171
  console.log("Known agents:");
169
172
  for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
170
173
  console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
@@ -176,7 +179,7 @@ async function handleAgentCommand() {
176
179
  console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
177
180
  return;
178
181
  }
179
- const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-Ckyg9-fm.mjs').then(function (n) { return n.i; });
182
+ const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-CE4H8ZiN.mjs').then(function (n) { return n.i; });
180
183
  let cwd = process.cwd();
181
184
  const filteredArgs = [];
182
185
  for (let i = 0; i < agentArgs.length; i++) {
@@ -200,12 +203,12 @@ async function handleAgentCommand() {
200
203
  console.log(`Starting ${config.agentName} agent in ${cwd}...`);
201
204
  let backend;
202
205
  if (KNOWN_MCP_AGENTS[config.agentName]) {
203
- const { CodexMcpBackend } = await import('./run-Ckyg9-fm.mjs').then(function (n) { return n.j; });
206
+ const { CodexMcpBackend } = await import('./run-CE4H8ZiN.mjs').then(function (n) { return n.j; });
204
207
  backend = new CodexMcpBackend({ cwd, log: logFn });
205
208
  } else {
206
- const { AcpBackend } = await import('./run-Ckyg9-fm.mjs').then(function (n) { return n.h; });
207
- const { GeminiTransport } = await import('./run-Ckyg9-fm.mjs').then(function (n) { return n.G; });
208
- const { DefaultTransport } = await import('./run-Ckyg9-fm.mjs').then(function (n) { return n.D; });
209
+ const { AcpBackend } = await import('./run-CE4H8ZiN.mjs').then(function (n) { return n.h; });
210
+ const { GeminiTransport } = await import('./run-CE4H8ZiN.mjs').then(function (n) { return n.G; });
211
+ const { DefaultTransport } = await import('./run-CE4H8ZiN.mjs').then(function (n) { return n.D; });
209
212
  const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
210
213
  backend = new AcpBackend({
211
214
  agentName: config.agentName,
@@ -323,7 +326,7 @@ async function handleSessionCommand() {
323
326
  printSessionHelp();
324
327
  return;
325
328
  }
326
- const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionQueueAdd, sessionQueueList, sessionQueueClear } = await import('./commands-DsIoygTL.mjs');
329
+ const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionQueueAdd, sessionQueueList, sessionQueueClear } = await import('./commands-D1brd9fB.mjs');
327
330
  const parseFlagStr = (flag, shortFlag) => {
328
331
  for (let i = 1; i < sessionArgs.length; i++) {
329
332
  if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
@@ -357,13 +360,21 @@ async function handleSessionCommand() {
357
360
  }
358
361
  const message = parseFlagStr("--message");
359
362
  const wait = hasFlag("--wait");
363
+ const worktree = hasFlag("--worktree");
360
364
  const isolate = hasFlag("--isolate");
365
+ const permissionMode = parseFlagStr("--permission-mode") || parseFlagStr("-p");
361
366
  const securityContextPath = parseFlagStr("--security-context");
362
367
  const denyNetwork = hasFlag("--deny-network");
368
+ const parentSessionId = parseFlagStr("--parent");
369
+ const tagsFlag = parseFlagStr("--tags");
363
370
  const share = [];
364
371
  const denyRead = [];
365
372
  const allowWrite = [];
366
373
  const allowDomain = [];
374
+ const tags = [];
375
+ if (tagsFlag) {
376
+ tags.push(...tagsFlag.split(",").map((t) => t.trim()).filter(Boolean));
377
+ }
367
378
  for (let i = 1; i < sessionArgs.length; i++) {
368
379
  if (sessionArgs[i] === "--share" && i + 1 < sessionArgs.length) {
369
380
  share.push(sessionArgs[++i]);
@@ -375,18 +386,22 @@ async function handleSessionCommand() {
375
386
  allowDomain.push(sessionArgs[++i]);
376
387
  }
377
388
  }
378
- const { parseShareArg } = await import('./commands-DsIoygTL.mjs');
389
+ const { parseShareArg } = await import('./commands-D1brd9fB.mjs');
379
390
  const shareEntries = share.map((s) => parseShareArg(s));
380
391
  await sessionSpawn(agent, dir, targetMachineId, {
381
392
  message,
382
393
  wait,
394
+ worktree,
383
395
  isolate,
396
+ permissionMode,
384
397
  securityContextPath,
385
398
  share: shareEntries.length > 0 ? shareEntries : void 0,
386
399
  denyRead: denyRead.length > 0 ? denyRead : void 0,
387
400
  allowWrite: allowWrite.length > 0 ? allowWrite : void 0,
388
401
  denyNetwork,
389
- allowDomain: allowDomain.length > 0 ? allowDomain : void 0
402
+ allowDomain: allowDomain.length > 0 ? allowDomain : void 0,
403
+ tags: tags.length > 0 ? tags : void 0,
404
+ parentSessionId
390
405
  });
391
406
  } else if (sessionSubcommand === "stop") {
392
407
  if (!sessionArgs[1]) {
@@ -404,12 +419,13 @@ async function handleSessionCommand() {
404
419
  });
405
420
  } else if (sessionSubcommand === "messages" || sessionSubcommand === "msgs") {
406
421
  if (!sessionArgs[1]) {
407
- console.error("Usage: svamp session messages <session-id> [--last N] [--json] [--after N] [--limit N]");
422
+ console.error("Usage: svamp session messages <session-id> [--last N] [--json] [--raw] [--after N] [--limit N]");
408
423
  process.exit(1);
409
424
  }
410
425
  await sessionMessages(sessionArgs[1], targetMachineId, {
411
426
  last: parseFlagInt("--last"),
412
427
  json: hasFlag("--json"),
428
+ raw: hasFlag("--raw"),
413
429
  after: parseFlagInt("--after"),
414
430
  limit: parseFlagInt("--limit")
415
431
  });
@@ -431,11 +447,12 @@ async function handleSessionCommand() {
431
447
  });
432
448
  } else if (sessionSubcommand === "wait") {
433
449
  if (!sessionArgs[1]) {
434
- console.error("Usage: svamp session wait <session-id> [--timeout N]");
450
+ console.error("Usage: svamp session wait <session-id> [--timeout N] [--json]");
435
451
  process.exit(1);
436
452
  }
437
453
  await sessionWait(sessionArgs[1], targetMachineId, {
438
- timeout: parseFlagInt("--timeout")
454
+ timeout: parseFlagInt("--timeout"),
455
+ json: hasFlag("--json")
439
456
  });
440
457
  } else if (sessionSubcommand === "share") {
441
458
  if (!sessionArgs[1]) {
@@ -448,14 +465,35 @@ async function handleSessionCommand() {
448
465
  list: hasFlag("--list"),
449
466
  public: parseFlagStr("--public")
450
467
  });
468
+ } else if (sessionSubcommand === "approve") {
469
+ if (!sessionArgs[1]) {
470
+ console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
471
+ process.exit(1);
472
+ }
473
+ const { sessionApprove } = await import('./commands-D1brd9fB.mjs');
474
+ const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
475
+ await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
476
+ json: hasFlag("--json")
477
+ });
478
+ } else if (sessionSubcommand === "deny") {
479
+ if (!sessionArgs[1]) {
480
+ console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
481
+ process.exit(1);
482
+ }
483
+ const { sessionDeny } = await import('./commands-D1brd9fB.mjs');
484
+ const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
485
+ await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
486
+ json: hasFlag("--json")
487
+ });
451
488
  } else if (sessionSubcommand === "ralph-start" || sessionSubcommand === "ralph") {
452
489
  if (!sessionArgs[1] || !sessionArgs[2]) {
453
- console.error('Usage: svamp session ralph-start <session-id> "<task>" [--completion-promise TEXT] [--max-iterations N]');
490
+ console.error('Usage: svamp session ralph-start <session-id> "<task>" [--completion-promise TEXT] [--max-iterations N] [--cooldown N]');
454
491
  process.exit(1);
455
492
  }
456
493
  await sessionRalphStart(sessionArgs[1], sessionArgs[2], targetMachineId, {
457
494
  completionPromise: parseFlagStr("--completion-promise"),
458
- maxIterations: parseFlagInt("--max-iterations")
495
+ maxIterations: parseFlagInt("--max-iterations"),
496
+ cooldownSeconds: parseFlagInt("--cooldown")
459
497
  });
460
498
  } else if (sessionSubcommand === "ralph-cancel") {
461
499
  if (!sessionArgs[1]) {
@@ -508,7 +546,7 @@ async function handleMachineCommand() {
508
546
  return;
509
547
  }
510
548
  if (machineSubcommand === "share") {
511
- const { machineShare } = await import('./commands-DsIoygTL.mjs');
549
+ const { machineShare } = await import('./commands-D1brd9fB.mjs');
512
550
  let machineId;
513
551
  const shareArgs = [];
514
552
  for (let i = 1; i < machineArgs.length; i++) {
@@ -537,6 +575,50 @@ async function handleMachineCommand() {
537
575
  }
538
576
  }
539
577
  await machineShare(machineId, { add, remove, list, configPath, showConfig });
578
+ } else if (machineSubcommand === "exec") {
579
+ const { machineExec } = await import('./commands-D1brd9fB.mjs');
580
+ let machineId;
581
+ let cwd;
582
+ const cmdParts = [];
583
+ for (let i = 1; i < machineArgs.length; i++) {
584
+ if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
585
+ machineId = machineArgs[++i];
586
+ } else if (machineArgs[i] === "--cwd" && i + 1 < machineArgs.length) {
587
+ cwd = machineArgs[++i];
588
+ } else {
589
+ cmdParts.push(machineArgs[i]);
590
+ }
591
+ }
592
+ const command = cmdParts.join(" ");
593
+ if (!command) {
594
+ console.error("Usage: svamp machine exec <command> [--cwd <path>] [-m <id>]");
595
+ process.exit(1);
596
+ }
597
+ await machineExec(machineId, command, cwd);
598
+ } else if (machineSubcommand === "info") {
599
+ const { machineInfo } = await import('./commands-D1brd9fB.mjs');
600
+ let machineId;
601
+ for (let i = 1; i < machineArgs.length; i++) {
602
+ if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
603
+ machineId = machineArgs[++i];
604
+ }
605
+ }
606
+ await machineInfo(machineId);
607
+ } else if (machineSubcommand === "ls") {
608
+ const { machineLs } = await import('./commands-D1brd9fB.mjs');
609
+ let machineId;
610
+ let showHidden = false;
611
+ let path;
612
+ for (let i = 1; i < machineArgs.length; i++) {
613
+ if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
614
+ machineId = machineArgs[++i];
615
+ } else if (machineArgs[i] === "--hidden" || machineArgs[i] === "-a") {
616
+ showHidden = true;
617
+ } else if (!path) {
618
+ path = machineArgs[i];
619
+ }
620
+ }
621
+ await machineLs(machineId, path, showHidden);
540
622
  } else {
541
623
  console.error(`Unknown machine command: ${machineSubcommand}`);
542
624
  printMachineHelp();
@@ -551,7 +633,7 @@ async function handleSkillsCommand() {
551
633
  printSkillsHelp();
552
634
  return;
553
635
  }
554
- const { skillsFind, skillsInstall, skillsList, skillsRemove, skillsPublish } = await import('./commands-BEhSQqTp.mjs');
636
+ const { skillsFind, skillsInstall, skillsList, skillsRemove, skillsPublish } = await import('./commands-6EyqaoCp.mjs');
555
637
  if (skillsSubcommand === "find" || skillsSubcommand === "search") {
556
638
  const query = skillsArgs.slice(1).filter((a) => !a.startsWith("--")).join(" ");
557
639
  if (!query) {
@@ -898,28 +980,37 @@ function printHelp() {
898
980
  svamp \u2014 AI workspace on Hypha Cloud
899
981
 
900
982
  Usage:
901
- svamp Start interactive Claude session (synced to cloud)
902
- svamp start [-d <path>] Same as above, with explicit directory
903
- svamp login [url] Login to Hypha (opens browser, stores token)
904
- svamp daemon start Start the daemon (detached)
905
- svamp daemon stop Stop the daemon (sessions preserved for restart)
906
- svamp daemon restart Restart the daemon (sessions resume seamlessly)
907
- svamp daemon status Show daemon status
908
- svamp daemon install Install as system service (launchd/systemd/wrapper)
909
- svamp session list List active sessions
910
- svamp session spawn Spawn a new session on the daemon
911
- svamp session share <id> Manage session sharing
912
- svamp session attach <id> Attach to a session
913
- svamp session --help Show all session commands
914
- svamp machine share Manage machine sharing & security contexts
915
- svamp machine --help Show all machine commands
916
- svamp skills find <query> Search the skills marketplace
917
- svamp skills install <n> Install a skill from the marketplace
918
- svamp skills --help Show all skill commands
919
- svamp agent list List known agents
920
- svamp agent <name> Start local agent session (gemini, codex)
921
- svamp --version Show version
922
- svamp --help Show this help
983
+ svamp Start interactive Claude session (synced to cloud)
984
+ svamp start [-d <path>] Same as above, with explicit directory
985
+ svamp login [url] Login to Hypha (opens browser, stores token)
986
+ svamp daemon start Start the daemon (detached)
987
+ svamp daemon stop Stop the daemon (sessions preserved for restart)
988
+ svamp daemon restart Restart the daemon (sessions resume seamlessly)
989
+ svamp daemon status Show daemon status
990
+ svamp daemon install Install as system service (launchd/systemd/wrapper)
991
+ svamp session list List active sessions
992
+ svamp session spawn Spawn a new session on the daemon
993
+ svamp session send <id> <m> Send message to a session
994
+ svamp session wait <id> Wait for agent to become idle
995
+ svamp session info <id> Show session status & pending permissions
996
+ svamp session messages <id> Show message history
997
+ svamp session approve <id> Approve pending permission request
998
+ svamp session deny <id> Deny pending permission request
999
+ svamp session attach <id> Attach to a session (interactive terminal)
1000
+ svamp session share <id> Manage session sharing
1001
+ svamp session --help Show all session commands
1002
+ svamp machine share Manage machine sharing & security contexts
1003
+ svamp machine --help Show all machine commands
1004
+ svamp skills find <query> Search the skills marketplace
1005
+ svamp skills install <n> Install a skill from the marketplace
1006
+ svamp skills --help Show all skill commands
1007
+ svamp service expose <name> Expose a service from this sandbox
1008
+ svamp service list List service groups
1009
+ svamp service --help Show all service commands
1010
+ svamp agent list List known agents
1011
+ svamp agent <name> Start local agent session (gemini, codex)
1012
+ svamp --version Show version
1013
+ svamp --help Show this help
923
1014
 
924
1015
  Interactive mode:
925
1016
  When you run 'svamp' with no arguments, Claude starts in your terminal
@@ -954,19 +1045,75 @@ function printSessionHelp() {
954
1045
  console.log(`
955
1046
  svamp session \u2014 Manage daemon sessions (Claude, Gemini, Codex)
956
1047
 
957
- Usage:
958
- svamp session list [--active] [--json] List sessions (alias: ls)
959
- svamp session machines List discoverable machines
960
- svamp session spawn <agent> [-d <path>] [--message <msg>] [--wait]
961
- Spawn a new session
962
- svamp session stop <id> Stop a session
963
- svamp session info <id> [--json] Show session metadata + activity
1048
+ Commands:
1049
+ svamp session list [--active] [--json] List sessions (alias: ls)
1050
+ svamp session machines List discoverable machines
1051
+ svamp session spawn <agent> [-d <path>] [options] Spawn a new session
1052
+ svamp session stop <id> Stop a session
1053
+ svamp session info <id> [--json] Show status, activity & pending permissions
964
1054
  svamp session send <id> <message> [--wait] [--timeout N] [--json]
965
- Send a message to a session
966
- svamp session wait <id> [--timeout N] Wait for agent to become idle
967
- svamp session messages <id> [--last N] [--json] [--after N] [--limit N]
968
- Show messages (alias: msgs)
969
- svamp session attach <id> Attach to session (interactive)
1055
+ Send a message to a session
1056
+ svamp session wait <id> [--timeout N] [--json] Wait for agent to become idle
1057
+ svamp session messages <id> [--last N] [--json] [--raw] [--after N] [--limit N]
1058
+ Show messages (alias: msgs)
1059
+ svamp session attach <id> Attach to session (interactive terminal)
1060
+ svamp session approve <id> [request-id] [--json] Approve pending permission(s)
1061
+ svamp session deny <id> [request-id] [--json] Deny pending permission(s)
1062
+
1063
+ Spawn options:
1064
+ -d, --directory <path> Working directory (default: cwd)
1065
+ -p, --permission-mode <mode> Agent permission mode (see "Permission modes" below)
1066
+ --message <msg> Send initial message after spawn
1067
+ --wait Wait for agent to become idle before returning
1068
+ --worktree Create a git worktree branch (at .dev/worktree/<name>)
1069
+ --isolate Force OS-level sandbox isolation
1070
+ --security-context <path> Apply security context config (JSON file)
1071
+ --share <email>[:<role>] Share with user (repeatable). Role: view, interact, admin
1072
+ --deny-network Block all network access
1073
+ --deny-read <path> Deny reading path (repeatable)
1074
+ --allow-write <path> Allow writing path (repeatable)
1075
+ --allow-domain <domain> Allow network domain (repeatable)
1076
+
1077
+ Permission modes (-p, --permission-mode):
1078
+ default Prompt for each tool use (default)
1079
+ acceptEdits Auto-approve file edits, prompt for bash/dangerous tools
1080
+ bypassPermissions Auto-approve all tools (no prompts)
1081
+
1082
+ Permission workflow:
1083
+ When an agent runs with 'default' or 'acceptEdits' permission mode, it pauses
1084
+ when it needs to use a tool that requires approval. Use these commands to manage:
1085
+
1086
+ 1. Check status: svamp session info <id> --json
1087
+ \u2192 shows pendingPermissions array when agent is blocked
1088
+ 2. Wait & detect: svamp session wait <id> --json
1089
+ \u2192 exits with code 2 if permission pending (see exit codes)
1090
+ 3. Approve: svamp session approve <id> (approve all pending)
1091
+ svamp session approve <id> <rid> (approve specific request)
1092
+ 4. Deny: svamp session deny <id> (deny all pending)
1093
+ svamp session deny <id> <rid> (deny specific request)
1094
+
1095
+ Request IDs support prefix matching (e.g., "abc1" matches "abc12345-...").
1096
+
1097
+ Messages options:
1098
+ --last N Show only the last N messages
1099
+ --after N Start after sequence number N
1100
+ --limit N Max messages to fetch from server (default: 1000, cap: 500 per page)
1101
+ --json Output as JSON (FormattedMessage: id, seq, role, text, createdAt)
1102
+ --raw With --json: output full raw message objects (includes tool_use args,
1103
+ tool_result content, thinking blocks \u2014 use for programmatic parsing)
1104
+
1105
+ Exit codes (wait, send --wait, spawn --wait):
1106
+ 0 Agent is idle (task completed)
1107
+ 1 Error (timeout, connection failure, session not found)
1108
+ 2 Agent is waiting for permission approval \u2014 use approve/deny to continue
1109
+
1110
+ Global options:
1111
+ --machine <id>, -m <id> Target a specific machine (prefix match supported)
1112
+
1113
+ Agents: claude (default), gemini, codex
1114
+ Session and machine IDs support prefix matching (e.g., "abc1" matches "abc12345-...").
1115
+
1116
+ Sharing:
970
1117
  svamp session share <id> --list List shared users
971
1118
  svamp session share <id> --add <email>[:<role>] Share with user
972
1119
  svamp session share <id> --remove <email> Remove shared user
@@ -975,6 +1122,10 @@ Usage:
975
1122
  Options:
976
1123
  --machine <id>, -m <id> Target a specific machine (prefix match supported)
977
1124
 
1125
+ Spawn options:
1126
+ -p, --permission-mode <mode> Agent permission mode: default, acceptEdits, bypassPermissions
1127
+ --worktree Create a git worktree branch as working directory
1128
+
978
1129
  Spawn isolation options:
979
1130
  --share <email>[:<role>] Share session (repeatable). Role: view, interact, admin
980
1131
  --security-context <path> Path to security context JSON config file
@@ -984,39 +1135,57 @@ Spawn isolation options:
984
1135
  --deny-network Deny all network access
985
1136
  --allow-domain <domain> Allow network access to domain (repeatable)
986
1137
 
1138
+ Spawn grouping options:
1139
+ --tags <tag1,tag2> Comma-separated tags
1140
+ --parent <sessionId> Set parent session (auto-detected from SVAMP_SESSION_ID)
1141
+
987
1142
  Agents: claude (default), gemini, codex
988
1143
 
989
1144
  Session and machine IDs can be abbreviated (prefix match, like Docker).
990
1145
 
1146
+ NOTE: By default, spawned agents run with 'default' permission mode, which means
1147
+ the agent may pause to request permission for tool use (file edits, bash, etc.).
1148
+ Use -p bypassPermissions to run without approval prompts.
1149
+
991
1150
  Attach commands:
992
1151
  /quit, /detach Detach (session keeps running)
993
1152
  /abort, /cancel Cancel current agent turn
994
1153
  /kill Stop the session
995
1154
  /info Show session status
996
1155
 
1156
+ Ralph Loop (iterative task automation):
1157
+ svamp session ralph-start <id> "<task>" [--completion-promise TEXT] [--max-iterations N] [--cooldown N]
1158
+ svamp session ralph-cancel <id>
1159
+ svamp session ralph-status <id>
1160
+ (alias: svamp session ralph <id> "<task>" ...)
1161
+
1162
+ Message Queue:
1163
+ svamp session queue add <id> "<message>"
1164
+ svamp session queue list <id>
1165
+ svamp session queue clear <id>
1166
+
997
1167
  Examples:
998
- svamp session spawn claude -d ~/projects/myapp --message "Fix the bug" --wait
999
- svamp session spawn claude -d /tmp/sandbox --isolate --deny-network
1000
- svamp session spawn claude -d /tmp/proj --share alice@example.com:admin --deny-read /etc
1001
- svamp session spawn claude --security-context ./security.json
1002
- svamp session share abc12345 --add bob@example.com:view
1003
- svamp session share abc12345 --public view
1004
- svamp session share abc12345 --list
1168
+ # Spawn with bypassed permissions (no prompts)
1169
+ svamp session spawn claude -d ./proj -p bypassPermissions --message "fix tests" --wait
1005
1170
 
1006
- Ralph Loop (iterative task loop):
1007
- svamp session ralph-start <id> "<task>" [--completion-promise TEXT] [--max-iterations N]
1008
- Start a Ralph loop
1009
- svamp session ralph-cancel <id> Cancel active Ralph loop
1010
- svamp session ralph-status <id> Show Ralph loop status
1171
+ # Spawn with default permissions, handle approval via CLI
1172
+ svamp session spawn claude -d ./proj --message "refactor auth"
1173
+ svamp session wait abc1 --json # exits with code 2 if permission pending
1174
+ svamp session approve abc1 # approve all pending permissions
1175
+ svamp session wait abc1 # wait for completion
1011
1176
 
1012
- Message Queue:
1013
- svamp session queue add <id> "<message>" Add message to queue
1014
- svamp session queue list <id> List queued messages
1015
- svamp session queue clear <id> Clear the queue
1177
+ # Monitor session messages (raw for full tool details)
1178
+ svamp session messages abc1 --last 10 --json --raw
1016
1179
 
1017
- Ralph Loop Examples:
1018
- svamp session ralph-start abc12 "Fix all linting errors" --completion-promise "All linting errors fixed" --max-iterations 10
1019
- svamp session ralph-cancel abc12
1180
+ # Send message and wait for completion
1181
+ svamp session send abc1 "run the tests" --wait --json
1182
+
1183
+ # Isolation & sharing
1184
+ svamp session spawn claude -d /tmp/sandbox --isolate --deny-network
1185
+ svamp session spawn claude -d /tmp/proj --share alice@example.com:admin
1186
+
1187
+ # Ralph Loop
1188
+ svamp session ralph-start abc1 "Fix all linting errors" --max-iterations 10
1020
1189
  `);
1021
1190
  }
1022
1191
  function printMachineHelp() {
@@ -1024,6 +1193,9 @@ function printMachineHelp() {
1024
1193
  svamp machine \u2014 Machine management
1025
1194
 
1026
1195
  Usage:
1196
+ svamp machine info Show machine info & status
1197
+ svamp machine exec <command> [--cwd <path>] Run command on machine
1198
+ svamp machine ls [path] [--hidden] List directory on machine
1027
1199
  svamp machine share --list List shared users
1028
1200
  svamp machine share --add <email>[:<role>] Share machine with user
1029
1201
  svamp machine share --remove <email> Remove shared user
@@ -1032,28 +1204,17 @@ Usage:
1032
1204
 
1033
1205
  Options:
1034
1206
  --machine <id>, -m <id> Target a specific machine (prefix match supported)
1035
-
1036
- Security context config file format (JSON):
1037
- {
1038
- "default": {
1039
- "role": "interact",
1040
- "filesystem": { "denyRead": ["/etc/shadow"], "denyWrite": ["/usr"] },
1041
- "network": { "allowedDomains": ["api.anthropic.com"] }
1042
- },
1043
- "users": {
1044
- "alice@example.com": { "role": "admin" },
1045
- "bob@example.com": { "role": "view", "denyAllNetwork": true }
1046
- }
1047
- }
1048
-
1049
- The "default" entry applies to all users. Per-user entries override defaults.
1050
- Machine-level config is merged with session-level config at spawn time.
1207
+ --cwd <path> Working directory for exec (default: home dir)
1208
+ --hidden, -a Show hidden files in ls
1051
1209
 
1052
1210
  Examples:
1211
+ svamp machine info
1212
+ svamp machine exec "ls -la /tmp"
1213
+ svamp machine exec "df -h" -m cloud-box --cwd /
1214
+ svamp machine ls /home/user/projects
1215
+ svamp machine ls --hidden -m cloud-box
1053
1216
  svamp machine share --add alice@example.com:admin
1054
1217
  svamp machine share --config ./security-context.json
1055
- svamp machine share --show-config
1056
- svamp machine share --list
1057
1218
  `);
1058
1219
  }
1059
1220
  function printSkillsHelp() {