volute 0.4.0 → 0.6.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 (82) hide show
  1. package/README.md +22 -22
  2. package/dist/agent-X7GJLBLW.js +79 -0
  3. package/dist/{agent-manager-AUCKMGPR.js → agent-manager-JDVXU3ON.js} +4 -4
  4. package/dist/channel-SMCNOIVQ.js +262 -0
  5. package/dist/chunk-AOKAQGO4.js +107 -0
  6. package/dist/{chunk-VRVVQIYY.js → chunk-AZEL2IEK.js} +1 -1
  7. package/dist/chunk-B3R6L2GW.js +24 -0
  8. package/dist/{chunk-MXUCNIBG.js → chunk-BX7KI4S3.js} +68 -3
  9. package/dist/{chunk-I6OHXCMV.js → chunk-G6ZNGLUX.js} +47 -9
  10. package/dist/{chunk-DNOXHLE5.js → chunk-H7AMDUIA.js} +1 -1
  11. package/dist/{chunk-YGFIWIOF.js → chunk-JR4UXCTO.js} +1 -1
  12. package/dist/{chunk-3C2XR4IY.js → chunk-UWHWAPGO.js} +120 -107
  13. package/dist/{chunk-SOZA2TLP.js → chunk-W76KWE23.js} +1 -1
  14. package/dist/{chunk-GSPKUPKU.js → chunk-XUA3JUFK.js} +2 -1
  15. package/dist/chunk-ZYGKG6VC.js +22 -0
  16. package/dist/chunk-ZZOOTYXK.js +583 -0
  17. package/dist/cli.js +83 -74
  18. package/dist/{connector-DKDJTLYZ.js → connector-Y7JPNROO.js} +11 -6
  19. package/dist/connectors/discord.js +34 -5
  20. package/dist/connectors/slack.js +36 -8
  21. package/dist/connectors/telegram.js +55 -6
  22. package/dist/create-G525LWEA.js +91 -0
  23. package/dist/{daemon-client-XR24PUJF.js → daemon-client-442IV43D.js} +2 -2
  24. package/dist/daemon.js +1273 -384
  25. package/dist/{delete-55MXCEY5.js → delete-2PH2CGDY.js} +7 -8
  26. package/dist/{down-3OB6UVAJ.js → down-FXWAN66A.js} +1 -1
  27. package/dist/{env-JB27UAC3.js → env-7GLUJCWS.js} +8 -5
  28. package/dist/{history-BKG74I43.js → history-H72ZUIBN.js} +3 -3
  29. package/dist/{import-4CI2ZUTJ.js → import-AVKQJDYC.js} +8 -8
  30. package/dist/{logs-NXFFGUKY.js → logs-EDGK26AK.js} +2 -2
  31. package/dist/message-SCOQDR3P.js +32 -0
  32. package/dist/{package-Z2SFO2SV.js → package-4DP4Y4UO.js} +1 -1
  33. package/dist/restart-O4ETYLJF.js +29 -0
  34. package/dist/{schedule-A35SH4HT.js → schedule-S6QVC5ON.js} +10 -5
  35. package/dist/send-G7PE4DOJ.js +72 -0
  36. package/dist/{setup-2FDVN7OF.js → setup-F4TCWVSP.js} +5 -5
  37. package/dist/{start-LDPMCMYT.js → start-VHQ7LNWM.js} +3 -3
  38. package/dist/{status-MVSQG54T.js → status-QAJWXKMZ.js} +3 -3
  39. package/dist/{stop-5PZTZCLL.js → stop-CAGCT5NI.js} +6 -7
  40. package/dist/{up-F7TMTLRE.js → up-CSX3ZUIU.js} +16 -4
  41. package/dist/update-XSIX3GGP.js +140 -0
  42. package/dist/update-check-5ZADDHCK.js +17 -0
  43. package/dist/{upgrade-6ZW2RD64.js → upgrade-YXKPWDRU.js} +16 -15
  44. package/dist/{variant-T64BKARF.js → variant-4Z6W3PP6.js} +15 -10
  45. package/dist/web-assets/assets/index-D5PzIndO.js +308 -0
  46. package/dist/web-assets/index.html +2 -2
  47. package/drizzle/0003_clean_ego.sql +12 -0
  48. package/drizzle/meta/0003_snapshot.json +417 -0
  49. package/drizzle/meta/_journal.json +7 -0
  50. package/package.json +1 -1
  51. package/templates/_base/.init/.config/hooks/startup-context.sh +19 -1
  52. package/templates/_base/.init/.config/scripts/session-reader.ts +59 -0
  53. package/templates/_base/_skills/sessions/SKILL.md +49 -0
  54. package/templates/_base/_skills/volute-agent/SKILL.md +114 -14
  55. package/templates/_base/home/.config/routes.json +10 -0
  56. package/templates/_base/home/VOLUTE.md +14 -35
  57. package/templates/_base/src/lib/format-prefix.ts +7 -1
  58. package/templates/_base/src/lib/router.ts +193 -19
  59. package/templates/_base/src/lib/routing.ts +55 -18
  60. package/templates/_base/src/lib/session-monitor.ts +400 -0
  61. package/templates/_base/src/lib/types.ts +5 -1
  62. package/templates/agent-sdk/.init/.config/routes.json +5 -0
  63. package/templates/agent-sdk/.init/CLAUDE.md +2 -2
  64. package/templates/agent-sdk/src/agent.ts +18 -1
  65. package/templates/agent-sdk/src/lib/hooks/session-context.ts +32 -0
  66. package/templates/agent-sdk/src/server.ts +8 -2
  67. package/templates/agent-sdk/volute-template.json +1 -1
  68. package/templates/pi/.init/.config/routes.json +5 -0
  69. package/templates/pi/.init/AGENTS.md +1 -1
  70. package/templates/pi/src/agent.ts +12 -4
  71. package/templates/pi/src/lib/session-context-extension.ts +33 -0
  72. package/templates/pi/src/server.ts +1 -1
  73. package/templates/pi/volute-template.json +1 -1
  74. package/dist/channel-DQ6UY7QB.js +0 -67
  75. package/dist/chunk-5OCWMTVS.js +0 -152
  76. package/dist/chunk-ZHCE4DPY.js +0 -110
  77. package/dist/create-ILVOG75A.js +0 -79
  78. package/dist/send-3U6OTKG7.js +0 -57
  79. package/dist/web-assets/assets/index-NS621maO.js +0 -296
  80. package/templates/agent-sdk/.init/.config/sessions.json +0 -4
  81. package/templates/pi/.init/.config/sessions.json +0 -1
  82. package/dist/{service-SA4TTMDU.js → service-HZNIDNJF.js} +3 -3
@@ -1,16 +1,19 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ resolveAgentName
4
+ } from "./chunk-AZEL2IEK.js";
2
5
  import {
3
6
  parseArgs
4
7
  } from "./chunk-D424ZQGI.js";
5
8
  import {
6
9
  deleteAgentUser
7
- } from "./chunk-SOZA2TLP.js";
10
+ } from "./chunk-W76KWE23.js";
8
11
  import {
9
12
  agentDir,
10
13
  findAgent,
11
14
  removeAgent,
12
15
  removeAllVariants
13
- } from "./chunk-3C2XR4IY.js";
16
+ } from "./chunk-UWHWAPGO.js";
14
17
  import "./chunk-K3NQKI34.js";
15
18
 
16
19
  // src/commands/delete.ts
@@ -19,18 +22,14 @@ async function run(args) {
19
22
  const { positional, flags } = parseArgs(args, {
20
23
  force: { type: "boolean" }
21
24
  });
22
- const name = positional[0];
23
- if (!name) {
24
- console.error("Usage: volute delete <name> [--force]");
25
- process.exit(1);
26
- }
25
+ const name = resolveAgentName({ agent: positional[0] });
27
26
  const entry = findAgent(name);
28
27
  if (!entry) {
29
28
  console.error(`Unknown agent: ${name}`);
30
29
  process.exit(1);
31
30
  }
32
31
  try {
33
- const { daemonFetch } = await import("./daemon-client-XR24PUJF.js");
32
+ const { daemonFetch } = await import("./daemon-client-442IV43D.js");
34
33
  const res = await daemonFetch(`/api/agents/${encodeURIComponent(name)}/stop`, {
35
34
  method: "POST"
36
35
  });
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteHome
4
- } from "./chunk-3C2XR4IY.js";
4
+ } from "./chunk-UWHWAPGO.js";
5
5
  import "./chunk-K3NQKI34.js";
6
6
 
7
7
  // src/commands/down.ts
@@ -5,13 +5,13 @@ import {
5
5
  readEnv,
6
6
  sharedEnvPath,
7
7
  writeEnv
8
- } from "./chunk-DNOXHLE5.js";
8
+ } from "./chunk-H7AMDUIA.js";
9
9
  import {
10
10
  parseArgs
11
11
  } from "./chunk-D424ZQGI.js";
12
12
  import {
13
13
  resolveAgent
14
- } from "./chunk-3C2XR4IY.js";
14
+ } from "./chunk-UWHWAPGO.js";
15
15
  import "./chunk-K3NQKI34.js";
16
16
 
17
17
  // src/commands/env.ts
@@ -153,12 +153,15 @@ async function run(args) {
153
153
  console.log(`Removed ${key} [${scope}]`);
154
154
  break;
155
155
  }
156
+ case "--help":
157
+ case "-h":
158
+ case void 0:
159
+ console.log(`Usage: volute env <set|get|list|remove> [--agent <name>]`);
160
+ break;
156
161
  default:
157
162
  console.error(`Usage: volute env <set|get|list|remove> [--agent <name>]`);
158
- if (subcommand) {
159
- console.error(`
163
+ console.error(`
160
164
  Unknown subcommand: ${subcommand}`);
161
- }
162
165
  process.exit(1);
163
166
  }
164
167
  }
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveAgentName
4
- } from "./chunk-VRVVQIYY.js";
4
+ } from "./chunk-AZEL2IEK.js";
5
5
  import {
6
6
  parseArgs
7
7
  } from "./chunk-D424ZQGI.js";
8
8
  import {
9
9
  daemonFetch
10
- } from "./chunk-YGFIWIOF.js";
11
- import "./chunk-3C2XR4IY.js";
10
+ } from "./chunk-JR4UXCTO.js";
11
+ import "./chunk-UWHWAPGO.js";
12
12
  import "./chunk-K3NQKI34.js";
13
13
 
14
14
  // src/commands/history.ts
@@ -7,25 +7,25 @@ import {
7
7
  agentEnvPath,
8
8
  readEnv,
9
9
  writeEnv
10
- } from "./chunk-DNOXHLE5.js";
10
+ } from "./chunk-H7AMDUIA.js";
11
11
  import {
12
12
  composeTemplate,
13
13
  copyTemplateToDir,
14
14
  findTemplatesRoot
15
- } from "./chunk-GSPKUPKU.js";
15
+ } from "./chunk-XUA3JUFK.js";
16
+ import {
17
+ parseArgs
18
+ } from "./chunk-D424ZQGI.js";
16
19
  import {
17
20
  exec,
18
21
  execInherit
19
22
  } from "./chunk-5SKQ6J7T.js";
20
- import {
21
- parseArgs
22
- } from "./chunk-D424ZQGI.js";
23
23
  import {
24
24
  addAgent,
25
25
  agentDir,
26
26
  ensureVoluteHome,
27
27
  nextPort
28
- } from "./chunk-3C2XR4IY.js";
28
+ } from "./chunk-UWHWAPGO.js";
29
29
  import "./chunk-K3NQKI34.js";
30
30
 
31
31
  // src/commands/import.ts
@@ -394,7 +394,7 @@ ${user.trimEnd()}
394
394
  console.log(`
395
395
  Imported agent: ${name} (port ${port})`);
396
396
  console.log(`
397
- volute start ${name}`);
397
+ volute agent start ${name}`);
398
398
  }
399
399
  function resolveWorkspace(explicitPath) {
400
400
  if (explicitPath) {
@@ -416,7 +416,7 @@ function resolveWorkspace(explicitPath) {
416
416
  return openclawWs;
417
417
  }
418
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."
419
+ "Usage: volute agent 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
420
  );
421
421
  process.exit(1);
422
422
  }
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveAgentName
4
- } from "./chunk-VRVVQIYY.js";
4
+ } from "./chunk-AZEL2IEK.js";
5
5
  import {
6
6
  parseArgs
7
7
  } from "./chunk-D424ZQGI.js";
8
8
  import {
9
9
  resolveAgent
10
- } from "./chunk-3C2XR4IY.js";
10
+ } from "./chunk-UWHWAPGO.js";
11
11
  import "./chunk-K3NQKI34.js";
12
12
 
13
13
  // src/commands/logs.ts
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ import "./chunk-K3NQKI34.js";
3
+
4
+ // src/commands/message.ts
5
+ async function run(args) {
6
+ const subcommand = args[0];
7
+ switch (subcommand) {
8
+ case "send":
9
+ await import("./send-G7PE4DOJ.js").then((m) => m.run(args.slice(1)));
10
+ break;
11
+ case "history":
12
+ await import("./history-H72ZUIBN.js").then((m) => m.run(args.slice(1)));
13
+ break;
14
+ case "--help":
15
+ case "-h":
16
+ case void 0:
17
+ printUsage();
18
+ break;
19
+ default:
20
+ printUsage();
21
+ process.exit(1);
22
+ }
23
+ }
24
+ function printUsage() {
25
+ console.log(`Usage:
26
+ volute message send <name> "<msg>"
27
+ echo "msg" | volute message send <name>
28
+ volute message history [--agent <name>] [--channel <ch>] [--limit N]`);
29
+ }
30
+ export {
31
+ run
32
+ };
@@ -4,7 +4,7 @@ import "./chunk-K3NQKI34.js";
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "volute",
7
- version: "0.4.0",
7
+ version: "0.6.0",
8
8
  description: "CLI for creating and managing self-modifying AI agents powered by the Claude Agent SDK",
9
9
  type: "module",
10
10
  license: "MIT",
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveAgentName
4
+ } from "./chunk-AZEL2IEK.js";
5
+ import {
6
+ daemonFetch
7
+ } from "./chunk-JR4UXCTO.js";
8
+ import {
9
+ resolveAgent
10
+ } from "./chunk-UWHWAPGO.js";
11
+ import "./chunk-K3NQKI34.js";
12
+
13
+ // src/commands/restart.ts
14
+ async function run(args) {
15
+ const name = resolveAgentName({ agent: args[0] });
16
+ const { entry } = resolveAgent(name);
17
+ const res = await daemonFetch(`/api/agents/${encodeURIComponent(name)}/restart`, {
18
+ method: "POST"
19
+ });
20
+ const data = await res.json();
21
+ if (!res.ok) {
22
+ console.error(data.error || "Failed to restart agent");
23
+ process.exit(1);
24
+ }
25
+ console.log(`${name} restarted on port ${entry.port}`);
26
+ }
27
+ export {
28
+ run
29
+ };
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveAgentName
4
- } from "./chunk-VRVVQIYY.js";
4
+ } from "./chunk-AZEL2IEK.js";
5
5
  import {
6
6
  parseArgs
7
7
  } from "./chunk-D424ZQGI.js";
8
8
  import {
9
9
  daemonFetch
10
- } from "./chunk-YGFIWIOF.js";
11
- import "./chunk-3C2XR4IY.js";
10
+ } from "./chunk-JR4UXCTO.js";
11
+ import "./chunk-UWHWAPGO.js";
12
12
  import "./chunk-K3NQKI34.js";
13
13
 
14
14
  // src/commands/schedule.ts
@@ -24,13 +24,18 @@ async function run(args) {
24
24
  case "remove":
25
25
  await removeSchedule(args.slice(1));
26
26
  break;
27
+ case "--help":
28
+ case "-h":
29
+ case void 0:
30
+ printUsage();
31
+ break;
27
32
  default:
28
33
  printUsage();
29
- process.exit(subcommand ? 1 : 0);
34
+ process.exit(1);
30
35
  }
31
36
  }
32
37
  function printUsage() {
33
- console.error(`Usage:
38
+ console.log(`Usage:
34
39
  volute schedule list [--agent <name>]
35
40
  volute schedule add [--agent <name>] --cron "..." --message "..." [--id name]
36
41
  volute schedule remove [--agent <name>] --id <id>`);
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ readStdin
4
+ } from "./chunk-ZYGKG6VC.js";
5
+ import {
6
+ summarizeTool
7
+ } from "./chunk-B3R6L2GW.js";
8
+ import {
9
+ getChannelDriver
10
+ } from "./chunk-ZZOOTYXK.js";
11
+ import "./chunk-BX7KI4S3.js";
12
+ import {
13
+ daemonFetch
14
+ } from "./chunk-JR4UXCTO.js";
15
+ import "./chunk-UWHWAPGO.js";
16
+ import "./chunk-K3NQKI34.js";
17
+
18
+ // src/commands/send.ts
19
+ import { userInfo } from "os";
20
+ async function run(args) {
21
+ const name = args[0];
22
+ const message = args[1] ?? await readStdin();
23
+ if (!name || !message) {
24
+ console.error('Usage: volute message send <name> "<message>"');
25
+ console.error(' echo "message" | volute message send <name>');
26
+ process.exit(1);
27
+ }
28
+ const agentSelf = process.env.VOLUTE_AGENT;
29
+ const sender = agentSelf || userInfo().username;
30
+ const driver = getChannelDriver("volute");
31
+ if (!driver?.sendAndStream || !driver.createConversation) {
32
+ console.error("Volute driver not available");
33
+ process.exit(1);
34
+ }
35
+ const env = { VOLUTE_AGENT: name, VOLUTE_SENDER: sender };
36
+ let conversationId;
37
+ try {
38
+ conversationId = await driver.createConversation(env, [sender]);
39
+ } catch (err) {
40
+ console.error(err instanceof Error ? err.message : String(err));
41
+ process.exit(1);
42
+ }
43
+ try {
44
+ for await (const event of driver.sendAndStream(env, conversationId, message)) {
45
+ if (event.type === "text") {
46
+ process.stdout.write(event.content);
47
+ } else if (event.type === "tool_use") {
48
+ process.stderr.write(`${summarizeTool(event.name, event.input)}
49
+ `);
50
+ }
51
+ if (event.type === "done") break;
52
+ }
53
+ process.stdout.write("\n");
54
+ } catch (err) {
55
+ console.error(err instanceof Error ? err.message : String(err));
56
+ process.exit(1);
57
+ }
58
+ if (agentSelf) {
59
+ try {
60
+ await daemonFetch(`/api/agents/${encodeURIComponent(agentSelf)}/history`, {
61
+ method: "POST",
62
+ headers: { "Content-Type": "application/json" },
63
+ body: JSON.stringify({ channel: conversationId, content: message })
64
+ });
65
+ } catch (err) {
66
+ console.error(`Failed to persist to history: ${err instanceof Error ? err.message : err}`);
67
+ }
68
+ }
69
+ }
70
+ export {
71
+ run
72
+ };
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- resolveVoluteBin
4
- } from "./chunk-5SKQ6J7T.js";
5
2
  import {
6
3
  parseArgs
7
4
  } from "./chunk-D424ZQGI.js";
8
5
  import {
9
6
  ensureVoluteGroup
10
- } from "./chunk-SOZA2TLP.js";
11
- import "./chunk-3C2XR4IY.js";
7
+ } from "./chunk-W76KWE23.js";
8
+ import {
9
+ resolveVoluteBin
10
+ } from "./chunk-5SKQ6J7T.js";
11
+ import "./chunk-UWHWAPGO.js";
12
12
  import "./chunk-K3NQKI34.js";
13
13
 
14
14
  // src/commands/setup.ts
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonFetch
4
- } from "./chunk-YGFIWIOF.js";
4
+ } from "./chunk-JR4UXCTO.js";
5
5
  import {
6
6
  resolveAgent
7
- } from "./chunk-3C2XR4IY.js";
7
+ } from "./chunk-UWHWAPGO.js";
8
8
  import "./chunk-K3NQKI34.js";
9
9
 
10
10
  // src/commands/start.ts
11
11
  async function run(args) {
12
12
  const name = args[0];
13
13
  if (!name) {
14
- console.error("Usage: volute start <name>");
14
+ console.error("Usage: volute agent start <name>");
15
15
  process.exit(1);
16
16
  }
17
17
  const { entry } = resolveAgent(name);
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonFetch
4
- } from "./chunk-YGFIWIOF.js";
5
- import "./chunk-3C2XR4IY.js";
4
+ } from "./chunk-JR4UXCTO.js";
5
+ import "./chunk-UWHWAPGO.js";
6
6
  import "./chunk-K3NQKI34.js";
7
7
 
8
8
  // src/commands/status.ts
@@ -17,7 +17,7 @@ async function run(args) {
17
17
  }
18
18
  const agents = await res2.json();
19
19
  if (agents.length === 0) {
20
- console.log("No agents registered. Create one with: volute create <name>");
20
+ console.log("No agents registered. Create one with: volute agent create <name>");
21
21
  return;
22
22
  }
23
23
  const nameW = Math.max(4, ...agents.map((a) => a.name.length));
@@ -1,19 +1,18 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ resolveAgentName
4
+ } from "./chunk-AZEL2IEK.js";
2
5
  import {
3
6
  daemonFetch
4
- } from "./chunk-YGFIWIOF.js";
7
+ } from "./chunk-JR4UXCTO.js";
5
8
  import {
6
9
  resolveAgent
7
- } from "./chunk-3C2XR4IY.js";
10
+ } from "./chunk-UWHWAPGO.js";
8
11
  import "./chunk-K3NQKI34.js";
9
12
 
10
13
  // src/commands/stop.ts
11
14
  async function run(args) {
12
- const name = args[0];
13
- if (!name) {
14
- console.error("Usage: volute stop <name>");
15
- process.exit(1);
16
- }
15
+ const name = resolveAgentName({ agent: args[0] });
17
16
  resolveAgent(name);
18
17
  const res = await daemonFetch(`/api/agents/${encodeURIComponent(name)}/stop`, {
19
18
  method: "POST"
@@ -4,21 +4,32 @@ import {
4
4
  } from "./chunk-D424ZQGI.js";
5
5
  import {
6
6
  voluteHome
7
- } from "./chunk-3C2XR4IY.js";
7
+ } from "./chunk-UWHWAPGO.js";
8
8
  import "./chunk-K3NQKI34.js";
9
9
 
10
10
  // src/commands/up.ts
11
11
  import { spawn } from "child_process";
12
12
  import { existsSync, mkdirSync, openSync, readFileSync } from "fs";
13
13
  import { dirname, resolve } from "path";
14
+ function readGlobalConfig() {
15
+ const configPath = resolve(voluteHome(), "config.json");
16
+ if (!existsSync(configPath)) return {};
17
+ try {
18
+ return JSON.parse(readFileSync(configPath, "utf-8"));
19
+ } catch (err) {
20
+ console.error(`Invalid config file ${configPath}: ${err instanceof Error ? err.message : err}`);
21
+ process.exit(1);
22
+ }
23
+ }
14
24
  async function run(args) {
15
25
  const { flags } = parseArgs(args, {
16
26
  port: { type: "number" },
17
27
  host: { type: "string" },
18
28
  foreground: { type: "boolean" }
19
29
  });
20
- const port = flags.port ?? 4200;
21
- const hostname = flags.host ?? "127.0.0.1";
30
+ const config = readGlobalConfig();
31
+ const port = flags.port ?? config.port ?? 4200;
32
+ const hostname = flags.host ?? config.hostname ?? "127.0.0.1";
22
33
  const home = voluteHome();
23
34
  const pidPath = resolve(home, "daemon.pid");
24
35
  if (existsSync(pidPath)) {
@@ -58,7 +69,7 @@ async function run(args) {
58
69
  process.execPath,
59
70
  [daemonModule, "--port", String(port), "--host", hostname],
60
71
  {
61
- stdio: ["ignore", logFd, logFd],
72
+ stdio: ["ignore", "ignore", logFd],
62
73
  detached: true
63
74
  }
64
75
  );
@@ -93,5 +104,6 @@ async function run(args) {
93
104
  process.exit(1);
94
105
  }
95
106
  export {
107
+ readGlobalConfig,
96
108
  run
97
109
  };
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ checkForUpdate
4
+ } from "./chunk-AOKAQGO4.js";
5
+ import {
6
+ execInherit,
7
+ resolveVoluteBin
8
+ } from "./chunk-5SKQ6J7T.js";
9
+ import {
10
+ voluteHome
11
+ } from "./chunk-UWHWAPGO.js";
12
+ import "./chunk-K3NQKI34.js";
13
+
14
+ // src/commands/update.ts
15
+ import { existsSync, readFileSync, unlinkSync } from "fs";
16
+ import { resolve } from "path";
17
+ async function run(_args) {
18
+ const result = await checkForUpdate();
19
+ if (result.checkFailed) {
20
+ console.error("Could not reach npm registry. Check your network connection and try again.");
21
+ process.exit(1);
22
+ }
23
+ console.log(`Current version: ${result.current}`);
24
+ console.log(`Latest version: ${result.latest}`);
25
+ if (!result.updateAvailable) {
26
+ console.log("\nAlready up to date.");
27
+ return;
28
+ }
29
+ console.log(`
30
+ Updating volute ${result.current} \u2192 ${result.latest}...`);
31
+ const home = voluteHome();
32
+ const pidPath = resolve(home, "daemon.pid");
33
+ const configPath = resolve(home, "daemon.json");
34
+ let daemonWasRunning = false;
35
+ let daemonPort = 4200;
36
+ let daemonHost = "127.0.0.1";
37
+ if (existsSync(pidPath)) {
38
+ const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
39
+ try {
40
+ process.kill(pid, 0);
41
+ daemonWasRunning = true;
42
+ } catch {
43
+ try {
44
+ unlinkSync(pidPath);
45
+ } catch {
46
+ }
47
+ }
48
+ }
49
+ if (daemonWasRunning && existsSync(configPath)) {
50
+ try {
51
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
52
+ daemonPort = config.port ?? 4200;
53
+ daemonHost = config.hostname || "127.0.0.1";
54
+ } catch {
55
+ console.error("Warning: could not read daemon config, using default port/host");
56
+ }
57
+ }
58
+ if (daemonWasRunning) {
59
+ console.log("Stopping daemon...");
60
+ const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
61
+ try {
62
+ process.kill(-pid, "SIGTERM");
63
+ } catch {
64
+ try {
65
+ process.kill(pid, "SIGTERM");
66
+ } catch {
67
+ }
68
+ }
69
+ const maxWait = 1e4;
70
+ const start = Date.now();
71
+ while (Date.now() - start < maxWait) {
72
+ if (!existsSync(pidPath)) break;
73
+ await new Promise((r) => setTimeout(r, 200));
74
+ }
75
+ if (existsSync(pidPath)) {
76
+ try {
77
+ process.kill(-pid, "SIGKILL");
78
+ } catch {
79
+ try {
80
+ process.kill(pid, "SIGKILL");
81
+ } catch {
82
+ }
83
+ }
84
+ }
85
+ if (existsSync(pidPath)) {
86
+ try {
87
+ const stalePid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
88
+ process.kill(stalePid, 0);
89
+ console.error("Warning: daemon process may still be running. Aborting update.");
90
+ process.exit(1);
91
+ } catch {
92
+ try {
93
+ unlinkSync(pidPath);
94
+ } catch {
95
+ }
96
+ }
97
+ }
98
+ console.log("Daemon stopped.");
99
+ }
100
+ try {
101
+ await execInherit("npm", ["install", "-g", "volute@latest"]);
102
+ } catch (err) {
103
+ console.error(`
104
+ Update failed: ${err.message}`);
105
+ if (daemonWasRunning) {
106
+ console.log("Restarting daemon with current version...");
107
+ try {
108
+ await execInherit(resolveVoluteBin(), [
109
+ "up",
110
+ "--port",
111
+ String(daemonPort),
112
+ "--host",
113
+ daemonHost
114
+ ]);
115
+ } catch {
116
+ console.error("Failed to restart daemon. Run `volute up` manually.");
117
+ }
118
+ }
119
+ process.exit(1);
120
+ }
121
+ if (daemonWasRunning) {
122
+ console.log("Restarting daemon...");
123
+ try {
124
+ await execInherit(resolveVoluteBin(), [
125
+ "up",
126
+ "--port",
127
+ String(daemonPort),
128
+ "--host",
129
+ daemonHost
130
+ ]);
131
+ } catch {
132
+ console.error("Failed to restart daemon. Run `volute up` manually.");
133
+ }
134
+ }
135
+ console.log(`
136
+ Updated to volute v${result.latest}`);
137
+ }
138
+ export {
139
+ run
140
+ };
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ checkForUpdate,
4
+ checkForUpdateCached,
5
+ fetchLatestVersion,
6
+ getCurrentVersion,
7
+ isNewer
8
+ } from "./chunk-AOKAQGO4.js";
9
+ import "./chunk-UWHWAPGO.js";
10
+ import "./chunk-K3NQKI34.js";
11
+ export {
12
+ checkForUpdate,
13
+ checkForUpdateCached,
14
+ fetchLatestVersion,
15
+ getCurrentVersion,
16
+ isNewer
17
+ };