volute 0.11.4 → 0.12.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.
@@ -3,7 +3,7 @@ import {
3
3
  AgentManager,
4
4
  getAgentManager,
5
5
  initAgentManager
6
- } from "./chunk-YTOPX4PB.js";
6
+ } from "./chunk-PHJCXAWJ.js";
7
7
  import "./chunk-46S7YHUB.js";
8
8
  import "./chunk-QF22MYDJ.js";
9
9
  import "./chunk-DP2DX4WV.js";
@@ -188,7 +188,13 @@ var AgentManager = class {
188
188
  const logsDir = resolve(agentStateDir, "logs");
189
189
  mkdirSync(logsDir, { recursive: true });
190
190
  if (isIsolationEnabled()) {
191
- chownAgentDir(agentStateDir, baseName);
191
+ try {
192
+ chownAgentDir(agentStateDir, baseName);
193
+ } catch (err) {
194
+ throw new Error(
195
+ `Cannot start agent ${name}: failed to set ownership on state directory ${agentStateDir}: ${err instanceof Error ? err.message : err}`
196
+ );
197
+ }
192
198
  }
193
199
  const logStream = new RotatingLog(resolve(logsDir, "agent.log"));
194
200
  const agentEnv = loadMergedEnv(name);
@@ -200,8 +206,11 @@ var AgentManager = class {
200
206
  VOLUTE_AGENT_DIR: dir,
201
207
  VOLUTE_AGENT_PORT: String(port)
202
208
  };
209
+ if (isIsolationEnabled()) {
210
+ env.HOME = resolve(dir, "home");
211
+ }
203
212
  if (isIsolationEnabled() && process.env.CLAUDE_CONFIG_DIR) {
204
- const agentClaudeDir = resolve(dir, ".claude");
213
+ const agentClaudeDir = resolve(dir, "home", ".claude");
205
214
  try {
206
215
  mkdirSync(agentClaudeDir, { recursive: true });
207
216
  } catch (err) {
@@ -7,6 +7,15 @@ import {
7
7
  function slugify(text) {
8
8
  return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
9
9
  }
10
+ function buildVoluteSlug(opts) {
11
+ const isDM = opts.participants.length === 2;
12
+ if (isDM) {
13
+ const other = opts.participants.find((p) => p.username !== opts.agentUsername);
14
+ const otherSlug = other ? slugify(other.username) : "";
15
+ return otherSlug ? `volute:@${otherSlug}` : `volute:${opts.conversationId}`;
16
+ }
17
+ return opts.convTitle ? `volute:${slugify(opts.convTitle)}` : `volute:${opts.conversationId}`;
18
+ }
10
19
 
11
20
  // src/connectors/sdk.ts
12
21
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -148,6 +157,7 @@ function resolveChannelId(agentName, slug) {
148
157
 
149
158
  export {
150
159
  slugify,
160
+ buildVoluteSlug,
151
161
  loadEnv,
152
162
  loadFollowedChannels,
153
163
  splitMessage,
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ buildVoluteSlug,
3
4
  resolveChannelId,
4
5
  slugify,
5
6
  splitMessage,
6
7
  writeChannelEntry
7
- } from "./chunk-N6MLQ26B.js";
8
+ } from "./chunk-POLMWJFC.js";
8
9
  import {
9
10
  voluteHome
10
11
  } from "./chunk-DP2DX4WV.js";
@@ -452,26 +453,33 @@ async function listConversations4(env) {
452
453
  const convs = await res.json();
453
454
  const results = [];
454
455
  for (const conv of convs) {
455
- let participantCount;
456
+ let participants = [];
456
457
  try {
457
458
  const pRes = await fetch(
458
459
  `${url}/api/agents/${encodeURIComponent(agentName)}/conversations/${encodeURIComponent(conv.id)}/participants`,
459
460
  { headers }
460
461
  );
461
462
  if (pRes.ok) {
462
- const participants = await pRes.json();
463
- participantCount = participants.length;
463
+ participants = await pRes.json();
464
+ } else {
465
+ console.error(`[volute] failed to fetch participants for ${conv.id}: HTTP ${pRes.status}`);
464
466
  }
465
467
  } catch (err) {
466
468
  console.error(`[volute] failed to fetch participants for ${conv.id}:`, err);
467
469
  }
468
- const slug = conv.title ? `volute:${slugify(conv.title)}` : `volute:${conv.id}`;
470
+ const isDM = participants.length === 2;
471
+ const slug = buildVoluteSlug({
472
+ participants,
473
+ agentUsername: agentName,
474
+ convTitle: conv.title,
475
+ conversationId: conv.id
476
+ });
469
477
  results.push({
470
478
  id: slug,
471
479
  platformId: conv.id,
472
480
  name: conv.title ?? "(untitled)",
473
- type: participantCount === 2 ? "dm" : "group",
474
- participantCount
481
+ type: isDM ? "dm" : "group",
482
+ participantCount: participants.length
475
483
  });
476
484
  }
477
485
  return results;
@@ -510,16 +518,7 @@ async function createConversation4(env, participants, name) {
510
518
  throw new Error(data.error ?? `Failed to create conversation: ${res.status}`);
511
519
  }
512
520
  const conv = await res.json();
513
- const slug = name ? `volute:${slugify(name)}` : `volute:${conv.id}`;
514
- if (agentName) {
515
- writeChannelEntry(agentName, slug, {
516
- platformId: conv.id,
517
- platform: "volute",
518
- name: name ?? participants.join(", "),
519
- type: participants.length <= 1 ? "dm" : "group"
520
- });
521
- }
522
- return slug;
521
+ return `volute:${conv.id}`;
523
522
  }
524
523
 
525
524
  // src/lib/channels.ts
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ if (!process.env.VOLUTE_HOME) {
9
9
  var command = process.argv[2];
10
10
  var args = process.argv.slice(3);
11
11
  if (command === "--version" || command === "-v") {
12
- const { default: pkg } = await import("./package-KVUXPTEW.js");
12
+ const { default: pkg } = await import("./package-5LQNWBH7.js");
13
13
  console.log(pkg.version);
14
14
  process.exit(0);
15
15
  }
@@ -18,7 +18,7 @@ switch (command) {
18
18
  await import("./agent-2AQPI3QV.js").then((m) => m.run(args));
19
19
  break;
20
20
  case "send":
21
- await import("./send-X6OQGSD6.js").then((m) => m.run(args));
21
+ await import("./send-V5ESR5O2.js").then((m) => m.run(args));
22
22
  break;
23
23
  case "history":
24
24
  await import("./history-NI5QP27M.js").then((m) => m.run(args));
@@ -39,13 +39,13 @@ switch (command) {
39
39
  await import("./env-CGORIKVF.js").then((m) => m.run(args));
40
40
  break;
41
41
  case "up":
42
- await import("./up-365HL7UT.js").then((m) => m.run(args));
42
+ await import("./up-A6XT6AFX.js").then((m) => m.run(args));
43
43
  break;
44
44
  case "down":
45
45
  await import("./down-O2EQJ5DO.js").then((m) => m.run(args));
46
46
  break;
47
47
  case "restart":
48
- await import("./daemon-restart-5W5AGBZ2.js").then((m) => m.run(args));
48
+ await import("./daemon-restart-IVJ7X4PF.js").then((m) => m.run(args));
49
49
  break;
50
50
  case "setup":
51
51
  await import("./setup-7N4KYOYN.js").then((m) => m.run(args));
@@ -7,7 +7,7 @@ import {
7
7
  sendToAgent,
8
8
  slugify,
9
9
  writeChannelEntry
10
- } from "../chunk-N6MLQ26B.js";
10
+ } from "../chunk-POLMWJFC.js";
11
11
  import "../chunk-DP2DX4WV.js";
12
12
  import "../chunk-K3NQKI34.js";
13
13
 
@@ -6,7 +6,7 @@ import {
6
6
  onShutdown,
7
7
  sendToAgent,
8
8
  writeChannelEntry
9
- } from "../chunk-N6MLQ26B.js";
9
+ } from "../chunk-POLMWJFC.js";
10
10
  import "../chunk-DP2DX4WV.js";
11
11
  import "../chunk-K3NQKI34.js";
12
12
 
@@ -5,7 +5,7 @@ import {
5
5
  loadFollowedChannels,
6
6
  sendToAgent,
7
7
  writeChannelEntry
8
- } from "../chunk-N6MLQ26B.js";
8
+ } from "../chunk-POLMWJFC.js";
9
9
  import "../chunk-DP2DX4WV.js";
10
10
  import "../chunk-K3NQKI34.js";
11
11
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  run
4
- } from "./chunk-D5EVQTGJ.js";
4
+ } from "./chunk-IZEQ47HW.js";
5
5
  import {
6
6
  stopDaemon
7
7
  } from "./chunk-RGWADNLT.js";
package/dist/daemon.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  initAgentManager,
7
7
  loadJsonMap,
8
8
  saveJsonMap
9
- } from "./chunk-YTOPX4PB.js";
9
+ } from "./chunk-PHJCXAWJ.js";
10
10
  import {
11
11
  applyIsolation,
12
12
  chownAgentDir,
@@ -34,7 +34,7 @@ import {
34
34
  import {
35
35
  CHANNELS,
36
36
  getChannelDriver
37
- } from "./chunk-LIPPXNIE.js";
37
+ } from "./chunk-WKPMR5B2.js";
38
38
  import {
39
39
  exec,
40
40
  gitExec,
@@ -47,9 +47,9 @@ import {
47
47
  } from "./chunk-YY2QX2J6.js";
48
48
  import "./chunk-D424ZQGI.js";
49
49
  import {
50
- slugify,
50
+ buildVoluteSlug,
51
51
  writeChannelEntry
52
- } from "./chunk-N6MLQ26B.js";
52
+ } from "./chunk-POLMWJFC.js";
53
53
  import {
54
54
  addAgent,
55
55
  addVariant,
@@ -248,8 +248,14 @@ var ConnectorManager = class {
248
248
  const logsDir = resolve2(agentStateDir, "logs");
249
249
  mkdirSync(logsDir, { recursive: true });
250
250
  if (isIsolationEnabled()) {
251
- const [base] = agentName.split("@", 2);
252
- chownAgentDir(agentStateDir, base);
251
+ try {
252
+ const [base] = agentName.split("@", 2);
253
+ chownAgentDir(agentStateDir, base);
254
+ } catch (err) {
255
+ throw new Error(
256
+ `Cannot start connector ${type} for ${agentName}: failed to set ownership on state directory ${agentStateDir}: ${err instanceof Error ? err.message : err}`
257
+ );
258
+ }
253
259
  }
254
260
  const logStream = new RotatingLog(resolve2(logsDir, `${type}.log`));
255
261
  const agentEnv = loadMergedEnv(agentName);
@@ -1713,7 +1719,7 @@ var app = new Hono().post("/", requireAdmin, async (c) => {
1713
1719
  createAgentUser(name);
1714
1720
  chownAgentDir(dest, name);
1715
1721
  const ids = isIsolationEnabled() ? await getAgentUserIds(name) : void 0;
1716
- const env = ids ? { ...process.env, HOME: dest } : void 0;
1722
+ const env = ids ? { ...process.env, HOME: resolve9(dest, "home") } : void 0;
1717
1723
  await exec("npm", ["install"], { cwd: dest, uid: ids?.uid, gid: ids?.gid, env });
1718
1724
  let gitWarning;
1719
1725
  try {
@@ -1809,7 +1815,7 @@ ${user.trimEnd()}
1809
1815
  createAgentUser(name);
1810
1816
  chownAgentDir(dest, name);
1811
1817
  const ids = isIsolationEnabled() ? await getAgentUserIds(name) : void 0;
1812
- const env = ids ? { ...process.env, HOME: dest } : void 0;
1818
+ const env = ids ? { ...process.env, HOME: resolve9(dest, "home") } : void 0;
1813
1819
  await exec("npm", ["install"], { cwd: dest, uid: ids?.uid, gid: ids?.gid, env });
1814
1820
  if (!hasMemory && dailyLogCount > 0) {
1815
1821
  await consolidateMemory(dest);
@@ -3513,7 +3519,6 @@ var app13 = new Hono13().post("/:name/chat", zValidator3("json", chatSchema), as
3513
3519
  }
3514
3520
  const conv = await getConversation(conversationId);
3515
3521
  const convTitle = conv?.title;
3516
- const channel = convTitle ? `volute:${slugify(convTitle)}` : `volute:${conversationId}`;
3517
3522
  const contentBlocks = [];
3518
3523
  if (body.message) {
3519
3524
  contentBlocks.push({ type: "text", text: body.message });
@@ -3527,13 +3532,21 @@ var app13 = new Hono13().post("/:name/chat", zValidator3("json", chatSchema), as
3527
3532
  const participants = await getParticipants(conversationId);
3528
3533
  const agentParticipants = participants.filter((p) => p.userType === "agent");
3529
3534
  const participantNames = participants.map((p) => p.username);
3530
- const { getAgentManager: getAgentManager2 } = await import("./agent-manager-AZUDAKCP.js");
3535
+ const { getAgentManager: getAgentManager2 } = await import("./agent-manager-RMWXST3T.js");
3531
3536
  const manager = getAgentManager2();
3532
3537
  const runningAgents = agentParticipants.map((ap) => {
3533
3538
  const agentKey = ap.username === baseName ? name : ap.username;
3534
3539
  return manager.isRunning(agentKey) ? ap.username : null;
3535
3540
  }).filter((n) => n !== null && n !== senderName);
3536
3541
  const isDM = participants.length === 2;
3542
+ function channelForAgent(agentUsername) {
3543
+ return buildVoluteSlug({
3544
+ participants,
3545
+ agentUsername,
3546
+ convTitle,
3547
+ conversationId
3548
+ });
3549
+ }
3537
3550
  const channelEntry = {
3538
3551
  platformId: conversationId,
3539
3552
  platform: "volute",
@@ -3542,25 +3555,26 @@ var app13 = new Hono13().post("/:name/chat", zValidator3("json", chatSchema), as
3542
3555
  };
3543
3556
  for (const ap of agentParticipants) {
3544
3557
  try {
3545
- writeChannelEntry(ap.username, channel, channelEntry);
3558
+ writeChannelEntry(ap.username, channelForAgent(ap.username), channelEntry);
3546
3559
  } catch (err) {
3547
3560
  console.warn(`[chat] failed to write channel entry for ${ap.username}:`, err);
3548
3561
  }
3549
3562
  }
3550
- const typingMap = getTypingMap();
3551
- const currentlyTyping = typingMap.get(channel);
3552
- const payload = JSON.stringify({
3553
- content: contentBlocks,
3554
- channel,
3555
- conversationId,
3556
- sender: senderName,
3557
- participants: participantNames,
3558
- participantCount: participants.length,
3559
- isDM,
3560
- ...currentlyTyping.length > 0 ? { typing: currentlyTyping } : {}
3561
- });
3562
3563
  for (const agentName of runningAgents) {
3563
3564
  const targetName = agentName === baseName ? name : agentName;
3565
+ const channel = channelForAgent(agentName);
3566
+ const typingMap = getTypingMap();
3567
+ const currentlyTyping = typingMap.get(channel);
3568
+ const payload = JSON.stringify({
3569
+ content: contentBlocks,
3570
+ channel,
3571
+ conversationId,
3572
+ sender: senderName,
3573
+ participants: participantNames,
3574
+ participantCount: participants.length,
3575
+ isDM,
3576
+ ...currentlyTyping.length > 0 ? { typing: currentlyTyping } : {}
3577
+ });
3564
3578
  daemonFetchInternal(`/api/agents/${encodeURIComponent(targetName)}/message`, payload).then(async (res) => {
3565
3579
  if (!res.ok) {
3566
3580
  const text2 = await res.text().catch(() => "");
@@ -4,7 +4,7 @@ import "./chunk-K3NQKI34.js";
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "volute",
7
- version: "0.11.4",
7
+ version: "0.12.0",
8
8
  description: "CLI for creating and managing self-modifying AI agents powered by the Claude Agent SDK",
9
9
  type: "module",
10
10
  license: "MIT",
@@ -4,11 +4,11 @@ import {
4
4
  } from "./chunk-AZEL2IEK.js";
5
5
  import {
6
6
  getChannelDriver
7
- } from "./chunk-LIPPXNIE.js";
7
+ } from "./chunk-WKPMR5B2.js";
8
8
  import {
9
9
  parseArgs
10
10
  } from "./chunk-D424ZQGI.js";
11
- import "./chunk-N6MLQ26B.js";
11
+ import "./chunk-POLMWJFC.js";
12
12
  import {
13
13
  daemonFetch
14
14
  } from "./chunk-STOEJOJO.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  readGlobalConfig,
4
4
  run
5
- } from "./chunk-D5EVQTGJ.js";
5
+ } from "./chunk-IZEQ47HW.js";
6
6
  import "./chunk-ZKNBD5P3.js";
7
7
  import "./chunk-WTJI3JVR.js";
8
8
  import "./chunk-D424ZQGI.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "volute",
3
- "version": "0.11.4",
3
+ "version": "0.12.0",
4
4
  "description": "CLI for creating and managing self-modifying AI agents powered by the Claude Agent SDK",
5
5
  "type": "module",
6
6
  "license": "MIT",
File without changes