volute 0.20.0 → 0.21.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 (92) hide show
  1. package/README.md +7 -7
  2. package/dist/{activity-events-OMXKXD5N.js → activity-events-3WHHCOBB.js} +3 -4
  3. package/dist/{archive-ZCFOSTKB.js → archive-4ZQYK5MN.js} +4 -2
  4. package/dist/auth-HM2RSPY7.js +37 -0
  5. package/dist/{channel-PUQKGSQM.js → channel-BOOMFULW.js} +2 -2
  6. package/dist/{chunk-IKMY5X76.js → chunk-5462YKWP.js} +12 -9
  7. package/dist/{chunk-PUVXOZ6T.js → chunk-7LPTHFIL.js} +63 -64
  8. package/dist/{chunk-UU7A7KLB.js → chunk-A4S7H6G6.js} +5 -7
  9. package/dist/chunk-AKPFNL7L.js +148 -0
  10. package/dist/{chunk-EBGCNDMM.js → chunk-B2CPS4QU.js} +128 -114
  11. package/dist/{chunk-FCDU5BFX.js → chunk-HFCBO2GL.js} +2 -2
  12. package/dist/{chunk-GZ7DW4YL.js → chunk-HGCDWKSP.js} +2 -2
  13. package/dist/{chunk-DYZGP3EW.js → chunk-IPJXU366.js} +1 -1
  14. package/dist/{chunk-7UFKREVW.js → chunk-J5A3DF2U.js} +2 -2
  15. package/dist/{chunk-WC6ZHVRL.js → chunk-KFI7TQJ6.js} +2 -2
  16. package/dist/{chunk-AW7P4EVV.js → chunk-KTJGZ7M7.js} +55 -7
  17. package/dist/{chunk-TIWH32HP.js → chunk-L3LHXZD7.js} +3 -3
  18. package/dist/{chunk-OGXOMR65.js → chunk-NWPT4ASZ.js} +1 -1
  19. package/dist/{chunk-FGSYHIS3.js → chunk-OGZYB5GL.js} +252 -296
  20. package/dist/{chunk-SCUDS4US.js → chunk-ON3FF5JA.js} +1 -1
  21. package/dist/{chunk-O6ASDHFO.js → chunk-PC6R6UUW.js} +4 -4
  22. package/dist/{chunk-VDWCHYTS.js → chunk-PHU4DEAJ.js} +1 -1
  23. package/dist/{chunk-7NO7EV5Z.js → chunk-Q7AITQ44.js} +2 -2
  24. package/dist/{chunk-32VR2EOH.js → chunk-QUJUKM4U.js} +2 -2
  25. package/dist/{chunk-NSE7VJQA.js → chunk-SGPEZ32F.js} +29 -1
  26. package/dist/{chunk-RHEGSQFJ.js → chunk-WSLPZF72.js} +1 -1
  27. package/dist/cli.js +57 -119
  28. package/dist/{connector-JBVNZ7VK.js → connector-PYT5UOTZ.js} +6 -6
  29. package/dist/connectors/discord.js +2 -2
  30. package/dist/connectors/slack.js +2 -2
  31. package/dist/connectors/telegram.js +2 -2
  32. package/dist/{create-HP4OVVHF.js → create-WIDA3M4C.js} +1 -1
  33. package/dist/{daemon-client-ITWUCNFO.js → daemon-client-ZHCDL4RS.js} +2 -2
  34. package/dist/{daemon-restart-KPSWNYTH.js → daemon-restart-BH67ZOTE.js} +6 -6
  35. package/dist/daemon.js +1538 -687
  36. package/dist/{delete-BSU7K3RY.js → delete-LOIANQGD.js} +1 -1
  37. package/dist/down-LIOQ5JDH.js +14 -0
  38. package/dist/{env-A3LMO777.js → env-4PHIHTF4.js} +2 -2
  39. package/dist/{export-6QBUOQGC.js → export-XD6PJBQP.js} +19 -8
  40. package/dist/{file-C57SK5DK.js → file-X4L5TTOL.js} +2 -2
  41. package/dist/{history-WNK3DFUM.js → history-HTEKRNID.js} +2 -2
  42. package/dist/{import-XEC34Y4Z.js → import-E433B4KG.js} +3 -3
  43. package/dist/{log-PPPZDVEF.js → log-SRO5Q6AD.js} +2 -2
  44. package/dist/{login-HNH3EUQV.js → login-UO6AOVEA.js} +4 -4
  45. package/dist/{logout-I5CB5UZS.js → logout-UKD5LA37.js} +2 -2
  46. package/dist/{logs-SF2IMJN4.js → logs-HNTNNBDW.js} +2 -2
  47. package/dist/{merge-33C237A4.js → merge-B6SYTGI7.js} +2 -2
  48. package/dist/{mind-Z7CKD6DG.js → mind-BIDOF65R.js} +27 -11
  49. package/dist/{mind-activity-tracker-624QLQLC.js → mind-activity-tracker-PGC3DBJ7.js} +4 -5
  50. package/dist/{mind-manager-3DMYKZPB.js → mind-manager-3V2NXX4I.js} +5 -6
  51. package/dist/{package-4NHAVUUI.js → package-HQR52XSG.js} +1 -1
  52. package/dist/{pages-4DGQT7ZA.js → pages-KQBR5TAZ.js} +6 -6
  53. package/dist/{publish-TAJUET4I.js → publish-OJ4QMXVZ.js} +6 -6
  54. package/dist/{pull-XAEWQJ47.js → pull-GRQAXM2E.js} +2 -2
  55. package/dist/{register-VSPCMHKX.js → register-U2UO6TC4.js} +5 -5
  56. package/dist/registry-D2BSQ2X5.js +42 -0
  57. package/dist/{restart-IQKMCK5M.js → restart-CIDAKGG2.js} +3 -6
  58. package/dist/{schedule-FFZG23IW.js → schedule-NLR3LZLY.js} +2 -2
  59. package/dist/{seed-J43YDKXG.js → seed-3H2MRREW.js} +2 -2
  60. package/dist/{send-KVIZIGCE.js → send-RP2TA7SG.js} +132 -36
  61. package/dist/{service-LUR7WDO7.js → service-TVNEORO7.js} +31 -13
  62. package/dist/{setup-52YRV7VP.js → setup-OZDYCKDI.js} +9 -34
  63. package/dist/{shared-KO35ZM44.js → shared-DCQ2UXOM.js} +4 -4
  64. package/dist/{skill-BCVNI6TV.js → skill-Q2Y6PQ3L.js} +2 -2
  65. package/dist/skills/orientation/SKILL.md +2 -2
  66. package/dist/skills/volute-mind/SKILL.md +5 -5
  67. package/dist/{sprout-QN7Y4VVO.js → sprout-6Z6C42YM.js} +34 -30
  68. package/dist/{start-I5JYB65M.js → start-JR6CUUWF.js} +3 -6
  69. package/dist/{status-D7E5HHBV.js → status-5XDGYHKP.js} +2 -2
  70. package/dist/{status-FU2PFVVF.js → status-LV34BG6G.js} +3 -3
  71. package/dist/{status-4ESFLGH4.js → status-Z7NAFMBI.js} +5 -5
  72. package/dist/{stop-NBVKEFQQ.js → stop-VKPGK25U.js} +2 -5
  73. package/dist/template-hash-BIMA4ILT.js +8 -0
  74. package/dist/{up-FS7CKM6V.js → up-7BGDMFRT.js} +5 -5
  75. package/dist/{update-FJIHDJKM.js → update-4WT7VWHW.js} +5 -5
  76. package/dist/{update-check-MWE5AH4U.js → update-check-F5Z3ALXX.js} +2 -2
  77. package/dist/{upgrade-AIT24B5I.js → upgrade-ZEC2GGFO.js} +1 -1
  78. package/dist/{variant-63ZWO2W7.js → variant-A4I7PHXS.js} +16 -24
  79. package/dist/version-notify-TFS2U5CF.js +173 -0
  80. package/dist/web-assets/assets/index-BR3gtK3E.css +1 -0
  81. package/dist/web-assets/assets/index-CWmrZRQd.js +64 -0
  82. package/dist/web-assets/index.html +2 -2
  83. package/package.json +1 -1
  84. package/dist/chunk-5XNT2472.js +0 -36
  85. package/dist/chunk-UJ6GHNR7.js +0 -675
  86. package/dist/db-C2CJ46ZU.js +0 -10
  87. package/dist/delivery-manager-CSG7LXA4.js +0 -16
  88. package/dist/down-ZY35KMHR.js +0 -14
  89. package/dist/schema-GFH6RV3W.js +0 -26
  90. package/dist/variants-JAGWGBXG.js +0 -26
  91. package/dist/web-assets/assets/index-CUZTZzaW.js +0 -64
  92. package/dist/web-assets/assets/index-adVuCkqy.css +0 -1
@@ -6,19 +6,15 @@ import {
6
6
  import {
7
7
  resolveMindName
8
8
  } from "./chunk-NAOW2CLO.js";
9
- import {
10
- getChannelDriver
11
- } from "./chunk-UJ6GHNR7.js";
12
9
  import {
13
10
  parseArgs
14
11
  } from "./chunk-D424ZQGI.js";
15
- import "./chunk-RHEGSQFJ.js";
16
12
  import {
17
13
  daemonFetch
18
- } from "./chunk-WC6ZHVRL.js";
14
+ } from "./chunk-KFI7TQJ6.js";
19
15
  import {
20
16
  findMind
21
- } from "./chunk-EBGCNDMM.js";
17
+ } from "./chunk-B2CPS4QU.js";
22
18
  import "./chunk-K3NQKI34.js";
23
19
 
24
20
  // src/commands/send.ts
@@ -94,16 +90,88 @@ function loadImage(imagePath) {
94
90
  const data = readFileSync(imagePath).toString("base64");
95
91
  return { media_type: mediaType, data };
96
92
  }
93
+ async function waitForResponse(mindName, conversationId, timeoutMs) {
94
+ const client = getClient();
95
+ const eventPath = urlOf(
96
+ client.api.minds[":name"].conversations[":id"].events.$url({
97
+ param: { name: mindName, id: conversationId }
98
+ })
99
+ );
100
+ const controller = new AbortController();
101
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
102
+ let response;
103
+ try {
104
+ response = await daemonFetch(eventPath, {
105
+ signal: controller.signal
106
+ });
107
+ } catch {
108
+ clearTimeout(timeout);
109
+ console.error("Could not connect to event stream. Is the mind running?");
110
+ process.exit(1);
111
+ }
112
+ if (!response.body) {
113
+ clearTimeout(timeout);
114
+ return;
115
+ }
116
+ const reader = response.body.getReader();
117
+ const decoder = new TextDecoder();
118
+ let buffer = "";
119
+ try {
120
+ while (true) {
121
+ const { done, value } = await reader.read();
122
+ if (done) break;
123
+ buffer += decoder.decode(value, { stream: true });
124
+ const chunks = buffer.split("\n\n");
125
+ buffer = chunks.pop();
126
+ for (const chunk of chunks) {
127
+ for (const line of chunk.split("\n")) {
128
+ if (!line.startsWith("data: ")) continue;
129
+ const data = line.slice(6).trim();
130
+ if (!data) continue;
131
+ let event;
132
+ try {
133
+ event = JSON.parse(data);
134
+ } catch {
135
+ continue;
136
+ }
137
+ if (event.type === "message" && event.senderName === mindName && event.content) {
138
+ const text = event.content.filter((b) => b.type === "text" && !!b.text).map((b) => b.text).join("");
139
+ if (text) {
140
+ process.stdout.write(`${text}
141
+ `);
142
+ }
143
+ return;
144
+ }
145
+ }
146
+ }
147
+ }
148
+ } catch (err) {
149
+ if (err.name === "AbortError") {
150
+ console.error(`(timed out after ${timeoutMs / 1e3}s)`);
151
+ } else {
152
+ throw err;
153
+ }
154
+ } finally {
155
+ clearTimeout(timeout);
156
+ reader.cancel().catch(() => {
157
+ });
158
+ }
159
+ }
97
160
  async function run(args) {
98
161
  const { positional, flags } = parseArgs(args, {
99
162
  mind: { type: "string" },
100
- image: { type: "string" }
163
+ image: { type: "string" },
164
+ wait: { type: "boolean" },
165
+ timeout: { type: "number" },
166
+ sender: { type: "string" }
101
167
  });
102
168
  const target = positional[0];
103
169
  const message = positional[1] ?? await readStdin();
104
170
  const images = flags.image ? [loadImage(flags.image)] : void 0;
105
171
  if (!target || !message && !images) {
106
- console.error('Usage: volute send <target> "<message>" [--mind <name>] [--image <path>]');
172
+ console.error(
173
+ 'Usage: volute send <target> "<message>" [--mind <name>] [--image <path>] [--wait]'
174
+ );
107
175
  console.error(' echo "message" | volute send <target> [--mind <name>]');
108
176
  console.error("");
109
177
  console.error("Examples:");
@@ -112,6 +180,7 @@ async function run(args) {
112
180
  console.error(' volute send discord:server/channel "hello"');
113
181
  console.error(' volute send @mind "check this out" --image photo.png');
114
182
  console.error(" volute send @mind --image photo.png");
183
+ console.error(' volute send @mind "hello" --wait');
115
184
  process.exit(1);
116
185
  }
117
186
  if (target === "system" || target === "@system") {
@@ -130,44 +199,55 @@ To reply to a person, use their username from the message prefix (e.g. volute se
130
199
  isDM: true
131
200
  };
132
201
  }
133
- const driver = getChannelDriver(parsed.platform);
134
- if (!driver) {
135
- console.error(`No driver for platform: ${parsed.platform}`);
136
- process.exit(1);
137
- }
202
+ const client = getClient();
203
+ let waitMindName;
138
204
  let channelUri = parsed.uri;
139
205
  if (parsed.isDM && parsed.platform === "volute") {
140
206
  const targetName = parsed.identifier.slice(1);
141
207
  const mindSelf = process.env.VOLUTE_MIND;
142
- const sender = mindSelf || userInfo().username;
143
- if (!driver.createConversation) {
144
- console.error("Volute driver does not support creating conversations");
145
- process.exit(1);
146
- }
208
+ const sender = flags.sender || mindSelf || userInfo().username;
209
+ waitMindName = findMind(targetName) ? targetName : void 0;
147
210
  const targetIsMind = !!findMind(targetName);
148
211
  const contextMind = mindSelf && !targetIsMind ? mindSelf : targetName;
149
212
  const participants = mindSelf && !targetIsMind ? [targetName] : [sender];
150
- const env = {
151
- VOLUTE_MIND: contextMind,
152
- VOLUTE_SENDER: sender
153
- };
154
- try {
155
- channelUri = await driver.createConversation(env, participants);
156
- } catch (err) {
157
- console.error(err instanceof Error ? err.message : String(err));
213
+ const createRes = await daemonFetch(
214
+ urlOf(client.api.minds[":name"].channels.create.$url({ param: { name: contextMind } })),
215
+ {
216
+ method: "POST",
217
+ headers: { "Content-Type": "application/json" },
218
+ body: JSON.stringify({ platform: "volute", participants, sender })
219
+ }
220
+ );
221
+ if (!createRes.ok) {
222
+ const data = await createRes.json().catch(() => ({ error: "Unknown error" }));
223
+ console.error(data.error);
158
224
  process.exit(1);
159
225
  }
160
- try {
161
- await driver.send(env, channelUri, message ?? "", images);
162
- console.log("Message sent.");
163
- } catch (err) {
164
- console.error(err instanceof Error ? err.message : String(err));
226
+ const { slug } = await createRes.json();
227
+ channelUri = slug;
228
+ const sendRes = await daemonFetch(
229
+ urlOf(client.api.minds[":name"].channels.send.$url({ param: { name: contextMind } })),
230
+ {
231
+ method: "POST",
232
+ headers: { "Content-Type": "application/json" },
233
+ body: JSON.stringify({
234
+ platform: "volute",
235
+ uri: channelUri,
236
+ message: message ?? "",
237
+ images,
238
+ sender
239
+ })
240
+ }
241
+ );
242
+ if (!sendRes.ok) {
243
+ const data = await sendRes.json().catch(() => ({ error: "Unknown error" }));
244
+ console.error(data.error);
165
245
  process.exit(1);
166
246
  }
247
+ if (!flags.wait) console.log("Message sent.");
167
248
  if (mindSelf) {
168
249
  try {
169
- const client = getClient();
170
- await daemonFetch(
250
+ const histRes = await daemonFetch(
171
251
  urlOf(client.api.minds[":name"].history.$url({ param: { name: mindSelf } })),
172
252
  {
173
253
  method: "POST",
@@ -175,13 +255,15 @@ To reply to a person, use their username from the message prefix (e.g. volute se
175
255
  body: JSON.stringify({ channel: parsed.uri, content: message ?? "" })
176
256
  }
177
257
  );
258
+ if (!histRes.ok) {
259
+ console.error(`Failed to persist to history: HTTP ${histRes.status}`);
260
+ }
178
261
  } catch (err) {
179
262
  console.error(`Failed to persist to history: ${err instanceof Error ? err.message : err}`);
180
263
  }
181
264
  }
182
265
  } else {
183
266
  const mindName = resolveMindName(flags);
184
- const client = getClient();
185
267
  const res = await daemonFetch(
186
268
  urlOf(client.api.minds[":name"].channels.send.$url({ param: { name: mindName } })),
187
269
  {
@@ -200,10 +282,10 @@ To reply to a person, use their username from the message prefix (e.g. volute se
200
282
  console.error(body.error);
201
283
  process.exit(1);
202
284
  }
203
- console.log("Message sent.");
285
+ if (!flags.wait) console.log("Message sent.");
204
286
  if (process.env.VOLUTE_MIND) {
205
287
  try {
206
- await daemonFetch(
288
+ const histRes = await daemonFetch(
207
289
  urlOf(client.api.minds[":name"].history.$url({ param: { name: mindName } })),
208
290
  {
209
291
  method: "POST",
@@ -211,11 +293,25 @@ To reply to a person, use their username from the message prefix (e.g. volute se
211
293
  body: JSON.stringify({ channel: channelUri, content: message ?? "" })
212
294
  }
213
295
  );
296
+ if (!histRes.ok) {
297
+ console.error(`Failed to persist to history: HTTP ${histRes.status}`);
298
+ }
214
299
  } catch (err) {
215
300
  console.error(`Failed to persist to history: ${err instanceof Error ? err.message : err}`);
216
301
  }
217
302
  }
218
303
  }
304
+ if (flags.wait && waitMindName) {
305
+ const conversationId = channelUri.startsWith("volute:") ? channelUri.slice(7) : void 0;
306
+ if (!conversationId) {
307
+ console.error("--wait requires a volute conversation (DM to a mind)");
308
+ process.exit(1);
309
+ }
310
+ await waitForResponse(waitMindName, conversationId, flags.timeout ?? 12e4);
311
+ } else if (flags.wait && !waitMindName) {
312
+ console.error("--wait is only supported when sending to a mind");
313
+ process.exit(1);
314
+ }
219
315
  }
220
316
  export {
221
317
  run
@@ -4,15 +4,15 @@ import {
4
4
  LAUNCHD_PLIST_PATH,
5
5
  SYSTEM_SERVICE_PATH,
6
6
  USER_SYSTEMD_UNIT
7
- } from "./chunk-32VR2EOH.js";
7
+ } from "./chunk-QUJUKM4U.js";
8
8
  import {
9
9
  parseArgs
10
10
  } from "./chunk-D424ZQGI.js";
11
11
  import {
12
12
  resolveVoluteBin
13
- } from "./chunk-DYZGP3EW.js";
14
- import "./chunk-OGXOMR65.js";
15
- import "./chunk-EBGCNDMM.js";
13
+ } from "./chunk-IPJXU366.js";
14
+ import "./chunk-NWPT4ASZ.js";
15
+ import "./chunk-B2CPS4QU.js";
16
16
  import "./chunk-K3NQKI34.js";
17
17
 
18
18
  // src/commands/service.ts
@@ -87,16 +87,20 @@ async function install(port, host) {
87
87
  console.log("Service installed and loaded. Volute daemon will start on login.");
88
88
  } else if (platform === "linux") {
89
89
  if (existsSync(SYSTEM_SERVICE_PATH)) {
90
- console.error("A system-level Volute service is already installed (via `volute setup`).");
90
+ console.error(
91
+ "A system-level Volute service is already installed (via `volute service install --system`)."
92
+ );
91
93
  console.error("Use `systemctl status volute` to check its status.");
92
- console.error("To remove it first: sudo volute setup uninstall");
94
+ console.error("To remove it first: sudo volute service uninstall --system");
93
95
  process.exit(1);
94
96
  }
95
97
  if (process.getuid?.() === 0) {
96
98
  console.error(
97
99
  "Error: `volute service install` uses systemd user services, which don't work as root."
98
100
  );
99
- console.error("Use `volute setup` instead to install a system-level service.");
101
+ console.error(
102
+ "Use `volute service install --system` instead to install a system-level service."
103
+ );
100
104
  process.exit(1);
101
105
  }
102
106
  const path = USER_SYSTEMD_UNIT;
@@ -199,24 +203,38 @@ async function status() {
199
203
  async function run(args) {
200
204
  const { positional, flags } = parseArgs(args, {
201
205
  port: { type: "number" },
202
- host: { type: "string" }
206
+ host: { type: "string" },
207
+ system: { type: "boolean" },
208
+ force: { type: "boolean" }
203
209
  });
204
210
  const subcommand = positional[0];
205
211
  switch (subcommand) {
206
212
  case "install":
207
- await install(flags.port, flags.host);
213
+ if (flags.system) {
214
+ const setup = await import("./setup-OZDYCKDI.js");
215
+ setup.install(flags.port, flags.host);
216
+ } else {
217
+ await install(flags.port, flags.host);
218
+ }
208
219
  break;
209
220
  case "uninstall":
210
- await uninstall();
221
+ if (flags.system) {
222
+ const setup = await import("./setup-OZDYCKDI.js");
223
+ setup.uninstall(!!flags.force);
224
+ } else {
225
+ await uninstall();
226
+ }
211
227
  break;
212
228
  case "status":
213
229
  await status();
214
230
  break;
215
231
  default:
216
232
  console.log(`Usage:
217
- volute service install [--port N] [--host H] Install as system service
218
- volute service uninstall Remove system service
219
- volute service status Check service status`);
233
+ volute service install [--port N] [--host H] Install as user-level service
234
+ volute service install --system [--port N] [--host H] Install system service with user isolation
235
+ volute service uninstall Remove user-level service
236
+ volute service uninstall --system [--force] Remove system service (--force removes data + users)
237
+ volute service status Check service status`);
220
238
  if (subcommand) {
221
239
  console.error(`
222
240
  Unknown subcommand: ${subcommand}`);
@@ -1,17 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SYSTEM_SERVICE_PATH
4
- } from "./chunk-32VR2EOH.js";
5
- import {
6
- parseArgs
7
- } from "./chunk-D424ZQGI.js";
4
+ } from "./chunk-QUJUKM4U.js";
8
5
  import {
9
6
  resolveVoluteBin
10
- } from "./chunk-DYZGP3EW.js";
7
+ } from "./chunk-IPJXU366.js";
11
8
  import {
12
9
  ensureVoluteGroup
13
- } from "./chunk-OGXOMR65.js";
14
- import "./chunk-EBGCNDMM.js";
10
+ } from "./chunk-NWPT4ASZ.js";
11
+ import "./chunk-B2CPS4QU.js";
15
12
  import "./chunk-K3NQKI34.js";
16
13
 
17
14
  // src/commands/setup.ts
@@ -80,11 +77,11 @@ function generateUnit(voluteBin, port, host) {
80
77
  function install(port, host) {
81
78
  if (host) validateHost(host);
82
79
  if (process.getuid?.() !== 0) {
83
- console.error("Error: volute setup must be run as root (use sudo).");
80
+ console.error("Error: volute service install --system must be run as root (use sudo).");
84
81
  process.exit(1);
85
82
  }
86
83
  if (process.platform !== "linux") {
87
- console.error("Error: volute setup is only supported on Linux.");
84
+ console.error("Error: volute service install --system is only supported on Linux.");
88
85
  console.error("On macOS, use `volute service install` for user-level service management.");
89
86
  process.exit(1);
90
87
  }
@@ -164,7 +161,7 @@ Volute daemon is running. Data directory: ${DATA_DIR}`);
164
161
  }
165
162
  function uninstall(force) {
166
163
  if (process.getuid?.() !== 0) {
167
- console.error("Error: volute setup uninstall must be run as root (use sudo).");
164
+ console.error("Error: volute service uninstall --system must be run as root (use sudo).");
168
165
  process.exit(1);
169
166
  }
170
167
  if (!existsSync(SYSTEM_SERVICE_PATH)) {
@@ -227,29 +224,7 @@ function uninstall(force) {
227
224
  console.log("Use --force to also remove data and system users.");
228
225
  }
229
226
  }
230
- async function run(args) {
231
- const { positional, flags } = parseArgs(args, {
232
- port: { type: "number" },
233
- host: { type: "string" },
234
- force: { type: "boolean" }
235
- });
236
- const subcommand = positional[0];
237
- switch (subcommand) {
238
- case "uninstall":
239
- uninstall(!!flags.force);
240
- break;
241
- case void 0:
242
- install(flags.port, flags.host);
243
- break;
244
- default:
245
- console.log(`Usage:
246
- volute setup [--port N] [--host H] Install system-level service with user isolation
247
- volute setup uninstall [--force] Remove service (--force removes data + users)`);
248
- console.error(`
249
- Unknown subcommand: ${subcommand}`);
250
- process.exit(1);
251
- }
252
- }
253
227
  export {
254
- run
228
+ install,
229
+ uninstall
255
230
  };
@@ -6,16 +6,16 @@ async function run(args) {
6
6
  const subcommand = args[0];
7
7
  switch (subcommand) {
8
8
  case "merge":
9
- await import("./merge-33C237A4.js").then((m) => m.run(args.slice(1)));
9
+ await import("./merge-B6SYTGI7.js").then((m) => m.run(args.slice(1)));
10
10
  break;
11
11
  case "pull":
12
- await import("./pull-XAEWQJ47.js").then((m) => m.run(args.slice(1)));
12
+ await import("./pull-GRQAXM2E.js").then((m) => m.run(args.slice(1)));
13
13
  break;
14
14
  case "log":
15
- await import("./log-PPPZDVEF.js").then((m) => m.run(args.slice(1)));
15
+ await import("./log-SRO5Q6AD.js").then((m) => m.run(args.slice(1)));
16
16
  break;
17
17
  case "status":
18
- await import("./status-D7E5HHBV.js").then((m) => m.run(args.slice(1)));
18
+ await import("./status-5XDGYHKP.js").then((m) => m.run(args.slice(1)));
19
19
  break;
20
20
  case "--help":
21
21
  case "-h":
@@ -11,8 +11,8 @@ import {
11
11
  } from "./chunk-D424ZQGI.js";
12
12
  import {
13
13
  daemonFetch
14
- } from "./chunk-WC6ZHVRL.js";
15
- import "./chunk-EBGCNDMM.js";
14
+ } from "./chunk-KFI7TQJ6.js";
15
+ import "./chunk-B2CPS4QU.js";
16
16
  import "./chunk-K3NQKI34.js";
17
17
 
18
18
  // src/commands/skill.ts
@@ -39,7 +39,7 @@ Once you have a sense of who you are:
39
39
 
40
40
  1. Write `SOUL.md` — your identity, personality, and perspective. This becomes your system prompt.
41
41
  2. Write `MEMORY.md` — any important context, preferences, or knowledge to start with.
42
- 3. Run `volute sprout` to complete the transformation.
42
+ 3. Run `volute mind sprout` to complete the transformation.
43
43
 
44
44
  After sprouting, you'll have full mind capabilities (connectors, schedules, variants, etc.).
45
45
 
@@ -48,7 +48,7 @@ After sprouting, you'll have full mind capabilities (connectors, schedules, vari
48
48
  | Command | Purpose |
49
49
  |---------|---------|
50
50
  | `volute send @<name> "msg"` | Send a message to another user |
51
- | `volute sprout` | Complete orientation and become a full mind |
51
+ | `volute mind sprout` | Complete orientation and become a full mind |
52
52
 
53
53
  ## Files
54
54
 
@@ -22,8 +22,8 @@ You manage yourself through the `volute` CLI. Your mind name is auto-detected vi
22
22
  | `volute variant merge <name> [--summary "..." --memory "..."]` | Merge a variant back |
23
23
  | `volute variant delete <name>` | Delete a variant without merging |
24
24
  | `volute mind upgrade [--template <name>] [--continue]` | Upgrade your server code |
25
- | `volute connector connect <type>` | Enable a connector (discord, slack, etc.) |
26
- | `volute connector disconnect <type>` | Disable a connector |
25
+ | `volute mind connect <type>` | Enable a connector (discord, slack, etc.) |
26
+ | `volute mind disconnect <type>` | Disable a connector |
27
27
  | `volute channel read <platform>:<id> [--limit N]` | Read channel history |
28
28
  | `volute send <platform>:<id> "msg"` | Send a message proactively (or pipe via stdin) |
29
29
  | `volute channel list [<platform>]` | List conversations on a platform (or all platforms) |
@@ -286,9 +286,9 @@ Your pages are served at `https://{system}.volute.systems/~{your-name}/`. Create
286
286
 
287
287
  Registration commands (usually run by the operator, not the mind):
288
288
  ```sh
289
- volute register --name <system-name>
290
- volute login --key <api-key>
291
- volute logout
289
+ volute auth register --name <system-name>
290
+ volute auth login --key <api-key>
291
+ volute auth logout
292
292
  ```
293
293
 
294
294
  ## Git Introspection
@@ -1,19 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- STANDARD_SKILLS,
4
- getSharedSkill,
5
- installSkill,
6
- uninstallSkill
7
- } from "./chunk-IKMY5X76.js";
3
+ STANDARD_SKILLS
4
+ } from "./chunk-5462YKWP.js";
5
+ import "./chunk-SGPEZ32F.js";
8
6
  import "./chunk-YUIHSKR6.js";
9
- import "./chunk-5XNT2472.js";
10
- import "./chunk-NSE7VJQA.js";
11
- import "./chunk-DYZGP3EW.js";
12
- import "./chunk-OGXOMR65.js";
7
+ import "./chunk-IPJXU366.js";
8
+ import "./chunk-NWPT4ASZ.js";
13
9
  import {
14
10
  findMind,
15
11
  mindDir
16
- } from "./chunk-EBGCNDMM.js";
12
+ } from "./chunk-B2CPS4QU.js";
17
13
  import "./chunk-K3NQKI34.js";
18
14
 
19
15
  // src/commands/sprout.ts
@@ -23,7 +19,7 @@ var ORIENTATION_MARKER = "You don't have a soul yet";
23
19
  async function run(_args) {
24
20
  const mindName = process.env.VOLUTE_MIND;
25
21
  if (!mindName) {
26
- console.error("volute sprout must be run by a mind (VOLUTE_MIND not set)");
22
+ console.error("volute mind sprout must be run by a mind (VOLUTE_MIND not set)");
27
23
  process.exit(1);
28
24
  }
29
25
  const entry = findMind(mindName);
@@ -53,44 +49,52 @@ async function run(_args) {
53
49
  console.error("Write your MEMORY.md before sprouting.");
54
50
  process.exit(1);
55
51
  }
52
+ const { daemonFetch } = await import("./daemon-client-ZHCDL4RS.js");
53
+ const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
54
+ const client = getClient();
56
55
  const failedSkills = [];
57
56
  for (const skillId of STANDARD_SKILLS) {
58
- const shared = await getSharedSkill(skillId);
59
- if (!shared) {
60
- console.error(`Shared skill not found: ${skillId} \u2014 run 'volute up' to sync built-in skills`);
61
- failedSkills.push(skillId);
62
- continue;
63
- }
64
57
  const skillDir = resolve(dir, "home", ".claude", "skills", skillId);
65
58
  if (!existsSync(skillDir)) {
66
- try {
67
- await installSkill(mindName, dir, skillId);
68
- } catch (err) {
69
- console.error(`Failed to install skill ${skillId}: ${err.message}`);
59
+ const installRes = await daemonFetch(
60
+ urlOf(client.api.minds[":name"].skills.install.$url({ param: { name: mindName } })),
61
+ {
62
+ method: "POST",
63
+ headers: { "Content-Type": "application/json" },
64
+ body: JSON.stringify({ skillId })
65
+ }
66
+ );
67
+ if (!installRes.ok) {
68
+ const data = await installRes.json().catch(() => ({ error: `HTTP ${installRes.status}` }));
69
+ console.error(`Failed to install skill ${skillId}: ${data.error}`);
70
70
  failedSkills.push(skillId);
71
71
  }
72
72
  }
73
73
  }
74
74
  const orientationDir = resolve(dir, "home", ".claude", "skills", "orientation");
75
75
  if (existsSync(orientationDir)) {
76
- try {
77
- await uninstallSkill(mindName, dir, "orientation");
78
- } catch (err) {
79
- console.error(`Failed to uninstall orientation skill: ${err.message}`);
76
+ const delRes = await daemonFetch(
77
+ urlOf(
78
+ client.api.minds[":name"].skills[":skill"].$url({
79
+ param: { name: mindName, skill: "orientation" }
80
+ })
81
+ ),
82
+ { method: "DELETE" }
83
+ );
84
+ if (!delRes.ok) {
85
+ const data = await delRes.json().catch(() => ({ error: `HTTP ${delRes.status}` }));
86
+ console.error(`Failed to uninstall orientation skill: ${data.error}`);
80
87
  }
81
88
  }
82
89
  if (failedSkills.length > 0) {
83
90
  console.error(`Warning: failed to install skills: ${failedSkills.join(", ")}`);
84
91
  }
85
- const { daemonFetch } = await import("./daemon-client-ITWUCNFO.js");
86
- const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
87
- const client = getClient();
88
92
  const sproutRes = await daemonFetch(
89
93
  urlOf(client.api.minds[":name"].sprout.$url({ param: { name: mindName } })),
90
94
  { method: "POST" }
91
95
  );
92
96
  if (!sproutRes.ok) {
93
- const data = await sproutRes.json();
97
+ const data = await sproutRes.json().catch(() => ({ error: `HTTP ${sproutRes.status}` }));
94
98
  console.error(data.error ?? "Failed to update stage");
95
99
  process.exit(1);
96
100
  }
@@ -103,7 +107,7 @@ async function run(_args) {
103
107
  }
104
108
  );
105
109
  if (!res.ok) {
106
- const data = await res.json();
110
+ const data = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
107
111
  console.error(data.error ?? "Failed to restart after sprouting");
108
112
  process.exit(1);
109
113
  }
@@ -5,10 +5,8 @@ import {
5
5
  } from "./chunk-4RQBJWQX.js";
6
6
  import {
7
7
  daemonFetch
8
- } from "./chunk-WC6ZHVRL.js";
9
- import {
10
- resolveMind
11
- } from "./chunk-EBGCNDMM.js";
8
+ } from "./chunk-KFI7TQJ6.js";
9
+ import "./chunk-B2CPS4QU.js";
12
10
  import "./chunk-K3NQKI34.js";
13
11
 
14
12
  // src/commands/start.ts
@@ -18,7 +16,6 @@ async function run(args) {
18
16
  console.error("Usage: volute mind start <name>");
19
17
  process.exit(1);
20
18
  }
21
- const { entry } = resolveMind(name);
22
19
  const client = getClient();
23
20
  const res = await daemonFetch(urlOf(client.api.minds[":name"].start.$url({ param: { name } })), {
24
21
  method: "POST"
@@ -28,7 +25,7 @@ async function run(args) {
28
25
  console.error(data.error || "Failed to start mind");
29
26
  process.exit(1);
30
27
  }
31
- console.log(`${name} started on port ${entry.port}`);
28
+ console.log(`${name} started on port ${data.port}`);
32
29
  }
33
30
  export {
34
31
  run
@@ -7,8 +7,8 @@ import {
7
7
  } from "./chunk-D424ZQGI.js";
8
8
  import {
9
9
  daemonFetch
10
- } from "./chunk-WC6ZHVRL.js";
11
- import "./chunk-EBGCNDMM.js";
10
+ } from "./chunk-KFI7TQJ6.js";
11
+ import "./chunk-B2CPS4QU.js";
12
12
  import "./chunk-K3NQKI34.js";
13
13
 
14
14
  // src/commands/shared/status.ts