volute 0.2.1 → 0.3.0

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 (60) hide show
  1. package/README.md +46 -0
  2. package/dist/agent-manager-2LU6KULR.js +15 -0
  3. package/dist/{channel-2WJRM7PE.js → channel-H7N4SGR2.js} +7 -7
  4. package/dist/{chunk-XZN4WPNC.js → chunk-5SKQ6J7T.js} +9 -1
  5. package/dist/chunk-DEUAVGSA.js +81 -0
  6. package/dist/{chunk-L3BQEZ4Z.js → chunk-IPIPLGME.js} +74 -13
  7. package/dist/chunk-K3NQKI34.js +10 -0
  8. package/dist/chunk-NETNFBA5.js +28 -0
  9. package/dist/{chunk-6UCG6MIX.js → chunk-RALYNMHR.js} +1 -6
  10. package/dist/chunk-VRVVQIYY.js +15 -0
  11. package/dist/{chunk-4YXYAMFT.js → chunk-VVD3XO3E.js} +7 -6
  12. package/dist/{chunk-KFNNHQK7.js → chunk-YEIHRP2J.js} +1 -1
  13. package/dist/cli.js +56 -51
  14. package/dist/connector-6LWB5PRU.js +96 -0
  15. package/dist/connectors/discord.js +22 -1
  16. package/dist/{create-23AM7H5B.js → create-RSWWMGKT.js} +22 -5
  17. package/dist/daemon-client-27KMQQKX.js +9 -0
  18. package/dist/daemon.js +162 -132
  19. package/dist/{delete-GDMSOW3U.js → delete-4ERL2QHH.js} +7 -2
  20. package/dist/{down-WTF73FE7.js → down-HRC4MQCT.js} +10 -3
  21. package/dist/{env-YKUJOFHE.js → env-DBWDTIP6.js} +3 -2
  22. package/dist/{history-7WVVKMUY.js → history-W7BD2H74.js} +9 -8
  23. package/dist/{import-42DOLBDT.js → import-6HTSSDFW.js} +143 -36
  24. package/dist/{logs-SYRQOL6B.js → logs-NHWGHNBF.js} +8 -7
  25. package/dist/{schedule-J37XQM6E.js → schedule-DKZ2E2CL.js} +41 -41
  26. package/dist/{send-PLOYEYER.js → send-5LEJXPYV.js} +3 -2
  27. package/dist/service-SA4TTMDU.js +195 -0
  28. package/dist/setup-ZMNTOJAV.js +148 -0
  29. package/dist/{start-AG7QLULK.js → start-2BSXX6BS.js} +3 -2
  30. package/dist/{status-GCNU4M3K.js → status-N23CV27T.js} +3 -2
  31. package/dist/{stop-IL5Q6NER.js → stop-DSKBIJ2D.js} +3 -2
  32. package/dist/{up-ZC6G6K4K.js → up-4UGID4DM.js} +5 -3
  33. package/dist/{upgrade-DD5TNJWU.js → upgrade-BGFVRCVP.js} +4 -3
  34. package/dist/{merge-CSAVLSLY.js → variant-JPLJTS2P.js} +179 -10
  35. package/dist/web-assets/assets/index-BC5eSqbY.js +296 -0
  36. package/dist/web-assets/index.html +1 -1
  37. package/drizzle/0002_wealthy_the_call.sql +6 -0
  38. package/drizzle/meta/0002_snapshot.json +339 -0
  39. package/drizzle/meta/_journal.json +7 -0
  40. package/package.json +4 -1
  41. package/templates/_base/.init/SOUL.md +5 -1
  42. package/templates/_base/_skills/memory/SKILL.md +2 -2
  43. package/templates/_base/_skills/volute-agent/SKILL.md +28 -11
  44. package/templates/_base/home/VOLUTE.md +4 -2
  45. package/templates/_base/src/lib/auto-commit.ts +8 -3
  46. package/templates/_base/src/lib/types.ts +6 -2
  47. package/templates/_base/src/lib/volute-server.ts +5 -0
  48. package/templates/agent-sdk/.init/CLAUDE.md +15 -13
  49. package/templates/agent-sdk/src/agent.ts +12 -1
  50. package/templates/agent-sdk/src/lib/agent-sessions.ts +28 -4
  51. package/templates/pi/.init/AGENTS.md +11 -9
  52. package/templates/pi/src/agent.ts +16 -3
  53. package/templates/pi/src/lib/agent-sessions.ts +26 -4
  54. package/dist/agent-manager-SSJUZWOV.js +0 -13
  55. package/dist/connect-X5V5IMRW.js +0 -48
  56. package/dist/daemon-client-VN24HM5T.js +0 -10
  57. package/dist/disconnect-5JWFZ6RV.js +0 -30
  58. package/dist/fork-GRSVMBKI.js +0 -119
  59. package/dist/variants-QQIEKT6M.js +0 -60
  60. package/dist/web-assets/assets/index-DNNPoxMn.js +0 -158
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ deleteAgentUser
4
+ } from "./chunk-DEUAVGSA.js";
2
5
  import {
3
6
  parseArgs
4
7
  } from "./chunk-D424ZQGI.js";
@@ -7,7 +10,8 @@ import {
7
10
  findAgent,
8
11
  removeAgent,
9
12
  removeAllVariants
10
- } from "./chunk-6UCG6MIX.js";
13
+ } from "./chunk-RALYNMHR.js";
14
+ import "./chunk-K3NQKI34.js";
11
15
 
12
16
  // src/commands/delete.ts
13
17
  import { existsSync, rmSync } from "fs";
@@ -26,7 +30,7 @@ async function run(args) {
26
30
  process.exit(1);
27
31
  }
28
32
  try {
29
- const { daemonFetch } = await import("./daemon-client-VN24HM5T.js");
33
+ const { daemonFetch } = await import("./daemon-client-27KMQQKX.js");
30
34
  const res = await daemonFetch(`/api/agents/${encodeURIComponent(name)}/stop`, {
31
35
  method: "POST"
32
36
  });
@@ -45,6 +49,7 @@ async function run(args) {
45
49
  console.log("Use --force to also delete the agent directory.");
46
50
  } else {
47
51
  rmSync(dir, { recursive: true, force: true });
52
+ deleteAgentUser(name);
48
53
  console.log(`Deleted ${dir}`);
49
54
  }
50
55
  }
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteHome
4
- } from "./chunk-6UCG6MIX.js";
4
+ } from "./chunk-RALYNMHR.js";
5
+ import "./chunk-K3NQKI34.js";
5
6
 
6
7
  // src/commands/down.ts
7
8
  import { existsSync, readFileSync, unlinkSync } from "fs";
@@ -12,14 +13,20 @@ async function run(_args) {
12
13
  if (!existsSync(pidPath)) {
13
14
  const configPath = resolve(home, "daemon.json");
14
15
  let port = 4200;
16
+ let hostname = "localhost";
15
17
  if (existsSync(configPath)) {
16
18
  try {
17
- port = JSON.parse(readFileSync(configPath, "utf-8")).port ?? 4200;
19
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
20
+ port = config.port ?? 4200;
21
+ hostname = config.hostname || "localhost";
18
22
  } catch {
19
23
  }
20
24
  }
21
25
  try {
22
- const res = await fetch(`http://localhost:${port}/api/health`);
26
+ const url = new URL("http://localhost");
27
+ url.hostname = hostname;
28
+ url.port = String(port);
29
+ const res = await fetch(`${url.origin}/api/health`);
23
30
  if (res.ok) {
24
31
  console.error(`Daemon appears to be running on port ${port} but PID file is missing.`);
25
32
  console.error(`Kill the process manually: lsof -ti :${port} | xargs kill`);
@@ -5,13 +5,14 @@ import {
5
5
  readEnv,
6
6
  sharedEnvPath,
7
7
  writeEnv
8
- } from "./chunk-KFNNHQK7.js";
8
+ } from "./chunk-YEIHRP2J.js";
9
9
  import {
10
10
  parseArgs
11
11
  } from "./chunk-D424ZQGI.js";
12
12
  import {
13
13
  resolveAgent
14
- } from "./chunk-6UCG6MIX.js";
14
+ } from "./chunk-RALYNMHR.js";
15
+ import "./chunk-K3NQKI34.js";
15
16
 
16
17
  // src/commands/env.ts
17
18
  function getEnvPath(agentName) {
@@ -1,23 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonFetch
4
- } from "./chunk-4YXYAMFT.js";
4
+ } from "./chunk-VVD3XO3E.js";
5
+ import {
6
+ resolveAgentName
7
+ } from "./chunk-VRVVQIYY.js";
5
8
  import {
6
9
  parseArgs
7
10
  } from "./chunk-D424ZQGI.js";
8
- import "./chunk-6UCG6MIX.js";
11
+ import "./chunk-RALYNMHR.js";
12
+ import "./chunk-K3NQKI34.js";
9
13
 
10
14
  // src/commands/history.ts
11
15
  async function run(args) {
12
- const { positional, flags } = parseArgs(args, {
16
+ const { flags } = parseArgs(args, {
17
+ agent: { type: "string" },
13
18
  channel: { type: "string" },
14
19
  limit: { type: "string" }
15
20
  });
16
- const name = positional[0] || process.env.VOLUTE_AGENT;
17
- if (!name) {
18
- console.error("Usage: volute history [<agent>] [--channel <ch>] [--limit N]");
19
- process.exit(1);
20
- }
21
+ const name = resolveAgentName(flags);
21
22
  const params = new URLSearchParams();
22
23
  if (flags.channel) params.set("channel", flags.channel);
23
24
  if (flags.limit) params.set("limit", flags.limit);
@@ -1,4 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ readVoluteConfig,
4
+ writeVoluteConfig
5
+ } from "./chunk-NETNFBA5.js";
6
+ import {
7
+ agentEnvPath,
8
+ readEnv,
9
+ writeEnv
10
+ } from "./chunk-YEIHRP2J.js";
2
11
  import {
3
12
  composeTemplate,
4
13
  copyTemplateToDir,
@@ -7,7 +16,7 @@ import {
7
16
  import {
8
17
  exec,
9
18
  execInherit
10
- } from "./chunk-XZN4WPNC.js";
19
+ } from "./chunk-5SKQ6J7T.js";
11
20
  import {
12
21
  parseArgs
13
22
  } from "./chunk-D424ZQGI.js";
@@ -16,7 +25,8 @@ import {
16
25
  agentDir,
17
26
  ensureVoluteHome,
18
27
  nextPort
19
- } from "./chunk-6UCG6MIX.js";
28
+ } from "./chunk-RALYNMHR.js";
29
+ import "./chunk-K3NQKI34.js";
20
30
 
21
31
  // src/commands/import.ts
22
32
  import {
@@ -26,9 +36,11 @@ import {
26
36
  readdirSync as readdirSync2,
27
37
  readFileSync as readFileSync3,
28
38
  rmSync,
39
+ statSync,
29
40
  writeFileSync as writeFileSync3
30
41
  } from "fs";
31
- import { resolve as resolve3 } from "path";
42
+ import { homedir as homedir2 } from "os";
43
+ import { basename, resolve as resolve3 } from "path";
32
44
 
33
45
  // src/lib/consolidate.ts
34
46
  import { readdirSync, readFileSync, writeFileSync } from "fs";
@@ -282,22 +294,9 @@ async function run(args) {
282
294
  session: { type: "string" },
283
295
  template: { type: "string" }
284
296
  });
285
- const workspacePath = positional[0];
286
- if (!workspacePath) {
287
- console.error(
288
- "Usage: volute import <openclaw-workspace-path> [--name <name>] [--session <session-jsonl-path>] [--template <name>]"
289
- );
290
- process.exit(1);
291
- }
292
- const wsDir = resolve3(workspacePath);
293
- const soulPath = resolve3(wsDir, "SOUL.md");
294
- const identityPath = resolve3(wsDir, "IDENTITY.md");
295
- if (!existsSync(soulPath) || !existsSync(identityPath)) {
296
- console.error("Not a valid OpenClaw workspace: missing SOUL.md or IDENTITY.md");
297
- process.exit(1);
298
- }
299
- const soul = readFileSync3(soulPath, "utf-8");
300
- const identity = readFileSync3(identityPath, "utf-8");
297
+ const wsDir = resolveWorkspace(positional[0]);
298
+ const soul = readFileSync3(resolve3(wsDir, "SOUL.md"), "utf-8");
299
+ const identity = readFileSync3(resolve3(wsDir, "IDENTITY.md"), "utf-8");
301
300
  const userPath = resolve3(wsDir, "USER.md");
302
301
  const user = existsSync(userPath) ? readFileSync3(userPath, "utf-8") : "";
303
302
  const name = flags.name ?? parseNameFromIdentity(identity) ?? "imported-agent";
@@ -373,38 +372,146 @@ ${user.trimEnd()}
373
372
  await exec("git", ["init"], { cwd: dest });
374
373
  await exec("git", ["add", "-A"], { cwd: dest });
375
374
  await exec("git", ["commit", "-m", "import from OpenClaw"], { cwd: dest });
376
- if (flags.session && template !== "agent-sdk") {
377
- console.warn(
378
- "Warning: --session is only supported with the agent-sdk template, skipping session import"
379
- );
380
- }
381
- if (flags.session && template === "agent-sdk") {
382
- const sessionFile = resolve3(flags.session);
375
+ const sessionFile = flags.session ? resolve3(flags.session) : findOpenClawSession(wsDir);
376
+ if (sessionFile) {
383
377
  if (!existsSync(sessionFile)) {
384
378
  console.error(`Session file not found: ${sessionFile}`);
385
379
  process.exit(1);
386
380
  }
387
- console.log("Converting session...");
388
- const sessionId = convertSession({
389
- sessionPath: sessionFile,
390
- projectDir: dest
391
- });
392
- const voluteDir = resolve3(dest, ".volute");
393
- mkdirSync2(voluteDir, { recursive: true });
394
- writeFileSync3(resolve3(voluteDir, "session.json"), JSON.stringify({ sessionId }));
381
+ if (template === "pi") {
382
+ importPiSession(sessionFile, dest);
383
+ } else if (template === "agent-sdk") {
384
+ console.log("Converting session...");
385
+ const sessionId = convertSession({ sessionPath: sessionFile, projectDir: dest });
386
+ const voluteDir = resolve3(dest, ".volute");
387
+ mkdirSync2(voluteDir, { recursive: true });
388
+ writeFileSync3(resolve3(voluteDir, "session.json"), JSON.stringify({ sessionId }));
389
+ } else {
390
+ console.warn(`Session import not supported for template: ${template}`);
391
+ }
395
392
  }
393
+ importOpenClawConnectors(dest);
396
394
  console.log(`
397
395
  Imported agent: ${name} (port ${port})`);
398
396
  console.log(`
399
397
  volute start ${name}`);
400
398
  }
399
+ function resolveWorkspace(explicitPath) {
400
+ if (explicitPath) {
401
+ const wsDir = resolve3(explicitPath);
402
+ if (!existsSync(resolve3(wsDir, "SOUL.md")) || !existsSync(resolve3(wsDir, "IDENTITY.md"))) {
403
+ console.error("Not a valid OpenClaw workspace: missing SOUL.md or IDENTITY.md");
404
+ process.exit(1);
405
+ }
406
+ return wsDir;
407
+ }
408
+ const cwd = process.cwd();
409
+ if (existsSync(resolve3(cwd, "SOUL.md")) && existsSync(resolve3(cwd, "IDENTITY.md"))) {
410
+ console.log(`Using workspace: ${cwd}`);
411
+ return cwd;
412
+ }
413
+ const openclawWs = resolve3(homedir2(), ".openclaw/workspace");
414
+ if (existsSync(resolve3(openclawWs, "SOUL.md")) && existsSync(resolve3(openclawWs, "IDENTITY.md"))) {
415
+ console.log(`Using workspace: ${openclawWs}`);
416
+ return openclawWs;
417
+ }
418
+ console.error(
419
+ "Usage: volute import [<workspace-path>] [--name <name>] [--session <path>] [--template <name>]\n\nNo OpenClaw workspace found. Provide a path, run from a workspace, or ensure ~/.openclaw/workspace exists."
420
+ );
421
+ process.exit(1);
422
+ }
423
+ function findOpenClawSession(workspaceDir) {
424
+ const agentsDir = resolve3(homedir2(), ".openclaw/agents");
425
+ if (!existsSync(agentsDir)) return void 0;
426
+ const matches = [];
427
+ try {
428
+ for (const agent of readdirSync2(agentsDir)) {
429
+ const sessionsDir = resolve3(agentsDir, agent, "sessions");
430
+ if (!existsSync(sessionsDir)) continue;
431
+ for (const file of readdirSync2(sessionsDir)) {
432
+ if (!file.endsWith(".jsonl")) continue;
433
+ const fullPath = resolve3(sessionsDir, file);
434
+ if (sessionMatchesWorkspace(fullPath, workspaceDir)) {
435
+ matches.push({ path: fullPath, mtime: statSync(fullPath).mtimeMs });
436
+ }
437
+ }
438
+ }
439
+ } catch (err) {
440
+ console.warn("Warning: error scanning OpenClaw sessions:", err);
441
+ return void 0;
442
+ }
443
+ if (matches.length === 0) return void 0;
444
+ matches.sort((a, b) => b.mtime - a.mtime);
445
+ console.log(`Found session: ${matches[0].path}`);
446
+ return matches[0].path;
447
+ }
448
+ function sessionMatchesWorkspace(sessionPath, workspaceDir) {
449
+ try {
450
+ const fd = readFileSync3(sessionPath, "utf-8");
451
+ const firstLine = fd.slice(0, fd.indexOf("\n"));
452
+ const header = JSON.parse(firstLine);
453
+ return header.type === "session" && resolve3(header.cwd) === resolve3(workspaceDir);
454
+ } catch {
455
+ return false;
456
+ }
457
+ }
458
+ function importPiSession(sessionFile, agentDirPath) {
459
+ const homeDir = resolve3(agentDirPath, "home");
460
+ const piSessionDir = resolve3(agentDirPath, ".volute/pi-sessions/main");
461
+ mkdirSync2(piSessionDir, { recursive: true });
462
+ const content = readFileSync3(sessionFile, "utf-8");
463
+ const lines = content.trim().split("\n");
464
+ try {
465
+ const header = JSON.parse(lines[0]);
466
+ if (header.type === "session") {
467
+ header.cwd = homeDir;
468
+ lines[0] = JSON.stringify(header);
469
+ }
470
+ } catch {
471
+ }
472
+ const filename = basename(sessionFile);
473
+ const destPath = resolve3(piSessionDir, filename);
474
+ writeFileSync3(destPath, `${lines.join("\n")}
475
+ `);
476
+ console.log(`Imported session (${lines.length} entries)`);
477
+ }
478
+ function importOpenClawConnectors(agentDirPath) {
479
+ const configPath = resolve3(homedir2(), ".openclaw/openclaw.json");
480
+ if (!existsSync(configPath)) return;
481
+ let config;
482
+ try {
483
+ config = JSON.parse(readFileSync3(configPath, "utf-8"));
484
+ } catch (err) {
485
+ console.warn("Warning: failed to parse openclaw.json:", err);
486
+ return;
487
+ }
488
+ const discord = config.channels?.discord;
489
+ if (!discord?.enabled || !discord.token) return;
490
+ const envPath = agentEnvPath(agentDirPath);
491
+ const env = readEnv(envPath);
492
+ env.DISCORD_TOKEN = discord.token;
493
+ writeEnv(envPath, env);
494
+ const voluteConfig = readVoluteConfig(agentDirPath) ?? {};
495
+ const connectors = new Set(voluteConfig.connectors ?? []);
496
+ connectors.add("discord");
497
+ voluteConfig.connectors = [...connectors];
498
+ writeVoluteConfig(agentDirPath, voluteConfig);
499
+ console.log("Imported Discord connector config");
500
+ }
401
501
  function parseNameFromIdentity(identity) {
402
502
  const match = identity.match(/\*\*Name:\*\*\s*(.+)/);
403
503
  if (match) {
404
- return match[1].trim().toLowerCase().replace(/\s+/g, "-");
504
+ const raw = match[1].trim();
505
+ if (!raw || raw.startsWith("*") || raw.startsWith("(")) return void 0;
506
+ return raw.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9.-]/g, "");
405
507
  }
406
508
  return void 0;
407
509
  }
408
510
  export {
409
- run
511
+ findOpenClawSession,
512
+ importOpenClawConnectors,
513
+ importPiSession,
514
+ parseNameFromIdentity,
515
+ run,
516
+ sessionMatchesWorkspace
410
517
  };
@@ -1,25 +1,26 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ resolveAgentName
4
+ } from "./chunk-VRVVQIYY.js";
2
5
  import {
3
6
  parseArgs
4
7
  } from "./chunk-D424ZQGI.js";
5
8
  import {
6
9
  resolveAgent
7
- } from "./chunk-6UCG6MIX.js";
10
+ } from "./chunk-RALYNMHR.js";
11
+ import "./chunk-K3NQKI34.js";
8
12
 
9
13
  // src/commands/logs.ts
10
14
  import { spawn } from "child_process";
11
15
  import { existsSync } from "fs";
12
16
  import { resolve } from "path";
13
17
  async function run(args) {
14
- const { positional, flags } = parseArgs(args, {
18
+ const { flags } = parseArgs(args, {
19
+ agent: { type: "string" },
15
20
  follow: { type: "boolean" },
16
21
  n: { type: "number" }
17
22
  });
18
- const name = positional[0];
19
- if (!name) {
20
- console.error("Usage: volute logs <name> [--follow] [-n N]");
21
- process.exit(1);
22
- }
23
+ const name = resolveAgentName(flags);
23
24
  const { dir } = resolveAgent(name);
24
25
  const logFile = resolve(dir, ".volute", "logs", "agent.log");
25
26
  if (!existsSync(logFile)) {
@@ -1,39 +1,45 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonFetch
4
- } from "./chunk-4YXYAMFT.js";
5
- import "./chunk-6UCG6MIX.js";
4
+ } from "./chunk-VVD3XO3E.js";
5
+ import {
6
+ resolveAgentName
7
+ } from "./chunk-VRVVQIYY.js";
8
+ import {
9
+ parseArgs
10
+ } from "./chunk-D424ZQGI.js";
11
+ import "./chunk-RALYNMHR.js";
12
+ import "./chunk-K3NQKI34.js";
6
13
 
7
14
  // src/commands/schedule.ts
8
15
  async function run(args) {
9
16
  const subcommand = args[0];
10
- const agentName = args[1];
11
- if (!subcommand || !agentName) {
12
- printUsage();
13
- process.exit(1);
14
- }
15
17
  switch (subcommand) {
16
18
  case "list":
17
- await listSchedules(agentName);
19
+ await listSchedules(args.slice(1));
18
20
  break;
19
21
  case "add":
20
- await addSchedule(agentName, args.slice(2));
22
+ await addSchedule(args.slice(1));
21
23
  break;
22
24
  case "remove":
23
- await removeSchedule(agentName, args.slice(2));
25
+ await removeSchedule(args.slice(1));
24
26
  break;
25
27
  default:
26
28
  printUsage();
27
- process.exit(1);
29
+ process.exit(subcommand ? 1 : 0);
28
30
  }
29
31
  }
30
32
  function printUsage() {
31
33
  console.error(`Usage:
32
- volute schedule list <agent>
33
- volute schedule add <agent> --cron "..." --message "..." [--id name]
34
- volute schedule remove <agent> --id <id>`);
34
+ volute schedule list [--agent <name>]
35
+ volute schedule add [--agent <name>] --cron "..." --message "..." [--id name]
36
+ volute schedule remove [--agent <name>] --id <id>`);
35
37
  }
36
- async function listSchedules(agent) {
38
+ async function listSchedules(args) {
39
+ const { flags } = parseArgs(args, {
40
+ agent: { type: "string" }
41
+ });
42
+ const agent = resolveAgentName(flags);
37
43
  const res = await daemonFetch(`/api/agents/${encodeURIComponent(agent)}/schedules`);
38
44
  if (!res.ok) {
39
45
  const data = await res.json();
@@ -54,25 +60,20 @@ async function listSchedules(agent) {
54
60
  );
55
61
  }
56
62
  }
57
- async function addSchedule(agent, args) {
58
- let cron = "";
59
- let message = "";
60
- let id = "";
61
- for (let i = 0; i < args.length; i++) {
62
- if (args[i] === "--cron" && args[i + 1]) {
63
- cron = args[++i];
64
- } else if (args[i] === "--message" && args[i + 1]) {
65
- message = args[++i];
66
- } else if (args[i] === "--id" && args[i + 1]) {
67
- id = args[++i];
68
- }
69
- }
70
- if (!cron || !message) {
63
+ async function addSchedule(args) {
64
+ const { flags } = parseArgs(args, {
65
+ agent: { type: "string" },
66
+ cron: { type: "string" },
67
+ message: { type: "string" },
68
+ id: { type: "string" }
69
+ });
70
+ const agent = resolveAgentName(flags);
71
+ if (!flags.cron || !flags.message) {
71
72
  console.error("--cron and --message are required");
72
73
  process.exit(1);
73
74
  }
74
- const body = { cron, message };
75
- if (id) body.id = id;
75
+ const body = { cron: flags.cron, message: flags.message };
76
+ if (flags.id) body.id = flags.id;
76
77
  const res = await daemonFetch(`/api/agents/${encodeURIComponent(agent)}/schedules`, {
77
78
  method: "POST",
78
79
  headers: { "Content-Type": "application/json" },
@@ -86,19 +87,18 @@ async function addSchedule(agent, args) {
86
87
  const data = await res.json();
87
88
  console.log(`Schedule added: ${data.id}`);
88
89
  }
89
- async function removeSchedule(agent, args) {
90
- let id = "";
91
- for (let i = 0; i < args.length; i++) {
92
- if (args[i] === "--id" && args[i + 1]) {
93
- id = args[++i];
94
- }
95
- }
96
- if (!id) {
90
+ async function removeSchedule(args) {
91
+ const { flags } = parseArgs(args, {
92
+ agent: { type: "string" },
93
+ id: { type: "string" }
94
+ });
95
+ const agent = resolveAgentName(flags);
96
+ if (!flags.id) {
97
97
  console.error("--id is required");
98
98
  process.exit(1);
99
99
  }
100
100
  const res = await daemonFetch(
101
- `/api/agents/${encodeURIComponent(agent)}/schedules/${encodeURIComponent(id)}`,
101
+ `/api/agents/${encodeURIComponent(agent)}/schedules/${encodeURIComponent(flags.id)}`,
102
102
  { method: "DELETE" }
103
103
  );
104
104
  if (!res.ok) {
@@ -106,7 +106,7 @@ async function removeSchedule(agent, args) {
106
106
  console.error(data.error ?? `Failed to remove schedule: ${res.status}`);
107
107
  process.exit(1);
108
108
  }
109
- console.log(`Schedule removed: ${id}`);
109
+ console.log(`Schedule removed: ${flags.id}`);
110
110
  }
111
111
  export {
112
112
  run
@@ -4,8 +4,9 @@ import {
4
4
  } from "./chunk-N4YNKR3Q.js";
5
5
  import {
6
6
  daemonFetch
7
- } from "./chunk-4YXYAMFT.js";
8
- import "./chunk-6UCG6MIX.js";
7
+ } from "./chunk-VVD3XO3E.js";
8
+ import "./chunk-RALYNMHR.js";
9
+ import "./chunk-K3NQKI34.js";
9
10
 
10
11
  // src/commands/send.ts
11
12
  import { userInfo } from "os";