volute 0.7.0 → 0.8.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 (77) hide show
  1. package/README.md +16 -14
  2. package/dist/{agent-7JF7MT73.js → agent-YORVRB6I.js} +10 -10
  3. package/dist/{agent-manager-IMZ7ZMBF.js → agent-manager-CMMH5KQQ.js} +4 -4
  4. package/dist/{channel-SMCNOIVQ.js → channel-RDGHBFSI.js} +16 -56
  5. package/dist/{chunk-JR4UXCTO.js → chunk-23L3MKEV.js} +1 -1
  6. package/dist/{chunk-5SKQ6J7T.js → chunk-5C5JWR2L.js} +15 -7
  7. package/dist/{chunk-UWHWAPGO.js → chunk-DP2DX4WV.js} +9 -1
  8. package/dist/{chunk-7ACDT3P2.js → chunk-ECPQXRLB.js} +1 -2
  9. package/dist/{chunk-LLJNZPCU.js → chunk-HZ5LTOEJ.js} +1 -1
  10. package/dist/{chunk-W76KWE23.js → chunk-IQXBMFZG.js} +6 -4
  11. package/dist/{chunk-ZZOOTYXK.js → chunk-LIPPXNIE.js} +60 -74
  12. package/dist/{chunk-BX7KI4S3.js → chunk-N6MLQ26B.js} +23 -96
  13. package/dist/{chunk-H7AMDUIA.js → chunk-QF22MYDJ.js} +6 -5
  14. package/dist/{chunk-NKXULRSW.js → chunk-RT6Y7AR3.js} +1 -1
  15. package/dist/{chunk-62X577Y7.js → chunk-W6TMWYU3.js} +126 -73
  16. package/dist/{chunk-EG45HBSJ.js → chunk-XSJ27WEM.js} +1 -1
  17. package/dist/cli.js +22 -20
  18. package/dist/{connector-Y7JPNROO.js → connector-ZP6MEFF4.js} +3 -3
  19. package/dist/connectors/discord.js +18 -59
  20. package/dist/connectors/slack.js +21 -38
  21. package/dist/connectors/telegram.js +31 -49
  22. package/dist/{create-G525LWEA.js → create-HGJHLABX.js} +22 -17
  23. package/dist/{daemon-client-442IV43D.js → daemon-client-54J3EIZD.js} +2 -2
  24. package/dist/{daemon-restart-4HVEKYFY.js → daemon-restart-CPBLMMRI.js} +3 -3
  25. package/dist/daemon.js +342 -402
  26. package/dist/{delete-UOU4AFQN.js → delete-45TGQC4N.js} +10 -5
  27. package/dist/{down-AZVH5TCD.js → down-O4EWZTVA.js} +2 -2
  28. package/dist/{env-7GLUJCWS.js → env-KMNYGVZ2.js} +7 -9
  29. package/dist/{history-H72ZUIBN.js → history-PXJVYLVY.js} +2 -2
  30. package/dist/{import-AVKQJDYC.js → import-CNEDF3TD.js} +6 -6
  31. package/dist/{logs-EDGK26AK.js → logs-TZB3MTLZ.js} +5 -4
  32. package/dist/{package-T2WAVJOU.js → package-RJSONENE.js} +1 -1
  33. package/dist/{restart-O4ETYLJF.js → restart-KVH3TK5N.js} +2 -2
  34. package/dist/{schedule-S6QVC5ON.js → schedule-HCUCBNQI.js} +2 -2
  35. package/dist/send-BNC2S5BY.js +162 -0
  36. package/dist/{service-HZNIDNJF.js → service-XCADRKIS.js} +8 -1
  37. package/dist/{setup-F4TCWVSP.js → setup-32KH5KLN.js} +85 -26
  38. package/dist/{start-VHQ7LNWM.js → start-QU73YTJW.js} +2 -2
  39. package/dist/{status-QAJWXKMZ.js → status-Q6ZQJXNI.js} +2 -2
  40. package/dist/{stop-CAGCT5NI.js → stop-N7U5N6A7.js} +2 -2
  41. package/dist/{up-RWZF6MLT.js → up-V6EAA7OZ.js} +2 -2
  42. package/dist/{update-F7QWV2LB.js → update-EUCZ7XGG.js} +3 -3
  43. package/dist/{update-check-B4J6IEQ4.js → update-check-SM4244SU.js} +2 -2
  44. package/dist/{upgrade-YXKPWDRU.js → upgrade-CZF6PN7Y.js} +4 -4
  45. package/dist/{variant-4Z6W3PP6.js → variant-RKXPN5DH.js} +20 -46
  46. package/dist/web-assets/assets/index-D-3zx6vs.js +307 -0
  47. package/dist/web-assets/index.html +1 -1
  48. package/drizzle/0004_magical_silverclaw.sql +1 -0
  49. package/drizzle/meta/0004_snapshot.json +410 -0
  50. package/drizzle/meta/_journal.json +7 -0
  51. package/package.json +1 -1
  52. package/templates/_base/_skills/volute-agent/SKILL.md +32 -16
  53. package/templates/_base/home/.config/routes.json +4 -8
  54. package/templates/_base/home/VOLUTE.md +16 -14
  55. package/templates/_base/src/lib/auto-reply.ts +38 -0
  56. package/templates/_base/src/lib/daemon-client.ts +53 -0
  57. package/templates/_base/src/lib/router.ts +66 -14
  58. package/templates/_base/src/lib/routing.ts +48 -9
  59. package/templates/_base/src/lib/startup.ts +1 -25
  60. package/templates/_base/src/lib/types.ts +2 -1
  61. package/templates/_base/src/lib/volute-server.ts +29 -14
  62. package/templates/agent-sdk/src/agent.ts +53 -111
  63. package/templates/agent-sdk/src/lib/content.ts +41 -0
  64. package/templates/agent-sdk/src/lib/session-store.ts +43 -0
  65. package/templates/agent-sdk/src/lib/stream-consumer.ts +66 -0
  66. package/templates/agent-sdk/src/server.ts +5 -13
  67. package/templates/pi/.init/AGENTS.md +5 -5
  68. package/templates/pi/src/agent.ts +32 -84
  69. package/templates/pi/src/lib/content.ts +15 -0
  70. package/templates/pi/src/lib/event-handler.ts +74 -0
  71. package/templates/pi/src/lib/resolve-model.ts +21 -0
  72. package/templates/pi/src/server.ts +3 -7
  73. package/dist/chunk-B3R6L2GW.js +0 -24
  74. package/dist/chunk-ZYGKG6VC.js +0 -22
  75. package/dist/message-SCOQDR3P.js +0 -32
  76. package/dist/send-G7PE4DOJ.js +0 -72
  77. package/dist/web-assets/assets/index-B1CqjUYD.js +0 -308
package/README.md CHANGED
@@ -23,7 +23,7 @@ volute agent create atlas
23
23
  volute agent start atlas
24
24
 
25
25
  # Talk to it
26
- volute message send atlas "hey, what can you do?"
26
+ volute send @atlas "hey, what can you do?"
27
27
  ```
28
28
 
29
29
  You now have a running AI agent with persistent memory, auto-committing file changes, and session resume across restarts. Open `http://localhost:4200` for the web dashboard.
@@ -58,10 +58,10 @@ volute agent delete atlas --force # also delete files
58
58
  ### Sending messages
59
59
 
60
60
  ```sh
61
- volute message send atlas "what's on your mind?"
61
+ volute send @atlas "what's on your mind?"
62
62
  ```
63
63
 
64
- Responses stream back to your terminal in real time. The agent knows which channel each message came from — CLI, web, Discord, or system — and routes its response back to the source.
64
+ The agent knows which channel each message came from — CLI, web, Discord, or system — and routes its response back to the source.
65
65
 
66
66
  ### Anatomy of an agent
67
67
 
@@ -95,7 +95,7 @@ This is the interesting part. Agents can fork themselves into isolated branches,
95
95
  volute variant create experiment --agent atlas
96
96
 
97
97
  # Talk to the variant directly
98
- volute message send atlas@experiment "try a different approach"
98
+ volute send @atlas@experiment "try a different approach"
99
99
 
100
100
  # List all variants
101
101
  volute variant list --agent atlas
@@ -144,7 +144,7 @@ Read from and write to connector channels directly:
144
144
 
145
145
  ```sh
146
146
  volute channel read discord:123456789 --agent atlas # recent messages
147
- volute channel send discord:123456789 "hello" --agent atlas # send a message
147
+ volute send discord:123456789 "hello" --agent atlas # send a message
148
148
  ```
149
149
 
150
150
  ## Schedules
@@ -152,12 +152,12 @@ volute channel send discord:123456789 "hello" --agent atlas # send a message
152
152
  Cron-based scheduled messages — daily check-ins, periodic tasks, whatever you need.
153
153
 
154
154
  ```sh
155
- volute schedule add atlas \
155
+ volute schedule add --agent atlas \
156
156
  --cron "0 9 * * *" \
157
157
  --message "good morning — write your daily log"
158
158
 
159
- volute schedule list atlas
160
- volute schedule remove atlas --id <schedule-id>
159
+ volute schedule list --agent atlas
160
+ volute schedule remove --agent atlas --id <schedule-id>
161
161
  ```
162
162
 
163
163
  ## Environment variables
@@ -191,7 +191,7 @@ volute agent upgrade atlas # creates an "upgrade" variant
191
191
  # resolve conflicts if needed, then:
192
192
  volute agent upgrade atlas --continue
193
193
  # test:
194
- volute message send atlas@upgrade "are you working?"
194
+ volute send @atlas@upgrade "are you working?"
195
195
  # merge:
196
196
  volute variant merge upgrade --agent atlas
197
197
  ```
@@ -219,7 +219,7 @@ Set the model via `home/.config/volute.json` in the agent directory, or the `VOL
219
219
 
220
220
  ```sh
221
221
  docker build -t volute .
222
- docker run -d -p 4200:4200 -v volute-data:/data volute
222
+ docker run -d -p 4200:4200 -v volute-data:/data -v volute-agents:/agents volute
223
223
  ```
224
224
 
225
225
  Or with docker-compose:
@@ -242,9 +242,11 @@ Or manually:
242
242
 
243
243
  ```sh
244
244
  npm install -g volute
245
- sudo volute setup --host 0.0.0.0
245
+ sudo $(which volute) setup --host 0.0.0.0
246
246
  ```
247
247
 
248
+ > **Note:** If you installed Node via nvm, `sudo volute` won't find the binary. Use `sudo $(which volute)` or `sudo su` then run `volute setup` directly.
249
+
248
250
  This installs a system-level systemd service with data at `/var/lib/volute` and user isolation enabled. Check status with `systemctl status volute`. Uninstall with `sudo volute setup uninstall --force`.
249
251
 
250
252
  ### Auto-start (user-level)
@@ -252,9 +254,9 @@ This installs a system-level systemd service with data at `/var/lib/volute` and
252
254
  On macOS or Linux (without root), use the user-level service installer:
253
255
 
254
256
  ```sh
255
- volute service install # auto-start on login
256
- volute service status # check status
257
- volute service uninstall # remove
257
+ volute service install [--port N] [--host H] # auto-start on login
258
+ volute service status # check status
259
+ volute service uninstall # remove
258
260
  ```
259
261
 
260
262
  ## Development
@@ -6,42 +6,42 @@ async function run(args) {
6
6
  const subcommand = args[0];
7
7
  switch (subcommand) {
8
8
  case "create":
9
- await import("./create-G525LWEA.js").then((m) => m.run(args.slice(1)));
9
+ await import("./create-HGJHLABX.js").then((m) => m.run(args.slice(1)));
10
10
  break;
11
11
  case "start":
12
- await import("./start-VHQ7LNWM.js").then((m) => m.run(args.slice(1)));
12
+ await import("./start-QU73YTJW.js").then((m) => m.run(args.slice(1)));
13
13
  break;
14
14
  case "stop":
15
- await import("./stop-CAGCT5NI.js").then((m) => m.run(args.slice(1)));
15
+ await import("./stop-N7U5N6A7.js").then((m) => m.run(args.slice(1)));
16
16
  break;
17
17
  case "restart":
18
- await import("./restart-O4ETYLJF.js").then((m) => m.run(args.slice(1)));
18
+ await import("./restart-KVH3TK5N.js").then((m) => m.run(args.slice(1)));
19
19
  break;
20
20
  case "delete":
21
- await import("./delete-UOU4AFQN.js").then((m) => m.run(args.slice(1)));
21
+ await import("./delete-45TGQC4N.js").then((m) => m.run(args.slice(1)));
22
22
  break;
23
23
  case "list":
24
- await import("./status-QAJWXKMZ.js").then((m) => m.run(args.slice(1)));
24
+ await import("./status-Q6ZQJXNI.js").then((m) => m.run(args.slice(1)));
25
25
  break;
26
26
  case "status": {
27
27
  const rest = args.slice(1);
28
28
  if (!rest[0] && process.env.VOLUTE_AGENT) {
29
29
  rest.unshift(process.env.VOLUTE_AGENT);
30
30
  }
31
- await import("./status-QAJWXKMZ.js").then((m) => m.run(rest));
31
+ await import("./status-Q6ZQJXNI.js").then((m) => m.run(rest));
32
32
  break;
33
33
  }
34
34
  case "logs": {
35
35
  const rest = args.slice(1);
36
36
  const logsArgs = transformAgentFlag(rest);
37
- await import("./logs-EDGK26AK.js").then((m) => m.run(logsArgs));
37
+ await import("./logs-TZB3MTLZ.js").then((m) => m.run(logsArgs));
38
38
  break;
39
39
  }
40
40
  case "upgrade":
41
- await import("./upgrade-YXKPWDRU.js").then((m) => m.run(args.slice(1)));
41
+ await import("./upgrade-CZF6PN7Y.js").then((m) => m.run(args.slice(1)));
42
42
  break;
43
43
  case "import":
44
- await import("./import-AVKQJDYC.js").then((m) => m.run(args.slice(1)));
44
+ await import("./import-CNEDF3TD.js").then((m) => m.run(args.slice(1)));
45
45
  break;
46
46
  case "--help":
47
47
  case "-h":
@@ -3,10 +3,10 @@ import {
3
3
  AgentManager,
4
4
  getAgentManager,
5
5
  initAgentManager
6
- } from "./chunk-62X577Y7.js";
7
- import "./chunk-H7AMDUIA.js";
8
- import "./chunk-W76KWE23.js";
9
- import "./chunk-UWHWAPGO.js";
6
+ } from "./chunk-W6TMWYU3.js";
7
+ import "./chunk-QF22MYDJ.js";
8
+ import "./chunk-IQXBMFZG.js";
9
+ import "./chunk-DP2DX4WV.js";
10
10
  import "./chunk-K3NQKI34.js";
11
11
  export {
12
12
  AgentManager,
@@ -1,29 +1,26 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- readStdin
4
- } from "./chunk-ZYGKG6VC.js";
5
2
  import {
6
3
  resolveAgentName
7
4
  } from "./chunk-AZEL2IEK.js";
8
5
  import {
9
6
  CHANNELS,
10
7
  getChannelDriver
11
- } from "./chunk-ZZOOTYXK.js";
8
+ } from "./chunk-LIPPXNIE.js";
12
9
  import {
13
10
  loadMergedEnv
14
- } from "./chunk-H7AMDUIA.js";
11
+ } from "./chunk-QF22MYDJ.js";
15
12
  import {
16
13
  writeChannelEntry
17
- } from "./chunk-BX7KI4S3.js";
14
+ } from "./chunk-N6MLQ26B.js";
18
15
  import {
19
16
  parseArgs
20
17
  } from "./chunk-D424ZQGI.js";
21
18
  import {
22
19
  daemonFetch
23
- } from "./chunk-JR4UXCTO.js";
20
+ } from "./chunk-23L3MKEV.js";
24
21
  import {
25
- resolveAgent
26
- } from "./chunk-UWHWAPGO.js";
22
+ agentDir
23
+ } from "./chunk-DP2DX4WV.js";
27
24
  import "./chunk-K3NQKI34.js";
28
25
 
29
26
  // src/commands/channel.ts
@@ -33,9 +30,6 @@ async function run(args) {
33
30
  case "read":
34
31
  await readChannel(args.slice(1));
35
32
  break;
36
- case "send":
37
- await sendChannel(args.slice(1));
38
- break;
39
33
  case "list":
40
34
  await listChannels(args.slice(1));
41
35
  break;
@@ -61,12 +55,10 @@ async function run(args) {
61
55
  function printUsage() {
62
56
  console.log(`Usage:
63
57
  volute channel read <channel-uri> [--limit N] [--agent <name>]
64
- volute channel send <channel-uri> "<message>" [--agent <name>]
65
58
  volute channel list [<platform>] [--agent <name>]
66
59
  volute channel users <platform> [--agent <name>]
67
60
  volute channel create <platform> --participants user1,user2 [--name "..."] [--agent <name>]
68
- volute channel typing <channel-uri> [--agent <name>]
69
- echo "message" | volute channel send <channel-uri> [--agent <name>]`);
61
+ volute channel typing <channel-uri> [--agent <name>]`);
70
62
  }
71
63
  async function readChannel(args) {
72
64
  const { positional, flags } = parseArgs(args, {
@@ -81,8 +73,8 @@ async function readChannel(args) {
81
73
  const agentName = resolveAgentName(flags);
82
74
  const { platform } = parseUri(uri);
83
75
  const driver = requireDriver(platform);
84
- const { dir } = resolveAgent(agentName);
85
- const env = { ...loadMergedEnv(dir), VOLUTE_AGENT: agentName, VOLUTE_AGENT_DIR: dir };
76
+ const dir = agentDir(agentName);
77
+ const env = { ...loadMergedEnv(agentName), VOLUTE_AGENT: agentName, VOLUTE_AGENT_DIR: dir };
86
78
  try {
87
79
  const limit = flags.limit ?? 20;
88
80
  const output = await driver.read(env, uri, limit);
@@ -92,46 +84,14 @@ async function readChannel(args) {
92
84
  process.exit(1);
93
85
  }
94
86
  }
95
- async function sendChannel(args) {
96
- const { positional, flags } = parseArgs(args, {
97
- agent: { type: "string" }
98
- });
99
- const uri = positional[0];
100
- const message = positional[1] ?? await readStdin();
101
- if (!uri || !message) {
102
- console.error('Usage: volute channel send <channel-uri> "<message>" [--agent <name>]');
103
- console.error(' echo "message" | volute channel send <channel-uri> [--agent <name>]');
104
- process.exit(1);
105
- }
106
- const agentName = resolveAgentName(flags);
107
- const { platform } = parseUri(uri);
108
- const driver = requireDriver(platform);
109
- const { dir } = resolveAgent(agentName);
110
- const env = { ...loadMergedEnv(dir), VOLUTE_AGENT: agentName, VOLUTE_AGENT_DIR: dir };
111
- try {
112
- await driver.send(env, uri, message);
113
- try {
114
- await daemonFetch(`/api/agents/${encodeURIComponent(agentName)}/history`, {
115
- method: "POST",
116
- headers: { "Content-Type": "application/json" },
117
- body: JSON.stringify({ channel: uri, content: message })
118
- });
119
- } catch (err) {
120
- console.error(`Failed to persist to history: ${err instanceof Error ? err.message : err}`);
121
- }
122
- } catch (err) {
123
- console.error(err instanceof Error ? err.message : String(err));
124
- process.exit(1);
125
- }
126
- }
127
87
  async function listChannels(args) {
128
88
  const { positional, flags } = parseArgs(args, {
129
89
  agent: { type: "string" }
130
90
  });
131
91
  const platform = positional[0];
132
92
  const agentName = resolveAgentName(flags);
133
- const { dir } = resolveAgent(agentName);
134
- const env = { ...loadMergedEnv(dir), VOLUTE_AGENT: agentName, VOLUTE_AGENT_DIR: dir };
93
+ const dir = agentDir(agentName);
94
+ const env = { ...loadMergedEnv(agentName), VOLUTE_AGENT: agentName, VOLUTE_AGENT_DIR: dir };
135
95
  const platforms = platform ? [platform] : Object.keys(CHANNELS);
136
96
  for (const p of platforms) {
137
97
  const driver = getChannelDriver(p);
@@ -139,7 +99,7 @@ async function listChannels(args) {
139
99
  try {
140
100
  const convs = await driver.listConversations(env);
141
101
  for (const conv of convs) {
142
- writeChannelEntry(dir, conv.id, {
102
+ writeChannelEntry(agentName, conv.id, {
143
103
  platformId: conv.platformId,
144
104
  platform: p,
145
105
  name: conv.name,
@@ -171,8 +131,8 @@ async function listUsers(args) {
171
131
  process.exit(1);
172
132
  }
173
133
  const agentName = resolveAgentName(flags);
174
- const { dir } = resolveAgent(agentName);
175
- const env = { ...loadMergedEnv(dir), VOLUTE_AGENT: agentName, VOLUTE_AGENT_DIR: dir };
134
+ const dir = agentDir(agentName);
135
+ const env = { ...loadMergedEnv(agentName), VOLUTE_AGENT: agentName, VOLUTE_AGENT_DIR: dir };
176
136
  try {
177
137
  const users = await driver.listUsers(env);
178
138
  for (const user of users) {
@@ -202,8 +162,8 @@ async function createChannel(args) {
202
162
  process.exit(1);
203
163
  }
204
164
  const agentName = resolveAgentName(flags);
205
- const { dir } = resolveAgent(agentName);
206
- const env = { ...loadMergedEnv(dir), VOLUTE_AGENT: agentName, VOLUTE_AGENT_DIR: dir };
165
+ const dir = agentDir(agentName);
166
+ const env = { ...loadMergedEnv(agentName), VOLUTE_AGENT: agentName, VOLUTE_AGENT_DIR: dir };
207
167
  const participants = flags.participants.split(",").map((s) => s.trim());
208
168
  try {
209
169
  const slug = await driver.createConversation(env, participants, flags.name);
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteHome
4
- } from "./chunk-UWHWAPGO.js";
4
+ } from "./chunk-DP2DX4WV.js";
5
5
 
6
6
  // src/lib/daemon-client.ts
7
7
  import { existsSync, readFileSync } from "fs";
@@ -4,14 +4,19 @@
4
4
  import { execFile as execFileCb, execFileSync, spawn } from "child_process";
5
5
  function exec(cmd, args, options) {
6
6
  return new Promise((resolve, reject) => {
7
- execFileCb(cmd, args, { cwd: options?.cwd }, (err, stdout, stderr) => {
8
- if (err) {
9
- err.stderr = stderr;
10
- reject(err);
11
- } else {
12
- resolve(stdout);
7
+ execFileCb(
8
+ cmd,
9
+ args,
10
+ { cwd: options?.cwd, uid: options?.uid, gid: options?.gid, env: options?.env },
11
+ (err, stdout, stderr) => {
12
+ if (err) {
13
+ err.stderr = stderr;
14
+ reject(err);
15
+ } else {
16
+ resolve(stdout);
17
+ }
13
18
  }
14
- });
19
+ );
15
20
  });
16
21
  }
17
22
  function resolveVoluteBin() {
@@ -25,6 +30,9 @@ function execInherit(cmd, args, options) {
25
30
  return new Promise((resolve, reject) => {
26
31
  const child = spawn(cmd, args, {
27
32
  cwd: options?.cwd,
33
+ uid: options?.uid,
34
+ gid: options?.gid,
35
+ env: options?.env,
28
36
  stdio: "inherit"
29
37
  });
30
38
  child.on("error", reject);
@@ -20,7 +20,8 @@ function voluteHome() {
20
20
  return resolve(homedir(), ".volute");
21
21
  }
22
22
  function ensureVoluteHome() {
23
- mkdirSync(resolve(voluteHome(), "agents"), { recursive: true });
23
+ const agentsBase = process.env.VOLUTE_AGENTS_DIR ?? resolve(voluteHome(), "agents");
24
+ mkdirSync(agentsBase, { recursive: true });
24
25
  }
25
26
  function readRegistry() {
26
27
  const registryPath = resolve(voluteHome(), "agents.json");
@@ -75,8 +76,14 @@ function findAgent(name) {
75
76
  return readRegistry().find((e) => e.name === name);
76
77
  }
77
78
  function agentDir(name) {
79
+ if (process.env.VOLUTE_AGENTS_DIR) {
80
+ return resolve(process.env.VOLUTE_AGENTS_DIR, name);
81
+ }
78
82
  return resolve(voluteHome(), "agents", name);
79
83
  }
84
+ function stateDir(name) {
85
+ return resolve(voluteHome(), "state", name);
86
+ }
80
87
  function nextPort() {
81
88
  const entries = readRegistry();
82
89
  const usedPorts = new Set(entries.map((e) => e.port));
@@ -232,6 +239,7 @@ export {
232
239
  setAgentRunning,
233
240
  findAgent,
234
241
  agentDir,
242
+ stateDir,
235
243
  nextPort,
236
244
  daemonLoopback,
237
245
  resolveAgent
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteHome
4
- } from "./chunk-UWHWAPGO.js";
4
+ } from "./chunk-DP2DX4WV.js";
5
5
  import {
6
6
  __export
7
7
  } from "./chunk-K3NQKI34.js";
@@ -60,7 +60,6 @@ var agentMessages = sqliteTable(
60
60
  id: integer("id").primaryKey({ autoIncrement: true }),
61
61
  agent: text("agent").notNull(),
62
62
  channel: text("channel").notNull(),
63
- role: text("role").notNull(),
64
63
  sender: text("sender"),
65
64
  content: text("content").notNull(),
66
65
  created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteHome
4
- } from "./chunk-UWHWAPGO.js";
4
+ } from "./chunk-DP2DX4WV.js";
5
5
 
6
6
  // src/commands/down.ts
7
7
  import { existsSync, readFileSync, unlinkSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  validateAgentName
4
- } from "./chunk-UWHWAPGO.js";
4
+ } from "./chunk-DP2DX4WV.js";
5
5
 
6
6
  // src/lib/isolation.ts
7
7
  import { execFile, execFileSync } from "child_process";
@@ -13,7 +13,7 @@ function isIsolationEnabled() {
13
13
  function agentUserName(agentName) {
14
14
  const err = validateAgentName(agentName);
15
15
  if (err) throw new Error(`Invalid agent name for isolation: ${err}`);
16
- const prefix = process.env.VOLUTE_USER_PREFIX ?? "volute-";
16
+ const prefix = process.env.VOLUTE_USER_PREFIX ?? "agent-";
17
17
  return `${prefix}${agentName}`;
18
18
  }
19
19
  function ensureVoluteGroup(opts) {
@@ -37,7 +37,7 @@ function createAgentUser(name) {
37
37
  } catch {
38
38
  }
39
39
  try {
40
- execFileSync("useradd", ["-r", "-M", "-g", "volute", "-s", "/usr/sbin/nologin", user], {
40
+ execFileSync("useradd", ["-r", "-M", "-G", "volute", "-s", "/usr/sbin/nologin", user], {
41
41
  stdio: "ignore"
42
42
  });
43
43
  } catch (err) {
@@ -68,14 +68,16 @@ async function applyIsolation(spawnOpts, agentName) {
68
68
  function chownAgentDir(dir, name) {
69
69
  if (!isIsolationEnabled()) return;
70
70
  const user = agentUserName(name);
71
- execFileSync("chown", ["-R", `${user}:volute`, dir]);
71
+ execFileSync("chown", ["-R", `${user}:${user}`, dir]);
72
72
  execFileSync("chmod", ["700", dir]);
73
73
  }
74
74
 
75
75
  export {
76
+ isIsolationEnabled,
76
77
  ensureVoluteGroup,
77
78
  createAgentUser,
78
79
  deleteAgentUser,
80
+ getAgentUserIds,
79
81
  applyIsolation,
80
82
  chownAgentDir
81
83
  };