volute 0.3.0 → 0.4.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 (54) hide show
  1. package/README.md +7 -7
  2. package/dist/{agent-manager-2LU6KULR.js → agent-manager-AUCKMGPR.js} +4 -4
  3. package/dist/{channel-H7N4SGR2.js → channel-DQ6UY7QB.js} +17 -40
  4. package/dist/{chunk-RALYNMHR.js → chunk-3C2XR4IY.js} +1 -1
  5. package/dist/chunk-5OCWMTVS.js +152 -0
  6. package/dist/{chunk-YEIHRP2J.js → chunk-DNOXHLE5.js} +1 -1
  7. package/dist/{chunk-IPIPLGME.js → chunk-I6OHXCMV.js} +4 -4
  8. package/dist/chunk-MXUCNIBG.js +168 -0
  9. package/dist/{chunk-DEUAVGSA.js → chunk-SOZA2TLP.js} +1 -1
  10. package/dist/{chunk-VVD3XO3E.js → chunk-YGFIWIOF.js} +1 -1
  11. package/dist/{chunk-N4YNKR3Q.js → chunk-ZHCE4DPY.js} +20 -0
  12. package/dist/cli.js +36 -24
  13. package/dist/connector-DKDJTLYZ.js +152 -0
  14. package/dist/connectors/discord.js +102 -158
  15. package/dist/connectors/slack.js +170 -0
  16. package/dist/connectors/telegram.js +156 -0
  17. package/dist/{create-RSWWMGKT.js → create-ILVOG75A.js} +5 -5
  18. package/dist/{daemon-client-27KMQQKX.js → daemon-client-XR24PUJF.js} +2 -2
  19. package/dist/daemon.js +271 -151
  20. package/dist/{delete-4ERL2QHH.js → delete-55MXCEY5.js} +5 -5
  21. package/dist/{down-HRC4MQCT.js → down-3OB6UVAJ.js} +1 -1
  22. package/dist/{env-DBWDTIP6.js → env-JB27UAC3.js} +2 -2
  23. package/dist/{history-W7BD2H74.js → history-BKG74I43.js} +4 -4
  24. package/dist/{import-6HTSSDFW.js → import-4CI2ZUTJ.js} +17 -2
  25. package/dist/{logs-NHWGHNBF.js → logs-NXFFGUKY.js} +1 -1
  26. package/dist/package-Z2SFO2SV.js +89 -0
  27. package/dist/{schedule-DKZ2E2CL.js → schedule-A35SH4HT.js} +4 -4
  28. package/dist/{send-5LEJXPYV.js → send-3U6OTKG7.js} +8 -4
  29. package/dist/{setup-ZMNTOJAV.js → setup-2FDVN7OF.js} +4 -4
  30. package/dist/{start-2BSXX6BS.js → start-LDPMCMYT.js} +2 -2
  31. package/dist/{status-N23CV27T.js → status-MVSQG54T.js} +2 -2
  32. package/dist/{stop-DSKBIJ2D.js → stop-5PZTZCLL.js} +2 -2
  33. package/dist/{up-4UGID4DM.js → up-F7TMTLRE.js} +1 -1
  34. package/dist/{upgrade-BGFVRCVP.js → upgrade-6ZW2RD64.js} +32 -19
  35. package/dist/{variant-JPLJTS2P.js → variant-T64BKARF.js} +130 -18
  36. package/dist/web-assets/assets/{index-BC5eSqbY.js → index-NS621maO.js} +23 -23
  37. package/dist/web-assets/index.html +1 -1
  38. package/package.json +3 -1
  39. package/templates/_base/_skills/volute-agent/SKILL.md +5 -4
  40. package/templates/_base/home/VOLUTE.md +18 -6
  41. package/templates/_base/src/lib/file-handler.ts +46 -0
  42. package/templates/_base/src/lib/router.ts +180 -0
  43. package/templates/_base/src/lib/routing.ts +100 -0
  44. package/templates/_base/src/lib/types.ts +13 -2
  45. package/templates/_base/src/lib/volute-server.ts +20 -48
  46. package/templates/agent-sdk/src/agent.ts +268 -82
  47. package/templates/agent-sdk/src/server.ts +12 -3
  48. package/templates/pi/src/agent.ts +277 -58
  49. package/templates/pi/src/server.ts +15 -4
  50. package/dist/chunk-MY74SUOL.js +0 -81
  51. package/dist/connector-6LWB5PRU.js +0 -96
  52. package/templates/_base/src/lib/sessions.ts +0 -71
  53. package/templates/agent-sdk/src/lib/agent-sessions.ts +0 -204
  54. package/templates/pi/src/lib/agent-sessions.ts +0 -210
package/README.md CHANGED
@@ -121,7 +121,7 @@ Agents have access to the `volute` CLI from their working directory, so they can
121
121
 
122
122
  ## Connectors
123
123
 
124
- Connect agents to external services.
124
+ Connect agents to external services. Connectors are generic — any connector type that has an implementation (built-in, shared, or agent-specific) can be enabled.
125
125
 
126
126
  ### Discord
127
127
 
@@ -130,21 +130,21 @@ Connect agents to external services.
130
130
  volute env set DISCORD_TOKEN <your-bot-token>
131
131
 
132
132
  # Connect
133
- volute connect discord atlas
133
+ volute connector connect discord --agent atlas
134
134
 
135
135
  # Disconnect
136
- volute disconnect discord atlas
136
+ volute connector disconnect discord --agent atlas
137
137
  ```
138
138
 
139
- The agent receives Discord messages and responds in-channel. Tool calls are filtered out — Discord users see clean text responses.
139
+ The agent receives Discord messages and responds in-channel. Tool calls are filtered out — connector users see clean text responses.
140
140
 
141
141
  ### Channel commands
142
142
 
143
- Read from and write to channels directly:
143
+ Read from and write to connector channels directly:
144
144
 
145
145
  ```sh
146
- volute channel read discord:123456789 # recent messages
147
- volute channel send discord:123456789 "hello" # send a message
146
+ volute channel read discord:123456789 --agent atlas # recent messages
147
+ volute channel send discord:123456789 "hello" --agent atlas # send a message
148
148
  ```
149
149
 
150
150
  ## Schedules
@@ -3,10 +3,10 @@ import {
3
3
  AgentManager,
4
4
  getAgentManager,
5
5
  initAgentManager
6
- } from "./chunk-IPIPLGME.js";
7
- import "./chunk-YEIHRP2J.js";
8
- import "./chunk-DEUAVGSA.js";
9
- import "./chunk-RALYNMHR.js";
6
+ } from "./chunk-I6OHXCMV.js";
7
+ import "./chunk-DNOXHLE5.js";
8
+ import "./chunk-SOZA2TLP.js";
9
+ import "./chunk-3C2XR4IY.js";
10
10
  import "./chunk-K3NQKI34.js";
11
11
  export {
12
12
  AgentManager,
@@ -1,44 +1,21 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- loadMergedEnv
4
- } from "./chunk-YEIHRP2J.js";
5
2
  import {
6
3
  resolveAgentName
7
4
  } from "./chunk-VRVVQIYY.js";
5
+ import {
6
+ getChannelDriver
7
+ } from "./chunk-5OCWMTVS.js";
8
+ import {
9
+ loadMergedEnv
10
+ } from "./chunk-DNOXHLE5.js";
8
11
  import {
9
12
  parseArgs
10
13
  } from "./chunk-D424ZQGI.js";
11
14
  import {
12
15
  resolveAgent
13
- } from "./chunk-RALYNMHR.js";
16
+ } from "./chunk-3C2XR4IY.js";
14
17
  import "./chunk-K3NQKI34.js";
15
18
 
16
- // src/lib/channels/discord.ts
17
- var API_BASE = "https://discord.com/api/v10";
18
- async function read(token, channelId, limit) {
19
- const res = await fetch(`${API_BASE}/channels/${channelId}/messages?limit=${limit}`, {
20
- headers: { Authorization: `Bot ${token}` }
21
- });
22
- if (!res.ok) {
23
- throw new Error(`Discord API error: ${res.status} ${res.statusText}`);
24
- }
25
- const messages = await res.json();
26
- return messages.reverse().map((m) => `${m.author.username}: ${m.content}`).join("\n");
27
- }
28
- async function send(token, channelId, message) {
29
- const res = await fetch(`${API_BASE}/channels/${channelId}/messages`, {
30
- method: "POST",
31
- headers: {
32
- Authorization: `Bot ${token}`,
33
- "Content-Type": "application/json"
34
- },
35
- body: JSON.stringify({ content: message })
36
- });
37
- if (!res.ok) {
38
- throw new Error(`Discord API error: ${res.status} ${res.statusText}`);
39
- }
40
- }
41
-
42
19
  // src/commands/channel.ts
43
20
  async function run(args) {
44
21
  const { positional, flags } = parseArgs(args, {
@@ -62,26 +39,26 @@ async function run(args) {
62
39
  }
63
40
  const platform = uri.slice(0, colonIdx);
64
41
  const channelId = uri.slice(colonIdx + 1);
42
+ const driver = getChannelDriver(platform);
43
+ if (!driver) {
44
+ console.error(`No channel driver for platform: ${platform}`);
45
+ process.exit(1);
46
+ }
65
47
  const { dir } = resolveAgent(agentName);
66
48
  const env = loadMergedEnv(dir);
67
- if (platform === "discord") {
68
- const token = env.DISCORD_TOKEN;
69
- if (!token) {
70
- console.error("DISCORD_TOKEN not set. Run: volute env set DISCORD_TOKEN <token>");
71
- process.exit(1);
72
- }
49
+ try {
73
50
  if (subcommand === "read") {
74
51
  const limit = flags.limit ?? 20;
75
- const output = await read(token, channelId, limit);
52
+ const output = await driver.read(env, channelId, limit);
76
53
  console.log(output);
77
54
  } else if (subcommand === "send") {
78
- await send(token, channelId, message);
55
+ await driver.send(env, channelId, message);
79
56
  } else {
80
57
  console.error(`Unknown subcommand: ${subcommand}`);
81
58
  process.exit(1);
82
59
  }
83
- } else {
84
- console.error(`Unsupported platform: ${platform}`);
60
+ } catch (err) {
61
+ console.error(err instanceof Error ? err.message : String(err));
85
62
  process.exit(1);
86
63
  }
87
64
  }
@@ -81,7 +81,7 @@ function removeAllVariants(agentName) {
81
81
  }
82
82
  async function checkHealth(port) {
83
83
  try {
84
- const res = await fetch(`http://localhost:${port}/health`, {
84
+ const res = await fetch(`http://127.0.0.1:${port}/health`, {
85
85
  signal: AbortSignal.timeout(2e3)
86
86
  });
87
87
  if (!res.ok) return { ok: false };
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ __export
4
+ } from "./chunk-K3NQKI34.js";
5
+
6
+ // src/lib/channels/discord.ts
7
+ var discord_exports = {};
8
+ __export(discord_exports, {
9
+ read: () => read,
10
+ send: () => send
11
+ });
12
+ var API_BASE = "https://discord.com/api/v10";
13
+ function requireToken(env) {
14
+ const token = env.DISCORD_TOKEN;
15
+ if (!token) throw new Error("DISCORD_TOKEN not set");
16
+ return token;
17
+ }
18
+ async function read(env, channelId, limit) {
19
+ const token = requireToken(env);
20
+ const res = await fetch(`${API_BASE}/channels/${channelId}/messages?limit=${limit}`, {
21
+ headers: { Authorization: `Bot ${token}` }
22
+ });
23
+ if (!res.ok) {
24
+ throw new Error(`Discord API error: ${res.status} ${res.statusText}`);
25
+ }
26
+ const messages = await res.json();
27
+ return messages.reverse().map((m) => `${m.author.username}: ${m.content}`).join("\n");
28
+ }
29
+ async function send(env, channelId, message) {
30
+ const token = requireToken(env);
31
+ const res = await fetch(`${API_BASE}/channels/${channelId}/messages`, {
32
+ method: "POST",
33
+ headers: {
34
+ Authorization: `Bot ${token}`,
35
+ "Content-Type": "application/json"
36
+ },
37
+ body: JSON.stringify({ content: message })
38
+ });
39
+ if (!res.ok) {
40
+ throw new Error(`Discord API error: ${res.status} ${res.statusText}`);
41
+ }
42
+ }
43
+
44
+ // src/lib/channels/slack.ts
45
+ var slack_exports = {};
46
+ __export(slack_exports, {
47
+ read: () => read2,
48
+ send: () => send2
49
+ });
50
+ var API_BASE2 = "https://slack.com/api";
51
+ function requireToken2(env) {
52
+ const token = env.SLACK_BOT_TOKEN;
53
+ if (!token) throw new Error("SLACK_BOT_TOKEN not set");
54
+ return token;
55
+ }
56
+ async function slackApi(token, method, body) {
57
+ const res = await fetch(`${API_BASE2}/${method}`, {
58
+ method: "POST",
59
+ headers: {
60
+ Authorization: `Bearer ${token}`,
61
+ "Content-Type": "application/json"
62
+ },
63
+ body: JSON.stringify(body)
64
+ });
65
+ if (!res.ok) {
66
+ throw new Error(`Slack API HTTP error: ${res.status} ${res.statusText}`);
67
+ }
68
+ const data = await res.json();
69
+ if (!data.ok) {
70
+ throw new Error(`Slack API error: ${data.error}`);
71
+ }
72
+ return data;
73
+ }
74
+ async function read2(env, channelId, limit) {
75
+ const token = requireToken2(env);
76
+ const data = await slackApi(token, "conversations.history", {
77
+ channel: channelId,
78
+ limit
79
+ });
80
+ return data.messages.reverse().map((m) => `${m.user ?? m.bot_id ?? "unknown"}: ${m.text}`).join("\n");
81
+ }
82
+ async function send2(env, channelId, message) {
83
+ const token = requireToken2(env);
84
+ await slackApi(token, "chat.postMessage", {
85
+ channel: channelId,
86
+ text: message
87
+ });
88
+ }
89
+
90
+ // src/lib/channels/telegram.ts
91
+ var telegram_exports = {};
92
+ __export(telegram_exports, {
93
+ read: () => read3,
94
+ send: () => send3
95
+ });
96
+ var API_BASE3 = "https://api.telegram.org";
97
+ function requireToken3(env) {
98
+ const token = env.TELEGRAM_BOT_TOKEN;
99
+ if (!token) throw new Error("TELEGRAM_BOT_TOKEN not set");
100
+ return token;
101
+ }
102
+ async function read3(_env, _channelId, _limit) {
103
+ throw new Error(
104
+ "Telegram Bot API does not support reading chat history. Use volute channel send instead."
105
+ );
106
+ }
107
+ async function send3(env, chatId, message) {
108
+ const token = requireToken3(env);
109
+ const res = await fetch(`${API_BASE3}/bot${token}/sendMessage`, {
110
+ method: "POST",
111
+ headers: { "Content-Type": "application/json" },
112
+ body: JSON.stringify({ chat_id: chatId, text: message })
113
+ });
114
+ if (!res.ok) {
115
+ const body = await res.text().catch(() => "");
116
+ throw new Error(`Telegram API error: ${res.status} ${body}`);
117
+ }
118
+ }
119
+
120
+ // src/lib/channels.ts
121
+ var CHANNELS = {
122
+ web: { name: "web", displayName: "Web UI", showToolCalls: true },
123
+ discord: {
124
+ name: "discord",
125
+ displayName: "Discord",
126
+ showToolCalls: false,
127
+ driver: discord_exports
128
+ },
129
+ slack: {
130
+ name: "slack",
131
+ displayName: "Slack",
132
+ showToolCalls: false,
133
+ driver: slack_exports
134
+ },
135
+ telegram: {
136
+ name: "telegram",
137
+ displayName: "Telegram",
138
+ showToolCalls: false,
139
+ driver: telegram_exports
140
+ },
141
+ cli: { name: "cli", displayName: "CLI", showToolCalls: true },
142
+ agent: { name: "agent", displayName: "Agent", showToolCalls: true },
143
+ system: { name: "system", displayName: "System", showToolCalls: false }
144
+ };
145
+ function getChannelDriver(platform) {
146
+ return CHANNELS[platform]?.driver ?? null;
147
+ }
148
+
149
+ export {
150
+ CHANNELS,
151
+ getChannelDriver
152
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteHome
4
- } from "./chunk-RALYNMHR.js";
4
+ } from "./chunk-3C2XR4IY.js";
5
5
 
6
6
  // src/lib/env.ts
7
7
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  loadMergedEnv
4
- } from "./chunk-YEIHRP2J.js";
4
+ } from "./chunk-DNOXHLE5.js";
5
5
  import {
6
6
  applyIsolation
7
- } from "./chunk-DEUAVGSA.js";
7
+ } from "./chunk-SOZA2TLP.js";
8
8
  import {
9
9
  agentDir,
10
10
  findAgent,
@@ -13,7 +13,7 @@ import {
13
13
  setVariantRunning,
14
14
  validateBranchName,
15
15
  voluteHome
16
- } from "./chunk-RALYNMHR.js";
16
+ } from "./chunk-3C2XR4IY.js";
17
17
 
18
18
  // src/lib/agent-manager.ts
19
19
  import { execFile, spawn } from "child_process";
@@ -89,7 +89,7 @@ var AgentManager = class {
89
89
  const { dir, isVariant, baseName, variantName } = target;
90
90
  const port = target.port;
91
91
  try {
92
- const res = await fetch(`http://localhost:${port}/health`);
92
+ const res = await fetch(`http://127.0.0.1:${port}/health`);
93
93
  if (res.ok) {
94
94
  console.error(`[daemon] killing orphan process on port ${port}`);
95
95
  await killProcessOnPort(port);
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/connectors/sdk.ts
4
+ import { existsSync, readFileSync } from "fs";
5
+ import { resolve } from "path";
6
+ function loadEnv() {
7
+ const agentPort = process.env.VOLUTE_AGENT_PORT;
8
+ const agentName = process.env.VOLUTE_AGENT_NAME;
9
+ if (!agentPort || !agentName) {
10
+ console.error("Missing required env vars: VOLUTE_AGENT_PORT, VOLUTE_AGENT_NAME");
11
+ process.exit(1);
12
+ }
13
+ const agentDir = process.env.VOLUTE_AGENT_DIR;
14
+ const daemonUrl = process.env.VOLUTE_DAEMON_URL;
15
+ const daemonToken = process.env.VOLUTE_DAEMON_TOKEN;
16
+ const baseUrl = daemonUrl ? `${daemonUrl}/api/agents/${encodeURIComponent(agentName)}` : `http://127.0.0.1:${agentPort}`;
17
+ return { agentPort, agentName, agentDir, baseUrl, daemonUrl, daemonToken };
18
+ }
19
+ function loadFollowedChannels(env, platform) {
20
+ if (!env.agentDir) return [];
21
+ const configPath = resolve(env.agentDir, "home/.config/volute.json");
22
+ if (!existsSync(configPath)) return [];
23
+ try {
24
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
25
+ const platformConfig = config[platform];
26
+ return platformConfig?.channels ?? platformConfig?.chats ?? [];
27
+ } catch (err) {
28
+ console.warn(`Failed to load agent config: ${err}`);
29
+ return [];
30
+ }
31
+ }
32
+ function splitMessage(text, maxLength) {
33
+ const chunks = [];
34
+ while (text.length > maxLength) {
35
+ let splitAt = text.lastIndexOf("\n", maxLength);
36
+ if (splitAt < maxLength / 2) splitAt = maxLength;
37
+ chunks.push(text.slice(0, splitAt));
38
+ text = text.slice(splitAt).replace(/^\n/, "");
39
+ }
40
+ if (text) chunks.push(text);
41
+ return chunks;
42
+ }
43
+ async function* readNdjson(body) {
44
+ const reader = body.getReader();
45
+ const decoder = new TextDecoder();
46
+ let buffer = "";
47
+ try {
48
+ while (true) {
49
+ const { done, value } = await reader.read();
50
+ if (done) break;
51
+ buffer += decoder.decode(value, { stream: true });
52
+ const lines = buffer.split("\n");
53
+ buffer = lines.pop() || "";
54
+ for (const line of lines) {
55
+ if (!line.trim()) continue;
56
+ try {
57
+ yield JSON.parse(line);
58
+ } catch {
59
+ console.warn(`ndjson: skipping invalid line: ${line.slice(0, 100)}`);
60
+ }
61
+ }
62
+ }
63
+ if (buffer.trim()) {
64
+ try {
65
+ yield JSON.parse(buffer);
66
+ } catch {
67
+ console.warn(`ndjson: skipping invalid line: ${buffer.slice(0, 100)}`);
68
+ }
69
+ }
70
+ } finally {
71
+ reader.releaseLock();
72
+ }
73
+ }
74
+ function getHeaders(env) {
75
+ const headers = { "Content-Type": "application/json" };
76
+ if (env.daemonUrl && env.daemonToken) {
77
+ headers.Authorization = `Bearer ${env.daemonToken}`;
78
+ headers.Origin = env.daemonUrl;
79
+ }
80
+ return headers;
81
+ }
82
+ function onShutdown(cleanup) {
83
+ const handler = () => {
84
+ Promise.resolve(cleanup()).then(
85
+ () => process.exit(0),
86
+ (err) => {
87
+ console.error(`Shutdown error: ${err}`);
88
+ process.exit(1);
89
+ }
90
+ );
91
+ };
92
+ process.on("SIGINT", handler);
93
+ process.on("SIGTERM", handler);
94
+ }
95
+ async function fireAndForget(env, payload) {
96
+ try {
97
+ const res = await fetch(`${env.baseUrl}/message`, {
98
+ method: "POST",
99
+ headers: getHeaders(env),
100
+ body: JSON.stringify(payload)
101
+ });
102
+ if (!res.ok) {
103
+ console.error(`fireAndForget: agent returned ${res.status}`);
104
+ }
105
+ if (res.body) {
106
+ const reader = res.body.getReader();
107
+ while (!(await reader.read()).done) {
108
+ }
109
+ }
110
+ } catch (err) {
111
+ console.error(`Failed to forward message: ${err}`);
112
+ }
113
+ }
114
+ async function handleAgentMessage(env, payload, handlers) {
115
+ try {
116
+ const res = await fetch(`${env.baseUrl}/message`, {
117
+ method: "POST",
118
+ headers: getHeaders(env),
119
+ body: JSON.stringify(payload)
120
+ });
121
+ if (!res.ok) {
122
+ const body = await res.text().catch(() => "");
123
+ console.error(`Agent returned ${res.status}: ${body}`);
124
+ await handlers.onError(`Error: agent returned ${res.status}`);
125
+ return;
126
+ }
127
+ if (!res.body) {
128
+ await handlers.onError("Error: no response from agent");
129
+ return;
130
+ }
131
+ let accumulated = "";
132
+ const pendingImages = [];
133
+ for await (const event of readNdjson(res.body)) {
134
+ if (event.type === "text") {
135
+ accumulated += event.content;
136
+ } else if (event.type === "image") {
137
+ pendingImages.push({ data: event.data, media_type: event.media_type });
138
+ } else if (event.type === "tool_use") {
139
+ const text2 = accumulated.trim();
140
+ accumulated = "";
141
+ const images2 = pendingImages.splice(0);
142
+ if (text2 || images2.length > 0) {
143
+ await handlers.onFlush(text2, images2);
144
+ }
145
+ } else if (event.type === "done") {
146
+ break;
147
+ }
148
+ }
149
+ const text = accumulated.trim();
150
+ const images = pendingImages.splice(0);
151
+ if (text || images.length > 0) {
152
+ await handlers.onFlush(text, images);
153
+ }
154
+ } catch (err) {
155
+ console.error(`Failed to reach agent at ${env.baseUrl}/message:`, err);
156
+ const errMsg = err instanceof TypeError && err.cause?.code === "ECONNREFUSED" ? "Agent is not running" : `Error: ${err}`;
157
+ await handlers.onError(errMsg);
158
+ }
159
+ }
160
+
161
+ export {
162
+ loadEnv,
163
+ loadFollowedChannels,
164
+ splitMessage,
165
+ onShutdown,
166
+ fireAndForget,
167
+ handleAgentMessage
168
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  validateAgentName
4
- } from "./chunk-RALYNMHR.js";
4
+ } from "./chunk-3C2XR4IY.js";
5
5
 
6
6
  // src/lib/isolation.ts
7
7
  import { execFile, execFileSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteHome
4
- } from "./chunk-RALYNMHR.js";
4
+ } from "./chunk-3C2XR4IY.js";
5
5
 
6
6
  // src/lib/daemon-client.ts
7
7
  import { existsSync, readFileSync } from "fs";
@@ -1,5 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/lib/format-tool.ts
4
+ function summarizeTool(name, input) {
5
+ if (input && typeof input === "object") {
6
+ const args = input;
7
+ const val = args.path ?? args.command ?? args.query ?? args.url;
8
+ if (typeof val === "string") {
9
+ const brief = val.length > 60 ? `${val.slice(0, 57)}...` : val;
10
+ return `[${name} ${brief}]`;
11
+ }
12
+ }
13
+ return `[${name}]`;
14
+ }
15
+ function collectPart(event) {
16
+ if (event.type === "text") return event.content ?? "";
17
+ if (event.type === "tool_use") return summarizeTool(event.name ?? "", event.input);
18
+ return null;
19
+ }
20
+
3
21
  // src/lib/log-buffer.ts
4
22
  var LogBuffer = class {
5
23
  entries = [];
@@ -84,6 +102,8 @@ async function* readNdjson(body) {
84
102
  }
85
103
 
86
104
  export {
105
+ summarizeTool,
106
+ collectPart,
87
107
  logBuffer,
88
108
  logger_default,
89
109
  readNdjson
package/dist/cli.js CHANGED
@@ -3,65 +3,72 @@
3
3
  // src/cli.ts
4
4
  var command = process.argv[2];
5
5
  var args = process.argv.slice(3);
6
+ if (command === "--version" || command === "-v") {
7
+ const { default: pkg } = await import("./package-Z2SFO2SV.js");
8
+ console.log(pkg.version);
9
+ process.exit(0);
10
+ }
6
11
  switch (command) {
7
12
  case "create":
8
- await import("./create-RSWWMGKT.js").then((m) => m.run(args));
13
+ await import("./create-ILVOG75A.js").then((m) => m.run(args));
9
14
  break;
10
15
  case "start":
11
- await import("./start-2BSXX6BS.js").then((m) => m.run(args));
16
+ await import("./start-LDPMCMYT.js").then((m) => m.run(args));
12
17
  break;
13
18
  case "stop":
14
- await import("./stop-DSKBIJ2D.js").then((m) => m.run(args));
19
+ await import("./stop-5PZTZCLL.js").then((m) => m.run(args));
15
20
  break;
16
21
  case "logs":
17
- await import("./logs-NHWGHNBF.js").then((m) => m.run(args));
22
+ await import("./logs-NXFFGUKY.js").then((m) => m.run(args));
18
23
  break;
19
24
  case "status":
20
- await import("./status-N23CV27T.js").then((m) => m.run(args));
25
+ await import("./status-MVSQG54T.js").then((m) => m.run(args));
21
26
  break;
22
27
  case "variant":
23
- await import("./variant-JPLJTS2P.js").then((m) => m.run(args));
28
+ await import("./variant-T64BKARF.js").then((m) => m.run(args));
24
29
  break;
25
30
  case "send":
26
- await import("./send-5LEJXPYV.js").then((m) => m.run(args));
31
+ await import("./send-3U6OTKG7.js").then((m) => m.run(args));
27
32
  break;
28
33
  case "import":
29
- await import("./import-6HTSSDFW.js").then((m) => m.run(args));
34
+ await import("./import-4CI2ZUTJ.js").then((m) => m.run(args));
30
35
  break;
31
36
  case "delete":
32
- await import("./delete-4ERL2QHH.js").then((m) => m.run(args));
37
+ await import("./delete-55MXCEY5.js").then((m) => m.run(args));
33
38
  break;
34
39
  case "env":
35
- await import("./env-DBWDTIP6.js").then((m) => m.run(args));
40
+ await import("./env-JB27UAC3.js").then((m) => m.run(args));
36
41
  break;
37
42
  case "connector":
38
- await import("./connector-6LWB5PRU.js").then((m) => m.run(args));
43
+ await import("./connector-DKDJTLYZ.js").then((m) => m.run(args));
39
44
  break;
40
45
  case "channel":
41
- await import("./channel-H7N4SGR2.js").then((m) => m.run(args));
46
+ await import("./channel-DQ6UY7QB.js").then((m) => m.run(args));
42
47
  break;
43
48
  case "upgrade":
44
- await import("./upgrade-BGFVRCVP.js").then((m) => m.run(args));
49
+ await import("./upgrade-6ZW2RD64.js").then((m) => m.run(args));
45
50
  break;
46
51
  case "up":
47
- await import("./up-4UGID4DM.js").then((m) => m.run(args));
52
+ await import("./up-F7TMTLRE.js").then((m) => m.run(args));
48
53
  break;
49
54
  case "down":
50
- await import("./down-HRC4MQCT.js").then((m) => m.run(args));
55
+ await import("./down-3OB6UVAJ.js").then((m) => m.run(args));
51
56
  break;
52
57
  case "schedule":
53
- await import("./schedule-DKZ2E2CL.js").then((m) => m.run(args));
58
+ await import("./schedule-A35SH4HT.js").then((m) => m.run(args));
54
59
  break;
55
60
  case "history":
56
- await import("./history-W7BD2H74.js").then((m) => m.run(args));
61
+ await import("./history-BKG74I43.js").then((m) => m.run(args));
57
62
  break;
58
63
  case "service":
59
64
  await import("./service-SA4TTMDU.js").then((m) => m.run(args));
60
65
  break;
61
66
  case "setup":
62
- await import("./setup-ZMNTOJAV.js").then((m) => m.run(args));
67
+ await import("./setup-2FDVN7OF.js").then((m) => m.run(args));
63
68
  break;
64
- default:
69
+ case "--help":
70
+ case "-h":
71
+ case void 0:
65
72
  console.log(`volute \u2014 create and manage AI agents
66
73
 
67
74
  Commands:
@@ -74,6 +81,7 @@ Commands:
74
81
  volute variant create <name> Create a variant (worktree + server)
75
82
  volute variant list List variants for an agent
76
83
  volute variant merge <name> Merge a variant back
84
+ volute variant delete <name> Delete a variant
77
85
  volute import <path> Import an OpenClaw workspace
78
86
  volute env <set|get|list|remove> Manage environment variables
79
87
  volute connector connect <type> Enable a connector for an agent
@@ -94,11 +102,15 @@ Commands:
94
102
  volute setup [--port N] [--host H] Install system service with user isolation
95
103
  volute setup uninstall [--force] Remove system service + isolation
96
104
 
105
+ Options:
106
+ --version, -v Show version number
107
+ --help, -h Show this help message
108
+
97
109
  Agent commands (variant, connector, schedule, logs, history, channel) use
98
110
  --agent <name> or VOLUTE_AGENT env var to identify the agent.`);
99
- if (command) {
100
- console.error(`
101
- Unknown command: ${command}`);
102
- process.exit(1);
103
- }
111
+ break;
112
+ default:
113
+ console.error(`Unknown command: ${command}
114
+ Run 'volute --help' for usage.`);
115
+ process.exit(1);
104
116
  }