volute 0.11.0 → 0.11.2

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.
@@ -21,14 +21,14 @@ async function run(args) {
21
21
  await import("./delete-BOTVU4YO.js").then((m) => m.run(args.slice(1)));
22
22
  break;
23
23
  case "list":
24
- await import("./status-CTWXP6UW.js").then((m) => m.run(args.slice(1)));
24
+ await import("./status-QN5G4RRK.js").then((m) => m.run(args.slice(1)));
25
25
  break;
26
26
  case "status": {
27
27
  const rest = args.slice(1);
28
28
  if (!rest[0] && process.env.VOLUTE_AGENT) {
29
29
  rest.unshift(process.env.VOLUTE_AGENT);
30
30
  }
31
- await import("./status-CTWXP6UW.js").then((m) => m.run(rest));
31
+ await import("./status-QN5G4RRK.js").then((m) => m.run(rest));
32
32
  break;
33
33
  }
34
34
  case "logs": {
@@ -3,7 +3,7 @@ import {
3
3
  AgentManager,
4
4
  getAgentManager,
5
5
  initAgentManager
6
- } from "./chunk-KR6WRAJ4.js";
6
+ } from "./chunk-SJFWB3Q3.js";
7
7
  import "./chunk-46S7YHUB.js";
8
8
  import "./chunk-QF22MYDJ.js";
9
9
  import "./chunk-DP2DX4WV.js";
@@ -4,7 +4,7 @@ import {
4
4
  modeLabel,
5
5
  pollHealth,
6
6
  startService
7
- } from "./chunk-25GGN3OV.js";
7
+ } from "./chunk-ZKNBD5P3.js";
8
8
  import {
9
9
  parseArgs
10
10
  } from "./chunk-D424ZQGI.js";
@@ -5,7 +5,7 @@ import {
5
5
  pollHealthDown,
6
6
  readDaemonConfig,
7
7
  stopService
8
- } from "./chunk-25GGN3OV.js";
8
+ } from "./chunk-ZKNBD5P3.js";
9
9
  import {
10
10
  voluteHome
11
11
  } from "./chunk-DP2DX4WV.js";
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- applyIsolation
3
+ applyIsolation,
4
+ chownAgentDir,
5
+ isIsolationEnabled
4
6
  } from "./chunk-46S7YHUB.js";
5
7
  import {
6
8
  loadMergedEnv
@@ -17,7 +19,7 @@ import {
17
19
 
18
20
  // src/lib/agent-manager.ts
19
21
  import { execFile, spawn } from "child_process";
20
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
22
+ import { copyFileSync, existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
21
23
  import { resolve } from "path";
22
24
  import { promisify } from "util";
23
25
 
@@ -194,6 +196,34 @@ var AgentManager = class {
194
196
  VOLUTE_AGENT_DIR: dir,
195
197
  VOLUTE_AGENT_PORT: String(port)
196
198
  };
199
+ if (isIsolationEnabled() && process.env.CLAUDE_CONFIG_DIR) {
200
+ const agentClaudeDir = resolve(dir, ".claude");
201
+ try {
202
+ mkdirSync(agentClaudeDir, { recursive: true });
203
+ } catch (err) {
204
+ throw new Error(
205
+ `Cannot start agent ${name}: failed to create config directory at ${agentClaudeDir}: ${err instanceof Error ? err.message : err}`
206
+ );
207
+ }
208
+ const sharedCreds = resolve(process.env.CLAUDE_CONFIG_DIR, ".credentials.json");
209
+ const agentCreds = resolve(agentClaudeDir, ".credentials.json");
210
+ if (existsSync3(sharedCreds)) {
211
+ try {
212
+ copyFileSync(sharedCreds, agentCreds);
213
+ } catch (err) {
214
+ throw new Error(
215
+ `Cannot start agent ${name}: failed to copy credentials to ${agentClaudeDir}: ${err instanceof Error ? err.message : err}`
216
+ );
217
+ }
218
+ } else {
219
+ console.warn(
220
+ `[daemon] shared credentials not found at ${sharedCreds} for agent ${name}. Copy ~/.claude/.credentials.json to ${process.env.CLAUDE_CONFIG_DIR}/.credentials.json or set ANTHROPIC_API_KEY in the agent's environment.`
221
+ );
222
+ }
223
+ const baseName2 = name.split("@", 2)[0];
224
+ chownAgentDir(agentClaudeDir, baseName2);
225
+ env.CLAUDE_CONFIG_DIR = agentClaudeDir;
226
+ }
197
227
  const tsxBin = resolve(dir, "node_modules", ".bin", "tsx");
198
228
  const spawnOpts = {
199
229
  cwd: dir,
@@ -19,6 +19,10 @@ function exec(cmd, args, options) {
19
19
  );
20
20
  });
21
21
  }
22
+ function gitExec(args, options) {
23
+ const fullArgs = process.env.VOLUTE_ISOLATION === "user" ? ["-c", `safe.directory=${options.cwd}`, ...args] : args;
24
+ return exec("git", fullArgs, options);
25
+ }
22
26
  function resolveVoluteBin() {
23
27
  try {
24
28
  return execFileSync("which", ["volute"], { encoding: "utf-8" }).trim();
@@ -45,6 +49,7 @@ function execInherit(cmd, args, options) {
45
49
 
46
50
  export {
47
51
  exec,
52
+ gitExec,
48
53
  resolveVoluteBin,
49
54
  execInherit
50
55
  };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  execInherit
4
- } from "./chunk-5C5JWR2L.js";
4
+ } from "./chunk-WTJI3JVR.js";
5
5
  import {
6
6
  voluteHome
7
7
  } from "./chunk-DP2DX4WV.js";
package/dist/cli.js CHANGED
@@ -9,13 +9,13 @@ 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-4QEVVIDG.js");
12
+ const { default: pkg } = await import("./package-6P4FEQHC.js");
13
13
  console.log(pkg.version);
14
14
  process.exit(0);
15
15
  }
16
16
  switch (command) {
17
17
  case "agent":
18
- await import("./agent-JGO6N7IA.js").then((m) => m.run(args));
18
+ await import("./agent-ER2OFKWQ.js").then((m) => m.run(args));
19
19
  break;
20
20
  case "send":
21
21
  await import("./send-X6OQGSD6.js").then((m) => m.run(args));
@@ -39,25 +39,25 @@ 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-6ORVZLBR.js").then((m) => m.run(args));
42
+ await import("./up-AZ5TUREI.js").then((m) => m.run(args));
43
43
  break;
44
44
  case "down":
45
- await import("./down-XV2OQJ7O.js").then((m) => m.run(args));
45
+ await import("./down-O2EQJ5DO.js").then((m) => m.run(args));
46
46
  break;
47
47
  case "restart":
48
- await import("./daemon-restart-BO25T4J6.js").then((m) => m.run(args));
48
+ await import("./daemon-restart-YITZ6Y2E.js").then((m) => m.run(args));
49
49
  break;
50
50
  case "setup":
51
- await import("./setup-GMZOD52B.js").then((m) => m.run(args));
51
+ await import("./setup-7N4KYOYN.js").then((m) => m.run(args));
52
52
  break;
53
53
  case "service":
54
- await import("./service-U6SN5OZO.js").then((m) => m.run(args));
54
+ await import("./service-UL3OCODG.js").then((m) => m.run(args));
55
55
  break;
56
56
  case "update":
57
- await import("./update-BPKQX5OY.js").then((m) => m.run(args));
57
+ await import("./update-EZNCCKXS.js").then((m) => m.run(args));
58
58
  break;
59
59
  case "status":
60
- await import("./status-CTWXP6UW.js").then((m) => m.run(args));
60
+ await import("./status-QN5G4RRK.js").then((m) => m.run(args));
61
61
  break;
62
62
  case "--help":
63
63
  case "-h":
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  run
4
- } from "./chunk-34GBEBQH.js";
4
+ } from "./chunk-COY6TMEK.js";
5
5
  import {
6
6
  stopDaemon
7
- } from "./chunk-GGLTM53H.js";
7
+ } from "./chunk-RGWADNLT.js";
8
8
  import {
9
9
  getServiceMode,
10
10
  modeLabel,
11
11
  pollHealth,
12
12
  readDaemonConfig,
13
13
  restartService
14
- } from "./chunk-25GGN3OV.js";
15
- import "./chunk-5C5JWR2L.js";
14
+ } from "./chunk-ZKNBD5P3.js";
15
+ import "./chunk-WTJI3JVR.js";
16
16
  import "./chunk-D424ZQGI.js";
17
17
  import "./chunk-DP2DX4WV.js";
18
18
  import "./chunk-K3NQKI34.js";
package/dist/daemon.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  initAgentManager,
7
7
  loadJsonMap,
8
8
  saveJsonMap
9
- } from "./chunk-KR6WRAJ4.js";
9
+ } from "./chunk-SJFWB3Q3.js";
10
10
  import {
11
11
  applyIsolation,
12
12
  chownAgentDir,
@@ -37,8 +37,9 @@ import {
37
37
  } from "./chunk-LIPPXNIE.js";
38
38
  import {
39
39
  exec,
40
+ gitExec,
40
41
  resolveVoluteBin
41
- } from "./chunk-5C5JWR2L.js";
42
+ } from "./chunk-WTJI3JVR.js";
42
43
  import {
43
44
  checkForUpdate,
44
45
  checkForUpdateCached,
@@ -1604,23 +1605,23 @@ var TEMPLATE_BRANCH = "volute/template";
1604
1605
  async function initTemplateBranch(projectRoot, composedDir, manifest, ids, env) {
1605
1606
  const templateFiles = listFiles(composedDir).filter((f) => !f.startsWith(".init/") && !f.startsWith(".init\\")).map((f) => manifest.rename[f] ?? f);
1606
1607
  const opts = { cwd: projectRoot, uid: ids?.uid, gid: ids?.gid, env };
1607
- await exec("git", ["checkout", "--orphan", TEMPLATE_BRANCH], opts);
1608
- await exec("git", ["add", "--", ...templateFiles], opts);
1609
- await exec("git", ["commit", "-m", "template update"], opts);
1610
- await exec("git", ["checkout", "-b", "main"], opts);
1611
- await exec("git", ["add", "-A"], opts);
1612
- await exec("git", ["commit", "-m", "initial commit"], opts);
1608
+ await gitExec(["checkout", "--orphan", TEMPLATE_BRANCH], opts);
1609
+ await gitExec(["add", "--", ...templateFiles], opts);
1610
+ await gitExec(["commit", "-m", "template update"], opts);
1611
+ await gitExec(["checkout", "-b", "main"], opts);
1612
+ await gitExec(["add", "-A"], opts);
1613
+ await gitExec(["commit", "-m", "initial commit"], opts);
1613
1614
  }
1614
1615
  async function updateTemplateBranch(projectRoot, template, agentName) {
1615
1616
  const tempWorktree = resolve9(projectRoot, ".variants", "_template_update");
1616
1617
  let branchExists = false;
1617
1618
  try {
1618
- await exec("git", ["rev-parse", "--verify", TEMPLATE_BRANCH], { cwd: projectRoot });
1619
+ await gitExec(["rev-parse", "--verify", TEMPLATE_BRANCH], { cwd: projectRoot });
1619
1620
  branchExists = true;
1620
1621
  } catch {
1621
1622
  }
1622
1623
  try {
1623
- await exec("git", ["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
1624
+ await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
1624
1625
  } catch {
1625
1626
  }
1626
1627
  if (existsSync6(tempWorktree)) {
@@ -1630,17 +1631,17 @@ async function updateTemplateBranch(projectRoot, template, agentName) {
1630
1631
  const { composedDir, manifest } = composeTemplate(templatesRoot, template);
1631
1632
  try {
1632
1633
  if (branchExists) {
1633
- await exec("git", ["worktree", "add", tempWorktree, TEMPLATE_BRANCH], {
1634
+ await gitExec(["worktree", "add", tempWorktree, TEMPLATE_BRANCH], {
1634
1635
  cwd: projectRoot
1635
1636
  });
1636
1637
  } else {
1637
- await exec("git", ["worktree", "add", "--detach", tempWorktree], { cwd: projectRoot });
1638
- await exec("git", ["checkout", "--orphan", TEMPLATE_BRANCH], { cwd: tempWorktree });
1639
- await exec("git", ["rm", "-rf", "--cached", "."], { cwd: tempWorktree });
1640
- await exec("git", ["clean", "-fd"], { cwd: tempWorktree });
1638
+ await gitExec(["worktree", "add", "--detach", tempWorktree], { cwd: projectRoot });
1639
+ await gitExec(["checkout", "--orphan", TEMPLATE_BRANCH], { cwd: tempWorktree });
1640
+ await gitExec(["rm", "-rf", "--cached", "."], { cwd: tempWorktree });
1641
+ await gitExec(["clean", "-fd"], { cwd: tempWorktree });
1641
1642
  }
1642
1643
  if (branchExists) {
1643
- await exec("git", ["rm", "-rf", "."], { cwd: tempWorktree }).catch(() => {
1644
+ await gitExec(["rm", "-rf", "."], { cwd: tempWorktree }).catch(() => {
1644
1645
  });
1645
1646
  }
1646
1647
  copyTemplateToDir(composedDir, tempWorktree, agentName, manifest);
@@ -1648,15 +1649,15 @@ async function updateTemplateBranch(projectRoot, template, agentName) {
1648
1649
  if (existsSync6(initDir)) {
1649
1650
  rmSync2(initDir, { recursive: true, force: true });
1650
1651
  }
1651
- await exec("git", ["add", "-A"], { cwd: tempWorktree });
1652
+ await gitExec(["add", "-A"], { cwd: tempWorktree });
1652
1653
  try {
1653
- await exec("git", ["diff", "--cached", "--quiet"], { cwd: tempWorktree });
1654
+ await gitExec(["diff", "--cached", "--quiet"], { cwd: tempWorktree });
1654
1655
  } catch {
1655
- await exec("git", ["commit", "-m", "template update"], { cwd: tempWorktree });
1656
+ await gitExec(["commit", "-m", "template update"], { cwd: tempWorktree });
1656
1657
  }
1657
1658
  } finally {
1658
1659
  try {
1659
- await exec("git", ["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
1660
+ await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
1660
1661
  } catch {
1661
1662
  }
1662
1663
  if (existsSync6(tempWorktree)) {
@@ -1667,15 +1668,14 @@ async function updateTemplateBranch(projectRoot, template, agentName) {
1667
1668
  }
1668
1669
  async function mergeTemplateBranch(worktreeDir) {
1669
1670
  try {
1670
- await exec(
1671
- "git",
1671
+ await gitExec(
1672
1672
  ["merge", TEMPLATE_BRANCH, "--allow-unrelated-histories", "-m", "merge template update"],
1673
1673
  { cwd: worktreeDir }
1674
1674
  );
1675
1675
  return false;
1676
1676
  } catch (e) {
1677
1677
  try {
1678
- const status = await exec("git", ["status", "--porcelain"], { cwd: worktreeDir });
1678
+ const status = await gitExec(["status", "--porcelain"], { cwd: worktreeDir });
1679
1679
  const hasConflictMarkers = status.split("\n").some((line) => line.startsWith("UU") || line.startsWith("AA"));
1680
1680
  if (hasConflictMarkers) return true;
1681
1681
  } catch {
@@ -1712,7 +1712,7 @@ var app = new Hono().post("/", requireAdmin, async (c) => {
1712
1712
  await exec("npm", ["install"], { cwd: dest, uid: ids?.uid, gid: ids?.gid, env });
1713
1713
  let gitWarning;
1714
1714
  try {
1715
- await exec("git", ["init"], { cwd: dest, uid: ids?.uid, gid: ids?.gid, env });
1715
+ await gitExec(["init"], { cwd: dest, uid: ids?.uid, gid: ids?.gid, env });
1716
1716
  await initTemplateBranch(dest, composedDir, manifest, ids, env);
1717
1717
  } catch {
1718
1718
  rmSync2(resolve9(dest, ".git"), { recursive: true, force: true });
@@ -1809,9 +1809,9 @@ ${user.trimEnd()}
1809
1809
  if (!hasMemory && dailyLogCount > 0) {
1810
1810
  await consolidateMemory(dest);
1811
1811
  }
1812
- await exec("git", ["init"], { cwd: dest, uid: ids?.uid, gid: ids?.gid, env });
1813
- await exec("git", ["add", "-A"], { cwd: dest, uid: ids?.uid, gid: ids?.gid, env });
1814
- await exec("git", ["commit", "-m", "import from OpenClaw"], {
1812
+ await gitExec(["init"], { cwd: dest, uid: ids?.uid, gid: ids?.gid, env });
1813
+ await gitExec(["add", "-A"], { cwd: dest, uid: ids?.uid, gid: ids?.gid, env });
1814
+ await gitExec(["commit", "-m", "import from OpenClaw"], {
1815
1815
  cwd: dest,
1816
1816
  uid: ids?.uid,
1817
1817
  gid: ids?.gid,
@@ -1932,15 +1932,13 @@ ${user.trimEnd()}
1932
1932
  if (variant) {
1933
1933
  const projectRoot = agentDir(baseName);
1934
1934
  if (existsSync6(variant.path)) {
1935
- const status = (await exec("git", ["status", "--porcelain"], { cwd: variant.path })).trim();
1935
+ const status = (await gitExec(["status", "--porcelain"], { cwd: variant.path })).trim();
1936
1936
  if (status) {
1937
1937
  try {
1938
- await exec("git", ["add", "-A"], { cwd: variant.path });
1939
- await exec(
1940
- "git",
1941
- ["commit", "-m", "Auto-commit uncommitted changes before merge"],
1942
- { cwd: variant.path }
1943
- );
1938
+ await gitExec(["add", "-A"], { cwd: variant.path });
1939
+ await gitExec(["commit", "-m", "Auto-commit uncommitted changes before merge"], {
1940
+ cwd: variant.path
1941
+ });
1944
1942
  } catch (e) {
1945
1943
  console.error(
1946
1944
  `[daemon] failed to auto-commit variant worktree for ${baseName}:`,
@@ -1949,28 +1947,28 @@ ${user.trimEnd()}
1949
1947
  }
1950
1948
  }
1951
1949
  }
1952
- const mainStatus = (await exec("git", ["status", "--porcelain"], { cwd: projectRoot })).trim();
1950
+ const mainStatus = (await gitExec(["status", "--porcelain"], { cwd: projectRoot })).trim();
1953
1951
  if (mainStatus) {
1954
1952
  try {
1955
- await exec("git", ["add", "-A"], { cwd: projectRoot });
1956
- await exec("git", ["commit", "-m", "Auto-commit uncommitted changes before merge"], {
1953
+ await gitExec(["add", "-A"], { cwd: projectRoot });
1954
+ await gitExec(["commit", "-m", "Auto-commit uncommitted changes before merge"], {
1957
1955
  cwd: projectRoot
1958
1956
  });
1959
1957
  } catch (e) {
1960
1958
  console.error(`[daemon] failed to auto-commit main worktree for ${baseName}:`, e);
1961
1959
  }
1962
1960
  }
1963
- await exec("git", ["merge", variant.branch], { cwd: projectRoot });
1961
+ await gitExec(["merge", variant.branch], { cwd: projectRoot });
1964
1962
  if (existsSync6(variant.path)) {
1965
1963
  try {
1966
- await exec("git", ["worktree", "remove", "--force", variant.path], {
1964
+ await gitExec(["worktree", "remove", "--force", variant.path], {
1967
1965
  cwd: projectRoot
1968
1966
  });
1969
1967
  } catch {
1970
1968
  }
1971
1969
  }
1972
1970
  try {
1973
- await exec("git", ["branch", "-D", variant.branch], { cwd: projectRoot });
1971
+ await gitExec(["branch", "-D", variant.branch], { cwd: projectRoot });
1974
1972
  } catch {
1975
1973
  }
1976
1974
  removeVariant(baseName, mergeVariantName);
@@ -1979,6 +1977,7 @@ ${user.trimEnd()}
1979
1977
  } catch (e) {
1980
1978
  console.error(`[daemon] npm install failed after merge for ${baseName}:`, e);
1981
1979
  }
1980
+ chownAgentDir(projectRoot, baseName);
1982
1981
  }
1983
1982
  }
1984
1983
  if (context) {
@@ -2055,14 +2054,14 @@ ${user.trimEnd()}
2055
2054
  if (!existsSync6(worktreeDir2)) {
2056
2055
  return c.json({ error: "No upgrade in progress" }, 400);
2057
2056
  }
2058
- const status = await exec("git", ["status", "--porcelain"], { cwd: worktreeDir2 });
2057
+ const status = await gitExec(["status", "--porcelain"], { cwd: worktreeDir2 });
2059
2058
  const hasConflicts2 = status.split("\n").some((line) => line.startsWith("UU") || line.startsWith("AA"));
2060
2059
  if (hasConflicts2) {
2061
2060
  return c.json({ error: "Unresolved conflicts remain" }, 409);
2062
2061
  }
2063
2062
  try {
2064
- await exec("git", ["add", "-A"], { cwd: worktreeDir2 });
2065
- await exec("git", ["commit", "--no-edit"], { cwd: worktreeDir2 });
2063
+ await gitExec(["add", "-A"], { cwd: worktreeDir2 });
2064
+ await gitExec(["commit", "--no-edit"], { cwd: worktreeDir2 });
2066
2065
  } catch (e) {
2067
2066
  const msg = e instanceof Error ? e.message : String(e);
2068
2067
  if (!msg.includes("nothing to commit")) throw e;
@@ -2077,6 +2076,7 @@ ${user.trimEnd()}
2077
2076
  port: variantPort,
2078
2077
  created: (/* @__PURE__ */ new Date()).toISOString()
2079
2078
  });
2079
+ chownAgentDir(dir, agentName);
2080
2080
  await getAgentManager().startAgent(`${agentName}@${UPGRADE_VARIANT}`);
2081
2081
  return c.json({
2082
2082
  ok: true,
@@ -2090,13 +2090,21 @@ ${user.trimEnd()}
2090
2090
  } catch {
2091
2091
  }
2092
2092
  try {
2093
- await exec("git", ["worktree", "remove", "--force", worktreeDir2], { cwd: dir });
2093
+ await gitExec(["worktree", "remove", "--force", worktreeDir2], { cwd: dir });
2094
2094
  } catch {
2095
2095
  }
2096
2096
  try {
2097
- await exec("git", ["branch", "-D", UPGRADE_VARIANT], { cwd: dir });
2097
+ await gitExec(["branch", "-D", UPGRADE_VARIANT], { cwd: dir });
2098
2098
  } catch {
2099
2099
  }
2100
+ try {
2101
+ chownAgentDir(dir, agentName);
2102
+ } catch (chownErr) {
2103
+ console.error(
2104
+ `[daemon] failed to fix ownership during upgrade cleanup for ${agentName}:`,
2105
+ chownErr
2106
+ );
2107
+ }
2100
2108
  return c.json(
2101
2109
  { error: err instanceof Error ? err.message : "Failed to continue upgrade" },
2102
2110
  500
@@ -2110,9 +2118,9 @@ ${user.trimEnd()}
2110
2118
  409
2111
2119
  );
2112
2120
  }
2113
- await exec("git", ["worktree", "prune"], { cwd: dir });
2121
+ await gitExec(["worktree", "prune"], { cwd: dir });
2114
2122
  try {
2115
- await exec("git", ["branch", "-D", UPGRADE_VARIANT], { cwd: dir });
2123
+ await gitExec(["branch", "-D", UPGRADE_VARIANT], { cwd: dir });
2116
2124
  } catch {
2117
2125
  }
2118
2126
  await updateTemplateBranch(dir, template, agentName);
@@ -2120,8 +2128,9 @@ ${user.trimEnd()}
2120
2128
  if (!existsSync6(parentDir)) {
2121
2129
  mkdirSync5(parentDir, { recursive: true });
2122
2130
  }
2123
- await exec("git", ["worktree", "add", "-b", UPGRADE_VARIANT, worktreeDir], { cwd: dir });
2131
+ await gitExec(["worktree", "add", "-b", UPGRADE_VARIANT, worktreeDir], { cwd: dir });
2124
2132
  const hasConflicts = await mergeTemplateBranch(worktreeDir);
2133
+ chownAgentDir(dir, agentName);
2125
2134
  if (hasConflicts) {
2126
2135
  return c.json({
2127
2136
  ok: false,
@@ -2140,6 +2149,7 @@ ${user.trimEnd()}
2140
2149
  port: variantPort,
2141
2150
  created: (/* @__PURE__ */ new Date()).toISOString()
2142
2151
  });
2152
+ chownAgentDir(dir, agentName);
2143
2153
  await getAgentManager().startAgent(`${agentName}@${UPGRADE_VARIANT}`);
2144
2154
  return c.json({
2145
2155
  ok: true,
@@ -2153,13 +2163,21 @@ ${user.trimEnd()}
2153
2163
  } catch {
2154
2164
  }
2155
2165
  try {
2156
- await exec("git", ["worktree", "remove", "--force", worktreeDir], { cwd: dir });
2166
+ await gitExec(["worktree", "remove", "--force", worktreeDir], { cwd: dir });
2157
2167
  } catch {
2158
2168
  }
2159
2169
  try {
2160
- await exec("git", ["branch", "-D", UPGRADE_VARIANT], { cwd: dir });
2170
+ await gitExec(["branch", "-D", UPGRADE_VARIANT], { cwd: dir });
2161
2171
  } catch {
2162
2172
  }
2173
+ try {
2174
+ chownAgentDir(dir, agentName);
2175
+ } catch (chownErr) {
2176
+ console.error(
2177
+ `[daemon] failed to fix ownership during upgrade cleanup for ${agentName}:`,
2178
+ chownErr
2179
+ );
2180
+ }
2163
2181
  return c.json(
2164
2182
  { error: err instanceof Error ? err.message : "Failed to complete upgrade" },
2165
2183
  500
@@ -3035,7 +3053,7 @@ var app12 = new Hono12().get("/:name/variants", async (c) => {
3035
3053
  }
3036
3054
  mkdirSync7(resolve13(projectRoot, ".variants"), { recursive: true });
3037
3055
  try {
3038
- await exec("git", ["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
3056
+ await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
3039
3057
  } catch (e) {
3040
3058
  const msg = e instanceof Error ? e.message : String(e);
3041
3059
  return c.json({ error: `Failed to create worktree: ${msg}` }, 500);
@@ -3058,6 +3076,7 @@ var app12 = new Hono12().get("/:name/variants", async (c) => {
3058
3076
  created: (/* @__PURE__ */ new Date()).toISOString()
3059
3077
  };
3060
3078
  addVariant(agentName, variant);
3079
+ chownAgentDir(projectRoot, agentName);
3061
3080
  if (!body.noStart) {
3062
3081
  try {
3063
3082
  await getAgentManager().startAgent(`${agentName}@${variantName}`);
@@ -3086,11 +3105,11 @@ var app12 = new Hono12().get("/:name/variants", async (c) => {
3086
3105
  }
3087
3106
  const projectRoot = agentDir(agentName);
3088
3107
  if (existsSync9(variant.path)) {
3089
- const status = (await exec("git", ["status", "--porcelain"], { cwd: variant.path })).trim();
3108
+ const status = (await gitExec(["status", "--porcelain"], { cwd: variant.path })).trim();
3090
3109
  if (status) {
3091
3110
  try {
3092
- await exec("git", ["add", "-A"], { cwd: variant.path });
3093
- await exec("git", ["commit", "-m", "Auto-commit uncommitted changes before merge"], {
3111
+ await gitExec(["add", "-A"], { cwd: variant.path });
3112
+ await gitExec(["commit", "-m", "Auto-commit uncommitted changes before merge"], {
3094
3113
  cwd: variant.path
3095
3114
  });
3096
3115
  } catch (e) {
@@ -3123,11 +3142,11 @@ var app12 = new Hono12().get("/:name/variants", async (c) => {
3123
3142
  );
3124
3143
  }
3125
3144
  }
3126
- const mainStatus = (await exec("git", ["status", "--porcelain"], { cwd: projectRoot })).trim();
3145
+ const mainStatus = (await gitExec(["status", "--porcelain"], { cwd: projectRoot })).trim();
3127
3146
  if (mainStatus) {
3128
3147
  try {
3129
- await exec("git", ["add", "-A"], { cwd: projectRoot });
3130
- await exec("git", ["commit", "-m", "Auto-commit uncommitted changes before merge"], {
3148
+ await gitExec(["add", "-A"], { cwd: projectRoot });
3149
+ await gitExec(["commit", "-m", "Auto-commit uncommitted changes before merge"], {
3131
3150
  cwd: projectRoot
3132
3151
  });
3133
3152
  } catch (e) {
@@ -3138,18 +3157,18 @@ var app12 = new Hono12().get("/:name/variants", async (c) => {
3138
3157
  }
3139
3158
  }
3140
3159
  try {
3141
- await exec("git", ["merge", variant.branch], { cwd: projectRoot });
3160
+ await gitExec(["merge", variant.branch], { cwd: projectRoot });
3142
3161
  } catch (e) {
3143
3162
  return c.json({ error: "Merge failed. Resolve conflicts manually." }, 500);
3144
3163
  }
3145
3164
  if (existsSync9(variant.path)) {
3146
3165
  try {
3147
- await exec("git", ["worktree", "remove", "--force", variant.path], { cwd: projectRoot });
3166
+ await gitExec(["worktree", "remove", "--force", variant.path], { cwd: projectRoot });
3148
3167
  } catch {
3149
3168
  }
3150
3169
  }
3151
3170
  try {
3152
- await exec("git", ["branch", "-D", variant.branch], { cwd: projectRoot });
3171
+ await gitExec(["branch", "-D", variant.branch], { cwd: projectRoot });
3153
3172
  } catch {
3154
3173
  }
3155
3174
  removeVariant(agentName, variantName);
@@ -3157,6 +3176,7 @@ var app12 = new Hono12().get("/:name/variants", async (c) => {
3157
3176
  await exec("npm", ["install"], { cwd: projectRoot });
3158
3177
  } catch {
3159
3178
  }
3179
+ chownAgentDir(projectRoot, agentName);
3160
3180
  const manager = getAgentManager();
3161
3181
  const context = {
3162
3182
  type: "merged",
@@ -3195,15 +3215,16 @@ var app12 = new Hono12().get("/:name/variants", async (c) => {
3195
3215
  }
3196
3216
  if (existsSync9(variant.path)) {
3197
3217
  try {
3198
- await exec("git", ["worktree", "remove", "--force", variant.path], { cwd: projectRoot });
3218
+ await gitExec(["worktree", "remove", "--force", variant.path], { cwd: projectRoot });
3199
3219
  } catch {
3200
3220
  }
3201
3221
  }
3202
3222
  try {
3203
- await exec("git", ["branch", "-D", variant.branch], { cwd: projectRoot });
3223
+ await gitExec(["branch", "-D", variant.branch], { cwd: projectRoot });
3204
3224
  } catch {
3205
3225
  }
3206
3226
  removeVariant(agentName, variantName);
3227
+ chownAgentDir(projectRoot, agentName);
3207
3228
  return c.json({ ok: true });
3208
3229
  });
3209
3230
  var variants_default = app12;
@@ -3501,7 +3522,7 @@ var app13 = new Hono13().post("/:name/chat", zValidator3("json", chatSchema), as
3501
3522
  const participants = await getParticipants(conversationId);
3502
3523
  const agentParticipants = participants.filter((p) => p.userType === "agent");
3503
3524
  const participantNames = participants.map((p) => p.username);
3504
- const { getAgentManager: getAgentManager2 } = await import("./agent-manager-4OCID725.js");
3525
+ const { getAgentManager: getAgentManager2 } = await import("./agent-manager-RXNMLNUQ.js");
3505
3526
  const manager = getAgentManager2();
3506
3527
  const runningAgents = agentParticipants.map((ap) => {
3507
3528
  const agentKey = ap.username === baseName ? name : ap.username;
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  run,
4
4
  stopDaemon
5
- } from "./chunk-GGLTM53H.js";
6
- import "./chunk-25GGN3OV.js";
7
- import "./chunk-5C5JWR2L.js";
5
+ } from "./chunk-RGWADNLT.js";
6
+ import "./chunk-ZKNBD5P3.js";
7
+ import "./chunk-WTJI3JVR.js";
8
8
  import "./chunk-DP2DX4WV.js";
9
9
  import "./chunk-K3NQKI34.js";
10
10
  export {
@@ -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.0",
7
+ version: "0.11.2",
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,10 +4,10 @@ import {
4
4
  LAUNCHD_PLIST_PATH,
5
5
  SYSTEM_SERVICE_PATH,
6
6
  USER_SYSTEMD_UNIT
7
- } from "./chunk-25GGN3OV.js";
7
+ } from "./chunk-ZKNBD5P3.js";
8
8
  import {
9
9
  resolveVoluteBin
10
- } from "./chunk-5C5JWR2L.js";
10
+ } from "./chunk-WTJI3JVR.js";
11
11
  import {
12
12
  parseArgs
13
13
  } from "./chunk-D424ZQGI.js";
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SYSTEM_SERVICE_PATH
4
- } from "./chunk-25GGN3OV.js";
4
+ } from "./chunk-ZKNBD5P3.js";
5
5
  import {
6
6
  ensureVoluteGroup
7
7
  } from "./chunk-46S7YHUB.js";
8
8
  import {
9
9
  resolveVoluteBin
10
- } from "./chunk-5C5JWR2L.js";
10
+ } from "./chunk-WTJI3JVR.js";
11
11
  import {
12
12
  parseArgs
13
13
  } from "./chunk-D424ZQGI.js";
@@ -4,8 +4,8 @@ import {
4
4
  getServiceMode,
5
5
  modeLabel,
6
6
  readDaemonConfig
7
- } from "./chunk-25GGN3OV.js";
8
- import "./chunk-5C5JWR2L.js";
7
+ } from "./chunk-ZKNBD5P3.js";
8
+ import "./chunk-WTJI3JVR.js";
9
9
  import {
10
10
  checkForUpdate
11
11
  } from "./chunk-RT6Y7AR3.js";
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  readGlobalConfig,
4
4
  run
5
- } from "./chunk-34GBEBQH.js";
6
- import "./chunk-25GGN3OV.js";
7
- import "./chunk-5C5JWR2L.js";
5
+ } from "./chunk-COY6TMEK.js";
6
+ import "./chunk-ZKNBD5P3.js";
7
+ import "./chunk-WTJI3JVR.js";
8
8
  import "./chunk-D424ZQGI.js";
9
9
  import "./chunk-DP2DX4WV.js";
10
10
  import "./chunk-K3NQKI34.js";
@@ -5,12 +5,12 @@ import {
5
5
  pollHealth,
6
6
  readDaemonConfig,
7
7
  restartService
8
- } from "./chunk-25GGN3OV.js";
8
+ } from "./chunk-ZKNBD5P3.js";
9
9
  import {
10
10
  exec,
11
11
  execInherit,
12
12
  resolveVoluteBin
13
- } from "./chunk-5C5JWR2L.js";
13
+ } from "./chunk-WTJI3JVR.js";
14
14
  import {
15
15
  checkForUpdate
16
16
  } from "./chunk-RT6Y7AR3.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "volute",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
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",