volute 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +29 -29
  2. package/dist/agent-Z2B6EFEQ.js +75 -0
  3. package/dist/{agent-manager-AUCKMGPR.js → agent-manager-PXBKA2GK.js} +4 -4
  4. package/dist/channel-MK5OK2SI.js +113 -0
  5. package/dist/chunk-5X7HGB6L.js +107 -0
  6. package/dist/{chunk-YGFIWIOF.js → chunk-7L4AN5D4.js} +1 -1
  7. package/dist/{chunk-VRVVQIYY.js → chunk-AZEL2IEK.js} +1 -1
  8. package/dist/chunk-B3R6L2GW.js +24 -0
  9. package/dist/{chunk-DNOXHLE5.js → chunk-HE67X4T6.js} +1 -1
  10. package/dist/{chunk-I6OHXCMV.js → chunk-MW2KFO3B.js} +47 -9
  11. package/dist/chunk-MXUCNIBG.js +168 -0
  12. package/dist/chunk-SMISE4SV.js +226 -0
  13. package/dist/{chunk-SOZA2TLP.js → chunk-UAVD2AHX.js} +1 -1
  14. package/dist/{chunk-3C2XR4IY.js → chunk-UX25Z2ND.js} +113 -107
  15. package/dist/{chunk-GSPKUPKU.js → chunk-XUA3JUFK.js} +2 -1
  16. package/dist/chunk-ZYGKG6VC.js +22 -0
  17. package/dist/cli.js +98 -75
  18. package/dist/connector-LYEMXQEV.js +157 -0
  19. package/dist/connectors/discord.js +104 -161
  20. package/dist/connectors/slack.js +179 -0
  21. package/dist/connectors/telegram.js +175 -0
  22. package/dist/conversation-ERXEQZTY.js +163 -0
  23. package/dist/create-RVCZN6HE.js +91 -0
  24. package/dist/{daemon-client-XR24PUJF.js → daemon-client-ZY6UUN2M.js} +2 -2
  25. package/dist/daemon.js +824 -252
  26. package/dist/{delete-GQ7JEK2S.js → delete-3QH7VYIN.js} +8 -9
  27. package/dist/{down-3OB6UVAJ.js → down-O7IFZLVJ.js} +1 -1
  28. package/dist/{env-JB27UAC3.js → env-4D4REPJF.js} +8 -5
  29. package/dist/{history-3VRUBGGV.js → history-OEONB53Z.js} +5 -5
  30. package/dist/{import-K4MP2GX7.js → import-MXJB2EII.js} +23 -8
  31. package/dist/{logs-NXFFGUKY.js → logs-DF342W4M.js} +2 -2
  32. package/dist/message-ADHWFHSI.js +32 -0
  33. package/dist/package-VQOE7JNH.js +89 -0
  34. package/dist/{schedule-4I5TYHFH.js → schedule-NAG6F463.js} +12 -7
  35. package/dist/send-66QMKRUH.js +75 -0
  36. package/dist/{setup-SRS7AUAA.js → setup-RPRRGG2F.js} +6 -6
  37. package/dist/{start-LDPMCMYT.js → start-TUOXDSFL.js} +3 -3
  38. package/dist/{status-MVSQG54T.js → status-A36EHRO4.js} +3 -3
  39. package/dist/{stop-5PZTZCLL.js → stop-AOJZLQ5X.js} +6 -7
  40. package/dist/{up-UT3IMKCA.js → up-7ILD7GU7.js} +2 -2
  41. package/dist/update-LPSIAWQ2.js +140 -0
  42. package/dist/update-check-Y33QDCFL.js +17 -0
  43. package/dist/{upgrade-CDKECCGN.js → upgrade-FX2TKJ2S.js} +16 -15
  44. package/dist/{variant-CVYM3EQG.js → variant-LAB67OC2.js} +17 -12
  45. package/dist/web-assets/assets/index-BbRmoxoA.js +308 -0
  46. package/dist/web-assets/index.html +2 -2
  47. package/drizzle/0003_clean_ego.sql +12 -0
  48. package/drizzle/meta/0003_snapshot.json +417 -0
  49. package/drizzle/meta/_journal.json +7 -0
  50. package/package.json +3 -1
  51. package/templates/_base/.init/.config/hooks/startup-context.sh +19 -1
  52. package/templates/_base/_skills/volute-agent/SKILL.md +112 -16
  53. package/templates/_base/home/.config/routes.json +10 -0
  54. package/templates/_base/home/VOLUTE.md +19 -28
  55. package/templates/_base/src/lib/file-handler.ts +46 -0
  56. package/templates/_base/src/lib/format-prefix.ts +1 -1
  57. package/templates/_base/src/lib/router.ts +327 -0
  58. package/templates/_base/src/lib/routing.ts +137 -0
  59. package/templates/_base/src/lib/types.ts +16 -3
  60. package/templates/_base/src/lib/volute-server.ts +20 -48
  61. package/templates/agent-sdk/.init/.config/routes.json +5 -0
  62. package/templates/agent-sdk/.init/CLAUDE.md +2 -2
  63. package/templates/agent-sdk/src/agent.ts +269 -82
  64. package/templates/agent-sdk/src/server.ts +19 -4
  65. package/templates/agent-sdk/volute-template.json +1 -1
  66. package/templates/pi/.init/.config/routes.json +5 -0
  67. package/templates/pi/.init/AGENTS.md +1 -1
  68. package/templates/pi/src/agent.ts +279 -58
  69. package/templates/pi/src/server.ts +15 -4
  70. package/templates/pi/volute-template.json +1 -1
  71. package/dist/channel-7FZ6D25H.js +0 -90
  72. package/dist/chunk-N4YNKR3Q.js +0 -90
  73. package/dist/connector-TVJULIRT.js +0 -96
  74. package/dist/create-BRG2DBWI.js +0 -79
  75. package/dist/send-UK3JBZIB.js +0 -53
  76. package/dist/web-assets/assets/index-BC5eSqbY.js +0 -296
  77. package/templates/_base/src/lib/sessions.ts +0 -71
  78. package/templates/agent-sdk/.init/.config/sessions.json +0 -4
  79. package/templates/agent-sdk/src/lib/agent-sessions.ts +0 -204
  80. package/templates/pi/.init/.config/sessions.json +0 -1
  81. package/templates/pi/src/lib/agent-sessions.ts +0 -210
  82. package/dist/{service-SA4TTMDU.js → service-HZNIDNJF.js} +3 -3
package/README.md CHANGED
@@ -17,13 +17,13 @@ npm install -g volute
17
17
  volute up
18
18
 
19
19
  # Create an agent
20
- volute create atlas
20
+ volute agent create atlas
21
21
 
22
22
  # Start it
23
- volute start atlas
23
+ volute agent start atlas
24
24
 
25
25
  # Talk to it
26
- volute send atlas "hey, what can you do?"
26
+ volute message 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.
@@ -45,20 +45,20 @@ The daemon handles agent lifecycle, crash recovery (auto-restarts after 3 second
45
45
  ### Lifecycle
46
46
 
47
47
  ```sh
48
- volute create atlas # scaffold a new agent
49
- volute start atlas # start it
50
- volute stop atlas # stop it
51
- volute status # list all agents
52
- volute status atlas # check one
53
- volute logs atlas --follow # tail logs
54
- volute delete atlas # remove from registry
55
- volute delete atlas --force # also delete files
48
+ volute agent create atlas # scaffold a new agent
49
+ volute agent start atlas # start it
50
+ volute agent stop atlas # stop it
51
+ volute agent list # list all agents
52
+ volute agent status atlas # check one
53
+ volute agent logs atlas --follow # tail logs
54
+ volute agent delete atlas # remove from registry
55
+ volute agent delete atlas --force # also delete files
56
56
  ```
57
57
 
58
58
  ### Sending messages
59
59
 
60
60
  ```sh
61
- volute send atlas "what's on your mind?"
61
+ volute message send atlas "what's on your mind?"
62
62
  ```
63
63
 
64
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.
@@ -92,16 +92,16 @@ This is the interesting part. Agents can fork themselves into isolated branches,
92
92
 
93
93
  ```sh
94
94
  # Create a variant — gets its own git worktree and running server
95
- volute fork atlas experiment
95
+ volute variant create experiment --agent atlas
96
96
 
97
97
  # Talk to the variant directly
98
- volute send atlas@experiment "try a different approach"
98
+ volute message send atlas@experiment "try a different approach"
99
99
 
100
100
  # List all variants
101
- volute variants atlas
101
+ volute variant list --agent atlas
102
102
 
103
103
  # Merge it back (verifies, merges, cleans up, restarts the main agent)
104
- volute merge atlas experiment --summary "improved response style"
104
+ volute variant merge experiment --agent atlas --summary "improved response style"
105
105
  ```
106
106
 
107
107
  What happens:
@@ -114,14 +114,14 @@ What happens:
114
114
  You can fork with a custom personality:
115
115
 
116
116
  ```sh
117
- volute fork atlas poet --soul "You are a poet who responds only in verse."
117
+ volute variant create poet --agent atlas --soul "You are a poet who responds only in verse."
118
118
  ```
119
119
 
120
120
  Agents have access to the `volute` CLI from their working directory, so they can fork, test, and merge their own variants autonomously.
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
@@ -187,13 +187,13 @@ The daemon serves a web UI at `http://localhost:4200` (or whatever port you chos
187
187
  When the Volute template updates, you can upgrade agents without touching their identity:
188
188
 
189
189
  ```sh
190
- volute upgrade atlas # creates an "upgrade" variant
190
+ volute agent upgrade atlas # creates an "upgrade" variant
191
191
  # resolve conflicts if needed, then:
192
- volute upgrade atlas --continue
192
+ volute agent upgrade atlas --continue
193
193
  # test:
194
- volute send atlas@upgrade "are you working?"
194
+ volute message send atlas@upgrade "are you working?"
195
195
  # merge:
196
- volute merge atlas upgrade
196
+ volute variant merge upgrade --agent atlas
197
197
  ```
198
198
 
199
199
  Your agent's `SOUL.md` and `MEMORY.md` are never overwritten.
@@ -206,7 +206,7 @@ Two built-in templates:
206
206
  - **`pi`** — [pi-coding-agent](https://github.com/nicepkg/pi) for multi-provider LLM support
207
207
 
208
208
  ```sh
209
- volute create atlas --template pi
209
+ volute agent create atlas --template pi
210
210
  ```
211
211
 
212
212
  ## Model configuration
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ import "./chunk-K3NQKI34.js";
3
+
4
+ // src/commands/agent.ts
5
+ async function run(args) {
6
+ const subcommand = args[0];
7
+ switch (subcommand) {
8
+ case "create":
9
+ await import("./create-RVCZN6HE.js").then((m) => m.run(args.slice(1)));
10
+ break;
11
+ case "start":
12
+ await import("./start-TUOXDSFL.js").then((m) => m.run(args.slice(1)));
13
+ break;
14
+ case "stop":
15
+ await import("./stop-AOJZLQ5X.js").then((m) => m.run(args.slice(1)));
16
+ break;
17
+ case "delete":
18
+ await import("./delete-3QH7VYIN.js").then((m) => m.run(args.slice(1)));
19
+ break;
20
+ case "list":
21
+ await import("./status-A36EHRO4.js").then((m) => m.run(args.slice(1)));
22
+ break;
23
+ case "status": {
24
+ const rest = args.slice(1);
25
+ if (!rest[0] && process.env.VOLUTE_AGENT) {
26
+ rest.unshift(process.env.VOLUTE_AGENT);
27
+ }
28
+ await import("./status-A36EHRO4.js").then((m) => m.run(rest));
29
+ break;
30
+ }
31
+ case "logs": {
32
+ const rest = args.slice(1);
33
+ const logsArgs = transformAgentFlag(rest);
34
+ await import("./logs-DF342W4M.js").then((m) => m.run(logsArgs));
35
+ break;
36
+ }
37
+ case "upgrade":
38
+ await import("./upgrade-FX2TKJ2S.js").then((m) => m.run(args.slice(1)));
39
+ break;
40
+ case "import":
41
+ await import("./import-MXJB2EII.js").then((m) => m.run(args.slice(1)));
42
+ break;
43
+ case "--help":
44
+ case "-h":
45
+ case void 0:
46
+ printUsage();
47
+ break;
48
+ default:
49
+ printUsage();
50
+ process.exit(1);
51
+ }
52
+ }
53
+ function transformAgentFlag(args) {
54
+ if (args.length > 0 && args[0] && !args[0].startsWith("-")) {
55
+ return ["--agent", args[0], ...args.slice(1)];
56
+ }
57
+ return args;
58
+ }
59
+ function printUsage() {
60
+ console.log(`Usage:
61
+ volute agent create <name> [--template <name>]
62
+ volute agent start <name>
63
+ volute agent stop [name]
64
+ volute agent delete [name] [--force]
65
+ volute agent list
66
+ volute agent status [name]
67
+ volute agent logs [name] [--follow] [-n N]
68
+ volute agent upgrade [name] [--template <name>] [--continue]
69
+ volute agent import <path> [--name <name>] [--session <path>] [--template <name>]
70
+
71
+ Agent name can be omitted (where shown as [name]) if VOLUTE_AGENT is set.`);
72
+ }
73
+ export {
74
+ run
75
+ };
@@ -3,10 +3,10 @@ import {
3
3
  AgentManager,
4
4
  getAgentManager,
5
5
  initAgentManager
6
- } from "./chunk-I6OHXCMV.js";
7
- import "./chunk-DNOXHLE5.js";
8
- import "./chunk-SOZA2TLP.js";
9
- import "./chunk-3C2XR4IY.js";
6
+ } from "./chunk-MW2KFO3B.js";
7
+ import "./chunk-HE67X4T6.js";
8
+ import "./chunk-UAVD2AHX.js";
9
+ import "./chunk-UX25Z2ND.js";
10
10
  import "./chunk-K3NQKI34.js";
11
11
  export {
12
12
  AgentManager,
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ readStdin
4
+ } from "./chunk-ZYGKG6VC.js";
5
+ import {
6
+ resolveAgentName
7
+ } from "./chunk-AZEL2IEK.js";
8
+ import {
9
+ getChannelDriver
10
+ } from "./chunk-SMISE4SV.js";
11
+ import {
12
+ loadMergedEnv
13
+ } from "./chunk-HE67X4T6.js";
14
+ import {
15
+ parseArgs
16
+ } from "./chunk-D424ZQGI.js";
17
+ import {
18
+ resolveAgent
19
+ } from "./chunk-UX25Z2ND.js";
20
+ import "./chunk-K3NQKI34.js";
21
+
22
+ // src/commands/channel.ts
23
+ async function run(args) {
24
+ const subcommand = args[0];
25
+ switch (subcommand) {
26
+ case "read":
27
+ await readChannel(args.slice(1));
28
+ break;
29
+ case "send":
30
+ await sendChannel(args.slice(1));
31
+ break;
32
+ case "--help":
33
+ case "-h":
34
+ case void 0:
35
+ printUsage();
36
+ break;
37
+ default:
38
+ printUsage();
39
+ process.exit(1);
40
+ }
41
+ }
42
+ function printUsage() {
43
+ console.log(`Usage:
44
+ volute channel read <channel-uri> [--limit N] [--agent <name>]
45
+ volute channel send <channel-uri> "<message>" [--agent <name>]
46
+ echo "message" | volute channel send <channel-uri> [--agent <name>]`);
47
+ }
48
+ async function readChannel(args) {
49
+ const { positional, flags } = parseArgs(args, {
50
+ agent: { type: "string" },
51
+ limit: { type: "number" }
52
+ });
53
+ const uri = positional[0];
54
+ if (!uri) {
55
+ console.error("Usage: volute channel read <channel-uri> [--limit N] [--agent <name>]");
56
+ process.exit(1);
57
+ }
58
+ const agentName = resolveAgentName(flags);
59
+ const { platform, channelId } = parseUri(uri);
60
+ const driver = requireDriver(platform);
61
+ const { dir } = resolveAgent(agentName);
62
+ const env = { ...loadMergedEnv(dir), VOLUTE_AGENT: agentName };
63
+ try {
64
+ const limit = flags.limit ?? 20;
65
+ const output = await driver.read(env, channelId, limit);
66
+ console.log(output);
67
+ } catch (err) {
68
+ console.error(err instanceof Error ? err.message : String(err));
69
+ process.exit(1);
70
+ }
71
+ }
72
+ async function sendChannel(args) {
73
+ const { positional, flags } = parseArgs(args, {
74
+ agent: { type: "string" }
75
+ });
76
+ const uri = positional[0];
77
+ const message = positional[1] ?? await readStdin();
78
+ if (!uri || !message) {
79
+ console.error('Usage: volute channel send <channel-uri> "<message>" [--agent <name>]');
80
+ console.error(' echo "message" | volute channel send <channel-uri> [--agent <name>]');
81
+ process.exit(1);
82
+ }
83
+ const agentName = resolveAgentName(flags);
84
+ const { platform, channelId } = parseUri(uri);
85
+ const driver = requireDriver(platform);
86
+ const { dir } = resolveAgent(agentName);
87
+ const env = { ...loadMergedEnv(dir), VOLUTE_AGENT: agentName };
88
+ try {
89
+ await driver.send(env, channelId, message);
90
+ } catch (err) {
91
+ console.error(err instanceof Error ? err.message : String(err));
92
+ process.exit(1);
93
+ }
94
+ }
95
+ function parseUri(uri) {
96
+ const colonIdx = uri.indexOf(":");
97
+ if (colonIdx === -1) {
98
+ console.error(`Invalid channel URI: ${uri} (expected format: platform:id)`);
99
+ process.exit(1);
100
+ }
101
+ return { platform: uri.slice(0, colonIdx), channelId: uri.slice(colonIdx + 1) };
102
+ }
103
+ function requireDriver(platform) {
104
+ const driver = getChannelDriver(platform);
105
+ if (!driver) {
106
+ console.error(`No channel driver for platform: ${platform}`);
107
+ process.exit(1);
108
+ }
109
+ return driver;
110
+ }
111
+ export {
112
+ run
113
+ };
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ voluteHome
4
+ } from "./chunk-UX25Z2ND.js";
5
+
6
+ // src/lib/update-check.ts
7
+ import { existsSync, readFileSync, writeFileSync } from "fs";
8
+ import { resolve } from "path";
9
+ var CACHE_TTL = 60 * 60 * 1e3;
10
+ function cachePath() {
11
+ return resolve(voluteHome(), "update-check.json");
12
+ }
13
+ function readCache() {
14
+ try {
15
+ const data = JSON.parse(readFileSync(cachePath(), "utf-8"));
16
+ if (data.latest && typeof data.checkedAt === "number") return data;
17
+ } catch {
18
+ }
19
+ return null;
20
+ }
21
+ function writeCache(latest) {
22
+ try {
23
+ writeFileSync(cachePath(), `${JSON.stringify({ latest, checkedAt: Date.now() })}
24
+ `);
25
+ } catch {
26
+ }
27
+ }
28
+ function getCurrentVersion() {
29
+ const thisDir = new URL(".", import.meta.url).pathname;
30
+ const candidates = [
31
+ resolve(thisDir, "../../package.json"),
32
+ resolve(thisDir, "../../../package.json")
33
+ ];
34
+ for (const p of candidates) {
35
+ if (existsSync(p)) {
36
+ try {
37
+ return JSON.parse(readFileSync(p, "utf-8")).version;
38
+ } catch {
39
+ }
40
+ }
41
+ }
42
+ return "0.0.0";
43
+ }
44
+ async function fetchLatestVersion() {
45
+ const controller = new AbortController();
46
+ const timeout = setTimeout(() => controller.abort(), 5e3);
47
+ timeout.unref?.();
48
+ try {
49
+ const res = await fetch("https://registry.npmjs.org/volute/latest", {
50
+ signal: controller.signal
51
+ });
52
+ if (!res.ok) throw new Error(`npm registry returned ${res.status}`);
53
+ const data = await res.json();
54
+ if (typeof data.version !== "string") throw new Error("invalid npm response");
55
+ return data.version;
56
+ } finally {
57
+ clearTimeout(timeout);
58
+ }
59
+ }
60
+ function isNewer(current, latest) {
61
+ const parse = (v) => v.split("-")[0].split(".").map(Number);
62
+ const hasPrerelease = (v) => v.includes("-");
63
+ const c = parse(current);
64
+ const l = parse(latest);
65
+ for (let i = 0; i < 3; i++) {
66
+ if ((l[i] ?? 0) > (c[i] ?? 0)) return true;
67
+ if ((l[i] ?? 0) < (c[i] ?? 0)) return false;
68
+ }
69
+ if (hasPrerelease(current) && !hasPrerelease(latest)) return true;
70
+ return false;
71
+ }
72
+ async function checkForUpdate() {
73
+ const current = getCurrentVersion();
74
+ const cache = readCache();
75
+ if (cache && Date.now() - cache.checkedAt < CACHE_TTL) {
76
+ return {
77
+ current,
78
+ latest: cache.latest,
79
+ updateAvailable: isNewer(current, cache.latest)
80
+ };
81
+ }
82
+ try {
83
+ const latest = await fetchLatestVersion();
84
+ writeCache(latest);
85
+ return { current, latest, updateAvailable: isNewer(current, latest) };
86
+ } catch {
87
+ return { current, latest: current, updateAvailable: false, checkFailed: true };
88
+ }
89
+ }
90
+ function checkForUpdateCached() {
91
+ const cache = readCache();
92
+ if (!cache) return null;
93
+ const current = getCurrentVersion();
94
+ return {
95
+ current,
96
+ latest: cache.latest,
97
+ updateAvailable: isNewer(current, cache.latest)
98
+ };
99
+ }
100
+
101
+ export {
102
+ getCurrentVersion,
103
+ fetchLatestVersion,
104
+ isNewer,
105
+ checkForUpdate,
106
+ checkForUpdateCached
107
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteHome
4
- } from "./chunk-3C2XR4IY.js";
4
+ } from "./chunk-UX25Z2ND.js";
5
5
 
6
6
  // src/lib/daemon-client.ts
7
7
  import { existsSync, readFileSync } from "fs";
@@ -4,7 +4,7 @@
4
4
  function resolveAgentName(flags) {
5
5
  const name = flags.agent || process.env.VOLUTE_AGENT;
6
6
  if (!name) {
7
- console.error("No agent specified. Use --agent <name> or set VOLUTE_AGENT.");
7
+ console.error("No agent specified. Provide a name or set VOLUTE_AGENT.");
8
8
  process.exit(1);
9
9
  }
10
10
  return name;
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
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
+
21
+ export {
22
+ summarizeTool,
23
+ collectPart
24
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteHome
4
- } from "./chunk-3C2XR4IY.js";
4
+ } from "./chunk-UX25Z2ND.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-DNOXHLE5.js";
4
+ } from "./chunk-HE67X4T6.js";
5
5
  import {
6
6
  applyIsolation
7
- } from "./chunk-SOZA2TLP.js";
7
+ } from "./chunk-UAVD2AHX.js";
8
8
  import {
9
9
  agentDir,
10
10
  findAgent,
@@ -13,11 +13,11 @@ import {
13
13
  setVariantRunning,
14
14
  validateBranchName,
15
15
  voluteHome
16
- } from "./chunk-3C2XR4IY.js";
16
+ } from "./chunk-UX25Z2ND.js";
17
17
 
18
18
  // src/lib/agent-manager.ts
19
19
  import { execFile, spawn } from "child_process";
20
- import { createWriteStream, existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, unlinkSync as unlinkSync2 } from "fs";
20
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, unlinkSync as unlinkSync2 } from "fs";
21
21
  import { resolve } from "path";
22
22
  import { promisify } from "util";
23
23
 
@@ -58,6 +58,45 @@ function clearJsonMap(path, map) {
58
58
  }
59
59
  }
60
60
 
61
+ // src/lib/rotating-log.ts
62
+ import { createWriteStream, existsSync as existsSync2, renameSync, statSync } from "fs";
63
+ import { Writable } from "stream";
64
+ var MAX_SIZE = 10 * 1024 * 1024;
65
+ var RotatingLog = class extends Writable {
66
+ constructor(path, maxSize = MAX_SIZE) {
67
+ super();
68
+ this.path = path;
69
+ this.maxSize = maxSize;
70
+ this.on("error", () => {
71
+ });
72
+ try {
73
+ this.size = existsSync2(path) ? statSync(path).size : 0;
74
+ } catch {
75
+ this.size = 0;
76
+ }
77
+ this.stream = createWriteStream(path, { flags: "a" });
78
+ }
79
+ stream;
80
+ size;
81
+ _write(chunk, _encoding, callback) {
82
+ this.size += chunk.length;
83
+ if (this.size > this.maxSize) {
84
+ try {
85
+ renameSync(this.path, `${this.path}.1`);
86
+ const oldStream = this.stream;
87
+ this.stream = createWriteStream(this.path);
88
+ this.size = chunk.length;
89
+ oldStream.end();
90
+ } catch {
91
+ }
92
+ }
93
+ this.stream.write(chunk, callback);
94
+ }
95
+ _final(callback) {
96
+ this.stream.end(callback);
97
+ }
98
+ };
99
+
61
100
  // src/lib/agent-manager.ts
62
101
  var execFileAsync = promisify(execFile);
63
102
  var MAX_RESTART_ATTEMPTS = 5;
@@ -78,7 +117,7 @@ var AgentManager = class {
78
117
  return { dir: variant.path, port: variant.port, isVariant: true, baseName, variantName };
79
118
  }
80
119
  const dir = agentDir(baseName);
81
- if (!existsSync2(dir)) throw new Error(`Agent directory missing: ${dir}`);
120
+ if (!existsSync3(dir)) throw new Error(`Agent directory missing: ${dir}`);
82
121
  return { dir, port: entry.port, isVariant: false, baseName };
83
122
  }
84
123
  async startAgent(name) {
@@ -100,9 +139,7 @@ var AgentManager = class {
100
139
  const voluteDir = resolve(dir, ".volute");
101
140
  const logsDir = resolve(voluteDir, "logs");
102
141
  mkdirSync(logsDir, { recursive: true });
103
- const logStream = createWriteStream(resolve(logsDir, "agent.log"), {
104
- flags: "a"
105
- });
142
+ const logStream = new RotatingLog(resolve(logsDir, "agent.log"));
106
143
  const agentEnv = loadMergedEnv(dir);
107
144
  const { VOLUTE_DAEMON_TOKEN: _, ...parentEnv } = process.env;
108
145
  const env = { ...parentEnv, ...agentEnv, VOLUTE_AGENT: name };
@@ -198,7 +235,7 @@ var AgentManager = class {
198
235
  }
199
236
  async handleRestart(name, dir) {
200
237
  const restartPath = resolve(dir, ".volute", "restart.json");
201
- if (!existsSync2(restartPath)) return false;
238
+ if (!existsSync3(restartPath)) return false;
202
239
  try {
203
240
  const signal = JSON.parse(readFileSync2(restartPath, "utf-8"));
204
241
  unlinkSync2(restartPath);
@@ -326,6 +363,7 @@ export {
326
363
  loadJsonMap,
327
364
  saveJsonMap,
328
365
  clearJsonMap,
366
+ RotatingLog,
329
367
  AgentManager,
330
368
  initAgentManager,
331
369
  getAgentManager