volute 0.51.0 → 0.52.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 (50) hide show
  1. package/dist/{auth-X6EMNEGB.js → auth-KRDSM55Q.js} +3 -1
  2. package/dist/{chunk-VAEZCIJC.js → chunk-724DVYHU.js} +8 -8
  3. package/dist/{chunk-HKP6OAJP.js → chunk-7LT3YZUR.js} +12 -0
  4. package/dist/{chunk-ICL6T4SN.js → chunk-AXFLY5GU.js} +11 -2
  5. package/dist/{chunk-DN3LKLYR.js → chunk-CW7BQKF6.js} +3 -3
  6. package/dist/{chunk-AI47FDGL.js → chunk-ITK6HV47.js} +1 -1
  7. package/dist/{chunk-VSBMLB2W.js → chunk-K2F237KS.js} +2 -2
  8. package/dist/{chunk-QT4D5XCI.js → chunk-RPPTGPYF.js} +1 -1
  9. package/dist/{chunk-7HN63Q7J.js → chunk-RU74YG46.js} +5 -5
  10. package/dist/{chunk-Q7XQLKZB.js → chunk-SW2U6HRB.js} +2 -2
  11. package/dist/{chunk-BSHZ23MS.js → chunk-XRWUQPCA.js} +2 -2
  12. package/dist/{chunk-CDKQJWGK.js → chunk-YVR6EHWL.js} +2 -2
  13. package/dist/{chunk-VP5PFNZO.js → chunk-ZEZQNP2G.js} +35 -19
  14. package/dist/cli.js +6 -6
  15. package/dist/{cloud-sync-GPXYPTIC.js → cloud-sync-H7EWZASD.js} +9 -9
  16. package/dist/{daemon-restart-2EWBRTN5.js → daemon-restart-4FWUA5JF.js} +1 -1
  17. package/dist/daemon.js +321 -186
  18. package/dist/{delete-O7PEFQDF.js → delete-CYVZUAV2.js} +4 -0
  19. package/dist/{delivery-manager-HGVZSEES.js → delivery-manager-VYXVKUMP.js} +4 -4
  20. package/dist/{echo-text-6ANI5HHN.js → echo-text-PEEV7FQU.js} +10 -10
  21. package/dist/{extensions-NY6WST33.js → extensions-N6L5NYTK.js} +9 -9
  22. package/dist/{join-PYA36HEC.js → join-KLRU72JJ.js} +10 -2
  23. package/dist/{message-delivery-JHMAJ2GU.js → message-delivery-7URC52ME.js} +9 -9
  24. package/dist/{mind-WF6QIXWV.js → mind-NEXGT3KE.js} +4 -4
  25. package/dist/{mind-service-DZCUUC7J.js → mind-service-E26ZQXDS.js} +9 -9
  26. package/dist/{package-B6O5APCZ.js → package-2W2XKSIP.js} +2 -2
  27. package/dist/{scheduler-TNBN54ZK.js → scheduler-JTTWZDYU.js} +4 -4
  28. package/dist/{seed-K2LYODIH.js → seed-64XEHRUP.js} +1 -1
  29. package/dist/{seed-cmd-2EWBTR6P.js → seed-cmd-UEL2QB3Q.js} +2 -2
  30. package/dist/{seed-create-VGTLU5FD.js → seed-create-4JRQDPGA.js} +1 -1
  31. package/dist/{seed-sprout-PILHJ3YS.js → seed-sprout-NIDIOJXT.js} +2 -2
  32. package/dist/{setup-MDPSK2XG.js → setup-4IX6PCD3.js} +1 -1
  33. package/dist/skills/volute-mind/references/variants.md +1 -1
  34. package/dist/{skills-NH2GQKAF.js → skills-MPUALV3S.js} +1 -1
  35. package/dist/{sleep-manager-7JXEQQ2P.js → sleep-manager-OFP2GFXF.js} +9 -9
  36. package/dist/{spirit-25JVAL3M.js → spirit-4ECYIVGE.js} +2 -2
  37. package/dist/{spirit-availability-PJDWZJ3J.js → spirit-availability-Y54Y3675.js} +10 -10
  38. package/dist/{sprout-EXUZMIOR.js → sprout-GJMZFRGZ.js} +1 -1
  39. package/dist/{system-events-ZPSH63QX.js → system-events-V43HDA3T.js} +3 -1
  40. package/dist/{turn-tracker-TAT2HGK6.js → turn-tracker-C5PVIC3B.js} +1 -1
  41. package/dist/{up-J7XCAH7P.js → up-H6LJZDRK.js} +1 -1
  42. package/dist/{variant-cleanup-YXN25ZVW.js → variant-cleanup-STC6B5HR.js} +4 -4
  43. package/dist/{version-notify-EN3KJ7HH.js → version-notify-LBVHH5YV.js} +1 -1
  44. package/dist/web-assets/assets/index-B_eYTa3R.js +97 -0
  45. package/dist/web-assets/assets/{index-BOyJ4Gqs.css → index-DhZrzddW.css} +1 -1
  46. package/dist/web-assets/index.html +2 -2
  47. package/package.json +2 -2
  48. package/templates/_base/src/lib/auto-commit.ts +49 -11
  49. package/dist/web-assets/assets/index-CrxBwnzp.js +0 -95
  50. /package/dist/{chunk-IWAVIJO2.js → chunk-VPOMJMV6.js} +0 -0
package/dist/daemon.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  import {
25
25
  SPIRIT_NOTICE_PREFIX,
26
26
  ensureSpiritAvailable
27
- } from "./chunk-DN3LKLYR.js";
27
+ } from "./chunk-CW7BQKF6.js";
28
28
  import {
29
29
  isHomeOnlyArchive
30
30
  } from "./chunk-FLIEXG2T.js";
@@ -39,7 +39,7 @@ import {
39
39
  } from "./chunk-HTRSSOHY.js";
40
40
  import {
41
41
  cleanupVariant
42
- } from "./chunk-AI47FDGL.js";
42
+ } from "./chunk-ITK6HV47.js";
43
43
  import {
44
44
  checkForUpdate,
45
45
  checkForUpdateCached,
@@ -51,7 +51,7 @@ import {
51
51
  fixModelEscapes,
52
52
  getPlatformDriver,
53
53
  routeOutboundBridge
54
- } from "./chunk-BSHZ23MS.js";
54
+ } from "./chunk-XRWUQPCA.js";
55
55
  import {
56
56
  getBridgeConfig,
57
57
  readBridgesConfig,
@@ -105,8 +105,8 @@ import {
105
105
  stopMindFull,
106
106
  uninstallNpmExtension,
107
107
  writeSystemsConfig
108
- } from "./chunk-VP5PFNZO.js";
109
- import "./chunk-VSBMLB2W.js";
108
+ } from "./chunk-ZEZQNP2G.js";
109
+ import "./chunk-K2F237KS.js";
110
110
  import {
111
111
  applyInitFiles,
112
112
  applyTemplateHomeFiles,
@@ -119,7 +119,7 @@ import {
119
119
  import {
120
120
  getScheduler,
121
121
  initScheduler
122
- } from "./chunk-Q7XQLKZB.js";
122
+ } from "./chunk-SW2U6HRB.js";
123
123
  import {
124
124
  checkStaleSend,
125
125
  formatHoldNotice,
@@ -128,7 +128,7 @@ import {
128
128
  initDeliveryManager,
129
129
  isConversationId,
130
130
  publishTypingForChannels
131
- } from "./chunk-7HN63Q7J.js";
131
+ } from "./chunk-RU74YG46.js";
132
132
  import {
133
133
  MindStartupError,
134
134
  RestartTracker,
@@ -138,7 +138,7 @@ import {
138
138
  initMindManager,
139
139
  syncProviderToMinds,
140
140
  tryGetMindManager
141
- } from "./chunk-VAEZCIJC.js";
141
+ } from "./chunk-724DVYHU.js";
142
142
  import {
143
143
  extractTextContent
144
144
  } from "./chunk-UDZLPR34.js";
@@ -161,7 +161,7 @@ import {
161
161
  takeErrored,
162
162
  trackToolUse,
163
163
  utcDateTimeStr
164
- } from "./chunk-CDKQJWGK.js";
164
+ } from "./chunk-YVR6EHWL.js";
165
165
  import {
166
166
  SEED_SKILLS,
167
167
  STANDARD_SKILLS,
@@ -183,12 +183,13 @@ import {
183
183
  syncBuiltinSkills,
184
184
  uninstallSkill,
185
185
  updateSkill
186
- } from "./chunk-QT4D5XCI.js";
186
+ } from "./chunk-RPPTGPYF.js";
187
187
  import {
188
188
  approveUser,
189
189
  changePassword,
190
190
  countAdmins,
191
191
  createUser,
192
+ deleteExternalMindUser,
192
193
  deleteMindUser as deleteMindUser2,
193
194
  deleteUser,
194
195
  getDisplayNames,
@@ -204,9 +205,10 @@ import {
204
205
  updateUserProfile,
205
206
  verifyUser,
206
207
  withSenderDisplayNames
207
- } from "./chunk-HKP6OAJP.js";
208
+ } from "./chunk-7LT3YZUR.js";
208
209
  import {
209
210
  captureReflection,
211
+ cleanExpiredEvents,
210
212
  clearDeliveredEvents,
211
213
  deliverEvent,
212
214
  drainEvents,
@@ -217,7 +219,7 @@ import {
217
219
  listEvents,
218
220
  parseMeta,
219
221
  recordNotice
220
- } from "./chunk-ICL6T4SN.js";
222
+ } from "./chunk-AXFLY5GU.js";
221
223
  import {
222
224
  publish as publish2,
223
225
  subscribe as subscribe2,
@@ -397,7 +399,7 @@ import "./chunk-K3NQKI34.js";
397
399
  import { randomBytes as randomBytes3 } from "crypto";
398
400
  import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync12, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
399
401
  import { homedir as homedir3 } from "os";
400
- import { resolve as resolve19 } from "path";
402
+ import { resolve as resolve20 } from "path";
401
403
  import { format } from "util";
402
404
 
403
405
  // packages/daemon/src/lib/daemon/backup-manager.ts
@@ -508,7 +510,7 @@ var BackupManager = class {
508
510
  } catch (pubErr) {
509
511
  blog.error("failed to publish backup-failure activity", logger_default.errorData(pubErr));
510
512
  }
511
- const { deliverEvent: deliverEvent2 } = await import("./system-events-ZPSH63QX.js");
513
+ const { deliverEvent: deliverEvent2 } = await import("./system-events-V43HDA3T.js");
512
514
  await deliverEvent2(getSpiritName(), {
513
515
  type: "notice",
514
516
  meta: { subtype: "backup" },
@@ -732,8 +734,8 @@ var BridgeManager = class {
732
734
  if (!tracked) return;
733
735
  this.stopping.add(platform);
734
736
  this.bridges.delete(platform);
735
- await new Promise((resolve20) => {
736
- tracked.child.on("exit", () => resolve20());
737
+ await new Promise((resolve21) => {
738
+ tracked.child.on("exit", () => resolve21());
737
739
  try {
738
740
  if (tracked.child.pid) {
739
741
  process.kill(-tracked.child.pid, "SIGTERM");
@@ -744,7 +746,7 @@ var BridgeManager = class {
744
746
  if (err instanceof Error && err.code !== "ESRCH") {
745
747
  blog2.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
746
748
  }
747
- resolve20();
749
+ resolve21();
748
750
  }
749
751
  setTimeout(() => {
750
752
  try {
@@ -755,7 +757,7 @@ var BridgeManager = class {
755
757
  }
756
758
  } catch {
757
759
  }
758
- resolve20();
760
+ resolve21();
759
761
  }, 5e3);
760
762
  });
761
763
  this.stopping.delete(platform);
@@ -865,6 +867,11 @@ async function runMaintenance() {
865
867
  } catch (err) {
866
868
  logger_default.warn("maintenance: failed to clean expired logs", logger_default.errorData(err));
867
869
  }
870
+ try {
871
+ await cleanExpiredEvents();
872
+ } catch (err) {
873
+ logger_default.warn("maintenance: failed to clean expired events", logger_default.errorData(err));
874
+ }
868
875
  }
869
876
  function startMaintenanceInterval(intervalMs = MAINTENANCE_INTERVAL_MS, task = runMaintenance) {
870
877
  const handle = setInterval(() => void task(), intervalMs);
@@ -1427,10 +1434,10 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1427
1434
  stream.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
1428
1435
  });
1429
1436
  });
1430
- await new Promise((resolve20) => {
1437
+ await new Promise((resolve21) => {
1431
1438
  stream.onAbort(() => {
1432
1439
  unsubscribe();
1433
- resolve20();
1440
+ resolve21();
1434
1441
  });
1435
1442
  });
1436
1443
  });
@@ -1455,7 +1462,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1455
1462
  config2.name = name.trim() || void 0;
1456
1463
  writeGlobalConfig(config2);
1457
1464
  if (config2.name !== previousName) {
1458
- const { notifySpiritSystemChange } = await import("./spirit-25JVAL3M.js");
1465
+ const { notifySpiritSystemChange } = await import("./spirit-4ECYIVGE.js");
1459
1466
  await notifySpiritSystemChange();
1460
1467
  }
1461
1468
  return c.json({ name: config2.name ?? null });
@@ -1814,8 +1821,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1814
1821
  createdAt: Date.now()
1815
1822
  };
1816
1823
  oauthFlows.set(flowId, flow);
1817
- const promptPromise = needsManualCode ? new Promise((resolve20) => {
1818
- flow.resolveCode = resolve20;
1824
+ const promptPromise = needsManualCode ? new Promise((resolve21) => {
1825
+ flow.resolveCode = resolve21;
1819
1826
  }) : void 0;
1820
1827
  oauthProvider.login({
1821
1828
  onAuth: (info) => {
@@ -1854,7 +1861,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1854
1861
  existing.error = err instanceof Error ? err.message : String(err);
1855
1862
  }
1856
1863
  });
1857
- await new Promise((resolve20) => setTimeout(resolve20, 2e3));
1864
+ await new Promise((resolve21) => setTimeout(resolve21, 2e3));
1858
1865
  const state = oauthFlows.get(flowId);
1859
1866
  return c.json({
1860
1867
  flowId,
@@ -2115,8 +2122,8 @@ var app2 = new Hono2().get("/events", async (c) => {
2115
2122
  });
2116
2123
  }, 15e3);
2117
2124
  cleanups.push(() => clearInterval(keepAlive));
2118
- await new Promise((resolve20) => {
2119
- stream.onAbort(() => resolve20());
2125
+ await new Promise((resolve21) => {
2126
+ stream.onAbort(() => resolve21());
2120
2127
  });
2121
2128
  } finally {
2122
2129
  for (const cleanup of cleanups) {
@@ -2149,6 +2156,11 @@ function isNotModified(c, etag) {
2149
2156
  }
2150
2157
 
2151
2158
  // packages/daemon/src/web/api/auth.ts
2159
+ async function withExternalFlag(list) {
2160
+ if (!list.some((u) => u.user_type === "mind")) return list;
2161
+ const local = new Set((await readAllMinds()).map((m) => m.name));
2162
+ return list.map((u) => u.user_type === "mind" ? { ...u, external: !local.has(u.username) } : u);
2163
+ }
2152
2164
  function tryJoinSystem(userId) {
2153
2165
  if (!process.env.VOLUTE_DAEMON_TOKEN) return;
2154
2166
  joinSystemChannel(userId).catch(() => {
@@ -2302,9 +2314,9 @@ var admin = new Hono3().use(authMiddleware).get("/users", async (c) => {
2302
2314
  }
2303
2315
  const type = c.req.query("type");
2304
2316
  if (type === "human" || type === "mind") {
2305
- return c.json(await listUsersByType(type));
2317
+ return c.json(await withExternalFlag(await listUsersByType(type)));
2306
2318
  }
2307
- return c.json(await listUsers());
2319
+ return c.json(await withExternalFlag(await listUsers()));
2308
2320
  }).get("/users/pending", async (c) => {
2309
2321
  const user = c.get("user");
2310
2322
  if (user.role !== "admin") return c.json({ error: "Forbidden" }, 403);
@@ -2401,7 +2413,11 @@ var admin = new Hono3().use(authMiddleware).get("/users", async (c) => {
2401
2413
  if (adminCount <= 1) return c.json({ error: "Cannot delete the last admin" }, 400);
2402
2414
  }
2403
2415
  if (target.user_type === "mind") {
2404
- return c.json({ error: "Use the mind deletion API to delete minds" }, 400);
2416
+ if (await findMind(target.username)) {
2417
+ return c.json({ error: "Use the mind deletion API to delete minds" }, 400);
2418
+ }
2419
+ await deleteExternalMindUser(id);
2420
+ return c.json({ ok: true });
2405
2421
  }
2406
2422
  await deleteUser(id);
2407
2423
  return c.json({ ok: true });
@@ -2668,7 +2684,7 @@ async function fanOutToMinds(opts) {
2668
2684
  );
2669
2685
  }
2670
2686
  if (ap.userType === "system") {
2671
- import("./spirit-availability-PJDWZJ3J.js").then(({ ensureSpiritAvailable: ensureSpiritAvailable2 }) => ensureSpiritAvailable2()).catch((err) => logger_default.warn("fan-out: on-demand spirit start failed", logger_default.errorData(err)));
2687
+ import("./spirit-availability-Y54Y3675.js").then(({ ensureSpiritAvailable: ensureSpiritAvailable2 }) => ensureSpiritAvailable2()).catch((err) => logger_default.warn("fan-out: on-demand spirit start failed", logger_default.errorData(err)));
2672
2688
  }
2673
2689
  }
2674
2690
  return null;
@@ -3055,7 +3071,7 @@ async function notifyMind(mindName, message) {
3055
3071
  const entry = await findMind(mindName);
3056
3072
  if (!entry) return;
3057
3073
  try {
3058
- const { deliverEvent: deliverEvent2 } = await import("./system-events-ZPSH63QX.js");
3074
+ const { deliverEvent: deliverEvent2 } = await import("./system-events-V43HDA3T.js");
3059
3075
  await deliverEvent2(mindName, { type: "file-share", body: message });
3060
3076
  } catch (err) {
3061
3077
  logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
@@ -4026,9 +4042,9 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
4026
4042
  stream.onAbort(() => {
4027
4043
  tail.kill();
4028
4044
  });
4029
- await new Promise((resolve20) => {
4030
- tail.on("exit", resolve20);
4031
- stream.onAbort(resolve20);
4045
+ await new Promise((resolve21) => {
4046
+ tail.on("exit", resolve21);
4047
+ stream.onAbort(resolve21);
4032
4048
  });
4033
4049
  });
4034
4050
  }).get("/:name/logs/tail", requireSelf(), async (c) => {
@@ -4046,8 +4062,8 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
4046
4062
  tail.stdout.on("data", (data) => {
4047
4063
  output += data.toString();
4048
4064
  });
4049
- await new Promise((resolve20) => {
4050
- tail.on("exit", resolve20);
4065
+ await new Promise((resolve21) => {
4066
+ tail.on("exit", resolve21);
4051
4067
  });
4052
4068
  return c.text(output);
4053
4069
  });
@@ -4147,7 +4163,7 @@ import {
4147
4163
  rmSync as rmSync3,
4148
4164
  writeFileSync as writeFileSync8
4149
4165
  } from "fs";
4150
- import { relative, resolve as resolve12 } from "path";
4166
+ import { relative, resolve as resolve13 } from "path";
4151
4167
  import { zValidator as zValidator6 } from "@hono/zod-validator";
4152
4168
  import { and as and5, desc as desc3, eq as eq5, sql as sql3 } from "drizzle-orm";
4153
4169
  import { Hono as Hono16 } from "hono";
@@ -4675,6 +4691,8 @@ function deriveThinkingLevel(config2) {
4675
4691
  }
4676
4692
 
4677
4693
  // packages/daemon/src/lib/mind/variants.ts
4694
+ import { statSync as statSync3 } from "fs";
4695
+ import { resolve as resolve11 } from "path";
4678
4696
  var SAFE_BRANCH_RE = /^[a-zA-Z0-9._\-/]+$/;
4679
4697
  function validateBranchName(branch) {
4680
4698
  if (!SAFE_BRANCH_RE.test(branch)) {
@@ -4687,6 +4705,55 @@ function validateBranchName(branch) {
4687
4705
  }
4688
4706
  var MERGE_EXCLUDED_PATHS = ["home/MEMORY.md", "home/memory/journal/"];
4689
4707
  var MAX_DELTA_CHARS = 12e3;
4708
+ var NEVER_REPORT_PREFIXES = ["home/.claude/", "home/.pi/", "home/.agents/"];
4709
+ var MAX_LISTED_UNRESOLVED_FILES = 20;
4710
+ async function findUnresolvedHomeFiles(cwd) {
4711
+ const raw = await gitExec(
4712
+ ["ls-files", "--others", "--ignored", "--exclude-standard", "-z", "--", "home"],
4713
+ { cwd }
4714
+ );
4715
+ const allPaths = raw.split("\0").filter((path) => path && !NEVER_REPORT_PREFIXES.some((prefix) => path.startsWith(prefix)));
4716
+ const files = [];
4717
+ let totalBytes = 0;
4718
+ for (const path of allPaths) {
4719
+ let bytes = -1;
4720
+ try {
4721
+ bytes = statSync3(resolve11(cwd, path)).size;
4722
+ } catch {
4723
+ }
4724
+ if (bytes > 0) totalBytes += bytes;
4725
+ if (files.length < MAX_LISTED_UNRESOLVED_FILES) files.push({ path, bytes });
4726
+ }
4727
+ return { files, totalCount: allPaths.length, totalBytes };
4728
+ }
4729
+ function formatBytes(bytes) {
4730
+ if (bytes < 0) return "size unknown";
4731
+ if (bytes < 1024) return `${bytes} B`;
4732
+ const units = ["KB", "MB", "GB", "TB"];
4733
+ let value = bytes / 1024;
4734
+ for (const unit of units) {
4735
+ if (value < 1024) return `${value.toFixed(1)} ${unit}`;
4736
+ value /= 1024;
4737
+ }
4738
+ return `${value.toFixed(1)} PB`;
4739
+ }
4740
+ function formatUnresolvedHomeFilesMessage(variantName, result) {
4741
+ const lines = result.files.map(
4742
+ (f) => ` - ${f.path.replace(/^home\//, "")} (${formatBytes(f.bytes)})`
4743
+ );
4744
+ const remaining = result.totalCount - result.files.length;
4745
+ if (remaining > 0) lines.push(` ...and ${remaining} more`);
4746
+ return `Cannot join variant "${variantName}": it has ${result.totalCount} untracked file${result.totalCount === 1 ? "" : "s"} under home/ that .gitignore is hiding from git \u2014 never committed, and joining would destroy them when the variant is cleaned up (total: ${formatBytes(result.totalBytes)}):
4747
+
4748
+ ${lines.join("\n")}
4749
+
4750
+ Before retrying the join, resolve each file in the variant \u2014 one of:
4751
+ 1. Track it: git add -f -- <path> (then commit it, or let auto-commit pick it up next turn)
4752
+ 2. Copy it out of home/ to somewhere safe, then delete it
4753
+ 3. Delete it if it's disposable
4754
+
4755
+ Once resolved, retry the join. To join anyway and discard everything listed above, pass discardUnresolved: true.`;
4756
+ }
4690
4757
  async function mergeVariantExcludingMemory(projectRoot, variantBranch) {
4691
4758
  const opts = { cwd: projectRoot };
4692
4759
  let memoryDelta = "";
@@ -4889,7 +4956,7 @@ async function waitForImagegenJob(mind, id, timeoutMs) {
4889
4956
  import { randomUUID } from "crypto";
4890
4957
  import { mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
4891
4958
  import { homedir } from "os";
4892
- import { resolve as resolve11 } from "path";
4959
+ import { resolve as resolve12 } from "path";
4893
4960
  function convertSession(opts) {
4894
4961
  const lines = readFileSync8(opts.sessionPath, "utf-8").trim().split("\n");
4895
4962
  const sessionId = randomUUID();
@@ -5005,9 +5072,9 @@ function convertSession(opts) {
5005
5072
  }
5006
5073
  }
5007
5074
  const projectId = opts.projectDir.replace(/\//g, "-");
5008
- const sdkDir = resolve11(homedir(), ".claude", "projects", projectId);
5075
+ const sdkDir = resolve12(homedir(), ".claude", "projects", projectId);
5009
5076
  mkdirSync5(sdkDir, { recursive: true });
5010
- const sdkPath = resolve11(sdkDir, `${sessionId}.jsonl`);
5077
+ const sdkPath = resolve12(sdkDir, `${sessionId}.jsonl`);
5011
5078
  writeFileSync7(sdkPath, `${sdkEvents.join("\n")}
5012
5079
  `);
5013
5080
  console.log(`Converted ${sdkEvents.length} messages \u2192 ${sdkPath}`);
@@ -5074,7 +5141,7 @@ async function getMindStatus(name, port, registryRunning, seed) {
5074
5141
  let status = "stopped";
5075
5142
  let wakeAt = null;
5076
5143
  try {
5077
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
5144
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
5078
5145
  const sleepManager = getSleepManagerIfReady2();
5079
5146
  if (sleepManager?.isSleeping(name)) {
5080
5147
  status = "sleeping";
@@ -5153,7 +5220,7 @@ async function initTemplateBranch(projectRoot, composedDir, manifest, mindName,
5153
5220
  await gitExec(["commit", "-m", "initial commit"], opts);
5154
5221
  }
5155
5222
  async function updateTemplateBranch(projectRoot, template, mindName) {
5156
- const tempWorktree = resolve12(projectRoot, ".variants", "_template_update");
5223
+ const tempWorktree = resolve13(projectRoot, ".variants", "_template_update");
5157
5224
  let branchExists = false;
5158
5225
  try {
5159
5226
  await gitExec(["rev-parse", "--verify", TEMPLATE_BRANCH], { cwd: projectRoot });
@@ -5185,15 +5252,15 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
5185
5252
  });
5186
5253
  }
5187
5254
  copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
5188
- const initDir = resolve12(tempWorktree, ".init");
5255
+ const initDir = resolve13(tempWorktree, ".init");
5189
5256
  if (existsSync8(initDir)) {
5190
5257
  rmSync3(initDir, { recursive: true, force: true });
5191
5258
  }
5192
- const homeDir = resolve12(tempWorktree, "home");
5259
+ const homeDir = resolve13(tempWorktree, "home");
5193
5260
  if (existsSync8(homeDir)) {
5194
5261
  for (const entry of readdirSync2(homeDir)) {
5195
5262
  if (entry !== "VOLUTE.md") {
5196
- rmSync3(resolve12(homeDir, entry), { recursive: true, force: true });
5263
+ rmSync3(resolve13(homeDir, entry), { recursive: true, force: true });
5197
5264
  }
5198
5265
  }
5199
5266
  }
@@ -5252,7 +5319,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
5252
5319
  let switchWarning;
5253
5320
  if (templateChanged) {
5254
5321
  try {
5255
- applyTemplateHomeFiles(resolve12(dir, "home"), template);
5322
+ applyTemplateHomeFiles(resolve13(dir, "home"), template);
5256
5323
  const migratedSkills = migrateSkillsToTemplate(dir, oldTemplate, template);
5257
5324
  await gitExec(["add", "home/"], { cwd: dir });
5258
5325
  try {
@@ -5308,7 +5375,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
5308
5375
  return { ok: true, warning: switchWarning };
5309
5376
  }
5310
5377
  async function importFromArchive(c, tempDir, nameOverride, manifest) {
5311
- const extractedMindDir = resolve12(tempDir, "mind");
5378
+ const extractedMindDir = resolve13(tempDir, "mind");
5312
5379
  if (!existsSync8(extractedMindDir)) {
5313
5380
  return c.json({ error: "Invalid archive: missing mind/ directory" }, 400);
5314
5381
  }
@@ -5335,9 +5402,9 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
5335
5402
  }
5336
5403
  const state = stateDir(name);
5337
5404
  mkdirSync6(state, { recursive: true });
5338
- const envJson = resolve12(tempDir, "state/env.json");
5405
+ const envJson = resolve13(tempDir, "state/env.json");
5339
5406
  if (existsSync8(envJson)) {
5340
- cpSync(envJson, resolve12(state, "env.json"));
5407
+ cpSync(envJson, resolve13(state, "env.json"));
5341
5408
  }
5342
5409
  const port = await nextPort();
5343
5410
  await addMind(name, port, manifest.stage, manifest.template);
@@ -5346,23 +5413,23 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
5346
5413
  } catch (err) {
5347
5414
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
5348
5415
  }
5349
- const homeDir = resolve12(dest, "home");
5416
+ const homeDir = resolve13(dest, "home");
5350
5417
  ensureVoluteGroup();
5351
5418
  createMindUser(name, homeDir);
5352
5419
  await chownMindDir(dest, name);
5353
5420
  await npmInstallAsMind(dest, name);
5354
5421
  await importHistoryFromArchive(name, tempDir);
5355
5422
  importSessionsFromArchive(dest, tempDir);
5356
- if (!existsSync8(resolve12(dest, ".git"))) {
5423
+ if (!existsSync8(resolve13(dest, ".git"))) {
5357
5424
  try {
5358
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve12(dest, "home") } : void 0;
5425
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve13(dest, "home") } : void 0;
5359
5426
  await gitExec(["init"], { cwd: dest, mindName: name, env });
5360
5427
  await configureGitIdentity(name, { cwd: dest, mindName: name, env });
5361
5428
  await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
5362
5429
  await gitExec(["commit", "-m", "import from archive"], { cwd: dest, mindName: name, env });
5363
5430
  } catch (err) {
5364
5431
  logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
5365
- rmSync3(resolve12(dest, ".git"), { recursive: true, force: true });
5432
+ rmSync3(resolve13(dest, ".git"), { recursive: true, force: true });
5366
5433
  }
5367
5434
  }
5368
5435
  await chownMindDir(dest, name);
@@ -5395,22 +5462,22 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
5395
5462
  try {
5396
5463
  copyTemplateToDir(composedDir, dest, name, templateManifest);
5397
5464
  applyInitFiles(dest);
5398
- const extractedHome = resolve12(extractedMindDir, "home");
5465
+ const extractedHome = resolve13(extractedMindDir, "home");
5399
5466
  if (existsSync8(extractedHome)) {
5400
- cpSync(extractedHome, resolve12(dest, "home"), { recursive: true });
5467
+ cpSync(extractedHome, resolve13(dest, "home"), { recursive: true });
5401
5468
  }
5402
- const extractedMindInternal = resolve12(extractedMindDir, ".mind");
5469
+ const extractedMindInternal = resolve13(extractedMindDir, ".mind");
5403
5470
  if (existsSync8(extractedMindInternal)) {
5404
- cpSync(extractedMindInternal, resolve12(dest, ".mind"), { recursive: true });
5471
+ cpSync(extractedMindInternal, resolve13(dest, ".mind"), { recursive: true });
5405
5472
  }
5406
- const identityDir = resolve12(dest, ".mind/identity");
5473
+ const identityDir = resolve13(dest, ".mind/identity");
5407
5474
  let publicKeyPem;
5408
- if (!manifest.includes.identity || !existsSync8(resolve12(identityDir, "private.pem"))) {
5475
+ if (!manifest.includes.identity || !existsSync8(resolve13(identityDir, "private.pem"))) {
5409
5476
  ({ publicKeyPem } = generateIdentity(dest));
5410
5477
  } else {
5411
- publicKeyPem = readFileSync9(resolve12(identityDir, "public.pem"), "utf-8");
5478
+ publicKeyPem = readFileSync9(resolve13(identityDir, "public.pem"), "utf-8");
5412
5479
  }
5413
- const promptsPath = resolve12(dest, "home/.config/prompts.json");
5480
+ const promptsPath = resolve13(dest, "home/.config/prompts.json");
5414
5481
  if (!existsSync8(promptsPath)) {
5415
5482
  const mindPrompts = await getMindPromptDefaults();
5416
5483
  writeFileSync8(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
@@ -5418,13 +5485,13 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
5418
5485
  }
5419
5486
  const state = stateDir(name);
5420
5487
  mkdirSync6(state, { recursive: true });
5421
- const envJson = resolve12(tempDir, "state/env.json");
5488
+ const envJson = resolve13(tempDir, "state/env.json");
5422
5489
  if (existsSync8(envJson)) {
5423
- cpSync(envJson, resolve12(state, "env.json"));
5490
+ cpSync(envJson, resolve13(state, "env.json"));
5424
5491
  }
5425
5492
  const port = await nextPort();
5426
5493
  await addMind(name, port, manifest.stage, manifest.template);
5427
- const homeDir = resolve12(dest, "home");
5494
+ const homeDir = resolve13(dest, "home");
5428
5495
  ensureVoluteGroup();
5429
5496
  createMindUser(name, homeDir);
5430
5497
  await chownMindDir(dest, name);
@@ -5437,7 +5504,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
5437
5504
  await initTemplateBranch(dest, composedDir, templateManifest, name, env);
5438
5505
  } catch (err) {
5439
5506
  logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
5440
- rmSync3(resolve12(dest, ".git"), { recursive: true, force: true });
5507
+ rmSync3(resolve13(dest, ".git"), { recursive: true, force: true });
5441
5508
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
5442
5509
  }
5443
5510
  const skillSet = manifest.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions();
@@ -5480,7 +5547,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
5480
5547
  }
5481
5548
  }
5482
5549
  async function importHistoryFromArchive(name, tempDir) {
5483
- const historyJsonl = resolve12(tempDir, "history.jsonl");
5550
+ const historyJsonl = resolve13(tempDir, "history.jsonl");
5484
5551
  if (!existsSync8(historyJsonl)) return;
5485
5552
  try {
5486
5553
  const db = await getDb();
@@ -5521,13 +5588,13 @@ async function importHistoryFromArchive(name, tempDir) {
5521
5588
  }
5522
5589
  }
5523
5590
  function importSessionsFromArchive(dest, tempDir) {
5524
- const sessionsDir = resolve12(tempDir, "sessions");
5591
+ const sessionsDir = resolve13(tempDir, "sessions");
5525
5592
  if (!existsSync8(sessionsDir)) return;
5526
5593
  try {
5527
- const destSessions = resolve12(dest, ".mind/sessions");
5594
+ const destSessions = resolve13(dest, ".mind/sessions");
5528
5595
  mkdirSync6(destSessions, { recursive: true });
5529
5596
  for (const file of readdirSync2(sessionsDir)) {
5530
- cpSync(resolve12(sessionsDir, file), resolve12(destSessions, file));
5597
+ cpSync(resolve13(sessionsDir, file), resolve13(destSessions, file));
5531
5598
  }
5532
5599
  } catch (err) {
5533
5600
  logger_default.error("Failed to import sessions from archive", logger_default.errorData(err));
@@ -5644,7 +5711,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
5644
5711
  writeVoluteConfig(dest, config2);
5645
5712
  const modelId = body.model ?? cog?.model;
5646
5713
  effectiveModel = modelId ? qualifyModelId(modelId) : void 0;
5647
- const sdkConfigPath = resolve12(dest, "home/.config/config.json");
5714
+ const sdkConfigPath = resolve13(dest, "home/.config/config.json");
5648
5715
  if (modelId || cog?.compaction) {
5649
5716
  const existing = existsSync8(sdkConfigPath) ? JSON.parse(readFileSync9(sdkConfigPath, "utf-8")) : {};
5650
5717
  if (modelId) {
@@ -5659,7 +5726,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
5659
5726
  }
5660
5727
  const mindPrompts = await getMindPromptDefaults();
5661
5728
  writeFileSync8(
5662
- resolve12(dest, "home/.config/prompts.json"),
5729
+ resolve13(dest, "home/.config/prompts.json"),
5663
5730
  `${JSON.stringify(mindPrompts, null, 2)}
5664
5731
  `
5665
5732
  );
@@ -5671,7 +5738,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
5671
5738
  } catch (err) {
5672
5739
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
5673
5740
  }
5674
- const homeDir = resolve12(dest, "home");
5741
+ const homeDir = resolve13(dest, "home");
5675
5742
  ensureVoluteGroup();
5676
5743
  createMindUser(name, homeDir);
5677
5744
  await chownMindDir(dest, name);
@@ -5684,7 +5751,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
5684
5751
  await initTemplateBranch(dest, composedDir, manifest, name, env);
5685
5752
  } catch (err) {
5686
5753
  logger_default.error(`git setup failed for ${name}`, logger_default.errorData(err));
5687
- rmSync3(resolve12(dest, ".git"), { recursive: true, force: true });
5754
+ rmSync3(resolve13(dest, ".git"), { recursive: true, force: true });
5688
5755
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
5689
5756
  }
5690
5757
  if (body.stage === "seed") {
@@ -5693,7 +5760,7 @@ Your creator described you as: "${body.description}"
5693
5760
  ` : "";
5694
5761
  const seedSoulRaw = body.seedSoul ?? await getPrompt("seed_soul", { name, description: descLine });
5695
5762
  const seedSoul = body.seedSoul ? substitute(seedSoulRaw, { name, description: descLine }) : seedSoulRaw;
5696
- writeFileSync8(resolve12(dest, "home/SOUL.md"), seedSoul);
5763
+ writeFileSync8(resolve13(dest, "home/SOUL.md"), seedSoul);
5697
5764
  }
5698
5765
  let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
5699
5766
  if (body.stage === "seed" && !body.skills) {
@@ -5719,7 +5786,7 @@ Your creator described you as: "${body.description}"
5719
5786
  const spiritName = getSpiritName();
5720
5787
  const spiritEntry = await findMind(spiritName);
5721
5788
  if (spiritEntry) {
5722
- const { spiritDir } = await import("./spirit-25JVAL3M.js");
5789
+ const { spiritDir } = await import("./spirit-4ECYIVGE.js");
5723
5790
  const sDir = spiritEntry.dir ?? spiritDir();
5724
5791
  const spiritConfig = readVoluteConfig(sDir) ?? {};
5725
5792
  const schedules = spiritConfig.schedules ?? [];
@@ -5734,7 +5801,7 @@ Your creator described you as: "${body.description}"
5734
5801
  });
5735
5802
  spiritConfig.schedules = schedules;
5736
5803
  writeVoluteConfig(sDir, spiritConfig);
5737
- const { getScheduler: getScheduler2 } = await import("./scheduler-TNBN54ZK.js");
5804
+ const { getScheduler: getScheduler2 } = await import("./scheduler-JTTWZDYU.js");
5738
5805
  getScheduler2().loadSchedules(spiritName, sDir);
5739
5806
  }
5740
5807
  }
@@ -5745,11 +5812,11 @@ Your creator described you as: "${body.description}"
5745
5812
  if (body.stage !== "seed") {
5746
5813
  const customSoul = await getPromptIfCustom("default_soul");
5747
5814
  if (customSoul) {
5748
- writeFileSync8(resolve12(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
5815
+ writeFileSync8(resolve13(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
5749
5816
  }
5750
5817
  const customMemory = await getPromptIfCustom("default_memory");
5751
5818
  if (customMemory) {
5752
- writeFileSync8(resolve12(dest, "home/MEMORY.md"), customMemory);
5819
+ writeFileSync8(resolve13(dest, "home/MEMORY.md"), customMemory);
5753
5820
  }
5754
5821
  }
5755
5822
  await chownMindDir(dest, name);
@@ -5810,12 +5877,12 @@ Your creator described you as: "${body.description}"
5810
5877
  return importFromArchive(c, body.archivePath, body.name, body.manifest);
5811
5878
  }
5812
5879
  const wsDir = body.workspacePath;
5813
- if (!wsDir || !existsSync8(resolve12(wsDir, "SOUL.md")) || !existsSync8(resolve12(wsDir, "IDENTITY.md"))) {
5880
+ if (!wsDir || !existsSync8(resolve13(wsDir, "SOUL.md")) || !existsSync8(resolve13(wsDir, "IDENTITY.md"))) {
5814
5881
  return c.json({ error: "Invalid workspace: missing SOUL.md or IDENTITY.md" }, 400);
5815
5882
  }
5816
- const soul = readFileSync9(resolve12(wsDir, "SOUL.md"), "utf-8");
5817
- const identity = readFileSync9(resolve12(wsDir, "IDENTITY.md"), "utf-8");
5818
- const userPath = resolve12(wsDir, "USER.md");
5883
+ const soul = readFileSync9(resolve13(wsDir, "SOUL.md"), "utf-8");
5884
+ const identity = readFileSync9(resolve13(wsDir, "IDENTITY.md"), "utf-8");
5885
+ const userPath = resolve13(wsDir, "USER.md");
5819
5886
  const user = existsSync8(userPath) ? readFileSync9(userPath, "utf-8") : "";
5820
5887
  const name = body.name ?? parseNameFromIdentity(identity) ?? "imported-mind";
5821
5888
  const template = body.template ?? "claude";
@@ -5843,26 +5910,26 @@ ${user.trimEnd()}
5843
5910
  copyTemplateToDir(composedDir, dest, name, manifest);
5844
5911
  applyInitFiles(dest);
5845
5912
  const { publicKeyPem: importPublicKey } = generateIdentity(dest);
5846
- writeFileSync8(resolve12(dest, "home/SOUL.md"), mergedSoul);
5847
- const wsMemoryPath = resolve12(wsDir, "MEMORY.md");
5913
+ writeFileSync8(resolve13(dest, "home/SOUL.md"), mergedSoul);
5914
+ const wsMemoryPath = resolve13(wsDir, "MEMORY.md");
5848
5915
  const hasMemory = existsSync8(wsMemoryPath);
5849
5916
  if (hasMemory) {
5850
5917
  const existingMemory = readFileSync9(wsMemoryPath, "utf-8");
5851
5918
  writeFileSync8(
5852
- resolve12(dest, "home/MEMORY.md"),
5919
+ resolve13(dest, "home/MEMORY.md"),
5853
5920
  `${existingMemory.trimEnd()}${mergedMemoryExtra}`
5854
5921
  );
5855
5922
  } else if (user) {
5856
- writeFileSync8(resolve12(dest, "home/MEMORY.md"), `${user.trimEnd()}
5923
+ writeFileSync8(resolve13(dest, "home/MEMORY.md"), `${user.trimEnd()}
5857
5924
  `);
5858
5925
  }
5859
- const wsMemoryDir = resolve12(wsDir, "memory");
5926
+ const wsMemoryDir = resolve13(wsDir, "memory");
5860
5927
  let dailyLogCount = 0;
5861
5928
  if (existsSync8(wsMemoryDir)) {
5862
- const destMemoryDir = resolve12(dest, "home/memory");
5929
+ const destMemoryDir = resolve13(dest, "home/memory");
5863
5930
  const files = readdirSync2(wsMemoryDir).filter((f) => f.endsWith(".md"));
5864
5931
  for (const file of files) {
5865
- cpSync(resolve12(wsMemoryDir, file), resolve12(destMemoryDir, file));
5932
+ cpSync(resolve13(wsMemoryDir, file), resolve13(destMemoryDir, file));
5866
5933
  }
5867
5934
  dailyLogCount = files.length;
5868
5935
  }
@@ -5873,7 +5940,7 @@ ${user.trimEnd()}
5873
5940
  } catch (err) {
5874
5941
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
5875
5942
  }
5876
- const homeDir = resolve12(dest, "home");
5943
+ const homeDir = resolve13(dest, "home");
5877
5944
  ensureVoluteGroup();
5878
5945
  createMindUser(name, homeDir);
5879
5946
  await chownMindDir(dest, name);
@@ -5881,20 +5948,20 @@ ${user.trimEnd()}
5881
5948
  if (!hasMemory && dailyLogCount > 0) {
5882
5949
  await consolidateMemory(dest);
5883
5950
  }
5884
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve12(dest, "home") } : void 0;
5951
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve13(dest, "home") } : void 0;
5885
5952
  await gitExec(["init"], { cwd: dest, mindName: name, env });
5886
5953
  await configureGitIdentity(name, { cwd: dest, mindName: name, env });
5887
5954
  await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
5888
5955
  await gitExec(["commit", "-m", "import from OpenClaw"], { cwd: dest, mindName: name, env });
5889
- const sessionFile = body.sessionPath ? resolve12(body.sessionPath) : findOpenClawSession(wsDir);
5956
+ const sessionFile = body.sessionPath ? resolve13(body.sessionPath) : findOpenClawSession(wsDir);
5890
5957
  if (sessionFile && existsSync8(sessionFile)) {
5891
5958
  if (template === "pi") {
5892
5959
  importPiSession(sessionFile, dest);
5893
5960
  } else if (template === "claude") {
5894
5961
  const sessionId = convertSession({ sessionPath: sessionFile, projectDir: dest });
5895
- const mindRuntimeDir = resolve12(dest, ".mind");
5962
+ const mindRuntimeDir = resolve13(dest, ".mind");
5896
5963
  mkdirSync6(mindRuntimeDir, { recursive: true });
5897
- writeFileSync8(resolve12(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
5964
+ writeFileSync8(resolve13(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
5898
5965
  }
5899
5966
  }
5900
5967
  importOpenClawConnectors(name, dest);
@@ -5940,7 +6007,7 @@ ${user.trimEnd()}
5940
6007
  stage: entry.stage,
5941
6008
  dir: entry.dir
5942
6009
  });
5943
- const hasPages = existsSync8(resolve12(mindDir(entry.name), "home", "pages"));
6010
+ const hasPages = existsSync8(resolve13(mindDir(entry.name), "home", "pages"));
5944
6011
  const lastActiveAt = lastActiveMap.get(entry.name) ?? null;
5945
6012
  if (!privileged) return toPublicMind(entry, mindStatus, { hasPages, lastActiveAt });
5946
6013
  return {
@@ -5963,7 +6030,7 @@ ${user.trimEnd()}
5963
6030
  stage: entry.stage,
5964
6031
  dir: entry.dir
5965
6032
  });
5966
- const hasPages = existsSync8(resolve12(mindDir(name), "home", "pages"));
6033
+ const hasPages = existsSync8(resolve13(mindDir(name), "home", "pages"));
5967
6034
  if (!isPrivileged(c)) {
5968
6035
  return c.json(toPublicMind(entry, mindStatus, { hasPages }));
5969
6036
  }
@@ -6040,7 +6107,7 @@ ${user.trimEnd()}
6040
6107
  const manager = getMindManager();
6041
6108
  try {
6042
6109
  if (context?.type === "reload") {
6043
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6110
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6044
6111
  const sleepState = getSleepManagerIfReady2()?.getState(name);
6045
6112
  if (sleepState?.sleeping) {
6046
6113
  logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
@@ -6060,6 +6127,7 @@ ${user.trimEnd()}
6060
6127
  const variantEntry = await findMind(mergeVariantName);
6061
6128
  if (variantEntry && variantEntry.parent === baseName && variantEntry.dir && variantEntry.branch) {
6062
6129
  const projectRoot = mindDir(baseName);
6130
+ const discardUnresolved = context.discardUnresolvedHomeFiles === true;
6063
6131
  if (existsSync8(variantEntry.dir)) {
6064
6132
  const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
6065
6133
  if (status) {
@@ -6089,13 +6157,41 @@ ${user.trimEnd()}
6089
6157
  }
6090
6158
  const preMergeHead = (await gitExec(["rev-parse", "HEAD"], { cwd: projectRoot })).trim();
6091
6159
  const memoryDelta = await mergeVariantExcludingMemory(projectRoot, variantEntry.branch);
6092
- if (memoryDelta && context) context.memoryDelta = memoryDelta;
6093
- await cleanupVariant(mergeVariantName, baseName, projectRoot, variantEntry.dir);
6094
- if (await npmInstallNeeded(projectRoot, preMergeHead)) {
6160
+ let unresolvedNotice;
6161
+ if (existsSync8(variantEntry.dir) && !discardUnresolved) {
6095
6162
  try {
6096
- await npmInstallAsMind(projectRoot, baseName);
6097
- } catch (e) {
6098
- logger_default.error(`npm install failed after merge for ${baseName}`, logger_default.errorData(e));
6163
+ const unresolved = await findUnresolvedHomeFiles(variantEntry.dir);
6164
+ if (unresolved.totalCount > 0) {
6165
+ unresolvedNotice = formatUnresolvedHomeFilesMessage(mergeVariantName, unresolved);
6166
+ }
6167
+ } catch (err) {
6168
+ unresolvedNotice = `Could not verify variant ${mergeVariantName} has no unresolved home/ files: ${err instanceof Error ? err.message : String(err)}. Variant left intact \u2014 retry the join.`;
6169
+ }
6170
+ }
6171
+ if (unresolvedNotice) {
6172
+ logger_default.warn(
6173
+ `variant join blocked for ${baseName}: ${mergeVariantName} \u2014 ${unresolvedNotice}`
6174
+ );
6175
+ await recordNotice({
6176
+ mind: baseName,
6177
+ thread: "main",
6178
+ kind: "join_blocked",
6179
+ reason: "unresolved_variant_files",
6180
+ detail: unresolvedNotice
6181
+ });
6182
+ if (context) {
6183
+ context.type = "restart";
6184
+ context.name = void 0;
6185
+ }
6186
+ } else {
6187
+ if (memoryDelta && context) context.memoryDelta = memoryDelta;
6188
+ await cleanupVariant(mergeVariantName, baseName, projectRoot, variantEntry.dir);
6189
+ if (await npmInstallNeeded(projectRoot, preMergeHead)) {
6190
+ try {
6191
+ await npmInstallAsMind(projectRoot, baseName);
6192
+ } catch (e) {
6193
+ logger_default.error(`npm install failed after merge for ${baseName}`, logger_default.errorData(e));
6194
+ }
6099
6195
  }
6100
6196
  }
6101
6197
  }
@@ -6138,6 +6234,7 @@ ${user.trimEnd()}
6138
6234
  );
6139
6235
  return c.json({ ok: true, port: targetPort });
6140
6236
  } catch (err) {
6237
+ logger_default.error(`failed to restart mind ${name}`, logger_default.errorData(err));
6141
6238
  return c.json({ error: err instanceof Error ? err.message : "Failed to restart mind" }, 500);
6142
6239
  }
6143
6240
  }).post("/:name/stop", requireSelf(), async (c) => {
@@ -6152,13 +6249,14 @@ ${user.trimEnd()}
6152
6249
  await stopMindFull(name);
6153
6250
  return c.json({ ok: true });
6154
6251
  } catch (err) {
6252
+ logger_default.error(`failed to stop mind ${name}`, logger_default.errorData(err));
6155
6253
  return c.json({ error: err instanceof Error ? err.message : "Failed to stop mind" }, 500);
6156
6254
  }
6157
6255
  }).get("/:name/sleep", requireSelf(), async (c) => {
6158
6256
  const name = c.req.param("name");
6159
6257
  const entry = await findMind(name);
6160
6258
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6161
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6259
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6162
6260
  const sm = getSleepManagerIfReady2();
6163
6261
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6164
6262
  return c.json(sm.getState(name));
@@ -6166,7 +6264,7 @@ ${user.trimEnd()}
6166
6264
  const name = c.req.param("name");
6167
6265
  const entry = await findMind(name);
6168
6266
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6169
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6267
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6170
6268
  const sm = getSleepManagerIfReady2();
6171
6269
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6172
6270
  if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
@@ -6186,7 +6284,7 @@ ${user.trimEnd()}
6186
6284
  const name = c.req.param("name");
6187
6285
  const entry = await findMind(name);
6188
6286
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6189
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6287
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6190
6288
  const sm = getSleepManagerIfReady2();
6191
6289
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6192
6290
  const sleepState = sm.getState(name);
@@ -6201,7 +6299,7 @@ ${user.trimEnd()}
6201
6299
  const name = c.req.param("name");
6202
6300
  const entry = await findMind(name);
6203
6301
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6204
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6302
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6205
6303
  const sm = getSleepManagerIfReady2();
6206
6304
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6207
6305
  const flushed = await sm.flushQueuedMessages(name);
@@ -6217,7 +6315,7 @@ ${user.trimEnd()}
6217
6315
  if (body.displayName !== void 0) profile.displayName = body.displayName;
6218
6316
  if (body.description !== void 0) profile.description = body.description;
6219
6317
  if (body.avatar !== void 0) {
6220
- const homeDir = resolve12(dir, "home");
6318
+ const homeDir = resolve13(dir, "home");
6221
6319
  const avatarPath = safeResolveWithinBase(homeDir, body.avatar);
6222
6320
  if (!avatarPath) {
6223
6321
  return c.json({ error: "Avatar path must be inside the mind's home directory" }, 400);
@@ -6229,7 +6327,7 @@ ${user.trimEnd()}
6229
6327
  }
6230
6328
  config2.profile = profile;
6231
6329
  writeVoluteConfig(dir, config2);
6232
- const { syncMindProfile: syncMindProfile2 } = await import("./auth-X6EMNEGB.js");
6330
+ const { syncMindProfile: syncMindProfile2 } = await import("./auth-KRDSM55Q.js");
6233
6331
  await syncMindProfile2(name, profile);
6234
6332
  broadcast({ type: "profile_updated", mind: name, summary: `${name} profile updated` });
6235
6333
  return c.json({ ok: true });
@@ -6273,7 +6371,7 @@ ${user.trimEnd()}
6273
6371
  });
6274
6372
  }
6275
6373
  if (!force) {
6276
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6374
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6277
6375
  if (getSleepManagerIfReady2()?.isSleeping(name)) {
6278
6376
  return c.json({ output: "" });
6279
6377
  }
@@ -6370,7 +6468,7 @@ ${user.trimEnd()}
6370
6468
  try {
6371
6469
  const sproutedDir = entry.dir ?? mindDir(name);
6372
6470
  if (setupDefaultDreaming(sproutedDir).schedulesChanged) {
6373
- const { getScheduler: getScheduler2 } = await import("./scheduler-TNBN54ZK.js");
6471
+ const { getScheduler: getScheduler2 } = await import("./scheduler-JTTWZDYU.js");
6374
6472
  getScheduler2().loadSchedules(name, sproutedDir);
6375
6473
  }
6376
6474
  } catch (err) {
@@ -6380,7 +6478,7 @@ ${user.trimEnd()}
6380
6478
  const spiritName = getSpiritName();
6381
6479
  const spiritEntry = await findMind(spiritName);
6382
6480
  if (spiritEntry) {
6383
- const { firstWeekSchedules, spiritDir } = await import("./spirit-25JVAL3M.js");
6481
+ const { firstWeekSchedules, spiritDir } = await import("./spirit-4ECYIVGE.js");
6384
6482
  const sDir = spiritEntry.dir ?? spiritDir();
6385
6483
  const spiritConfig = readVoluteConfig(sDir);
6386
6484
  if (spiritConfig) {
@@ -6394,7 +6492,7 @@ ${user.trimEnd()}
6394
6492
  spiritConfig.schedules = schedules;
6395
6493
  writeVoluteConfig(sDir, spiritConfig);
6396
6494
  try {
6397
- const { getScheduler: getScheduler2 } = await import("./scheduler-TNBN54ZK.js");
6495
+ const { getScheduler: getScheduler2 } = await import("./scheduler-JTTWZDYU.js");
6398
6496
  getScheduler2().loadSchedules(spiritName, sDir);
6399
6497
  } catch (err) {
6400
6498
  logger_default.warn(
@@ -6416,9 +6514,25 @@ ${user.trimEnd()}
6416
6514
  const name = c.req.param("name");
6417
6515
  const entry = await findMind(name);
6418
6516
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6517
+ const manager = getMindManager();
6518
+ if (entry.parent) {
6519
+ if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 500);
6520
+ const parentEntry = await findMind(entry.parent);
6521
+ if (!parentEntry) return c.json({ error: `Parent mind ${entry.parent} not found` }, 404);
6522
+ if (manager.isRunning(name)) {
6523
+ await stopMindFull(name);
6524
+ }
6525
+ await cleanupVariant(name, entry.parent, parentEntry.dir ?? mindDir(entry.parent), entry.dir);
6526
+ invalidateMindUserCache(name);
6527
+ fireWebhook({
6528
+ event: "mind_deleted",
6529
+ mind: name,
6530
+ data: { port: entry.port, stage: entry.stage, template: entry.template }
6531
+ });
6532
+ return c.json({ ok: true, variant: true });
6533
+ }
6419
6534
  const dir = mindDir(name);
6420
6535
  const force = c.req.query("force") === "true";
6421
- const manager = getMindManager();
6422
6536
  if (manager.isRunning(name)) {
6423
6537
  await stopMindFull(name);
6424
6538
  }
@@ -6463,16 +6577,16 @@ ${user.trimEnd()}
6463
6577
  }
6464
6578
  const UPGRADE_BRANCH = "upgrade";
6465
6579
  const upgradeVariantName = `${mindName}-upgrade`;
6466
- const worktreeDir = resolve12(dir, ".variants", UPGRADE_BRANCH);
6580
+ const worktreeDir = resolve13(dir, ".variants", UPGRADE_BRANCH);
6467
6581
  if (body.abort) {
6468
6582
  if (!existsSync8(worktreeDir)) {
6469
6583
  return c.json({ error: "No upgrade in progress" }, 400);
6470
6584
  }
6471
6585
  try {
6472
6586
  try {
6473
- const gitDirContent = readFileSync9(resolve12(worktreeDir, ".git"), "utf-8").trim();
6587
+ const gitDirContent = readFileSync9(resolve13(worktreeDir, ".git"), "utf-8").trim();
6474
6588
  const gitDir = gitDirContent.replace("gitdir: ", "");
6475
- if (existsSync8(resolve12(gitDir, "MERGE_HEAD"))) {
6589
+ if (existsSync8(resolve13(gitDir, "MERGE_HEAD"))) {
6476
6590
  await gitExec(["merge", "--abort"], { cwd: worktreeDir });
6477
6591
  }
6478
6592
  } catch {
@@ -6556,7 +6670,7 @@ ${user.trimEnd()}
6556
6670
  }
6557
6671
  if (body.diff) {
6558
6672
  try {
6559
- if (!existsSync8(resolve12(dir, ".git"))) {
6673
+ if (!existsSync8(resolve13(dir, ".git"))) {
6560
6674
  return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
6561
6675
  }
6562
6676
  await updateTemplateBranch(dir, template, mindName);
@@ -6580,16 +6694,16 @@ ${user.trimEnd()}
6580
6694
  409
6581
6695
  );
6582
6696
  }
6583
- if (!existsSync8(resolve12(dir, ".git"))) {
6697
+ if (!existsSync8(resolve13(dir, ".git"))) {
6584
6698
  try {
6585
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve12(dir, "home") } : void 0;
6699
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve13(dir, "home") } : void 0;
6586
6700
  await gitExec(["init"], { cwd: dir, mindName, env });
6587
6701
  await configureGitIdentity(mindName, { cwd: dir, mindName, env });
6588
6702
  await gitExec(["add", "-A"], { cwd: dir, mindName, env });
6589
6703
  await gitExec(["commit", "-m", "initial commit"], { cwd: dir, mindName, env });
6590
6704
  await chownMindDir(dir, mindName);
6591
6705
  } catch (err) {
6592
- rmSync3(resolve12(dir, ".git"), { recursive: true, force: true });
6706
+ rmSync3(resolve13(dir, ".git"), { recursive: true, force: true });
6593
6707
  return c.json(
6594
6708
  {
6595
6709
  error: `Git initialization failed: ${err instanceof Error ? err.message : String(err)}`
@@ -6604,7 +6718,7 @@ ${user.trimEnd()}
6604
6718
  } catch {
6605
6719
  }
6606
6720
  await updateTemplateBranch(dir, template, mindName);
6607
- const parentDir = resolve12(dir, ".variants");
6721
+ const parentDir = resolve13(dir, ".variants");
6608
6722
  if (!existsSync8(parentDir)) {
6609
6723
  mkdirSync6(parentDir, { recursive: true });
6610
6724
  }
@@ -6741,7 +6855,7 @@ ${user.trimEnd()}
6741
6855
  if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
6742
6856
  let config2 = readVoluteConfig(dir);
6743
6857
  if (!config2 && entry.template === "pi") {
6744
- const piConfigPath = resolve12(dir, "home/.config/config.json");
6858
+ const piConfigPath = resolve13(dir, "home/.config/config.json");
6745
6859
  if (existsSync8(piConfigPath)) {
6746
6860
  try {
6747
6861
  config2 = JSON.parse(readFileSync9(piConfigPath, "utf-8"));
@@ -6750,7 +6864,7 @@ ${user.trimEnd()}
6750
6864
  }
6751
6865
  }
6752
6866
  let templateConfig = {};
6753
- const configJsonPath = resolve12(dir, "home/.config/config.json");
6867
+ const configJsonPath = resolve13(dir, "home/.config/config.json");
6754
6868
  if (existsSync8(configJsonPath)) {
6755
6869
  try {
6756
6870
  templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
@@ -6819,12 +6933,12 @@ ${user.trimEnd()}
6819
6933
  }
6820
6934
  writeVoluteConfig(dir, existing);
6821
6935
  if (body.unescapeNewlines !== void 0) {
6822
- const { clearEchoTextCache } = await import("./echo-text-6ANI5HHN.js");
6936
+ const { clearEchoTextCache } = await import("./echo-text-PEEV7FQU.js");
6823
6937
  clearEchoTextCache(name);
6824
6938
  }
6825
6939
  const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.compaction !== void 0;
6826
6940
  if (needsConfigJson) {
6827
- const configJsonPath = resolve12(dir, "home/.config/config.json");
6941
+ const configJsonPath = resolve13(dir, "home/.config/config.json");
6828
6942
  let templateConfig = {};
6829
6943
  if (existsSync8(configJsonPath)) {
6830
6944
  try {
@@ -7593,7 +7707,7 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
7593
7707
  const entry = await findMind(name);
7594
7708
  if (!entry) return c.json({ error: "Mind not found" }, 404);
7595
7709
  const body = await c.req.text();
7596
- const { deliverEvent: deliverEvent2 } = await import("./system-events-ZPSH63QX.js");
7710
+ const { deliverEvent: deliverEvent2 } = await import("./system-events-V43HDA3T.js");
7597
7711
  const { id, delivered } = await deliverEvent2(name, {
7598
7712
  type: "webhook",
7599
7713
  body,
@@ -7611,14 +7725,14 @@ var schedules_default = app15;
7611
7725
  // packages/daemon/src/web/api/setup.ts
7612
7726
  import { mkdirSync as mkdirSync7 } from "fs";
7613
7727
  import { homedir as homedir2 } from "os";
7614
- import { resolve as resolve13 } from "path";
7728
+ import { resolve as resolve14 } from "path";
7615
7729
  import { Hono as Hono19 } from "hono";
7616
7730
  import { setCookie as setCookie2 } from "hono/cookie";
7617
7731
  var DEFAULT_API_URL2 = "https://volute.systems";
7618
7732
  var setup = new Hono19();
7619
7733
  function writeSetupConfig(systemName, description) {
7620
- const configHome = process.env.VOLUTE_HOME ?? resolve13(homedir2(), ".volute");
7621
- const mindsDir = resolve13(configHome, "minds");
7734
+ const configHome = process.env.VOLUTE_HOME ?? resolve14(homedir2(), ".volute");
7735
+ const mindsDir = resolve14(configHome, "minds");
7622
7736
  mkdirSync7(configHome, { recursive: true });
7623
7737
  mkdirSync7(mindsDir, { recursive: true });
7624
7738
  const existingConfig = readGlobalConfig();
@@ -7652,7 +7766,7 @@ setup.get("/status", async (c) => {
7652
7766
  let hasAccount = false;
7653
7767
  if (hasSystem) {
7654
7768
  try {
7655
- const { listUsersByType: listUsersByType2 } = await import("./auth-X6EMNEGB.js");
7769
+ const { listUsersByType: listUsersByType2 } = await import("./auth-KRDSM55Q.js");
7656
7770
  const brains = await listUsersByType2("human");
7657
7771
  hasAccount = brains.length > 0;
7658
7772
  } catch (err) {
@@ -7864,7 +7978,7 @@ setup.post("/account", async (c) => {
7864
7978
  }
7865
7979
  }
7866
7980
  try {
7867
- const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-X6EMNEGB.js");
7981
+ const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-KRDSM55Q.js");
7868
7982
  const user = await createUser2(body.username.trim(), body.password);
7869
7983
  if (body.displayName?.trim()) {
7870
7984
  await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
@@ -7957,8 +8071,8 @@ setup.post("/complete", async (c) => {
7957
8071
  return c.json({ error: "Setup already complete" }, 400);
7958
8072
  }
7959
8073
  try {
7960
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-25JVAL3M.js");
7961
- const { startSpiritFull } = await import("./mind-service-DZCUUC7J.js");
8074
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-4ECYIVGE.js");
8075
+ const { startSpiritFull } = await import("./mind-service-E26ZQXDS.js");
7962
8076
  await ensureSpiritProject();
7963
8077
  await syncSpiritTemplate();
7964
8078
  const warnings = [];
@@ -7995,7 +8109,7 @@ setup.post("/complete", async (c) => {
7995
8109
  }
7996
8110
  let spiritConversationId;
7997
8111
  try {
7998
- const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-X6EMNEGB.js");
8112
+ const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-KRDSM55Q.js");
7999
8113
  const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-ZL6PHROD.js");
8000
8114
  const spiritUser = await getOrCreateMindUser2(spiritName);
8001
8115
  const brains = await listUsersByType2("human");
@@ -8018,8 +8132,8 @@ setup.post("/complete", async (c) => {
8018
8132
  logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
8019
8133
  if (spiritConversationId && spiritStarted) {
8020
8134
  try {
8021
- const { deliverMessage: deliverMessage2 } = await import("./message-delivery-JHMAJ2GU.js");
8022
- const { listUsersByType: listUsers2 } = await import("./auth-X6EMNEGB.js");
8135
+ const { deliverMessage: deliverMessage2 } = await import("./message-delivery-7URC52ME.js");
8136
+ const { listUsersByType: listUsers2 } = await import("./auth-KRDSM55Q.js");
8023
8137
  const admins = await listUsers2("human");
8024
8138
  const admin2 = admins.find((u) => u.role === "admin");
8025
8139
  if (admin2) {
@@ -8062,7 +8176,7 @@ var setup_default = setup;
8062
8176
  // packages/daemon/src/web/api/skills.ts
8063
8177
  import { existsSync as existsSync9, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync4 } from "fs";
8064
8178
  import { tmpdir } from "os";
8065
- import { join, resolve as resolve14 } from "path";
8179
+ import { join, resolve as resolve15 } from "path";
8066
8180
  import AdmZip from "adm-zip";
8067
8181
  import { Hono as Hono20 } from "hono";
8068
8182
  var app16 = new Hono20().get("/", async (c) => {
@@ -8138,7 +8252,7 @@ var app16 = new Hono20().get("/", async (c) => {
8138
8252
  try {
8139
8253
  const zip = new AdmZip(buffer);
8140
8254
  for (const entry of zip.getEntries()) {
8141
- const target = resolve14(tmpDir, entry.entryName);
8255
+ const target = resolve15(tmpDir, entry.entryName);
8142
8256
  if (!target.startsWith(tmpDir)) {
8143
8257
  return c.json({ error: "Invalid zip: paths must not escape archive" }, 400);
8144
8258
  }
@@ -8512,8 +8626,8 @@ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
8512
8626
  });
8513
8627
  }, 15e3);
8514
8628
  cleanups.push(() => clearInterval(keepAlive));
8515
- await new Promise((resolve20) => {
8516
- stream.onAbort(() => resolve20());
8629
+ await new Promise((resolve21) => {
8630
+ stream.onAbort(() => resolve21());
8517
8631
  });
8518
8632
  } finally {
8519
8633
  for (const cleanup of cleanups) {
@@ -8795,18 +8909,18 @@ var feed_default = app21;
8795
8909
 
8796
8910
  // packages/daemon/src/web/api/variants.ts
8797
8911
  import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
8798
- import { resolve as resolve17 } from "path";
8912
+ import { resolve as resolve18 } from "path";
8799
8913
  import { Hono as Hono26 } from "hono";
8800
8914
 
8801
8915
  // packages/daemon/src/lib/mind/farewell.ts
8802
8916
  import { existsSync as existsSync10, readFileSync as readFileSync10, rmSync as rmSync5 } from "fs";
8803
- import { resolve as resolve15 } from "path";
8917
+ import { resolve as resolve16 } from "path";
8804
8918
  var flog = logger_default.child("farewell");
8805
8919
  var FAREWELL_RELPATH = ".mind/farewell.md";
8806
8920
  var FAREWELL_MIND_PATH = "../.mind/farewell.md";
8807
8921
  var FAREWELL_TIMEOUT_MS = 12e4;
8808
8922
  function farewellPath(variantDir) {
8809
- return resolve15(variantDir, FAREWELL_RELPATH);
8923
+ return resolve16(variantDir, FAREWELL_RELPATH);
8810
8924
  }
8811
8925
  function readFarewell(variantDir) {
8812
8926
  const path = farewellPath(variantDir);
@@ -8866,8 +8980,8 @@ async function runFarewellTurn(opts) {
8866
8980
 
8867
8981
  // packages/daemon/src/lib/mind/spawn-server.ts
8868
8982
  import { spawn as spawn4 } from "child_process";
8869
- import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync11, statSync as statSync3 } from "fs";
8870
- import { resolve as resolve16 } from "path";
8983
+ import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync11, statSync as statSync4 } from "fs";
8984
+ import { resolve as resolve17 } from "path";
8871
8985
  async function spawnServer(cwd, port, options) {
8872
8986
  let cmd = process.env.VOLUTE_NODE_PATH ?? process.execPath;
8873
8987
  let args = ["--import", "tsx", "src/server.ts", "--port", String(port)];
@@ -8888,34 +9002,34 @@ function spawnAttached(cmd, args, cwd) {
8888
9002
  cwd,
8889
9003
  stdio: ["ignore", "pipe", "pipe"]
8890
9004
  });
8891
- return new Promise((resolve20) => {
8892
- const timeout = setTimeout(() => resolve20(null), 3e4);
9005
+ return new Promise((resolve21) => {
9006
+ const timeout = setTimeout(() => resolve21(null), 3e4);
8893
9007
  function checkOutput(data) {
8894
9008
  const match = data.toString().match(/listening on :(\d+)/);
8895
9009
  if (match) {
8896
9010
  clearTimeout(timeout);
8897
- resolve20({ child, actualPort: parseInt(match[1], 10) });
9011
+ resolve21({ child, actualPort: parseInt(match[1], 10) });
8898
9012
  }
8899
9013
  }
8900
9014
  child.stdout?.on("data", checkOutput);
8901
9015
  child.stderr?.on("data", checkOutput);
8902
9016
  child.on("error", () => {
8903
9017
  clearTimeout(timeout);
8904
- resolve20(null);
9018
+ resolve21(null);
8905
9019
  });
8906
9020
  child.on("exit", () => {
8907
9021
  clearTimeout(timeout);
8908
- resolve20(null);
9022
+ resolve21(null);
8909
9023
  });
8910
9024
  });
8911
9025
  }
8912
9026
  function spawnDetached(cmd, args, cwd, logDir) {
8913
- const logsDir = logDir ?? resolve16(cwd, ".mind", "logs");
9027
+ const logsDir = logDir ?? resolve17(cwd, ".mind", "logs");
8914
9028
  mkdirSync8(logsDir, { recursive: true });
8915
- const logPath = resolve16(logsDir, "mind.log");
9029
+ const logPath = resolve17(logsDir, "mind.log");
8916
9030
  let startOffset = 0;
8917
9031
  try {
8918
- startOffset = statSync3(logPath).size;
9032
+ startOffset = statSync4(logPath).size;
8919
9033
  } catch {
8920
9034
  }
8921
9035
  const logFd = openSync(logPath, "a");
@@ -9053,11 +9167,11 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9053
9167
  return c.json({ error: `Name already in use: ${variantName}` }, 409);
9054
9168
  }
9055
9169
  const projectRoot = entry.dir ?? mindDir(mindName);
9056
- const variantDir = resolve17(projectRoot, ".variants", variantName);
9170
+ const variantDir = resolve18(projectRoot, ".variants", variantName);
9057
9171
  if (existsSync11(variantDir)) {
9058
9172
  return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
9059
9173
  }
9060
- mkdirSync9(resolve17(projectRoot, ".variants"), { recursive: true });
9174
+ mkdirSync9(resolve18(projectRoot, ".variants"), { recursive: true });
9061
9175
  try {
9062
9176
  await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
9063
9177
  } catch (e) {
@@ -9093,7 +9207,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9093
9207
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
9094
9208
  await exec(cmd, args, {
9095
9209
  cwd: variantDir,
9096
- env: { ...process.env, HOME: resolve17(variantDir, "home") }
9210
+ env: { ...process.env, HOME: resolve18(variantDir, "home") }
9097
9211
  });
9098
9212
  } else {
9099
9213
  await exec("npm", ["install"], { cwd: variantDir });
@@ -9104,7 +9218,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9104
9218
  return c.json({ error: `npm install failed: ${msg}` }, 500);
9105
9219
  }
9106
9220
  if (body.soul) {
9107
- writeFileSync9(resolve17(variantDir, "home/SOUL.md"), body.soul);
9221
+ writeFileSync9(resolve18(variantDir, "home/SOUL.md"), body.soul);
9108
9222
  }
9109
9223
  const variantPort = body.port ?? await nextPort();
9110
9224
  try {
@@ -9157,7 +9271,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9157
9271
  } catch {
9158
9272
  }
9159
9273
  const projectRoot = parentEntry.dir ?? mindDir(mindName);
9160
- const failAfterGitWrite = async (message, extra) => {
9274
+ const failAfterGitWrite = async (message, extra, status = 500) => {
9161
9275
  try {
9162
9276
  await chownMindDir(projectRoot, mindName);
9163
9277
  } catch (err) {
@@ -9173,7 +9287,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9173
9287
  500
9174
9288
  );
9175
9289
  }
9176
- return c.json({ error: message, ...extra }, 500);
9290
+ return c.json({ error: message, ...extra }, status);
9177
9291
  };
9178
9292
  let farewell;
9179
9293
  try {
@@ -9245,6 +9359,27 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9245
9359
  { conflicts: err.conflicts }
9246
9360
  );
9247
9361
  }
9362
+ if (existsSync11(variantEntry.dir) && !body.discardUnresolved) {
9363
+ let unresolved;
9364
+ try {
9365
+ unresolved = await findUnresolvedHomeFiles(variantEntry.dir);
9366
+ } catch (err) {
9367
+ return failAfterGitWrite(
9368
+ `Could not verify variant ${variantName} has no unresolved home/ files: ${err instanceof Error ? err.message : String(err)}. Variant left intact \u2014 retry the join.`
9369
+ );
9370
+ }
9371
+ if (unresolved.totalCount > 0) {
9372
+ return failAfterGitWrite(
9373
+ formatUnresolvedHomeFilesMessage(variantName, unresolved),
9374
+ {
9375
+ unresolvedFiles: unresolved.files,
9376
+ unresolvedCount: unresolved.totalCount,
9377
+ unresolvedBytes: unresolved.totalBytes
9378
+ },
9379
+ 409
9380
+ );
9381
+ }
9382
+ }
9248
9383
  await cleanupVariant(variantName, mindName, projectRoot, variantEntry.dir, { stop: true });
9249
9384
  await chownMindDir(projectRoot, mindName);
9250
9385
  if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
@@ -9263,7 +9398,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9263
9398
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
9264
9399
  await exec(cmd, args, {
9265
9400
  cwd: projectRoot,
9266
- env: { ...process.env, HOME: resolve17(projectRoot, "home") }
9401
+ env: { ...process.env, HOME: resolve18(projectRoot, "home") }
9267
9402
  });
9268
9403
  } else {
9269
9404
  await exec("npm", ["install"], { cwd: projectRoot });
@@ -9750,11 +9885,11 @@ var app24 = new Hono28().get("/:name/conversations/:id/events", async (c) => {
9750
9885
  if (!stream.aborted) console.error("[chat] SSE ping error:", err);
9751
9886
  });
9752
9887
  }, 15e3);
9753
- await new Promise((resolve20) => {
9888
+ await new Promise((resolve21) => {
9754
9889
  stream.onAbort(() => {
9755
9890
  unsubscribe();
9756
9891
  clearInterval(keepAlive);
9757
- resolve20();
9892
+ resolve21();
9758
9893
  });
9759
9894
  });
9760
9895
  });
@@ -9974,7 +10109,7 @@ var app_default = app26;
9974
10109
  import { existsSync as existsSync12 } from "fs";
9975
10110
  import { readFile as readFile2, stat as stat2 } from "fs/promises";
9976
10111
  import { createServer as createHttpsServer } from "https";
9977
- import { dirname as dirname3, extname as extname3, resolve as resolve18 } from "path";
10112
+ import { dirname as dirname3, extname as extname3, resolve as resolve19 } from "path";
9978
10113
  import { serve } from "@hono/node-server";
9979
10114
  var MIME_TYPES2 = {
9980
10115
  ".html": "text/html",
@@ -9993,7 +10128,7 @@ async function startServer({
9993
10128
  let assetsDir = "";
9994
10129
  let searchDir = dirname3(new URL(import.meta.url).pathname);
9995
10130
  for (let i = 0; i < 5; i++) {
9996
- const candidate = resolve18(searchDir, "dist", "web-assets");
10131
+ const candidate = resolve19(searchDir, "dist", "web-assets");
9997
10132
  if (existsSync12(candidate)) {
9998
10133
  assetsDir = candidate;
9999
10134
  break;
@@ -10004,7 +10139,7 @@ async function startServer({
10004
10139
  app_default.get("*", async (c) => {
10005
10140
  const urlPath = new URL(c.req.url).pathname;
10006
10141
  if (urlPath.startsWith("/api/") || urlPath.startsWith("/ext/")) return c.notFound();
10007
- const filePath = resolve18(assetsDir, urlPath.slice(1));
10142
+ const filePath = resolve19(assetsDir, urlPath.slice(1));
10008
10143
  if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
10009
10144
  const s = await stat2(filePath).catch(() => null);
10010
10145
  if (s?.isFile()) {
@@ -10017,7 +10152,7 @@ async function startServer({
10017
10152
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
10018
10153
  return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
10019
10154
  }
10020
- const indexPath = resolve18(assetsDir, "index.html");
10155
+ const indexPath = resolve19(assetsDir, "index.html");
10021
10156
  const indexStat = await stat2(indexPath).catch(() => null);
10022
10157
  if (indexStat?.isFile()) {
10023
10158
  const body = await readFile2(indexPath, "utf-8");
@@ -10034,10 +10169,10 @@ async function startServer({
10034
10169
  createServer: createHttpsServer,
10035
10170
  serverOptions: { key: tls.key, cert: tls.cert }
10036
10171
  });
10037
- await new Promise((resolve20, reject) => {
10172
+ await new Promise((resolve21, reject) => {
10038
10173
  server2.on("listening", () => {
10039
10174
  logger_default.info("Volute UI running (https)", { hostname, port });
10040
- resolve20();
10175
+ resolve21();
10041
10176
  });
10042
10177
  server2.on("error", (err) => {
10043
10178
  reject(err);
@@ -10045,13 +10180,13 @@ async function startServer({
10045
10180
  });
10046
10181
  const internalPort = port + 1;
10047
10182
  const internalServer = serve({ fetch: app_default.fetch, port: internalPort, hostname: "127.0.0.1" });
10048
- await new Promise((resolve20, reject) => {
10183
+ await new Promise((resolve21, reject) => {
10049
10184
  internalServer.on("listening", () => {
10050
10185
  logger_default.info("Volute API running (http, internal)", {
10051
10186
  hostname: "127.0.0.1",
10052
10187
  port: internalPort
10053
10188
  });
10054
- resolve20();
10189
+ resolve21();
10055
10190
  });
10056
10191
  internalServer.on("error", (err) => {
10057
10192
  reject(err);
@@ -10060,10 +10195,10 @@ async function startServer({
10060
10195
  return { server: server2, internalPort };
10061
10196
  }
10062
10197
  const server = serve({ fetch: app_default.fetch, port, hostname });
10063
- await new Promise((resolve20, reject) => {
10198
+ await new Promise((resolve21, reject) => {
10064
10199
  server.on("listening", () => {
10065
10200
  logger_default.info("Volute API running (http)", { hostname, port });
10066
- resolve20();
10201
+ resolve21();
10067
10202
  });
10068
10203
  server.on("error", (err) => {
10069
10204
  reject(err);
@@ -10074,17 +10209,17 @@ async function startServer({
10074
10209
 
10075
10210
  // packages/daemon/src/daemon.ts
10076
10211
  if (!process.env.VOLUTE_HOME) {
10077
- process.env.VOLUTE_HOME = resolve19(homedir3(), ".volute");
10212
+ process.env.VOLUTE_HOME = resolve20(homedir3(), ".volute");
10078
10213
  }
10079
10214
  if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
10080
10215
  process.env.TZ = process.env.VOLUTE_TIMEZONE;
10081
10216
  }
10082
10217
  function writeDaemonConfig(systemDir, config2, token) {
10083
- const configPath = resolve19(systemDir, "daemon.json");
10218
+ const configPath = resolve20(systemDir, "daemon.json");
10084
10219
  writeFileSync10(configPath, `${JSON.stringify(config2, null, 2)}
10085
10220
  `, { mode: 420 });
10086
10221
  chmodSync(configPath, 420);
10087
- const tokenPath = resolve19(systemDir, "daemon-token");
10222
+ const tokenPath = resolve20(systemDir, "daemon-token");
10088
10223
  writeFileSync10(tokenPath, `${token}
10089
10224
  `, { mode: 384 });
10090
10225
  chmodSync(tokenPath, 384);
@@ -10095,7 +10230,7 @@ async function startDaemon(opts) {
10095
10230
  const home = voluteHome();
10096
10231
  const systemDir = voluteSystemDir();
10097
10232
  if (!opts.foreground) {
10098
- const rotatingLog = new RotatingLog(resolve19(systemDir, "daemon.log"));
10233
+ const rotatingLog = new RotatingLog(resolve20(systemDir, "daemon.log"));
10099
10234
  logger_default.setOutput((line) => rotatingLog.write(`${line}
10100
10235
  `));
10101
10236
  const write = (...args) => rotatingLog.write(`${format(...args)}
@@ -10105,9 +10240,9 @@ async function startDaemon(opts) {
10105
10240
  console.warn = write;
10106
10241
  console.info = write;
10107
10242
  }
10108
- const DAEMON_PID_PATH = resolve19(systemDir, "daemon.pid");
10109
- const DAEMON_JSON_PATH = resolve19(systemDir, "daemon.json");
10110
- const DAEMON_TOKEN_PATH = resolve19(systemDir, "daemon-token");
10243
+ const DAEMON_PID_PATH = resolve20(systemDir, "daemon.pid");
10244
+ const DAEMON_JSON_PATH = resolve20(systemDir, "daemon.json");
10245
+ const DAEMON_TOKEN_PATH = resolve20(systemDir, "daemon-token");
10111
10246
  mkdirSync10(home, { recursive: true });
10112
10247
  ensureSystemDir();
10113
10248
  const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-WZSXHHRJ.js");
@@ -10168,7 +10303,7 @@ async function startDaemon(opts) {
10168
10303
  logger_default.warn("failed to backfill minds into #system", logger_default.errorData(err));
10169
10304
  }
10170
10305
  try {
10171
- const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-X6EMNEGB.js");
10306
+ const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-KRDSM55Q.js");
10172
10307
  await getOrCreateSystemUser2();
10173
10308
  } catch (err) {
10174
10309
  logger_default.warn(
@@ -10236,7 +10371,7 @@ async function startDaemon(opts) {
10236
10371
  const orphanedTurns = await completeOrphanedTurns();
10237
10372
  summarizeOrphanedTurns(orphanedTurns);
10238
10373
  try {
10239
- const { reconcileVariants } = await import("./variant-cleanup-YXN25ZVW.js");
10374
+ const { reconcileVariants } = await import("./variant-cleanup-STC6B5HR.js");
10240
10375
  await reconcileVariants();
10241
10376
  } catch (err) {
10242
10377
  logger_default.error("failed to reconcile variants", logger_default.errorData(err));
@@ -10272,8 +10407,8 @@ async function startDaemon(opts) {
10272
10407
  try {
10273
10408
  const { isSetupComplete: isSetupComplete2, getSpiritName: getSpiritName2 } = await import("./setup-WZSXHHRJ.js");
10274
10409
  if (isSetupComplete2()) {
10275
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-25JVAL3M.js");
10276
- const { startSpiritFull } = await import("./mind-service-DZCUUC7J.js");
10410
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-4ECYIVGE.js");
10411
+ const { startSpiritFull } = await import("./mind-service-E26ZQXDS.js");
10277
10412
  await ensureSpiritProject();
10278
10413
  const spiritName = getSpiritName2();
10279
10414
  const spiritEntry = await findMind(spiritName);
@@ -10292,7 +10427,7 @@ async function startDaemon(opts) {
10292
10427
  bridgeManager.startBridges(daemonPort).catch((err) => {
10293
10428
  logger_default.warn("failed to start bridges", logger_default.errorData(err));
10294
10429
  });
10295
- import("./cloud-sync-GPXYPTIC.js").then(
10430
+ import("./cloud-sync-H7EWZASD.js").then(
10296
10431
  ({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
10297
10432
  logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
10298
10433
  })
@@ -10300,7 +10435,7 @@ async function startDaemon(opts) {
10300
10435
  logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
10301
10436
  });
10302
10437
  try {
10303
- const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-EN3KJ7HH.js");
10438
+ const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-LBVHH5YV.js");
10304
10439
  backfillTemplateHashes().then(() => warnStaleTemplates()).catch((err) => {
10305
10440
  logger_default.warn("failed to check template staleness", logger_default.errorData(err));
10306
10441
  });