volute 0.1.0 → 0.2.1

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 (66) hide show
  1. package/README.md +1 -2
  2. package/dist/agent-manager-SSJUZWOV.js +13 -0
  3. package/dist/{channel-Q642YUZE.js → channel-2WJRM7PE.js} +2 -2
  4. package/dist/{chunk-H5XQARAP.js → chunk-4YXYAMFT.js} +3 -3
  5. package/dist/{chunk-5YW4B7CG.js → chunk-6UCG6MIX.js} +72 -23
  6. package/dist/{chunk-A5ZJEMHT.js → chunk-KFNNHQK7.js} +4 -4
  7. package/dist/chunk-L3BQEZ4Z.js +271 -0
  8. package/dist/{chunk-N4QN44LC.js → chunk-MY74SUOL.js} +29 -22
  9. package/dist/{chunk-KSMIWOCN.js → chunk-N4YNKR3Q.js} +6 -0
  10. package/dist/cli.js +23 -19
  11. package/dist/{connect-LW6G23AV.js → connect-X5V5IMRW.js} +3 -3
  12. package/dist/connectors/discord.js +9 -2
  13. package/dist/{create-3K6O2SDC.js → create-23AM7H5B.js} +1 -1
  14. package/dist/{daemon-client-ZTHW7ROS.js → daemon-client-VN24HM5T.js} +2 -2
  15. package/dist/daemon.js +394 -436
  16. package/dist/{delete-JNGY7ZFH.js → delete-GDMSOW3U.js} +2 -2
  17. package/dist/{disconnect-ACVTKTRE.js → disconnect-5JWFZ6RV.js} +2 -2
  18. package/dist/{down-FYCUYC5H.js → down-WTF73FE7.js} +5 -4
  19. package/dist/{env-7SLRN3MG.js → env-YKUJOFHE.js} +12 -5
  20. package/dist/{fork-BB3DZ426.js → fork-GRSVMBKI.js} +39 -32
  21. package/dist/history-7WVVKMUY.js +46 -0
  22. package/dist/{import-W2AMTEV5.js → import-42DOLBDT.js} +1 -1
  23. package/dist/{logs-BUHRIQ2L.js → logs-SYRQOL6B.js} +1 -1
  24. package/dist/{merge-446QTE7Q.js → merge-CSAVLSLY.js} +33 -36
  25. package/dist/{schedule-KKSOVUDF.js → schedule-J37XQM6E.js} +2 -2
  26. package/dist/{send-WQSVSRDD.js → send-PLOYEYER.js} +7 -5
  27. package/dist/{start-LKMWS6ZE.js → start-AG7QLULK.js} +2 -2
  28. package/dist/{status-CIEKUI3V.js → status-GCNU4M3K.js} +9 -2
  29. package/dist/{stop-YTOAGYE4.js → stop-IL5Q6NER.js} +2 -2
  30. package/dist/{up-AJJ4GCXY.js → up-ZC6G6K4K.js} +21 -37
  31. package/dist/{upgrade-JACA6YMO.js → upgrade-DD5TNJWU.js} +3 -5
  32. package/dist/{variants-HPY4DEWU.js → variants-QQIEKT6M.js} +2 -2
  33. package/drizzle/0000_flaky_mariko_yashida.sql +34 -0
  34. package/drizzle/0001_careless_warpath.sql +12 -0
  35. package/drizzle/meta/0000_snapshot.json +227 -0
  36. package/drizzle/meta/0001_snapshot.json +298 -0
  37. package/drizzle/meta/_journal.json +20 -0
  38. package/package.json +2 -1
  39. package/templates/_base/.init/.config/hooks/startup-context.sh +28 -0
  40. package/templates/_base/_skills/memory/SKILL.md +56 -13
  41. package/templates/_base/_skills/volute-agent/SKILL.md +27 -3
  42. package/templates/_base/home/VOLUTE.md +25 -0
  43. package/templates/_base/src/lib/format-prefix.ts +24 -0
  44. package/templates/_base/src/lib/sessions.ts +71 -0
  45. package/templates/_base/src/lib/startup.ts +132 -0
  46. package/templates/_base/src/lib/types.ts +3 -0
  47. package/templates/_base/src/lib/volute-server.ts +18 -2
  48. package/templates/agent-sdk/.init/.claude/settings.json +14 -0
  49. package/templates/agent-sdk/.init/.config/sessions.json +4 -0
  50. package/templates/agent-sdk/.init/CLAUDE.md +3 -2
  51. package/templates/agent-sdk/package.json.tmpl +1 -1
  52. package/templates/agent-sdk/src/agent.ts +101 -0
  53. package/templates/agent-sdk/src/lib/agent-sessions.ts +180 -0
  54. package/templates/agent-sdk/src/server.ts +33 -129
  55. package/templates/agent-sdk/volute-template.json +1 -1
  56. package/templates/pi/.init/.config/sessions.json +1 -0
  57. package/templates/pi/.init/AGENTS.md +2 -1
  58. package/templates/pi/src/agent.ts +61 -0
  59. package/templates/pi/src/lib/agent-sessions.ts +188 -0
  60. package/templates/pi/src/server.ts +28 -102
  61. package/templates/pi/volute-template.json +1 -1
  62. package/templates/agent-sdk/src/lib/agent.ts +0 -199
  63. package/templates/pi/src/lib/agent.ts +0 -205
  64. /package/templates/_base/.init/memory/{.gitkeep → journal/.gitkeep} +0 -0
  65. /package/templates/_base/{volute.json.tmpl → home/.config/volute.json.tmpl} +0 -0
  66. /package/templates/pi/{volute.json.tmpl → home/.config/volute.json.tmpl} +0 -0
@@ -7,7 +7,7 @@ import {
7
7
  findAgent,
8
8
  removeAgent,
9
9
  removeAllVariants
10
- } from "./chunk-5YW4B7CG.js";
10
+ } from "./chunk-6UCG6MIX.js";
11
11
 
12
12
  // src/commands/delete.ts
13
13
  import { existsSync, rmSync } from "fs";
@@ -26,7 +26,7 @@ async function run(args) {
26
26
  process.exit(1);
27
27
  }
28
28
  try {
29
- const { daemonFetch } = await import("./daemon-client-ZTHW7ROS.js");
29
+ const { daemonFetch } = await import("./daemon-client-VN24HM5T.js");
30
30
  const res = await daemonFetch(`/api/agents/${encodeURIComponent(name)}/stop`, {
31
31
  method: "POST"
32
32
  });
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonFetch
4
- } from "./chunk-H5XQARAP.js";
5
- import "./chunk-5YW4B7CG.js";
4
+ } from "./chunk-4YXYAMFT.js";
5
+ import "./chunk-6UCG6MIX.js";
6
6
 
7
7
  // src/commands/disconnect.ts
8
8
  async function run(args) {
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- VOLUTE_HOME
4
- } from "./chunk-5YW4B7CG.js";
3
+ voluteHome
4
+ } from "./chunk-6UCG6MIX.js";
5
5
 
6
6
  // src/commands/down.ts
7
7
  import { existsSync, readFileSync, unlinkSync } from "fs";
8
8
  import { resolve } from "path";
9
9
  async function run(_args) {
10
- const pidPath = resolve(VOLUTE_HOME, "daemon.pid");
10
+ const home = voluteHome();
11
+ const pidPath = resolve(home, "daemon.pid");
11
12
  if (!existsSync(pidPath)) {
12
- const configPath = resolve(VOLUTE_HOME, "daemon.json");
13
+ const configPath = resolve(home, "daemon.json");
13
14
  let port = 4200;
14
15
  if (existsSync(configPath)) {
15
16
  try {
@@ -5,13 +5,13 @@ import {
5
5
  readEnv,
6
6
  sharedEnvPath,
7
7
  writeEnv
8
- } from "./chunk-A5ZJEMHT.js";
8
+ } from "./chunk-KFNNHQK7.js";
9
9
  import {
10
10
  parseArgs
11
11
  } from "./chunk-D424ZQGI.js";
12
12
  import {
13
13
  resolveAgent
14
- } from "./chunk-5YW4B7CG.js";
14
+ } from "./chunk-6UCG6MIX.js";
15
15
 
16
16
  // src/commands/env.ts
17
17
  function getEnvPath(agentName) {
@@ -51,9 +51,14 @@ async function promptValue(key) {
51
51
  process.stdin.on("data", onData);
52
52
  });
53
53
  }
54
+ function maskValue(value) {
55
+ if (value.length <= 6) return "***";
56
+ return `${value.slice(0, 3)}...${value.slice(-3)}`;
57
+ }
54
58
  async function run(args) {
55
59
  const { positional, flags } = parseArgs(args, {
56
- agent: { type: "string" }
60
+ agent: { type: "string" },
61
+ reveal: { type: "boolean" }
57
62
  });
58
63
  const subcommand = positional[0];
59
64
  switch (subcommand) {
@@ -110,7 +115,8 @@ async function run(args) {
110
115
  }
111
116
  for (const key of [...allKeys].sort()) {
112
117
  const scope = key in agent ? "agent" : "shared";
113
- const value = key in agent ? agent[key] : shared[key];
118
+ const raw = key in agent ? agent[key] : shared[key];
119
+ const value = flags.reveal ? raw : maskValue(raw);
114
120
  console.log(`${key}=${value} [${scope}]`);
115
121
  }
116
122
  } else {
@@ -121,7 +127,8 @@ async function run(args) {
121
127
  return;
122
128
  }
123
129
  for (const key of keys.sort()) {
124
- console.log(`${key}=${env[key]} [shared]`);
130
+ const value = flags.reveal ? env[key] : maskValue(env[key]);
131
+ console.log(`${key}=${value} [shared]`);
125
132
  }
126
133
  }
127
134
  break;
@@ -1,19 +1,20 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- spawnServer
4
- } from "./chunk-N4QN44LC.js";
5
2
  import {
6
3
  exec,
7
4
  execInherit
8
5
  } from "./chunk-XZN4WPNC.js";
6
+ import {
7
+ daemonFetch
8
+ } from "./chunk-4YXYAMFT.js";
9
9
  import {
10
10
  parseArgs
11
11
  } from "./chunk-D424ZQGI.js";
12
12
  import {
13
13
  addVariant,
14
+ nextPort,
14
15
  resolveAgent,
15
16
  validateBranchName
16
- } from "./chunk-5YW4B7CG.js";
17
+ } from "./chunk-6UCG6MIX.js";
17
18
 
18
19
  // src/commands/fork.ts
19
20
  import { existsSync, mkdirSync, writeFileSync } from "fs";
@@ -41,17 +42,17 @@ async function run(args) {
41
42
  process.exit(1);
42
43
  }
43
44
  const { dir: projectRoot } = resolveAgent(agentName);
44
- const worktreeDir = resolve(projectRoot, ".worktrees", variantName);
45
- if (existsSync(worktreeDir)) {
46
- console.error(`Worktree already exists: ${worktreeDir}`);
45
+ const variantDir = resolve(projectRoot, ".variants", variantName);
46
+ if (existsSync(variantDir)) {
47
+ console.error(`Variant directory already exists: ${variantDir}`);
47
48
  process.exit(1);
48
49
  }
49
- const parentDir = resolve(projectRoot, ".worktrees");
50
+ const parentDir = resolve(projectRoot, ".variants");
50
51
  if (!existsSync(parentDir)) {
51
52
  mkdirSync(parentDir, { recursive: true });
52
53
  }
53
54
  try {
54
- await exec("git", ["worktree", "add", "-b", variantName, worktreeDir], { cwd: projectRoot });
55
+ await exec("git", ["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
55
56
  } catch (e) {
56
57
  const msg = e instanceof Error ? e.message : String(e);
57
58
  console.error(`Failed to create worktree: ${msg}`);
@@ -60,9 +61,9 @@ async function run(args) {
60
61
  if (!json) console.log("Installing dependencies...");
61
62
  try {
62
63
  if (json) {
63
- await exec("npm", ["install"], { cwd: worktreeDir });
64
+ await exec("npm", ["install"], { cwd: variantDir });
64
65
  } else {
65
- await execInherit("npm", ["install"], { cwd: worktreeDir });
66
+ await execInherit("npm", ["install"], { cwd: variantDir });
66
67
  }
67
68
  } catch (e) {
68
69
  const msg = e instanceof Error ? e.message : String(e);
@@ -70,30 +71,39 @@ async function run(args) {
70
71
  process.exit(1);
71
72
  }
72
73
  if (soul) {
73
- writeFileSync(resolve(worktreeDir, "home/SOUL.md"), soul);
74
- }
75
- let actualPort = null;
76
- let pid = null;
77
- if (!noStart) {
78
- const requestedPort = port ?? 0;
79
- if (!json) console.log("Starting server...");
80
- const result = await spawnServer(worktreeDir, requestedPort, { detached: true });
81
- if (!result) {
82
- console.error("Server failed to start within timeout");
83
- process.exit(1);
84
- }
85
- actualPort = result.actualPort;
86
- pid = result.child.pid ?? null;
74
+ writeFileSync(resolve(variantDir, "home/SOUL.md"), soul);
87
75
  }
76
+ const variantPort = port ?? nextPort();
88
77
  const variant = {
89
78
  name: variantName,
90
79
  branch: variantName,
91
- path: worktreeDir,
92
- port: actualPort ?? port ?? 0,
93
- pid,
80
+ path: variantDir,
81
+ port: variantPort,
94
82
  created: (/* @__PURE__ */ new Date()).toISOString()
95
83
  };
96
84
  addVariant(agentName, variant);
85
+ if (!noStart) {
86
+ if (!json) console.log("Starting variant via daemon...");
87
+ try {
88
+ const res = await daemonFetch(
89
+ `/api/agents/${encodeURIComponent(`${agentName}@${variantName}`)}/start`,
90
+ {
91
+ method: "POST"
92
+ }
93
+ );
94
+ if (!res.ok) {
95
+ const data = await res.json();
96
+ console.error(data.error ?? "Failed to start variant");
97
+ process.exit(1);
98
+ }
99
+ } catch {
100
+ console.error("Failed to start variant. Is the daemon running? (volute up)");
101
+ console.error(
102
+ `The variant was created but not started. Use: volute start ${agentName}@${variantName}`
103
+ );
104
+ process.exit(1);
105
+ }
106
+ }
97
107
  if (json) {
98
108
  console.log(JSON.stringify(variant, null, 2));
99
109
  } else {
@@ -101,10 +111,7 @@ async function run(args) {
101
111
  Variant created: ${variantName}`);
102
112
  console.log(` Branch: ${variant.branch}`);
103
113
  console.log(` Path: ${variant.path}`);
104
- if (actualPort) {
105
- console.log(` Port: ${actualPort}`);
106
- console.log(` PID: ${pid}`);
107
- }
114
+ console.log(` Port: ${variantPort}`);
108
115
  }
109
116
  }
110
117
  export {
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ daemonFetch
4
+ } from "./chunk-4YXYAMFT.js";
5
+ import {
6
+ parseArgs
7
+ } from "./chunk-D424ZQGI.js";
8
+ import "./chunk-6UCG6MIX.js";
9
+
10
+ // src/commands/history.ts
11
+ async function run(args) {
12
+ const { positional, flags } = parseArgs(args, {
13
+ channel: { type: "string" },
14
+ limit: { type: "string" }
15
+ });
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 params = new URLSearchParams();
22
+ if (flags.channel) params.set("channel", flags.channel);
23
+ if (flags.limit) params.set("limit", flags.limit);
24
+ const qs = params.toString();
25
+ const path = `/api/agents/${encodeURIComponent(name)}/history${qs ? `?${qs}` : ""}`;
26
+ const res = await daemonFetch(path);
27
+ if (!res.ok) {
28
+ let errorMsg = `Failed to get history: ${res.status}`;
29
+ try {
30
+ const data = await res.json();
31
+ if (data.error) errorMsg = data.error;
32
+ } catch {
33
+ }
34
+ console.error(errorMsg);
35
+ process.exit(1);
36
+ }
37
+ const rows = await res.json();
38
+ for (const row of rows.reverse()) {
39
+ const time = new Date(row.created_at).toLocaleString();
40
+ const sender = row.sender ?? row.role;
41
+ console.log(`[${time}] [${row.channel}] ${sender}: ${row.content}`);
42
+ }
43
+ }
44
+ export {
45
+ run
46
+ };
@@ -16,7 +16,7 @@ import {
16
16
  agentDir,
17
17
  ensureVoluteHome,
18
18
  nextPort
19
- } from "./chunk-5YW4B7CG.js";
19
+ } from "./chunk-6UCG6MIX.js";
20
20
 
21
21
  // src/commands/import.ts
22
22
  import {
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-D424ZQGI.js";
5
5
  import {
6
6
  resolveAgent
7
- } from "./chunk-5YW4B7CG.js";
7
+ } from "./chunk-6UCG6MIX.js";
8
8
 
9
9
  // src/commands/logs.ts
10
10
  import { spawn } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  spawnServer
4
- } from "./chunk-N4QN44LC.js";
4
+ } from "./chunk-MY74SUOL.js";
5
5
  import {
6
6
  exec,
7
7
  execInherit
@@ -15,7 +15,7 @@ import {
15
15
  removeVariant,
16
16
  resolveAgent,
17
17
  validateBranchName
18
- } from "./chunk-5YW4B7CG.js";
18
+ } from "./chunk-6UCG6MIX.js";
19
19
 
20
20
  // src/commands/merge.ts
21
21
  import { existsSync, mkdirSync, writeFileSync } from "fs";
@@ -113,40 +113,30 @@ async function run(args) {
113
113
  const status = (await exec("git", ["status", "--porcelain"], { cwd: variant.path })).trim();
114
114
  if (status) {
115
115
  console.log("Committing uncommitted changes in variant...");
116
- await exec("git", ["add", "-A"], { cwd: variant.path });
117
- await exec("git", ["commit", "-m", "Auto-commit uncommitted changes before merge"], {
118
- cwd: variant.path
119
- });
116
+ try {
117
+ await exec("git", ["add", "-A"], { cwd: variant.path });
118
+ await exec("git", ["commit", "-m", "Auto-commit uncommitted changes before merge"], {
119
+ cwd: variant.path
120
+ });
121
+ } catch (err) {
122
+ console.error("Failed to auto-commit variant changes:", err);
123
+ console.error("Please commit or stash changes in the variant manually before merging.");
124
+ process.exit(1);
125
+ }
120
126
  }
121
127
  }
122
128
  if (!flags["skip-verify"]) {
123
129
  console.log("Verifying variant...");
124
- let port = variant.port;
125
- let tempServerPid;
126
- let running = false;
127
- if (variant.pid) {
128
- try {
129
- process.kill(variant.pid, 0);
130
- running = true;
131
- } catch {
132
- }
133
- }
134
- if (!running) {
135
- console.log("Starting temporary server for verification...");
136
- const result = await spawnServer(variant.path, 0, { detached: true });
137
- if (!result) {
138
- console.error("Failed to start server for verification. Use --skip-verify to skip.");
139
- process.exit(1);
140
- }
141
- port = result.actualPort;
142
- tempServerPid = result.child.pid;
130
+ console.log("Starting temporary server for verification...");
131
+ const result = await spawnServer(variant.path, 0, { detached: true });
132
+ if (!result) {
133
+ console.error("Failed to start server for verification. Use --skip-verify to skip.");
134
+ process.exit(1);
143
135
  }
144
- const verified = await verify(port);
145
- if (tempServerPid) {
146
- try {
147
- process.kill(tempServerPid);
148
- } catch {
149
- }
136
+ const verified = await verify(result.actualPort);
137
+ try {
138
+ process.kill(result.child.pid);
139
+ } catch {
150
140
  }
151
141
  if (!verified) {
152
142
  console.error("Verification failed. Fix issues or use --skip-verify to proceed anyway.");
@@ -154,11 +144,18 @@ async function run(args) {
154
144
  }
155
145
  console.log("Verification passed.");
156
146
  }
157
- if (variant.pid) {
147
+ const mainStatus = (await exec("git", ["status", "--porcelain"], { cwd: projectRoot })).trim();
148
+ if (mainStatus) {
149
+ console.log("Committing uncommitted changes in main...");
158
150
  try {
159
- process.kill(variant.pid);
160
- console.log(`Killed server (pid ${variant.pid})`);
161
- } catch {
151
+ await exec("git", ["add", "-A"], { cwd: projectRoot });
152
+ await exec("git", ["commit", "-m", "Auto-commit uncommitted changes before merge"], {
153
+ cwd: projectRoot
154
+ });
155
+ } catch (err) {
156
+ console.error("Failed to auto-commit main changes:", err);
157
+ console.error("Please commit or stash your changes manually before merging.");
158
+ process.exit(1);
162
159
  }
163
160
  }
164
161
  console.log(`Merging branch: ${variant.branch}`);
@@ -199,7 +196,7 @@ async function run(args) {
199
196
  );
200
197
  if (process.env.VOLUTE_SUPERVISOR) return;
201
198
  try {
202
- const { daemonFetch } = await import("./daemon-client-ZTHW7ROS.js");
199
+ const { daemonFetch } = await import("./daemon-client-VN24HM5T.js");
203
200
  console.log("Restarting agent via daemon...");
204
201
  const res = await daemonFetch(`/api/agents/${encodeURIComponent(agentName)}/restart`, {
205
202
  method: "POST"
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonFetch
4
- } from "./chunk-H5XQARAP.js";
5
- import "./chunk-5YW4B7CG.js";
4
+ } from "./chunk-4YXYAMFT.js";
5
+ import "./chunk-6UCG6MIX.js";
6
6
 
7
7
  // src/commands/schedule.ts
8
8
  async function run(args) {
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readNdjson
4
- } from "./chunk-KSMIWOCN.js";
4
+ } from "./chunk-N4YNKR3Q.js";
5
5
  import {
6
6
  daemonFetch
7
- } from "./chunk-H5XQARAP.js";
8
- import "./chunk-5YW4B7CG.js";
7
+ } from "./chunk-4YXYAMFT.js";
8
+ import "./chunk-6UCG6MIX.js";
9
9
 
10
10
  // src/commands/send.ts
11
11
  import { userInfo } from "os";
@@ -16,13 +16,15 @@ async function run(args) {
16
16
  console.error('Usage: volute send <name> "<message>"');
17
17
  process.exit(1);
18
18
  }
19
- const sender = userInfo().username;
19
+ const agentSelf = process.env.VOLUTE_AGENT;
20
+ const sender = agentSelf || userInfo().username;
21
+ const channel = agentSelf ? "agent" : "cli";
20
22
  const res = await daemonFetch(`/api/agents/${encodeURIComponent(name)}/message`, {
21
23
  method: "POST",
22
24
  headers: { "Content-Type": "application/json" },
23
25
  body: JSON.stringify({
24
26
  content: [{ type: "text", text: message }],
25
- channel: "cli",
27
+ channel,
26
28
  sender
27
29
  })
28
30
  });
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonFetch
4
- } from "./chunk-H5XQARAP.js";
4
+ } from "./chunk-4YXYAMFT.js";
5
5
  import {
6
6
  resolveAgent
7
- } from "./chunk-5YW4B7CG.js";
7
+ } from "./chunk-6UCG6MIX.js";
8
8
 
9
9
  // src/commands/start.ts
10
10
  async function run(args) {
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonFetch
4
- } from "./chunk-H5XQARAP.js";
5
- import "./chunk-5YW4B7CG.js";
4
+ } from "./chunk-4YXYAMFT.js";
5
+ import "./chunk-6UCG6MIX.js";
6
6
 
7
7
  // src/commands/status.ts
8
8
  async function run(args) {
@@ -44,6 +44,13 @@ async function run(args) {
44
44
  for (const ch of agent.channels) {
45
45
  console.log(`${ch.name}: ${ch.status}`);
46
46
  }
47
+ if (agent.variants && agent.variants.length > 0) {
48
+ console.log("");
49
+ console.log("Variants:");
50
+ for (const v of agent.variants) {
51
+ console.log(` ${v.name} port=${v.port} ${v.status}`);
52
+ }
53
+ }
47
54
  }
48
55
  export {
49
56
  run
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonFetch
4
- } from "./chunk-H5XQARAP.js";
4
+ } from "./chunk-4YXYAMFT.js";
5
5
  import {
6
6
  resolveAgent
7
- } from "./chunk-5YW4B7CG.js";
7
+ } from "./chunk-6UCG6MIX.js";
8
8
 
9
9
  // src/commands/stop.ts
10
10
  async function run(args) {
@@ -3,8 +3,8 @@ import {
3
3
  parseArgs
4
4
  } from "./chunk-D424ZQGI.js";
5
5
  import {
6
- VOLUTE_HOME
7
- } from "./chunk-5YW4B7CG.js";
6
+ voluteHome
7
+ } from "./chunk-6UCG6MIX.js";
8
8
 
9
9
  // src/commands/up.ts
10
10
  import { spawn } from "child_process";
@@ -13,10 +13,13 @@ import { dirname, resolve } from "path";
13
13
  async function run(args) {
14
14
  const { flags } = parseArgs(args, {
15
15
  port: { type: "number" },
16
+ host: { type: "string" },
16
17
  foreground: { type: "boolean" }
17
18
  });
18
19
  const port = flags.port ?? 4200;
19
- const pidPath = resolve(VOLUTE_HOME, "daemon.pid");
20
+ const hostname = flags.host ?? "127.0.0.1";
21
+ const home = voluteHome();
22
+ const pidPath = resolve(home, "daemon.pid");
20
23
  if (existsSync(pidPath)) {
21
24
  try {
22
25
  const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
@@ -38,44 +41,25 @@ async function run(args) {
38
41
  }
39
42
  if (flags.foreground) {
40
43
  const { startDaemon } = await import("./daemon.js");
41
- await startDaemon({ port, foreground: true });
44
+ await startDaemon({ port, hostname, foreground: true });
42
45
  return;
43
46
  }
44
- let tsxBin = "";
45
- let searchDir = dirname(new URL(import.meta.url).pathname);
46
- for (let i = 0; i < 5; i++) {
47
- const candidate = resolve(searchDir, "node_modules", ".bin", "tsx");
48
- if (existsSync(candidate)) {
49
- tsxBin = candidate;
50
- break;
51
- }
52
- searchDir = dirname(searchDir);
53
- }
54
- if (!tsxBin) {
55
- console.error("Could not find tsx binary.");
56
- process.exit(1);
57
- }
58
- let daemonModule = "";
59
- searchDir = dirname(new URL(import.meta.url).pathname);
60
- for (let i = 0; i < 5; i++) {
61
- const candidate = resolve(searchDir, "src", "daemon.ts");
62
- if (existsSync(candidate)) {
63
- daemonModule = candidate;
64
- break;
65
- }
66
- searchDir = dirname(searchDir);
67
- }
68
- if (!daemonModule) {
69
- console.error("Could not find daemon module.");
47
+ const daemonModule = resolve(dirname(new URL(import.meta.url).pathname), "daemon.js");
48
+ if (!existsSync(daemonModule)) {
49
+ console.error("Could not find daemon module. Run `npm run build` first.");
70
50
  process.exit(1);
71
51
  }
72
- mkdirSync(VOLUTE_HOME, { recursive: true });
73
- const logFile = resolve(VOLUTE_HOME, "daemon.log");
52
+ mkdirSync(home, { recursive: true });
53
+ const logFile = resolve(home, "daemon.log");
74
54
  const logFd = openSync(logFile, "a");
75
- const child = spawn(tsxBin, [daemonModule, "--port", String(port)], {
76
- stdio: ["ignore", logFd, logFd],
77
- detached: true
78
- });
55
+ const child = spawn(
56
+ process.execPath,
57
+ [daemonModule, "--port", String(port), "--host", hostname],
58
+ {
59
+ stdio: ["ignore", logFd, logFd],
60
+ detached: true
61
+ }
62
+ );
79
63
  child.unref();
80
64
  const url = `http://localhost:${port}/api/health`;
81
65
  const maxWait = 3e4;
@@ -84,7 +68,7 @@ async function run(args) {
84
68
  try {
85
69
  const res = await fetch(url);
86
70
  if (res.ok) {
87
- console.log(`Volute daemon running on port ${port} (pid ${child.pid})`);
71
+ console.log(`Volute daemon running on ${hostname}:${port} (pid ${child.pid})`);
88
72
  console.log(`Logs: ${logFile}`);
89
73
  return;
90
74
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  spawnServer
4
- } from "./chunk-N4QN44LC.js";
4
+ } from "./chunk-MY74SUOL.js";
5
5
  import {
6
6
  composeTemplate,
7
7
  copyTemplateToDir,
@@ -17,7 +17,7 @@ import {
17
17
  import {
18
18
  addVariant,
19
19
  resolveAgent
20
- } from "./chunk-5YW4B7CG.js";
20
+ } from "./chunk-6UCG6MIX.js";
21
21
 
22
22
  // src/commands/upgrade.ts
23
23
  import { existsSync, mkdirSync, rmSync } from "fs";
@@ -189,14 +189,12 @@ async function installAndVerify(agentName, worktreeDir) {
189
189
  console.error("Server failed to start within timeout");
190
190
  process.exit(1);
191
191
  }
192
- const { actualPort, child } = result;
193
- const pid = child.pid ?? null;
192
+ const { actualPort } = result;
194
193
  addVariant(agentName, {
195
194
  name: VARIANT_NAME,
196
195
  branch: VARIANT_NAME,
197
196
  path: worktreeDir,
198
197
  port: actualPort,
199
- pid,
200
198
  created: (/* @__PURE__ */ new Date()).toISOString()
201
199
  });
202
200
  console.log(`
@@ -7,7 +7,7 @@ import {
7
7
  readVariants,
8
8
  resolveAgent,
9
9
  writeVariants
10
- } from "./chunk-5YW4B7CG.js";
10
+ } from "./chunk-6UCG6MIX.js";
11
11
 
12
12
  // src/commands/variants.ts
13
13
  async function run(args) {
@@ -39,7 +39,7 @@ async function run(args) {
39
39
  );
40
40
  const updated = results.map(({ status, ...v }) => ({
41
41
  ...v,
42
- pid: status === "dead" ? null : v.pid
42
+ running: status === "running"
43
43
  }));
44
44
  writeVariants(name, updated);
45
45
  if (json) {