svamp-cli 0.1.62 → 0.1.64

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.
@@ -29,14 +29,21 @@ function requireSandboxApiEnv() {
29
29
  }
30
30
  return env;
31
31
  }
32
- async function sandboxFetch(env, path, init) {
32
+ async function sandboxFetch(env, path, init, timeoutMs = 3e4) {
33
33
  const url = `${env.apiUrl.replace(/\/+$/, "")}${path}`;
34
34
  const headers = {
35
35
  "Authorization": `Bearer ${env.apiKey}`,
36
36
  "Content-Type": "application/json",
37
37
  ...init?.headers || {}
38
38
  };
39
- const res = await fetch(url, { ...init, headers });
39
+ const controller = new AbortController();
40
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
41
+ let res;
42
+ try {
43
+ res = await fetch(url, { ...init, headers, signal: controller.signal });
44
+ } finally {
45
+ clearTimeout(timer);
46
+ }
40
47
  if (!res.ok) {
41
48
  const body = await res.text().catch(() => "");
42
49
  let detail = body;
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-Bds_JVXp.mjs';
1
+ import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-BImPgXHd.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -106,10 +106,10 @@ async function main() {
106
106
  } else if (subcommand === "skills") {
107
107
  await handleSkillsCommand();
108
108
  } else if (subcommand === "service" || subcommand === "svc") {
109
- const { handleServiceCommand } = await import('./commands-DXia-6W4.mjs');
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-DTNg_sCX.mjs');
112
+ const { processCommand } = await import('./commands-BfMlD9o4.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-BYxU0Wzp.mjs').catch(() => ({ default: { version: "unknown" } }));
130
+ const pkg = await import('./package-Dg0hQJRC.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-Dg1i7D_o.mjs');
139
+ const { runInteractive } = await import('./run-C7VxH4X8.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-Bds_JVXp.mjs').then(function (n) { return n.i; });
184
+ const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-BImPgXHd.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-Bds_JVXp.mjs').then(function (n) { return n.i; });
196
+ const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-BImPgXHd.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-Bds_JVXp.mjs').then(function (n) { return n.j; });
220
+ const { CodexMcpBackend } = await import('./run-BImPgXHd.mjs').then(function (n) { return n.j; });
221
221
  backend = new CodexMcpBackend({ cwd, log: logFn });
222
222
  } else {
223
- const { AcpBackend } = await import('./run-Bds_JVXp.mjs').then(function (n) { return n.h; });
224
- const { GeminiTransport } = await import('./run-Bds_JVXp.mjs').then(function (n) { return n.G; });
225
- const { DefaultTransport } = await import('./run-Bds_JVXp.mjs').then(function (n) { return n.D; });
223
+ const { AcpBackend } = await import('./run-BImPgXHd.mjs').then(function (n) { return n.h; });
224
+ const { GeminiTransport } = await import('./run-BImPgXHd.mjs').then(function (n) { return n.G; });
225
+ const { DefaultTransport } = await import('./run-BImPgXHd.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-CBTCiCjK.mjs');
343
+ const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionQueueAdd, sessionQueueList, sessionQueueClear } = await import('./commands-Brx7D-77.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-CBTCiCjK.mjs');
403
+ const { parseShareArg } = await import('./commands-Brx7D-77.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-CBTCiCjK.mjs');
487
+ const { sessionApprove } = await import('./commands-Brx7D-77.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-CBTCiCjK.mjs');
497
+ const { sessionDeny } = await import('./commands-Brx7D-77.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")
@@ -563,7 +563,7 @@ async function handleMachineCommand() {
563
563
  return;
564
564
  }
565
565
  if (machineSubcommand === "share") {
566
- const { machineShare } = await import('./commands-CBTCiCjK.mjs');
566
+ const { machineShare } = await import('./commands-Brx7D-77.mjs');
567
567
  let machineId;
568
568
  const shareArgs = [];
569
569
  for (let i = 1; i < machineArgs.length; i++) {
@@ -593,7 +593,7 @@ async function handleMachineCommand() {
593
593
  }
594
594
  await machineShare(machineId, { add, remove, list, configPath, showConfig });
595
595
  } else if (machineSubcommand === "exec") {
596
- const { machineExec } = await import('./commands-CBTCiCjK.mjs');
596
+ const { machineExec } = await import('./commands-Brx7D-77.mjs');
597
597
  let machineId;
598
598
  let cwd;
599
599
  const cmdParts = [];
@@ -613,7 +613,7 @@ async function handleMachineCommand() {
613
613
  }
614
614
  await machineExec(machineId, command, cwd);
615
615
  } else if (machineSubcommand === "info") {
616
- const { machineInfo } = await import('./commands-CBTCiCjK.mjs');
616
+ const { machineInfo } = await import('./commands-Brx7D-77.mjs');
617
617
  let machineId;
618
618
  for (let i = 1; i < machineArgs.length; i++) {
619
619
  if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
@@ -622,7 +622,7 @@ async function handleMachineCommand() {
622
622
  }
623
623
  await machineInfo(machineId);
624
624
  } else if (machineSubcommand === "ls") {
625
- const { machineLs } = await import('./commands-CBTCiCjK.mjs');
625
+ const { machineLs } = await import('./commands-Brx7D-77.mjs');
626
626
  let machineId;
627
627
  let showHidden = false;
628
628
  let path;
@@ -650,7 +650,7 @@ async function handleSkillsCommand() {
650
650
  printSkillsHelp();
651
651
  return;
652
652
  }
653
- const { skillsFind, skillsInstall, skillsList, skillsRemove, skillsPublish } = await import('./commands-6EyqaoCp.mjs');
653
+ const { skillsFind, skillsInstall, skillsList, skillsRemove, skillsPublish } = await import('./commands-UFi0_ESV.mjs');
654
654
  if (skillsSubcommand === "find" || skillsSubcommand === "search") {
655
655
  const query = skillsArgs.slice(1).filter((a) => !a.startsWith("--")).join(" ");
656
656
  if (!query) {
@@ -1021,6 +1021,11 @@ Usage:
1021
1021
  svamp skills find <query> Search the skills marketplace
1022
1022
  svamp skills install <n> Install a skill from the marketplace
1023
1023
  svamp skills --help Show all skill commands
1024
+ svamp process apply <f.yaml> Create/update a supervised process (idempotent)
1025
+ svamp process list List supervised processes
1026
+ svamp process start <name> Start or create a process
1027
+ svamp process logs <name> Show process log output
1028
+ svamp process --help Show all process commands
1024
1029
  svamp service expose <name> Expose a service from this sandbox
1025
1030
  svamp service list List service groups
1026
1031
  svamp service --help Show all service commands
@@ -1,11 +1,11 @@
1
1
  import { writeFileSync, readFileSync } from 'fs';
2
2
  import { resolve } from 'path';
3
- import { connectAndGetMachine } from './commands-CBTCiCjK.mjs';
3
+ import { connectAndGetMachine } from './commands-Brx7D-77.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-Bds_JVXp.mjs';
8
+ import './run-BImPgXHd.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-Bds_JVXp.mjs';
5
+ import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-BImPgXHd.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
8
8
  import 'fs';
@@ -1,4 +1,4 @@
1
- import { createServiceGroup, listServiceGroups, getServiceGroup, deleteServiceGroup, addBackend, removeBackend, addPort, removePort, renameSubdomain, getSandboxEnv } from './api-Cegey1dh.mjs';
1
+ import { createServiceGroup, listServiceGroups, getServiceGroup, deleteServiceGroup, addBackend, removeBackend, addPort, removePort, renameSubdomain, getSandboxEnv } from './api-BRbsyqJ4.mjs';
2
2
 
3
3
  function getFlag(args, flag) {
4
4
  const idx = args.indexOf(flag);
@@ -296,7 +296,7 @@ Service is live:`);
296
296
  }
297
297
  } else {
298
298
  console.log(`No SANDBOX_ID detected \u2014 starting reverse tunnel.`);
299
- const { runTunnel } = await import('./tunnel-CtPReHFY.mjs');
299
+ const { runTunnel } = await import('./tunnel-C3UsqTxi.mjs');
300
300
  await runTunnel(name, ports);
301
301
  }
302
302
  } catch (err) {
@@ -312,7 +312,7 @@ async function serviceTunnel(args) {
312
312
  console.error("Usage: svamp service tunnel <name> --port <port> [--port <port2>]");
313
313
  process.exit(1);
314
314
  }
315
- const { runTunnel } = await import('./tunnel-CtPReHFY.mjs');
315
+ const { runTunnel } = await import('./tunnel-C3UsqTxi.mjs');
316
316
  await runTunnel(name, ports);
317
317
  }
318
318
  async function handleServiceCommand() {
@@ -9,6 +9,18 @@ const SKILLS_DIR = join(os__default.homedir(), ".claude", "skills");
9
9
  function getArtifactBaseUrl() {
10
10
  return `${SKILLS_SERVER}/${SKILLS_WORKSPACE}/artifacts`;
11
11
  }
12
+ async function fetchWithTimeout(url, options = {}, timeoutMs = 3e4) {
13
+ const controller = new AbortController();
14
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
15
+ try {
16
+ return await fetch(url, { ...options, signal: controller.signal });
17
+ } catch (err) {
18
+ if (err.name === "AbortError") throw new Error(`Request timed out after ${timeoutMs}ms: ${url}`);
19
+ throw err;
20
+ } finally {
21
+ clearTimeout(timer);
22
+ }
23
+ }
12
24
  function parseFrontmatter(content) {
13
25
  const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
14
26
  if (!match) return null;
@@ -54,7 +66,7 @@ async function searchSkills(query) {
54
66
  const base = getArtifactBaseUrl();
55
67
  const filters = encodeURIComponent(JSON.stringify({ type: "skill" }));
56
68
  const url = `${base}/${SKILLS_COLLECTION}/children?keywords=${encodeURIComponent(query)}&filters=${filters}&limit=50`;
57
- const resp = await fetch(url);
69
+ const resp = await fetchWithTimeout(url);
58
70
  if (!resp.ok) {
59
71
  if (resp.status === 404) return [];
60
72
  throw new Error(`Search failed: ${resp.status} ${resp.statusText}`);
@@ -65,7 +77,7 @@ async function searchSkills(query) {
65
77
  async function getSkillInfo(skillAlias) {
66
78
  const base = getArtifactBaseUrl();
67
79
  const url = `${base}/${skillAlias}`;
68
- const resp = await fetch(url);
80
+ const resp = await fetchWithTimeout(url);
69
81
  if (!resp.ok) {
70
82
  if (resp.status === 404) return null;
71
83
  throw new Error(`Get skill failed: ${resp.status} ${resp.statusText}`);
@@ -77,7 +89,7 @@ async function listSkillFiles(skillAlias, dir = "") {
77
89
  const base = getArtifactBaseUrl();
78
90
  const pathPart = dir ? `/${dir}/` : "/";
79
91
  const url = `${base}/${skillAlias}/files${pathPart}`;
80
- const resp = await fetch(url);
92
+ const resp = await fetchWithTimeout(url);
81
93
  if (!resp.ok) {
82
94
  throw new Error(`List files failed: ${resp.status} ${resp.statusText}`);
83
95
  }
@@ -87,7 +99,7 @@ async function listSkillFiles(skillAlias, dir = "") {
87
99
  async function downloadSkillFile(skillAlias, filePath) {
88
100
  const base = getArtifactBaseUrl();
89
101
  const url = `${base}/${skillAlias}/files/${filePath}`;
90
- const resp = await fetch(url, { redirect: "follow" });
102
+ const resp = await fetchWithTimeout(url, { redirect: "follow" }, 6e4);
91
103
  if (!resp.ok) {
92
104
  throw new Error(`Download failed for ${filePath}: ${resp.status} ${resp.statusText}`);
93
105
  }
@@ -221,6 +233,10 @@ async function skillsInstall(skillName, opts) {
221
233
  try {
222
234
  const content = await downloadSkillFile(skillName, filePath);
223
235
  const localPath = join(targetDir, filePath);
236
+ if (!localPath.startsWith(targetDir + "/")) {
237
+ errors.push(` ${filePath}: path outside skill directory (blocked)`);
238
+ continue;
239
+ }
224
240
  fs.mkdirSync(join(localPath, ".."), { recursive: true });
225
241
  fs.writeFileSync(localPath, content, "utf-8");
226
242
  downloaded++;
@@ -229,12 +245,10 @@ async function skillsInstall(skillName, opts) {
229
245
  }
230
246
  }
231
247
  if (errors.length > 0) {
232
- console.error(`Warning: ${errors.length} file(s) failed to download:`);
233
- errors.forEach((e) => console.error(e));
234
- }
235
- if (downloaded === 0) {
236
248
  fs.rmSync(targetDir, { recursive: true, force: true });
237
- console.error("Failed to download any files. Installation aborted.");
249
+ console.error(`Installation failed \u2014 ${errors.length} file(s) could not be downloaded:`);
250
+ errors.forEach((e) => console.error(e));
251
+ console.error("Partial installation cleaned up. Run the command again to retry.");
238
252
  process.exit(1);
239
253
  }
240
254
  const skillMdPath = join(targetDir, "SKILL.md");
@@ -383,25 +397,35 @@ async function skillsPublish(skillPath, opts) {
383
397
  }
384
398
  let artifactId;
385
399
  let isUpdate = false;
400
+ let existingArtifact = null;
386
401
  try {
387
- const existing = await am.read({
402
+ existingArtifact = await am.read({
388
403
  artifact_id: `${SKILLS_WORKSPACE}/${manifest.name}`,
389
404
  _rkwargs: true
390
405
  });
391
- artifactId = existing.id;
406
+ } catch {
407
+ }
408
+ if (existingArtifact) {
409
+ artifactId = existingArtifact.id;
392
410
  isUpdate = true;
393
411
  console.log(`Updating existing skill "${manifest.name}"...`);
394
- await am.edit({
395
- artifact_id: artifactId,
396
- manifest: {
397
- name: manifest.name,
398
- description: manifest.description,
399
- ...manifest.metadata && { metadata: manifest.metadata }
400
- },
401
- stage: true,
402
- _rkwargs: true
403
- });
404
- } catch {
412
+ try {
413
+ await am.edit({
414
+ artifact_id: artifactId,
415
+ manifest: {
416
+ name: manifest.name,
417
+ description: manifest.description,
418
+ ...manifest.metadata && { metadata: manifest.metadata }
419
+ },
420
+ stage: true,
421
+ _rkwargs: true
422
+ });
423
+ } catch (err) {
424
+ console.error(`Failed to stage skill artifact for editing: ${err.message}`);
425
+ await server.disconnect();
426
+ process.exit(1);
427
+ }
428
+ } else {
405
429
  try {
406
430
  const created = await am.create({
407
431
  alias: manifest.name,
@@ -441,11 +465,11 @@ async function skillsPublish(skillPath, opts) {
441
465
  uploadErrors.push(`${relPath}: failed to get upload URL`);
442
466
  continue;
443
467
  }
444
- const resp = await fetch(putUrl, {
468
+ const resp = await fetchWithTimeout(putUrl, {
445
469
  method: "PUT",
446
470
  body: content,
447
471
  headers: { "Content-Type": "application/octet-stream" }
448
- });
472
+ }, 12e4);
449
473
  if (!resp.ok) {
450
474
  uploadErrors.push(`${relPath}: upload returned ${resp.status}`);
451
475
  continue;
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-Bds_JVXp.mjs';
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-BImPgXHd.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.1.62";
2
+ var version = "0.1.64";
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";