volute 0.43.1 → 0.45.1

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 (132) hide show
  1. package/dist/{activity-events-UISXY4Y5.js → activity-events-OMCSM7XW.js} +3 -3
  2. package/dist/{ai-service-FBCCEYF5.js → ai-service-534WUSDL.js} +4 -4
  3. package/dist/{archive-I32WHCJB.js → archive-6R4TZMYI.js} +3 -3
  4. package/dist/{auth-3RIG6GKN.js → auth-FRZJVQCS.js} +4 -4
  5. package/dist/avatar-image-BNWEXSA2.js +16 -0
  6. package/dist/backup-OZXHL3JS.js +381 -0
  7. package/dist/{chat-SDSX5TVV.js → chat-I4EDDIQC.js} +2 -2
  8. package/dist/{chunk-AD46AYZQ.js → chunk-2BONPXAF.js} +1 -1
  9. package/dist/{chunk-ONM2AZFL.js → chunk-322KE457.js} +14 -2
  10. package/dist/{chunk-PGPLCJPK.js → chunk-3ERIL673.js} +1 -1
  11. package/dist/{chunk-QQ2MVQU3.js → chunk-5AUKCNPE.js} +10 -10
  12. package/dist/{chunk-XDTKJNW5.js → chunk-5GT7URXJ.js} +1 -1
  13. package/dist/{chunk-DMUPZQWP.js → chunk-77BVGCTZ.js} +8 -8
  14. package/dist/{chunk-EFL5UOY4.js → chunk-CYI534DJ.js} +3 -3
  15. package/dist/{chunk-57LBQ7JX.js → chunk-FHWUQZXE.js} +1 -1
  16. package/dist/{chunk-YAMO2U3N.js → chunk-H7IYFRAL.js} +1 -1
  17. package/dist/{chunk-M3PGGSBH.js → chunk-HVU45COX.js} +1 -1
  18. package/dist/{chunk-O3DXAR44.js → chunk-IEWZ7VD7.js} +2 -2
  19. package/dist/{chunk-DE4EKQFH.js → chunk-IUXTYXFI.js} +3 -3
  20. package/dist/{chunk-K4EHBHPE.js → chunk-JSRMEY52.js} +7 -5
  21. package/dist/{chunk-QHG4OMZL.js → chunk-KDLYIECM.js} +37 -32
  22. package/dist/{chunk-EE7SZJON.js → chunk-KP3KWNG6.js} +2 -2
  23. package/dist/chunk-KVKP6VQ5.js +318 -0
  24. package/dist/{chunk-JVK6QQIC.js → chunk-LAXUUY7O.js} +2 -2
  25. package/dist/{chunk-C6ESRQZ7.js → chunk-OXXTPILE.js} +1 -1
  26. package/dist/{chunk-ATEX3ZPG.js → chunk-Q2XBKQ2D.js} +2 -2
  27. package/dist/{chunk-GZJFC76M.js → chunk-QMJJWTNL.js} +1 -1
  28. package/dist/chunk-SQL7M4HJ.js +120 -0
  29. package/dist/{chunk-YSV3VJQK.js → chunk-TSK5PI4L.js} +1 -1
  30. package/dist/{chunk-4SVONUTC.js → chunk-U4FNXDEJ.js} +350 -207
  31. package/dist/{chunk-2HIVYZDB.js → chunk-UMI4UIJG.js} +1 -1
  32. package/dist/{chunk-Y6O35D7K.js → chunk-V4GYPD5L.js} +41 -16
  33. package/dist/{chunk-KINGVQSR.js → chunk-Y6OPHHGM.js} +5 -5
  34. package/dist/{chunk-SPLPKBES.js → chunk-ZIR7HSAX.js} +6 -9
  35. package/dist/{chunk-7G2EEYXX.js → chunk-ZMIMSIIT.js} +2 -2
  36. package/dist/{chunk-L3IV23ZG.js → chunk-ZV7MFISX.js} +2 -0
  37. package/dist/cli.js +53 -22
  38. package/dist/{cloud-sync-KOEBUFW5.js → cloud-sync-Y7LQPRE3.js} +16 -16
  39. package/dist/{conversations-67WWW25C.js → conversations-G4LYMHAA.js} +4 -4
  40. package/dist/{create-7W3LV3J7.js → create-2YY7IPMS.js} +1 -1
  41. package/dist/{daemon-restart-EZXB73W7.js → daemon-restart-ABP54YN6.js} +7 -7
  42. package/dist/daemon.js +679 -478
  43. package/dist/{db-CZV62BOQ.js → db-JFLCJCUG.js} +2 -2
  44. package/dist/{db-IJL6B26S.js → db-LZTLA7XC.js} +1 -1
  45. package/dist/delivery-manager-R5STGLXB.js +32 -0
  46. package/dist/{delivery-router-HXBHYHJM.js → delivery-router-6DE3BPHO.js} +3 -3
  47. package/dist/{down-RRNYIGCU.js → down-XCAZXWLB.js} +5 -5
  48. package/dist/echo-text-NQXYYYCU.js +32 -0
  49. package/dist/{exec-SJK7VUTC.js → exec-4GWHAHS3.js} +3 -3
  50. package/dist/{export-7LPCIB5J.js → export-ID7YUSLZ.js} +3 -3
  51. package/dist/{extensions-PQPZT6LS.js → extensions-AYSPKE33.js} +16 -16
  52. package/dist/{files-LV7VAKPC.js → files-BQ2WB5KC.js} +3 -3
  53. package/dist/{import-XPECCRQ7.js → import-SKID37QX.js} +6 -6
  54. package/dist/{isolation-5AYEY55P.js → isolation-5MB3J73F.js} +3 -3
  55. package/dist/{login-KJSN4JDA.js → login-LM4NF4ZB.js} +2 -2
  56. package/dist/{logout-TMJGUQV2.js → logout-CTJVIZGA.js} +2 -2
  57. package/dist/message-delivery-IUAXRPFE.js +34 -0
  58. package/dist/{mind-G3WEWDM4.js → mind-KLHC7XYR.js} +6 -6
  59. package/dist/{mind-activity-tracker-JHAT6456.js → mind-activity-tracker-BGHJE7XA.js} +4 -4
  60. package/dist/mind-service-BF2LUQMH.js +36 -0
  61. package/dist/{package-24TL6DTF.js → package-BMHV7UHN.js} +1 -1
  62. package/dist/{registry-7LQHTRUX.js → registry-NUJAGLQJ.js} +2 -2
  63. package/dist/{sandbox-SJH3XOPZ.js → sandbox-72MWV4JL.js} +4 -4
  64. package/dist/scheduler-YHJRRV6E.js +30 -0
  65. package/dist/{schema-LRUTFOER.js → schema-PVNG3PQM.js} +1 -1
  66. package/dist/{seed-HHSJTM6O.js → seed-4MKQ5QKG.js} +1 -1
  67. package/dist/{seed-cmd-UPQY35RG.js → seed-cmd-LCXMR7VV.js} +2 -2
  68. package/dist/{seed-create-MDRMXMSB.js → seed-create-N2BF5LQX.js} +3 -3
  69. package/dist/{seed-sprout-4M7IQWMH.js → seed-sprout-6ZDP23YI.js} +7 -7
  70. package/dist/{send-ZBZWIH5V.js → send-O6W53VBM.js} +37 -42
  71. package/dist/{service-4EVZKGSA.js → service-AQVPUANO.js} +4 -4
  72. package/dist/{service-install-SHRM6NHK.js → service-install-4QNUDKLM.js} +5 -5
  73. package/dist/{setup-ZD2LMBR3.js → setup-3O6O2JZ7.js} +7 -7
  74. package/dist/{setup-25MMJ3J4.js → setup-73YBJZQL.js} +3 -3
  75. package/dist/skills/memory/SKILL.md +2 -1
  76. package/dist/skills/orientation/SKILL.md +1 -1
  77. package/dist/skills/plan-coordinator/SKILL.md +2 -2
  78. package/dist/skills/volute-admin/SKILL.md +9 -6
  79. package/dist/skills/volute-mind/SKILL.md +15 -16
  80. package/dist/skills/volute-mind/references/extensions.md +5 -3
  81. package/dist/skills/volute-mind/references/integrations.md +2 -2
  82. package/dist/skills/volute-mind/references/routing.md +19 -23
  83. package/dist/skills/volute-mind/references/variants.md +10 -8
  84. package/dist/{skills-4KQ377GN.js → skills-ND4ZFYUW.js} +5 -5
  85. package/dist/sleep-manager-YAHDOIU5.js +34 -0
  86. package/dist/{spirit-53DQPRNR.js → spirit-II3HOERM.js} +7 -7
  87. package/dist/{sprout-YKM2M6D6.js → sprout-4KUG76AQ.js} +1 -1
  88. package/dist/{src-O4PRLMKM.js → src-JAOVXO5W.js} +1 -0
  89. package/dist/{src-3EGHHKZK.js → src-XFY3XDD6.js} +16 -11
  90. package/dist/{src-L2Z7X5UT.js → src-YH6PQ7LJ.js} +264 -52
  91. package/dist/{status-WTU2WHXY.js → status-E5DQNCAO.js} +5 -5
  92. package/dist/system-chat-E65T2HSW.js +34 -0
  93. package/dist/{tailscale-Q7ZJL7S7.js → tailscale-QAWVKQKU.js} +2 -2
  94. package/dist/{turn-tracker-JZYERJ76.js → turn-tracker-QQIVVXBI.js} +7 -5
  95. package/dist/{up-LFZA4GI5.js → up-LG56MPBI.js} +6 -6
  96. package/dist/{update-EJ7Q77ZX.js → update-7TYVH5FM.js} +5 -5
  97. package/dist/{update-check-ACYYNKTW.js → update-check-VSCSJ7KX.js} +3 -3
  98. package/dist/{upgrade-37DAGF6H.js → upgrade-NWAZ7MLD.js} +1 -1
  99. package/dist/{version-notify-SRQJCQEK.js → version-notify-CODJOUW2.js} +17 -17
  100. package/dist/web-assets/assets/index-B1JBQv2m.css +1 -0
  101. package/dist/web-assets/assets/index-Dac11sKB.js +86 -0
  102. package/dist/web-assets/ext-theme.css +5 -0
  103. package/dist/web-assets/index.html +2 -2
  104. package/package.json +1 -1
  105. package/packages/extensions/notes/dist/ui/assets/{index-BbgANhFm.js → index-D0-DgYyj.js} +1 -1
  106. package/packages/extensions/notes/dist/ui/index.html +1 -1
  107. package/packages/extensions/notes/skills/notes/SKILL.md +31 -3
  108. package/packages/extensions/pages/dist/ui/assets/{index-Dxk-DYrf.js → index-CQjEQg1r.js} +1 -1
  109. package/packages/extensions/pages/dist/ui/index.html +1 -1
  110. package/packages/extensions/plan/skills/plan/SKILL.md +1 -1
  111. package/templates/_base/.init/.config/prompts.json +1 -1
  112. package/templates/_base/.init/.local/hooks/startup-context.ts +21 -4
  113. package/templates/_base/.init/MEMORY.md +2 -1
  114. package/templates/_base/home/VOLUTE.md +6 -9
  115. package/templates/_base/src/lib/startup.ts +1 -1
  116. package/templates/claude/.init/CLAUDE.md +1 -1
  117. package/templates/claude/src/agent.ts +30 -3
  118. package/templates/claude/src/lib/stream-consumer.ts +7 -4
  119. package/templates/codex/.init/AGENTS.md +4 -2
  120. package/templates/codex/src/agent.ts +13 -7
  121. package/templates/pi/.init/MINDS.md +4 -2
  122. package/templates/pi/src/lib/event-handler.ts +6 -2
  123. package/dist/delivery-manager-OMCCJEVP.js +0 -32
  124. package/dist/echo-text-KFSUCZXL.js +0 -32
  125. package/dist/message-delivery-HRGFNWO7.js +0 -34
  126. package/dist/mind-service-2C7AINBO.js +0 -36
  127. package/dist/scheduler-VON2TB52.js +0 -30
  128. package/dist/sleep-manager-AG5SQDDI.js +0 -34
  129. package/dist/system-chat-54RN3K67.js +0 -34
  130. package/dist/web-assets/assets/index-D7udpBCx.css +0 -1
  131. package/dist/web-assets/assets/index-DTDmEfPU.js +0 -79
  132. package/templates/_base/.init/.config/hooks/pre-prompt/session-activity.ts +0 -40
package/dist/daemon.js CHANGED
@@ -1,4 +1,12 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ RESTIC_INSTALL_HINT,
4
+ initRepo,
5
+ listSnapshots,
6
+ readBackupState,
7
+ resticVersion,
8
+ runBackup
9
+ } from "./chunk-KVKP6VQ5.js";
2
10
  import {
3
11
  acceptPending,
4
12
  formatFileSize,
@@ -6,21 +14,25 @@ import {
6
14
  rejectPending,
7
15
  stageFile,
8
16
  validateFilePath
9
- } from "./chunk-2HIVYZDB.js";
17
+ } from "./chunk-UMI4UIJG.js";
10
18
  import {
11
19
  findOpenClawSession,
12
20
  importOpenClawConnectors,
13
21
  importPiSession,
14
22
  parseNameFromIdentity
15
- } from "./chunk-JVK6QQIC.js";
23
+ } from "./chunk-LAXUUY7O.js";
16
24
  import {
17
25
  checkForUpdate,
18
26
  checkForUpdateCached,
19
27
  getCurrentVersion
20
- } from "./chunk-AD46AYZQ.js";
28
+ } from "./chunk-2BONPXAF.js";
29
+ import {
30
+ normalizeAvatar,
31
+ safeResolveWithinBase
32
+ } from "./chunk-SQL7M4HJ.js";
21
33
  import {
22
34
  isHomeOnlyArchive
23
- } from "./chunk-GZJFC76M.js";
35
+ } from "./chunk-QMJJWTNL.js";
24
36
  import {
25
37
  computeTemplateHash
26
38
  } from "./chunk-QMJCNZ6C.js";
@@ -30,7 +42,7 @@ import {
30
42
  fixModelEscapes,
31
43
  getPlatformDriver,
32
44
  routeOutboundBridge
33
- } from "./chunk-DMUPZQWP.js";
45
+ } from "./chunk-77BVGCTZ.js";
34
46
  import {
35
47
  getBridgeConfig,
36
48
  readBridgesConfig,
@@ -39,7 +51,7 @@ import {
39
51
  resolveChannelMapping,
40
52
  setBridgeConfig,
41
53
  setChannelMapping
42
- } from "./chunk-57LBQ7JX.js";
54
+ } from "./chunk-FHWUQZXE.js";
43
55
  import {
44
56
  MindStartupError,
45
57
  RestartTracker,
@@ -48,6 +60,7 @@ import {
48
60
  announceToSystem,
49
61
  authMiddleware,
50
62
  checkHealth,
63
+ checkStaleSend,
51
64
  cleanExpiredSessions,
52
65
  clearDeliveredNotices,
53
66
  createSession,
@@ -56,6 +69,7 @@ import {
56
69
  deliverMessage,
57
70
  drainNotices,
58
71
  ensureSystemChannel,
72
+ formatHoldNotice,
59
73
  formatNotices,
60
74
  generateSystemReply,
61
75
  getAllDiscoveredExtensions,
@@ -98,15 +112,15 @@ import {
98
112
  syncProviderToMinds,
99
113
  uninstallNpmExtension,
100
114
  writeSystemsConfig
101
- } from "./chunk-4SVONUTC.js";
115
+ } from "./chunk-U4FNXDEJ.js";
102
116
  import {
103
117
  loadMergedEnv,
104
118
  mindEnvPath,
105
119
  readEnv,
106
120
  sharedEnvPath,
107
121
  writeEnv
108
- } from "./chunk-XDTKJNW5.js";
109
- import "./chunk-QQ2MVQU3.js";
122
+ } from "./chunk-5GT7URXJ.js";
123
+ import "./chunk-5AUKCNPE.js";
110
124
  import {
111
125
  applyInitFiles,
112
126
  applyTemplateHomeFiles,
@@ -135,7 +149,7 @@ import {
135
149
  syncBuiltinSkills,
136
150
  uninstallSkill,
137
151
  updateSkill
138
- } from "./chunk-KINGVQSR.js";
152
+ } from "./chunk-Y6OPHHGM.js";
139
153
  import {
140
154
  addMessage,
141
155
  createChannel,
@@ -167,7 +181,7 @@ import {
167
181
  setConversationPrivate,
168
182
  subscribe as subscribe2,
169
183
  updateChannelSettings
170
- } from "./chunk-K4EHBHPE.js";
184
+ } from "./chunk-JSRMEY52.js";
171
185
  import {
172
186
  readVoluteConfig,
173
187
  writeVoluteConfig
@@ -175,15 +189,15 @@ import {
175
189
  import {
176
190
  isSandboxEnabled,
177
191
  wrapForSandbox
178
- } from "./chunk-C6ESRQZ7.js";
192
+ } from "./chunk-OXXTPILE.js";
179
193
  import {
180
194
  getActiveMinds,
181
195
  onMindEvent,
182
196
  stopAll
183
- } from "./chunk-M3PGGSBH.js";
197
+ } from "./chunk-HVU45COX.js";
184
198
  import {
185
199
  extractTextContent
186
- } from "./chunk-SPLPKBES.js";
200
+ } from "./chunk-ZIR7HSAX.js";
187
201
  import {
188
202
  PROMPT_DEFAULTS,
189
203
  PROMPT_KEYS,
@@ -192,10 +206,10 @@ import {
192
206
  completeTurn,
193
207
  createTurn,
194
208
  getActiveTurnId,
195
- getLastToolUseEventId,
196
209
  getMindPromptDefaults,
197
210
  getPrompt,
198
211
  getPromptIfCustom,
212
+ getToolUseEventId,
199
213
  initSummarizer,
200
214
  markErrored,
201
215
  publish as publish2,
@@ -206,8 +220,8 @@ import {
206
220
  summarizeTurn,
207
221
  takeErrored,
208
222
  trackToolUse
209
- } from "./chunk-Y6O35D7K.js";
210
- import "./chunk-ATEX3ZPG.js";
223
+ } from "./chunk-V4GYPD5L.js";
224
+ import "./chunk-Q2XBKQ2D.js";
211
225
  import {
212
226
  chownMindDir,
213
227
  createMindUser,
@@ -218,7 +232,7 @@ import {
218
232
  isIsolationEnabled,
219
233
  resolveVoluteBin,
220
234
  wrapForIsolation
221
- } from "./chunk-PGPLCJPK.js";
235
+ } from "./chunk-3ERIL673.js";
222
236
  import {
223
237
  addCustomModel,
224
238
  buildCustomModel,
@@ -239,12 +253,12 @@ import {
239
253
  setProviderRefreshHook,
240
254
  setUtilityModel,
241
255
  unqualifyModelId
242
- } from "./chunk-YSV3VJQK.js";
256
+ } from "./chunk-TSK5PI4L.js";
243
257
  import {
244
258
  isSetupComplete,
245
259
  readGlobalConfig,
246
260
  writeGlobalConfig
247
- } from "./chunk-ONM2AZFL.js";
261
+ } from "./chunk-322KE457.js";
248
262
  import {
249
263
  approveUser,
250
264
  changePassword,
@@ -263,11 +277,11 @@ import {
263
277
  syncMindProfile,
264
278
  updateUserProfile,
265
279
  verifyUser
266
- } from "./chunk-EFL5UOY4.js";
280
+ } from "./chunk-CYI534DJ.js";
267
281
  import {
268
282
  broadcast,
269
283
  subscribe
270
- } from "./chunk-7G2EEYXX.js";
284
+ } from "./chunk-ZMIMSIIT.js";
271
285
  import {
272
286
  logBuffer,
273
287
  logger_default
@@ -299,7 +313,7 @@ import {
299
313
  validateMindName,
300
314
  voluteHome,
301
315
  voluteSystemDir
302
- } from "./chunk-YAMO2U3N.js";
316
+ } from "./chunk-H7IYFRAL.js";
303
317
  import {
304
318
  activity,
305
319
  channels,
@@ -310,16 +324,80 @@ import {
310
324
  systemPrompts,
311
325
  turns,
312
326
  users
313
- } from "./chunk-L3IV23ZG.js";
327
+ } from "./chunk-ZV7MFISX.js";
314
328
  import "./chunk-K3NQKI34.js";
315
329
 
316
330
  // packages/daemon/src/daemon.ts
317
- import { randomBytes as randomBytes2 } from "crypto";
331
+ import { randomBytes as randomBytes3 } from "crypto";
318
332
  import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync10, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "fs";
319
333
  import { homedir as homedir3 } from "os";
320
- import { resolve as resolve17 } from "path";
334
+ import { resolve as resolve16 } from "path";
321
335
  import { format } from "util";
322
336
 
337
+ // packages/daemon/src/lib/daemon/backup-manager.ts
338
+ import { CronExpressionParser } from "cron-parser";
339
+ var blog = logger_default.child("backup");
340
+ var DEFAULT_BACKUP_SCHEDULE = "0 3 * * *";
341
+ var BackupManager = class {
342
+ interval = null;
343
+ lastFiredMinute = -1;
344
+ warnedUnconfigured = false;
345
+ start() {
346
+ this.interval = setInterval(() => {
347
+ this.tick().catch((err) => blog.error("backup tick failed", logger_default.errorData(err)));
348
+ }, 6e4);
349
+ }
350
+ stop() {
351
+ if (this.interval) clearInterval(this.interval);
352
+ this.interval = null;
353
+ }
354
+ /**
355
+ * True at most once per scheduled fire minute (records the minute it
356
+ * consumed), and only when backups are enabled and runnable. Not a pure
357
+ * predicate — a second call in the same minute returns false.
358
+ */
359
+ isDue(now = /* @__PURE__ */ new Date()) {
360
+ const config2 = readGlobalConfig().backup;
361
+ if (!config2?.enabled) return false;
362
+ if (!config2.repository || !config2.password) {
363
+ if (!this.warnedUnconfigured) {
364
+ blog.warn("scheduled backups are enabled but no repository is initialized \u2014 not running");
365
+ this.warnedUnconfigured = true;
366
+ }
367
+ return false;
368
+ }
369
+ this.warnedUnconfigured = false;
370
+ const cron = config2.schedule || DEFAULT_BACKUP_SCHEDULE;
371
+ const epochMinute = Math.floor(now.getTime() / 6e4);
372
+ if (epochMinute === this.lastFiredMinute) return false;
373
+ let prevMinute;
374
+ try {
375
+ const interval = CronExpressionParser.parse(cron, { currentDate: now });
376
+ prevMinute = Math.floor(interval.prev().toDate().getTime() / 6e4);
377
+ } catch (err) {
378
+ blog.warn(`invalid backup cron "${cron}"`, logger_default.errorData(err));
379
+ return false;
380
+ }
381
+ if (prevMinute !== epochMinute) return false;
382
+ this.lastFiredMinute = epochMinute;
383
+ return true;
384
+ }
385
+ async tick() {
386
+ if (!this.isDue()) return;
387
+ blog.info("scheduled backup starting");
388
+ try {
389
+ await runBackup();
390
+ } catch (err) {
391
+ blog.error("scheduled backup failed", logger_default.errorData(err));
392
+ }
393
+ }
394
+ };
395
+ var backupManager = null;
396
+ function initBackupManager() {
397
+ if (!backupManager) backupManager = new BackupManager();
398
+ return backupManager;
399
+ }
400
+
323
401
  // packages/daemon/src/lib/daemon/bridge-manager.ts
324
402
  import { spawn } from "child_process";
325
403
  import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, unlinkSync, writeFileSync } from "fs";
@@ -388,7 +466,7 @@ function checkMissingBridgeEnv(def, env) {
388
466
  }
389
467
 
390
468
  // packages/daemon/src/lib/daemon/bridge-manager.ts
391
- var blog = logger_default.child("bridges");
469
+ var blog2 = logger_default.child("bridges");
392
470
  function searchUpwards(...segments) {
393
471
  let searchDir = dirname(new URL(import.meta.url).pathname);
394
472
  for (let i = 0; i < 5; i++) {
@@ -409,7 +487,7 @@ var BridgeManager = class {
409
487
  await Promise.all(
410
488
  platforms.map(
411
489
  (platform) => this.startBridge(platform, daemonPort).catch((err) => {
412
- blog.warn(`failed to start bridge ${platform}`, logger_default.errorData(err));
490
+ blog2.warn(`failed to start bridge ${platform}`, logger_default.errorData(err));
413
491
  })
414
492
  )
415
493
  );
@@ -438,7 +516,7 @@ var BridgeManager = class {
438
516
  }
439
517
  } catch (err) {
440
518
  if (err instanceof Error && err.code !== "ESRCH") {
441
- blog.warn(`failed to stop existing bridge ${platform}`, logger_default.errorData(err));
519
+ blog2.warn(`failed to stop existing bridge ${platform}`, logger_default.errorData(err));
442
520
  }
443
521
  res();
444
522
  }
@@ -503,32 +581,32 @@ var BridgeManager = class {
503
581
  }
504
582
  if (this.shuttingDown) return;
505
583
  if (this.stopping.has(platform)) return;
506
- blog.error(`bridge ${platform} exited with code ${code}`);
507
- if (lastStderr) blog.warn(`bridge ${platform} last output: ${lastStderr}`);
584
+ blog2.error(`bridge ${platform} exited with code ${code}`);
585
+ if (lastStderr) blog2.warn(`bridge ${platform} last output: ${lastStderr}`);
508
586
  const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(platform);
509
587
  if (!shouldRestart) {
510
- blog.error(`bridge ${platform} crashed ${attempt} times \u2014 giving up`);
588
+ blog2.error(`bridge ${platform} crashed ${attempt} times \u2014 giving up`);
511
589
  return;
512
590
  }
513
- blog.info(
591
+ blog2.info(
514
592
  `restarting bridge ${platform} \u2014 attempt ${attempt}/${this.restartTracker.maxRestartAttempts}, in ${delay}ms`
515
593
  );
516
594
  setTimeout(() => {
517
595
  if (this.shuttingDown || this.stopping.has(platform)) return;
518
596
  this.startBridge(platform, daemonPort).catch((err) => {
519
- blog.error(`failed to restart bridge ${platform}`, logger_default.errorData(err));
597
+ blog2.error(`failed to restart bridge ${platform}`, logger_default.errorData(err));
520
598
  });
521
599
  }, delay);
522
600
  });
523
- blog.info(`started bridge ${platform}`);
601
+ blog2.info(`started bridge ${platform}`);
524
602
  }
525
603
  async stopBridge(platform) {
526
604
  const tracked = this.bridges.get(platform);
527
605
  if (!tracked) return;
528
606
  this.stopping.add(platform);
529
607
  this.bridges.delete(platform);
530
- await new Promise((resolve18) => {
531
- tracked.child.on("exit", () => resolve18());
608
+ await new Promise((resolve17) => {
609
+ tracked.child.on("exit", () => resolve17());
532
610
  try {
533
611
  if (tracked.child.pid) {
534
612
  process.kill(-tracked.child.pid, "SIGTERM");
@@ -537,9 +615,9 @@ var BridgeManager = class {
537
615
  }
538
616
  } catch (err) {
539
617
  if (err instanceof Error && err.code !== "ESRCH") {
540
- blog.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
618
+ blog2.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
541
619
  }
542
- resolve18();
620
+ resolve17();
543
621
  }
544
622
  setTimeout(() => {
545
623
  try {
@@ -550,7 +628,7 @@ var BridgeManager = class {
550
628
  }
551
629
  } catch {
552
630
  }
553
- resolve18();
631
+ resolve17();
554
632
  }, 5e3);
555
633
  });
556
634
  this.stopping.delete(platform);
@@ -558,9 +636,9 @@ var BridgeManager = class {
558
636
  try {
559
637
  this.removeBridgePid(platform);
560
638
  } catch (err) {
561
- blog.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
639
+ blog2.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
562
640
  }
563
- blog.info(`stopped bridge ${platform}`);
641
+ blog2.info(`stopped bridge ${platform}`);
564
642
  }
565
643
  async stopAll() {
566
644
  this.shuttingDown = true;
@@ -590,7 +668,7 @@ var BridgeManager = class {
590
668
  unlinkSync(this.bridgePidPath(platform));
591
669
  } catch (err) {
592
670
  if (err instanceof Error && err.code !== "ENOENT") {
593
- blog.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
671
+ blog2.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
594
672
  }
595
673
  }
596
674
  }
@@ -608,18 +686,18 @@ var BridgeManager = class {
608
686
  } catch {
609
687
  }
610
688
  }
611
- blog.warn(`killed orphan bridge ${platform} (pid ${pid})`);
689
+ blog2.warn(`killed orphan bridge ${platform} (pid ${pid})`);
612
690
  }
613
691
  } catch (err) {
614
692
  if (err instanceof Error && err.code !== "ESRCH") {
615
- blog.debug(`orphan bridge ${platform} cleanup: ${err}`);
693
+ blog2.debug(`orphan bridge ${platform} cleanup: ${err}`);
616
694
  }
617
695
  }
618
696
  try {
619
697
  unlinkSync(pidPath);
620
698
  } catch (err) {
621
699
  if (err instanceof Error && err.code !== "ENOENT") {
622
- blog.warn(`failed to clean up PID file for orphan bridge ${platform}`, logger_default.errorData(err));
700
+ blog2.warn(`failed to clean up PID file for orphan bridge ${platform}`, logger_default.errorData(err));
623
701
  }
624
702
  }
625
703
  }
@@ -870,10 +948,10 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
870
948
  stream.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
871
949
  });
872
950
  });
873
- await new Promise((resolve18) => {
951
+ await new Promise((resolve17) => {
874
952
  stream.onAbort(() => {
875
953
  unsubscribe();
876
- resolve18();
954
+ resolve17();
877
955
  });
878
956
  });
879
957
  });
@@ -1217,8 +1295,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1217
1295
  createdAt: Date.now()
1218
1296
  };
1219
1297
  oauthFlows.set(flowId, flow);
1220
- const promptPromise = needsManualCode ? new Promise((resolve18) => {
1221
- flow.resolveCode = resolve18;
1298
+ const promptPromise = needsManualCode ? new Promise((resolve17) => {
1299
+ flow.resolveCode = resolve17;
1222
1300
  }) : void 0;
1223
1301
  oauthProvider.login({
1224
1302
  onAuth: (info) => {
@@ -1257,7 +1335,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1257
1335
  existing.error = err instanceof Error ? err.message : String(err);
1258
1336
  }
1259
1337
  });
1260
- await new Promise((resolve18) => setTimeout(resolve18, 2e3));
1338
+ await new Promise((resolve17) => setTimeout(resolve17, 2e3));
1261
1339
  const state = oauthFlows.get(flowId);
1262
1340
  return c.json({
1263
1341
  flowId,
@@ -1451,7 +1529,7 @@ function stopApiKeyRefresh() {
1451
1529
  var system_default = app;
1452
1530
 
1453
1531
  // packages/daemon/src/web/app.ts
1454
- import { Hono as Hono28 } from "hono";
1532
+ import { Hono as Hono29 } from "hono";
1455
1533
  import { bodyLimit } from "hono/body-limit";
1456
1534
  import { cors } from "hono/cors";
1457
1535
  import { csrf } from "hono/csrf";
@@ -1515,8 +1593,8 @@ var app2 = new Hono2().get("/events", async (c) => {
1515
1593
  });
1516
1594
  }, 15e3);
1517
1595
  cleanups.push(() => clearInterval(keepAlive));
1518
- await new Promise((resolve18) => {
1519
- stream.onAbort(() => resolve18());
1596
+ await new Promise((resolve17) => {
1597
+ stream.onAbort(() => resolve17());
1520
1598
  });
1521
1599
  } finally {
1522
1600
  for (const cleanup of cleanups) {
@@ -1531,12 +1609,24 @@ var app2 = new Hono2().get("/events", async (c) => {
1531
1609
  var activity_default = app2;
1532
1610
 
1533
1611
  // packages/daemon/src/web/api/auth.ts
1534
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync2 } from "fs";
1612
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync, statSync, writeFileSync as writeFileSync2 } from "fs";
1535
1613
  import { extname, resolve as resolve3 } from "path";
1536
1614
  import { zValidator as zValidator2 } from "@hono/zod-validator";
1537
1615
  import { Hono as Hono3 } from "hono";
1538
1616
  import { deleteCookie, getCookie, setCookie } from "hono/cookie";
1539
1617
  import { z as z2 } from "zod";
1618
+
1619
+ // packages/daemon/src/lib/util/http-cache.ts
1620
+ function fileEtag(stat3) {
1621
+ return `W/"${stat3.mtimeMs.toString(36)}-${stat3.size.toString(36)}"`;
1622
+ }
1623
+ function isNotModified(c, etag) {
1624
+ const inm = c.req.header("if-none-match");
1625
+ if (!inm) return false;
1626
+ return inm.split(",").some((t) => t.trim() === etag);
1627
+ }
1628
+
1629
+ // packages/daemon/src/web/api/auth.ts
1540
1630
  function tryJoinSystem(userId) {
1541
1631
  if (!process.env.VOLUTE_DAEMON_TOKEN) return;
1542
1632
  joinSystemChannel(userId).catch(() => {
@@ -1603,10 +1693,16 @@ var authenticated = new Hono3().use(authMiddleware).post("/change-password", zVa
1603
1693
  if (!AVATAR_MIME[ext]) {
1604
1694
  return c.json({ error: "Invalid file type (png, jpg, gif, webp only)" }, 400);
1605
1695
  }
1696
+ let buffer2 = Buffer.from(await file.arrayBuffer());
1697
+ let finalExt = ext;
1698
+ const normalized = await normalizeAvatar(buffer2);
1699
+ if (normalized) {
1700
+ buffer2 = normalized.buffer;
1701
+ finalExt = normalized.ext;
1702
+ }
1606
1703
  const dir = avatarsDir();
1607
1704
  mkdirSync2(dir, { recursive: true });
1608
- const filename = `avatar-${user.id}${ext}`;
1609
- const buffer2 = Buffer.from(await file.arrayBuffer());
1705
+ const filename = `avatar-${user.id}${finalExt}`;
1610
1706
  writeFileSync2(resolve3(dir, filename), buffer2);
1611
1707
  if (user.avatar && user.avatar !== filename) {
1612
1708
  const oldPath = resolve3(dir, user.avatar);
@@ -1786,19 +1882,129 @@ var app3 = new Hono3().post("/register", zValidator2("json", credentialsSchema),
1786
1882
  const ext = extname(filename).toLowerCase();
1787
1883
  const mime = AVATAR_MIME[ext];
1788
1884
  if (!mime) return c.json({ error: "Invalid file type" }, 400);
1789
- const data = readFileSync3(filePath);
1790
- return c.body(data, 200, {
1885
+ const fileStat = statSync(filePath);
1886
+ const etag = fileEtag(fileStat);
1887
+ const headers = {
1791
1888
  "Content-Type": mime,
1792
1889
  "Cache-Control": "public, max-age=3600",
1793
- "X-Content-Type-Options": "nosniff"
1794
- });
1890
+ "X-Content-Type-Options": "nosniff",
1891
+ ETag: etag
1892
+ };
1893
+ if (isNotModified(c, etag)) return c.body(null, 304, headers);
1894
+ const data = readFileSync3(filePath);
1895
+ return c.body(data, 200, headers);
1795
1896
  }).route("/", admin).route("/", authenticated);
1796
1897
  var auth_default = app3;
1797
1898
 
1798
- // packages/daemon/src/web/api/bridges.ts
1899
+ // packages/daemon/src/web/api/backup.ts
1900
+ import { randomBytes } from "crypto";
1799
1901
  import { zValidator as zValidator3 } from "@hono/zod-validator";
1902
+ import { CronExpressionParser as CronExpressionParser2 } from "cron-parser";
1800
1903
  import { Hono as Hono4 } from "hono";
1801
1904
  import { z as z3 } from "zod";
1905
+ function redactedConfig() {
1906
+ const backup2 = readGlobalConfig().backup ?? {};
1907
+ return {
1908
+ repository: backup2.repository,
1909
+ schedule: backup2.schedule ?? DEFAULT_BACKUP_SCHEDULE,
1910
+ enabled: backup2.enabled,
1911
+ keep: backup2.keep,
1912
+ includeSessions: backup2.includeSessions,
1913
+ hasPassword: !!backup2.password,
1914
+ envKeys: Object.keys(backup2.env ?? {})
1915
+ };
1916
+ }
1917
+ var configSchema = z3.object({
1918
+ repository: z3.string().optional(),
1919
+ schedule: z3.string().refine(
1920
+ (cron) => {
1921
+ try {
1922
+ CronExpressionParser2.parse(cron);
1923
+ return true;
1924
+ } catch {
1925
+ return false;
1926
+ }
1927
+ },
1928
+ { message: "Invalid cron expression" }
1929
+ ).optional(),
1930
+ enabled: z3.boolean().optional(),
1931
+ keep: z3.object({
1932
+ daily: z3.number().int().min(0).optional(),
1933
+ weekly: z3.number().int().min(0).optional(),
1934
+ monthly: z3.number().int().min(0).optional()
1935
+ }).refine((keep) => !(keep.daily === 0 && keep.weekly === 0 && keep.monthly === 0), {
1936
+ message: "Retention cannot be zero everywhere \u2014 prune would delete every snapshot"
1937
+ }).optional(),
1938
+ includeSessions: z3.boolean().optional(),
1939
+ password: z3.string().optional(),
1940
+ env: z3.record(z3.string(), z3.string()).optional()
1941
+ });
1942
+ var backup = new Hono4().get("/config", requireAdmin, (c) => c.json(redactedConfig())).put("/config", requireAdmin, zValidator3("json", configSchema), (c) => {
1943
+ const updates = c.req.valid("json");
1944
+ const config2 = readGlobalConfig();
1945
+ const current = config2.backup ?? {};
1946
+ config2.backup = {
1947
+ ...current,
1948
+ ...updates,
1949
+ // Empty-string password means "keep existing" so the UI can save
1950
+ // settings without re-entering the passphrase.
1951
+ password: updates.password || current.password,
1952
+ env: updates.env ?? current.env
1953
+ };
1954
+ writeGlobalConfig(config2);
1955
+ return c.json(redactedConfig());
1956
+ }).post("/init", requireAdmin, async (c) => {
1957
+ const config2 = readGlobalConfig();
1958
+ if (!config2.backup?.repository) {
1959
+ return c.json({ error: "Backup repository is not configured" }, 400);
1960
+ }
1961
+ let generatedPassword = null;
1962
+ if (!config2.backup.password) {
1963
+ generatedPassword = randomBytes(32).toString("base64url");
1964
+ config2.backup.password = generatedPassword;
1965
+ }
1966
+ try {
1967
+ await initRepo(config2.backup);
1968
+ } catch (err) {
1969
+ const stderr = err.stderr;
1970
+ const detail = err instanceof Error ? err.message : String(err);
1971
+ return c.json({ error: stderr?.trim() || detail }, 500);
1972
+ }
1973
+ if (generatedPassword) writeGlobalConfig(config2);
1974
+ return c.json({ ok: true, password: generatedPassword });
1975
+ }).post("/run", requireAdmin, async (c) => {
1976
+ try {
1977
+ const summary = await runBackup();
1978
+ return c.json(summary);
1979
+ } catch (err) {
1980
+ const stderr = err.stderr;
1981
+ const detail = err instanceof Error ? err.message : String(err);
1982
+ return c.json({ error: stderr?.trim() || detail }, 500);
1983
+ }
1984
+ }).get("/snapshots", requireAdmin, async (c) => {
1985
+ try {
1986
+ return c.json(await listSnapshots());
1987
+ } catch (err) {
1988
+ const stderr = err.stderr;
1989
+ const detail = err instanceof Error ? err.message : String(err);
1990
+ return c.json({ error: stderr?.trim() || detail }, 500);
1991
+ }
1992
+ }).get("/status", requireAdmin, async (c) => {
1993
+ const version = await resticVersion();
1994
+ return c.json({
1995
+ resticInstalled: version !== null,
1996
+ resticVersion: version,
1997
+ installHint: version === null ? RESTIC_INSTALL_HINT : null,
1998
+ config: redactedConfig(),
1999
+ state: readBackupState()
2000
+ });
2001
+ });
2002
+ var backup_default = backup;
2003
+
2004
+ // packages/daemon/src/web/api/bridges.ts
2005
+ import { zValidator as zValidator4 } from "@hono/zod-validator";
2006
+ import { Hono as Hono5 } from "hono";
2007
+ import { z as z4 } from "zod";
1802
2008
 
1803
2009
  // packages/daemon/src/lib/chat/puppets.ts
1804
2010
  import { and as and2, eq as eq2 } from "drizzle-orm";
@@ -1847,17 +2053,6 @@ async function findOrCreatePuppet(platform, platformId, displayName) {
1847
2053
  }
1848
2054
 
1849
2055
  // packages/daemon/src/lib/delivery/fan-out.ts
1850
- var MAX_CONSECUTIVE_MIND_TURNS = 6;
1851
- var consecutiveMindTurns = /* @__PURE__ */ new Map();
1852
- async function emitLoopNotice(conversationId) {
1853
- const systemUser = await getOrCreateSystemUser();
1854
- await addMessage(conversationId, "user", systemUser.username, [
1855
- {
1856
- type: "text",
1857
- text: `[System] This exchange has continued for ${MAX_CONSECUTIVE_MIND_TURNS} consecutive automated turns without human input, so automatic delivery between minds has been paused. Send a message to resume.`
1858
- }
1859
- ]);
1860
- }
1861
2056
  async function fanOutToMinds(opts) {
1862
2057
  const participants = opts.participants ?? await getParticipants(opts.conversationId);
1863
2058
  const mindParticipants = participants.filter(
@@ -1865,25 +2060,6 @@ async function fanOutToMinds(opts) {
1865
2060
  );
1866
2061
  const participantNames = participants.map((p) => p.username);
1867
2062
  const isDM = opts.isDM ?? participants.length === 2;
1868
- if (mindParticipants.length > 1) {
1869
- if (opts.senderIsMind) {
1870
- const count = (consecutiveMindTurns.get(opts.conversationId) ?? 0) + 1;
1871
- consecutiveMindTurns.set(opts.conversationId, count);
1872
- if (count > MAX_CONSECUTIVE_MIND_TURNS) {
1873
- if (count === MAX_CONSECUTIVE_MIND_TURNS + 1) {
1874
- await emitLoopNotice(opts.conversationId).catch(
1875
- (err) => logger_default.warn(`failed to emit loop notice for ${opts.conversationId}`, logger_default.errorData(err))
1876
- );
1877
- }
1878
- logger_default.warn(
1879
- `loop protection: paused mind fan-out for ${opts.conversationId} after ${count} consecutive mind turns`
1880
- );
1881
- return;
1882
- }
1883
- } else {
1884
- consecutiveMindTurns.delete(opts.conversationId);
1885
- }
1886
- }
1887
2063
  const manager = getMindManager();
1888
2064
  const sm = getSleepManagerIfReady();
1889
2065
  const targetMinds = mindParticipants.map((ap) => {
@@ -1917,27 +2093,27 @@ async function fanOutToMinds(opts) {
1917
2093
  }
1918
2094
 
1919
2095
  // packages/daemon/src/web/api/bridges.ts
1920
- var inboundSchema = z3.object({
1921
- content: z3.array(
1922
- z3.union([
1923
- z3.object({ type: z3.literal("text"), text: z3.string() }),
1924
- z3.object({ type: z3.literal("image"), media_type: z3.string(), data: z3.string() })
2096
+ var inboundSchema = z4.object({
2097
+ content: z4.array(
2098
+ z4.union([
2099
+ z4.object({ type: z4.literal("text"), text: z4.string() }),
2100
+ z4.object({ type: z4.literal("image"), media_type: z4.string(), data: z4.string() })
1925
2101
  ])
1926
2102
  ).min(1),
1927
- platformUserId: z3.string(),
1928
- displayName: z3.string(),
1929
- externalChannel: z3.string(),
1930
- isDM: z3.boolean(),
1931
- targetMind: z3.string().optional()
2103
+ platformUserId: z4.string(),
2104
+ displayName: z4.string(),
2105
+ externalChannel: z4.string(),
2106
+ isDM: z4.boolean(),
2107
+ targetMind: z4.string().optional()
1932
2108
  });
1933
- var mappingSchema = z3.object({
1934
- externalChannel: z3.string(),
1935
- voluteChannel: z3.string()
2109
+ var mappingSchema = z4.object({
2110
+ externalChannel: z4.string(),
2111
+ voluteChannel: z4.string()
1936
2112
  });
1937
- var enableSchema = z3.object({
1938
- defaultMind: z3.string()
2113
+ var enableSchema = z4.object({
2114
+ defaultMind: z4.string()
1939
2115
  });
1940
- var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSchema), async (c) => {
2116
+ var app4 = new Hono5().post("/:platform/inbound", zValidator4("json", inboundSchema), async (c) => {
1941
2117
  const user = c.get("user");
1942
2118
  if (user.id !== 0) return c.json({ error: "Bridge inbound requires daemon token" }, 403);
1943
2119
  const platform = c.req.param("platform");
@@ -1989,7 +2165,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
1989
2165
  }
1990
2166
  const participants = await getParticipants(channel.id);
1991
2167
  if (!participants.some((p) => p.userId === puppet.id)) {
1992
- const { addParticipant } = await import("./conversations-67WWW25C.js");
2168
+ const { addParticipant } = await import("./conversations-G4LYMHAA.js");
1993
2169
  await addParticipant(channel.id, puppet.id);
1994
2170
  }
1995
2171
  const contentBlocks = body.content;
@@ -2019,7 +2195,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
2019
2195
  };
2020
2196
  });
2021
2197
  return c.json(bridges);
2022
- }).post("/:platform", requireAdmin, zValidator3("json", enableSchema), async (c) => {
2198
+ }).post("/:platform", requireAdmin, zValidator4("json", enableSchema), async (c) => {
2023
2199
  const platform = c.req.param("platform");
2024
2200
  const body = c.req.valid("json");
2025
2201
  const def = getBridgeDef(platform);
@@ -2058,7 +2234,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
2058
2234
  await manager.stopBridge(platform);
2059
2235
  removeBridgeConfig(platform);
2060
2236
  return c.json({ ok: true });
2061
- }).put("/:platform/mappings", requireAdmin, zValidator3("json", mappingSchema), (c) => {
2237
+ }).put("/:platform/mappings", requireAdmin, zValidator4("json", mappingSchema), (c) => {
2062
2238
  const platform = c.req.param("platform");
2063
2239
  const body = c.req.valid("json");
2064
2240
  try {
@@ -2083,18 +2259,17 @@ async function fanOutToBridgedMinds(opts) {
2083
2259
  conversationId: opts.conversationId,
2084
2260
  contentBlocks: opts.contentBlocks,
2085
2261
  senderName: opts.senderName,
2086
- senderIsMind: false,
2087
2262
  isDM: opts.isDM
2088
2263
  });
2089
2264
  }
2090
2265
  var bridges_default = app4;
2091
2266
 
2092
2267
  // packages/daemon/src/web/api/channels.ts
2093
- import { Hono as Hono5 } from "hono";
2268
+ import { Hono as Hono6 } from "hono";
2094
2269
  function buildEnv(name) {
2095
2270
  return { ...loadMergedEnv(name), VOLUTE_MIND: name, VOLUTE_MIND_DIR: mindDir(name) };
2096
2271
  }
2097
- var app5 = new Hono5().post("/:name/channels/create", requireSelf(), async (c) => {
2272
+ var app5 = new Hono6().post("/:name/channels/create", requireSelf(), async (c) => {
2098
2273
  const name = c.req.param("name");
2099
2274
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
2100
2275
  const {
@@ -2119,8 +2294,8 @@ var app5 = new Hono5().post("/:name/channels/create", requireSelf(), async (c) =
2119
2294
  var channels_default = app5;
2120
2295
 
2121
2296
  // packages/daemon/src/web/api/config.ts
2122
- import { Hono as Hono6 } from "hono";
2123
- var config = new Hono6();
2297
+ import { Hono as Hono7 } from "hono";
2298
+ var config = new Hono7();
2124
2299
  config.get("/models", async (c) => {
2125
2300
  const enabled = new Set(getEnabledModels());
2126
2301
  const all = await getAvailableModels();
@@ -2147,8 +2322,8 @@ config.get("/status", (c) => {
2147
2322
  var config_default = config;
2148
2323
 
2149
2324
  // packages/daemon/src/web/api/env.ts
2150
- import { Hono as Hono7 } from "hono";
2151
- var app6 = new Hono7().get("/:name/env", requireSelf(), async (c) => {
2325
+ import { Hono as Hono8 } from "hono";
2326
+ var app6 = new Hono8().get("/:name/env", requireSelf(), async (c) => {
2152
2327
  const name = c.req.param("name");
2153
2328
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
2154
2329
  const shared = readEnv(sharedEnvPath());
@@ -2191,7 +2366,7 @@ var app6 = new Hono7().get("/:name/env", requireSelf(), async (c) => {
2191
2366
  writeEnv(path, env);
2192
2367
  return c.json({ ok: true });
2193
2368
  });
2194
- var sharedEnvApp = new Hono7().get("/", requireAdmin, (c) => {
2369
+ var sharedEnvApp = new Hono8().get("/", requireAdmin, (c) => {
2195
2370
  return c.json(readEnv(sharedEnvPath()));
2196
2371
  }).put("/:key", requireAdmin, async (c) => {
2197
2372
  const key = c.req.param("key");
@@ -2221,8 +2396,8 @@ var sharedEnvApp = new Hono7().get("/", requireAdmin, (c) => {
2221
2396
  var env_default = app6;
2222
2397
 
2223
2398
  // packages/daemon/src/web/api/extensions.ts
2224
- import { Hono as Hono8 } from "hono";
2225
- var app7 = new Hono8().get("/", (c) => {
2399
+ import { Hono as Hono9 } from "hono";
2400
+ var app7 = new Hono9().get("/", (c) => {
2226
2401
  return c.json(getLoadedExtensions());
2227
2402
  }).get("/all", (c) => {
2228
2403
  const detail = c.req.query("detail") === "true";
@@ -2267,20 +2442,20 @@ var app7 = new Hono8().get("/", (c) => {
2267
2442
  var extensions_default = app7;
2268
2443
 
2269
2444
  // packages/daemon/src/web/api/file-sharing.ts
2270
- import { readFileSync as readFileSync4, statSync } from "fs";
2445
+ import { readFileSync as readFileSync4, statSync as statSync2 } from "fs";
2271
2446
  import { resolve as resolve4 } from "path";
2272
- import { Hono as Hono9 } from "hono";
2447
+ import { Hono as Hono10 } from "hono";
2273
2448
  async function notifyMind(mindName, message) {
2274
2449
  const entry = await findMind(mindName);
2275
2450
  if (!entry) return;
2276
2451
  try {
2277
- const { sendSystemMessage } = await import("./system-chat-54RN3K67.js");
2452
+ const { sendSystemMessage } = await import("./system-chat-E65T2HSW.js");
2278
2453
  await sendSystemMessage(mindName, message);
2279
2454
  } catch (err) {
2280
2455
  logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
2281
2456
  }
2282
2457
  }
2283
- var app8 = new Hono9().post("/:name/files/send", requireSelf(), async (c) => {
2458
+ var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
2284
2459
  const senderName = c.req.param("name");
2285
2460
  const senderEntry = await findMind(senderName);
2286
2461
  if (!senderEntry) return c.json({ error: "Sender mind not found" }, 404);
@@ -2295,7 +2470,7 @@ var app8 = new Hono9().post("/:name/files/send", requireSelf(), async (c) => {
2295
2470
  const senderDir = mindDir(senderName);
2296
2471
  const filePath = resolve4(senderDir, "home", body.filePath);
2297
2472
  const MAX_FILE_SIZE3 = 50 * 1024 * 1024;
2298
- const stat3 = statSync(filePath, { throwIfNoEntry: false });
2473
+ const stat3 = statSync2(filePath, { throwIfNoEntry: false });
2299
2474
  if (!stat3) return c.json({ error: `File not found: ${body.filePath}` }, 404);
2300
2475
  if (stat3.size > MAX_FILE_SIZE3) {
2301
2476
  return c.json(
@@ -2399,34 +2574,8 @@ var file_sharing_default = app8;
2399
2574
  // packages/daemon/src/web/api/files.ts
2400
2575
  import { mkdirSync as mkdirSync3, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
2401
2576
  import { readdir, readFile, realpath, stat } from "fs/promises";
2402
- import { extname as extname2, resolve as resolve6 } from "path";
2403
- import { Hono as Hono10 } from "hono";
2404
-
2405
- // packages/daemon/src/lib/util/paths.ts
2406
- import { resolve as resolve5, sep } from "path";
2407
- var PathTraversalError = class extends Error {
2408
- constructor(base, userPath) {
2409
- super(`Path "${userPath}" escapes base directory "${base}"`);
2410
- this.name = "PathTraversalError";
2411
- }
2412
- };
2413
- function resolveWithinBase(base, userPath) {
2414
- const resolvedBase = resolve5(base);
2415
- const target = resolve5(resolvedBase, userPath);
2416
- if (target !== resolvedBase && !target.startsWith(resolvedBase + sep)) {
2417
- throw new PathTraversalError(base, userPath);
2418
- }
2419
- return target;
2420
- }
2421
- function safeResolveWithinBase(base, userPath) {
2422
- try {
2423
- return resolveWithinBase(base, userPath);
2424
- } catch {
2425
- return null;
2426
- }
2427
- }
2428
-
2429
- // packages/daemon/src/web/api/files.ts
2577
+ import { extname as extname2, resolve as resolve5 } from "path";
2578
+ import { Hono as Hono11 } from "hono";
2430
2579
  var AVATAR_MIME2 = {
2431
2580
  ".png": "image/png",
2432
2581
  ".jpg": "image/jpeg",
@@ -2453,7 +2602,7 @@ var MIME_TYPES = {
2453
2602
  ".woff": "font/woff",
2454
2603
  ".woff2": "font/woff2"
2455
2604
  };
2456
- var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2605
+ var app9 = new Hono11().post("/:name/avatar", requireSelf(), async (c) => {
2457
2606
  const name = c.req.param("name");
2458
2607
  const entry = await findMind(name);
2459
2608
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -2469,17 +2618,23 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2469
2618
  if (!AVATAR_MIME2[ext]) {
2470
2619
  return c.json({ error: "Invalid file type (png, jpg, gif, webp only)" }, 400);
2471
2620
  }
2621
+ let buffer2 = Buffer.from(await file.arrayBuffer());
2622
+ let finalExt = ext;
2623
+ const normalized = await normalizeAvatar(buffer2);
2624
+ if (normalized) {
2625
+ buffer2 = normalized.buffer;
2626
+ finalExt = normalized.ext;
2627
+ }
2472
2628
  const dir = entry.dir ?? mindDir(name);
2473
- const homeDir = resolve6(dir, "home");
2474
- const filename = `avatar${ext}`;
2475
- const avatarPath = resolve6(homeDir, filename);
2629
+ const homeDir = resolve5(dir, "home");
2630
+ const filename = `avatar${finalExt}`;
2631
+ const avatarPath = resolve5(homeDir, filename);
2476
2632
  const config2 = readVoluteConfig(dir) ?? {};
2477
2633
  const oldAvatar = config2.profile?.avatar;
2478
2634
  if (oldAvatar && oldAvatar !== filename) {
2479
2635
  const oldAvatarPath = safeResolveWithinBase(homeDir, oldAvatar);
2480
2636
  if (oldAvatarPath) rmSync2(oldAvatarPath, { force: true });
2481
2637
  }
2482
- const buffer2 = Buffer.from(await file.arrayBuffer());
2483
2638
  mkdirSync3(homeDir, { recursive: true });
2484
2639
  writeFileSync3(avatarPath, buffer2);
2485
2640
  const profile = config2.profile ?? {};
@@ -2499,8 +2654,8 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2499
2654
  const ext = extname2(config2.profile.avatar).toLowerCase();
2500
2655
  const mime = AVATAR_MIME2[ext];
2501
2656
  if (!mime) return c.json({ error: "Invalid avatar extension" }, 400);
2502
- const homeDir = resolve6(dir, "home");
2503
- const avatarPath = resolve6(homeDir, config2.profile.avatar);
2657
+ const homeDir = resolve5(dir, "home");
2658
+ const avatarPath = resolve5(homeDir, config2.profile.avatar);
2504
2659
  if (!avatarPath.startsWith(`${homeDir}/`)) return c.json({ error: "Invalid avatar path" }, 400);
2505
2660
  let realAvatarPath;
2506
2661
  try {
@@ -2516,11 +2671,15 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2516
2671
  try {
2517
2672
  const fileStat = await stat(realAvatarPath);
2518
2673
  if (fileStat.size > MAX_AVATAR_SIZE2) return c.json({ error: "Avatar file too large" }, 400);
2519
- const body = await readFile(realAvatarPath);
2520
- return c.body(body, 200, {
2674
+ const etag = fileEtag(fileStat);
2675
+ const headers = {
2521
2676
  "Content-Type": mime,
2522
- "Cache-Control": "public, max-age=300"
2523
- });
2677
+ "Cache-Control": "public, max-age=300",
2678
+ ETag: etag
2679
+ };
2680
+ if (isNotModified(c, etag)) return c.body(null, 304, headers);
2681
+ const body = await readFile(realAvatarPath);
2682
+ return c.body(body, 200, headers);
2524
2683
  } catch {
2525
2684
  return c.json({ error: "Failed to read avatar file" }, 500);
2526
2685
  }
@@ -2528,7 +2687,7 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2528
2687
  const name = c.req.param("name");
2529
2688
  const entry = await findMind(name);
2530
2689
  if (!entry) return c.json({ error: "Mind not found" }, 404);
2531
- const homeDir = resolve6(entry.dir ?? mindDir(name), "home");
2690
+ const homeDir = resolve5(entry.dir ?? mindDir(name), "home");
2532
2691
  let entries;
2533
2692
  try {
2534
2693
  entries = await readdir(homeDir, { withFileTypes: true });
@@ -2543,10 +2702,10 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2543
2702
  const name = c.req.param("name");
2544
2703
  const entry = await findMind(name);
2545
2704
  if (!entry) return c.json({ error: "Mind not found" }, 404);
2546
- const homeDir = resolve6(entry.dir ?? mindDir(name), "home");
2705
+ const homeDir = resolve5(entry.dir ?? mindDir(name), "home");
2547
2706
  const wildcard = c.req.path.replace(new RegExp(`^.*/minds/${name}/files`), "") || "/";
2548
2707
  const relativePath = wildcard.slice(1);
2549
- const requestedPath = resolve6(homeDir, relativePath);
2708
+ const requestedPath = resolve5(homeDir, relativePath);
2550
2709
  if (requestedPath !== homeDir && !requestedPath.startsWith(`${homeDir}/`))
2551
2710
  return c.text("Forbidden", 403);
2552
2711
  if (relativePath.split("/").some((seg) => seg.startsWith("."))) return c.text("Forbidden", 403);
@@ -2577,15 +2736,18 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2577
2736
  return c.json(items);
2578
2737
  }
2579
2738
  if (fileStat.size > MAX_FILE_SIZE) return c.text("File too large", 413);
2580
- const body = await readFile(resolvedPath);
2581
2739
  const mime = MIME_TYPES[extname2(resolvedPath).toLowerCase()] || "application/octet-stream";
2582
- return c.body(body, 200, { "Content-Type": mime });
2740
+ const etag = fileEtag(fileStat);
2741
+ const headers = { "Content-Type": mime, "Cache-Control": "no-cache", ETag: etag };
2742
+ if (isNotModified(c, etag)) return c.body(null, 304, headers);
2743
+ const body = await readFile(resolvedPath);
2744
+ return c.body(body, 200, headers);
2583
2745
  });
2584
2746
  var files_default = app9;
2585
2747
 
2586
2748
  // packages/daemon/src/web/api/history.ts
2587
2749
  import { and as and3, desc as desc2, eq as eq3, gte, inArray, sql } from "drizzle-orm";
2588
- import { Hono as Hono11 } from "hono";
2750
+ import { Hono as Hono12 } from "hono";
2589
2751
  async function resolveMindFilter(c) {
2590
2752
  const user = c.get("user");
2591
2753
  if (user.role === "admin" || user.role === "system") {
@@ -2593,7 +2755,7 @@ async function resolveMindFilter(c) {
2593
2755
  }
2594
2756
  return getBaseName(user.username);
2595
2757
  }
2596
- var history = new Hono11().get("/turns", async (c) => {
2758
+ var history = new Hono12().get("/turns", async (c) => {
2597
2759
  const mindFilter = await resolveMindFilter(c);
2598
2760
  const turnIdFilter = c.req.query("turnId");
2599
2761
  const turnIdsFilter = c.req.query("turnIds");
@@ -2984,21 +3146,21 @@ var history = new Hono11().get("/turns", async (c) => {
2984
3146
  var history_default = history;
2985
3147
 
2986
3148
  // packages/daemon/src/web/api/keys.ts
2987
- import { Hono as Hono12 } from "hono";
3149
+ import { Hono as Hono13 } from "hono";
2988
3150
 
2989
3151
  // packages/daemon/src/lib/mind/identity.ts
2990
3152
  import { createHash, generateKeyPairSync, sign, verify } from "crypto";
2991
3153
  import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
2992
- import { resolve as resolve7 } from "path";
3154
+ import { resolve as resolve6 } from "path";
2993
3155
  function generateIdentity(mindDir2) {
2994
- const identityDir = resolve7(mindDir2, ".mind/identity");
3156
+ const identityDir = resolve6(mindDir2, ".mind/identity");
2995
3157
  mkdirSync4(identityDir, { recursive: true });
2996
3158
  const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
2997
3159
  publicKeyEncoding: { type: "spki", format: "pem" },
2998
3160
  privateKeyEncoding: { type: "pkcs8", format: "pem" }
2999
3161
  });
3000
- const privatePath = resolve7(identityDir, "private.pem");
3001
- const publicPath = resolve7(identityDir, "public.pem");
3162
+ const privatePath = resolve6(identityDir, "private.pem");
3163
+ const publicPath = resolve6(identityDir, "public.pem");
3002
3164
  writeFileSync4(privatePath, privateKey, { mode: 384 });
3003
3165
  writeFileSync4(publicPath, publicKey, { mode: 420 });
3004
3166
  const config2 = readVoluteConfig(mindDir2) ?? {};
@@ -3013,7 +3175,7 @@ function getPublicKey(mindDir2) {
3013
3175
  const config2 = readVoluteConfig(mindDir2);
3014
3176
  const relPath = config2?.identity?.publicKey;
3015
3177
  if (!relPath) return null;
3016
- const fullPath = resolve7(mindDir2, relPath);
3178
+ const fullPath = resolve6(mindDir2, relPath);
3017
3179
  if (!existsSync4(fullPath)) return null;
3018
3180
  return readFileSync5(fullPath, "utf-8");
3019
3181
  }
@@ -3044,7 +3206,7 @@ async function publishPublicKey(mindName, publicKeyPem) {
3044
3206
  }
3045
3207
 
3046
3208
  // packages/daemon/src/web/api/keys.ts
3047
- var app10 = new Hono12().get("/:fingerprint", async (c) => {
3209
+ var app10 = new Hono13().get("/:fingerprint", async (c) => {
3048
3210
  const fingerprint = c.req.param("fingerprint");
3049
3211
  for (const entry of await readRegistry()) {
3050
3212
  try {
@@ -3063,14 +3225,14 @@ var keys_default = app10;
3063
3225
  // packages/daemon/src/web/api/logs.ts
3064
3226
  import { spawn as spawn2 } from "child_process";
3065
3227
  import { existsSync as existsSync5 } from "fs";
3066
- import { resolve as resolve8 } from "path";
3067
- import { Hono as Hono13 } from "hono";
3228
+ import { resolve as resolve7 } from "path";
3229
+ import { Hono as Hono14 } from "hono";
3068
3230
  import { streamSSE as streamSSE3 } from "hono/streaming";
3069
- var app11 = new Hono13().get("/:name/logs", requireSelf(), async (c) => {
3231
+ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
3070
3232
  const name = c.req.param("name");
3071
3233
  const entry = await findMind(name);
3072
3234
  if (!entry) return c.json({ error: "Mind not found" }, 404);
3073
- const logFile = resolve8(stateDir(name), "logs", "mind.log");
3235
+ const logFile = resolve7(stateDir(name), "logs", "mind.log");
3074
3236
  if (!existsSync5(logFile)) {
3075
3237
  return c.json({ error: "No log file found" }, 404);
3076
3238
  }
@@ -3089,16 +3251,16 @@ var app11 = new Hono13().get("/:name/logs", requireSelf(), async (c) => {
3089
3251
  stream.onAbort(() => {
3090
3252
  tail.kill();
3091
3253
  });
3092
- await new Promise((resolve18) => {
3093
- tail.on("exit", resolve18);
3094
- stream.onAbort(resolve18);
3254
+ await new Promise((resolve17) => {
3255
+ tail.on("exit", resolve17);
3256
+ stream.onAbort(resolve17);
3095
3257
  });
3096
3258
  });
3097
3259
  }).get("/:name/logs/tail", requireSelf(), async (c) => {
3098
3260
  const name = c.req.param("name");
3099
3261
  const entry = await findMind(name);
3100
3262
  if (!entry) return c.json({ error: "Mind not found" }, 404);
3101
- const logFile = resolve8(stateDir(name), "logs", "mind.log");
3263
+ const logFile = resolve7(stateDir(name), "logs", "mind.log");
3102
3264
  if (!existsSync5(logFile)) {
3103
3265
  return c.json({ error: "No log file found" }, 404);
3104
3266
  }
@@ -3109,18 +3271,18 @@ var app11 = new Hono13().get("/:name/logs", requireSelf(), async (c) => {
3109
3271
  tail.stdout.on("data", (data) => {
3110
3272
  output += data.toString();
3111
3273
  });
3112
- await new Promise((resolve18) => {
3113
- tail.on("exit", resolve18);
3274
+ await new Promise((resolve17) => {
3275
+ tail.on("exit", resolve17);
3114
3276
  });
3115
3277
  return c.text(output);
3116
3278
  });
3117
3279
  var logs_default = app11;
3118
3280
 
3119
3281
  // packages/daemon/src/web/api/mind-skills.ts
3120
- import { zValidator as zValidator4 } from "@hono/zod-validator";
3121
- import { Hono as Hono14 } from "hono";
3122
- import { z as z4 } from "zod";
3123
- var app12 = new Hono14().get("/:name/skills", async (c) => {
3282
+ import { zValidator as zValidator5 } from "@hono/zod-validator";
3283
+ import { Hono as Hono15 } from "hono";
3284
+ import { z as z5 } from "zod";
3285
+ var app12 = new Hono15().get("/:name/skills", async (c) => {
3124
3286
  const name = c.req.param("name");
3125
3287
  const entry = await findMind(name);
3126
3288
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -3130,7 +3292,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
3130
3292
  }).post(
3131
3293
  "/:name/skills/install",
3132
3294
  requireSelf(),
3133
- zValidator4("json", z4.object({ skillId: z4.string() })),
3295
+ zValidator5("json", z5.object({ skillId: z5.string() })),
3134
3296
  async (c) => {
3135
3297
  const name = c.req.param("name");
3136
3298
  const entry = await findMind(name);
@@ -3148,7 +3310,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
3148
3310
  ).post(
3149
3311
  "/:name/skills/update",
3150
3312
  requireSelf(),
3151
- zValidator4("json", z4.object({ skillId: z4.string() })),
3313
+ zValidator5("json", z5.object({ skillId: z5.string() })),
3152
3314
  async (c) => {
3153
3315
  const name = c.req.param("name");
3154
3316
  const entry = await findMind(name);
@@ -3166,7 +3328,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
3166
3328
  ).post(
3167
3329
  "/:name/skills/publish",
3168
3330
  requireSelf(),
3169
- zValidator4("json", z4.object({ skillId: z4.string() })),
3331
+ zValidator5("json", z5.object({ skillId: z5.string() })),
3170
3332
  async (c) => {
3171
3333
  const name = c.req.param("name");
3172
3334
  const entry = await findMind(name);
@@ -3207,11 +3369,11 @@ import {
3207
3369
  rmSync as rmSync4,
3208
3370
  writeFileSync as writeFileSync7
3209
3371
  } from "fs";
3210
- import { basename, resolve as resolve11 } from "path";
3211
- import { zValidator as zValidator5 } from "@hono/zod-validator";
3372
+ import { relative, resolve as resolve10 } from "path";
3373
+ import { zValidator as zValidator6 } from "@hono/zod-validator";
3212
3374
  import { and as and5, desc as desc4, eq as eq5, sql as sql3 } from "drizzle-orm";
3213
- import { Hono as Hono15 } from "hono";
3214
- import { z as z5 } from "zod";
3375
+ import { Hono as Hono16 } from "hono";
3376
+ import { z as z6 } from "zod";
3215
3377
 
3216
3378
  // packages/daemon/src/lib/daemon/turn-lifecycle.ts
3217
3379
  import { and as and4, desc as desc3, eq as eq4, inArray as inArray2, sql as sql2 } from "drizzle-orm";
@@ -3328,13 +3490,18 @@ async function handleMindEvent(mind, event) {
3328
3490
  }).returning({ id: mindHistory.id });
3329
3491
  insertedId = result[0]?.id;
3330
3492
  } catch (err) {
3331
- llog.error(`failed to persist event for ${mind}`, logger_default.errorData(err));
3493
+ llog.error(
3494
+ `HISTORY GAP: failed to persist ${event.type} event for ${mind}${event.session ? ` (session ${event.session})` : ""}${event.channel ? ` on ${event.channel}` : ""}`,
3495
+ logger_default.errorData(err)
3496
+ );
3332
3497
  }
3333
3498
  if (event.type === "tool_use" && insertedId != null) {
3334
- trackToolUse(mind, event.session, insertedId);
3499
+ const toolUseId = typeof event.metadata?.id === "string" ? event.metadata.id : void 0;
3500
+ trackToolUse(mind, event.session, insertedId, toolUseId);
3335
3501
  }
3336
3502
  if (event.type === "tool_result" && turnId && event.content) {
3337
- const toolUseEventId = getLastToolUseEventId(mind, event.session);
3503
+ const resultToolUseId = typeof event.metadata?.tool_use_id === "string" ? event.metadata.tool_use_id : void 0;
3504
+ const toolUseEventId = getToolUseEventId(mind, event.session, resultToolUseId);
3338
3505
  try {
3339
3506
  await linkToolResultToTurn(mind, turnId, event.content, toolUseEventId);
3340
3507
  } catch (err) {
@@ -3397,7 +3564,7 @@ async function handleMindEvent(mind, event) {
3397
3564
  session: event.session,
3398
3565
  kind: "budget",
3399
3566
  reason: "token_budget",
3400
- detail: "You've reached your token budget for this period. Further activity may be paused until the budget resets \u2014 wrap up or prioritize accordingly."
3567
+ detail: "You've used your token budget for this period, so your activity may pause until it resets. This isn't anything you did wrong \u2014 it's just a rest imposed by the budget. Anything that arrives while you're paused will be kept for you. If you're mid-thought, this turn is a good moment to jot it down."
3401
3568
  });
3402
3569
  }
3403
3570
  }
@@ -3427,18 +3594,18 @@ async function completeTurnAndSummarize(mind, event, insertedId) {
3427
3594
 
3428
3595
  // packages/daemon/src/lib/mind/consolidate.ts
3429
3596
  import { readdirSync, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
3430
- import { resolve as resolve9 } from "path";
3597
+ import { resolve as resolve8 } from "path";
3431
3598
  async function consolidateMemory(mindDir2) {
3432
- const soulPath = resolve9(mindDir2, "home/SOUL.md");
3433
- const memoryPath = resolve9(mindDir2, "home/MEMORY.md");
3434
- const memoryDir = resolve9(mindDir2, "home/memory");
3599
+ const soulPath = resolve8(mindDir2, "home/SOUL.md");
3600
+ const memoryPath = resolve8(mindDir2, "home/MEMORY.md");
3601
+ const memoryDir = resolve8(mindDir2, "home/memory");
3435
3602
  const soul = readFileSync6(soulPath, "utf-8");
3436
3603
  const logs = [];
3437
3604
  try {
3438
3605
  const files = readdirSync(memoryDir).filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).sort();
3439
3606
  for (const filename of files) {
3440
3607
  const date = filename.replace(".md", "");
3441
- const content2 = readFileSync6(resolve9(memoryDir, filename), "utf-8").trim();
3608
+ const content2 = readFileSync6(resolve8(memoryDir, filename), "utf-8").trim();
3442
3609
  if (content2) {
3443
3610
  logs.push(`### ${date}
3444
3611
 
@@ -3497,7 +3664,7 @@ ${content2}`);
3497
3664
  }
3498
3665
 
3499
3666
  // packages/daemon/src/lib/mind/last-known-good.ts
3500
- import { randomBytes } from "crypto";
3667
+ import { randomBytes as randomBytes2 } from "crypto";
3501
3668
  var glog = logger_default.child("last-known-good");
3502
3669
  async function hasSrcChanges(dir, mindName) {
3503
3670
  const status = (await gitExec(["status", "--porcelain", "--", "src"], { cwd: dir, mindName })).trim();
@@ -3506,7 +3673,7 @@ async function hasSrcChanges(dir, mindName) {
3506
3673
  async function rollbackSrcChanges(dir, mindName) {
3507
3674
  if (!await hasSrcChanges(dir, mindName)) return { parked: false };
3508
3675
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3509
- const branch = `broken/${ts}-${randomBytes(4).toString("hex")}`;
3676
+ const branch = `broken/${ts}-${randomBytes2(4).toString("hex")}`;
3510
3677
  const opts = { cwd: dir, mindName };
3511
3678
  await gitExec(["add", "--", "src"], opts);
3512
3679
  await gitExec(
@@ -3539,7 +3706,7 @@ async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
3539
3706
  logger_default.warn(`failed to stop variant ${variantName}`, logger_default.errorData(err));
3540
3707
  }
3541
3708
  }
3542
- const { findMind: findMind2 } = await import("./registry-7LQHTRUX.js");
3709
+ const { findMind: findMind2 } = await import("./registry-NUJAGLQJ.js");
3543
3710
  const variantEntry = await findMind2(variantName);
3544
3711
  const branchName = variantEntry?.branch ?? variantName;
3545
3712
  if (existsSync6(variantPath)) {
@@ -3591,7 +3758,7 @@ function validateBranchName(branch) {
3591
3758
  import { randomUUID } from "crypto";
3592
3759
  import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
3593
3760
  import { homedir } from "os";
3594
- import { resolve as resolve10 } from "path";
3761
+ import { resolve as resolve9 } from "path";
3595
3762
  function convertSession(opts) {
3596
3763
  const lines = readFileSync7(opts.sessionPath, "utf-8").trim().split("\n");
3597
3764
  const sessionId = randomUUID();
@@ -3707,9 +3874,9 @@ function convertSession(opts) {
3707
3874
  }
3708
3875
  }
3709
3876
  const projectId = opts.projectDir.replace(/\//g, "-");
3710
- const sdkDir = resolve10(homedir(), ".claude", "projects", projectId);
3877
+ const sdkDir = resolve9(homedir(), ".claude", "projects", projectId);
3711
3878
  mkdirSync5(sdkDir, { recursive: true });
3712
- const sdkPath = resolve10(sdkDir, `${sessionId}.jsonl`);
3879
+ const sdkPath = resolve9(sdkDir, `${sessionId}.jsonl`);
3713
3880
  writeFileSync6(sdkPath, `${sdkEvents.join("\n")}
3714
3881
  `);
3715
3882
  console.log(`Converted ${sdkEvents.length} messages \u2192 ${sdkPath}`);
@@ -3768,7 +3935,7 @@ async function getMindStatus(name, port, registryRunning) {
3768
3935
  const manager = getMindManager();
3769
3936
  let status = "stopped";
3770
3937
  try {
3771
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-AG5SQDDI.js");
3938
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-YAHDOIU5.js");
3772
3939
  if (getSleepManagerIfReady2()?.isSleeping(name)) {
3773
3940
  status = "sleeping";
3774
3941
  }
@@ -3814,7 +3981,7 @@ async function initTemplateBranch(projectRoot, composedDir, manifest, mindName,
3814
3981
  await gitExec(["commit", "-m", "initial commit"], opts);
3815
3982
  }
3816
3983
  async function updateTemplateBranch(projectRoot, template, mindName) {
3817
- const tempWorktree = resolve11(projectRoot, ".variants", "_template_update");
3984
+ const tempWorktree = resolve10(projectRoot, ".variants", "_template_update");
3818
3985
  let branchExists = false;
3819
3986
  try {
3820
3987
  await gitExec(["rev-parse", "--verify", TEMPLATE_BRANCH], { cwd: projectRoot });
@@ -3846,15 +4013,15 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
3846
4013
  });
3847
4014
  }
3848
4015
  copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
3849
- const initDir = resolve11(tempWorktree, ".init");
4016
+ const initDir = resolve10(tempWorktree, ".init");
3850
4017
  if (existsSync7(initDir)) {
3851
4018
  rmSync4(initDir, { recursive: true, force: true });
3852
4019
  }
3853
- const homeDir = resolve11(tempWorktree, "home");
4020
+ const homeDir = resolve10(tempWorktree, "home");
3854
4021
  if (existsSync7(homeDir)) {
3855
4022
  for (const entry of readdirSync2(homeDir)) {
3856
4023
  if (entry !== "VOLUTE.md") {
3857
- rmSync4(resolve11(homeDir, entry), { recursive: true, force: true });
4024
+ rmSync4(resolve10(homeDir, entry), { recursive: true, force: true });
3858
4025
  }
3859
4026
  }
3860
4027
  }
@@ -3895,7 +4062,7 @@ async function mergeTemplateBranch(worktreeDir) {
3895
4062
  async function npmInstallAsMind(cwd, mindName) {
3896
4063
  if (isIsolationEnabled()) {
3897
4064
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
3898
- await exec(cmd, args, { cwd, env: { ...process.env, HOME: resolve11(cwd, "home") } });
4065
+ await exec(cmd, args, { cwd, env: { ...process.env, HOME: resolve10(cwd, "home") } });
3899
4066
  } else {
3900
4067
  await exec("npm", ["install"], { cwd });
3901
4068
  }
@@ -3920,7 +4087,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
3920
4087
  let switchWarning;
3921
4088
  if (templateChanged) {
3922
4089
  try {
3923
- applyTemplateHomeFiles(resolve11(dir, "home"), template);
4090
+ applyTemplateHomeFiles(resolve10(dir, "home"), template);
3924
4091
  await gitExec(["add", "home/"], { cwd: dir });
3925
4092
  try {
3926
4093
  await gitExec(["diff", "--cached", "--quiet"], { cwd: dir });
@@ -3970,7 +4137,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
3970
4137
  return { ok: true, warning: switchWarning };
3971
4138
  }
3972
4139
  async function importFromArchive(c, tempDir, nameOverride, manifest) {
3973
- const extractedMindDir = resolve11(tempDir, "mind");
4140
+ const extractedMindDir = resolve10(tempDir, "mind");
3974
4141
  if (!existsSync7(extractedMindDir)) {
3975
4142
  return c.json({ error: "Invalid archive: missing mind/ directory" }, 400);
3976
4143
  }
@@ -3997,9 +4164,9 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
3997
4164
  }
3998
4165
  const state = stateDir(name);
3999
4166
  mkdirSync6(state, { recursive: true });
4000
- const envJson = resolve11(tempDir, "state/env.json");
4167
+ const envJson = resolve10(tempDir, "state/env.json");
4001
4168
  if (existsSync7(envJson)) {
4002
- cpSync(envJson, resolve11(state, "env.json"));
4169
+ cpSync(envJson, resolve10(state, "env.json"));
4003
4170
  }
4004
4171
  const port = await nextPort();
4005
4172
  await addMind(name, port, manifest.stage, manifest.template);
@@ -4008,23 +4175,23 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
4008
4175
  } catch (err) {
4009
4176
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
4010
4177
  }
4011
- const homeDir = resolve11(dest, "home");
4178
+ const homeDir = resolve10(dest, "home");
4012
4179
  ensureVoluteGroup();
4013
4180
  createMindUser(name, homeDir);
4014
4181
  await chownMindDir(dest, name);
4015
4182
  await npmInstallAsMind(dest, name);
4016
4183
  await importHistoryFromArchive(name, tempDir);
4017
4184
  importSessionsFromArchive(dest, tempDir);
4018
- if (!existsSync7(resolve11(dest, ".git"))) {
4185
+ if (!existsSync7(resolve10(dest, ".git"))) {
4019
4186
  try {
4020
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
4187
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dest, "home") } : void 0;
4021
4188
  await gitExec(["init"], { cwd: dest, mindName: name, env });
4022
4189
  await configureGitIdentity(name, { cwd: dest, mindName: name, env });
4023
4190
  await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
4024
4191
  await gitExec(["commit", "-m", "import from archive"], { cwd: dest, mindName: name, env });
4025
4192
  } catch (err) {
4026
4193
  logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
4027
- rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
4194
+ rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
4028
4195
  }
4029
4196
  }
4030
4197
  await chownMindDir(dest, name);
@@ -4057,22 +4224,22 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
4057
4224
  try {
4058
4225
  copyTemplateToDir(composedDir, dest, name, templateManifest);
4059
4226
  applyInitFiles(dest);
4060
- const extractedHome = resolve11(extractedMindDir, "home");
4227
+ const extractedHome = resolve10(extractedMindDir, "home");
4061
4228
  if (existsSync7(extractedHome)) {
4062
- cpSync(extractedHome, resolve11(dest, "home"), { recursive: true });
4229
+ cpSync(extractedHome, resolve10(dest, "home"), { recursive: true });
4063
4230
  }
4064
- const extractedMindInternal = resolve11(extractedMindDir, ".mind");
4231
+ const extractedMindInternal = resolve10(extractedMindDir, ".mind");
4065
4232
  if (existsSync7(extractedMindInternal)) {
4066
- cpSync(extractedMindInternal, resolve11(dest, ".mind"), { recursive: true });
4233
+ cpSync(extractedMindInternal, resolve10(dest, ".mind"), { recursive: true });
4067
4234
  }
4068
- const identityDir = resolve11(dest, ".mind/identity");
4235
+ const identityDir = resolve10(dest, ".mind/identity");
4069
4236
  let publicKeyPem;
4070
- if (!manifest.includes.identity || !existsSync7(resolve11(identityDir, "private.pem"))) {
4237
+ if (!manifest.includes.identity || !existsSync7(resolve10(identityDir, "private.pem"))) {
4071
4238
  ({ publicKeyPem } = generateIdentity(dest));
4072
4239
  } else {
4073
- publicKeyPem = readFileSync8(resolve11(identityDir, "public.pem"), "utf-8");
4240
+ publicKeyPem = readFileSync8(resolve10(identityDir, "public.pem"), "utf-8");
4074
4241
  }
4075
- const promptsPath = resolve11(dest, "home/.config/prompts.json");
4242
+ const promptsPath = resolve10(dest, "home/.config/prompts.json");
4076
4243
  if (!existsSync7(promptsPath)) {
4077
4244
  const mindPrompts = await getMindPromptDefaults();
4078
4245
  writeFileSync7(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
@@ -4080,13 +4247,13 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
4080
4247
  }
4081
4248
  const state = stateDir(name);
4082
4249
  mkdirSync6(state, { recursive: true });
4083
- const envJson = resolve11(tempDir, "state/env.json");
4250
+ const envJson = resolve10(tempDir, "state/env.json");
4084
4251
  if (existsSync7(envJson)) {
4085
- cpSync(envJson, resolve11(state, "env.json"));
4252
+ cpSync(envJson, resolve10(state, "env.json"));
4086
4253
  }
4087
4254
  const port = await nextPort();
4088
4255
  await addMind(name, port, manifest.stage, manifest.template);
4089
- const homeDir = resolve11(dest, "home");
4256
+ const homeDir = resolve10(dest, "home");
4090
4257
  ensureVoluteGroup();
4091
4258
  createMindUser(name, homeDir);
4092
4259
  await chownMindDir(dest, name);
@@ -4099,7 +4266,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
4099
4266
  await initTemplateBranch(dest, composedDir, templateManifest, name, env);
4100
4267
  } catch (err) {
4101
4268
  logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
4102
- rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
4269
+ rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
4103
4270
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
4104
4271
  }
4105
4272
  const skillSet = manifest.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions();
@@ -4142,7 +4309,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
4142
4309
  }
4143
4310
  }
4144
4311
  async function importHistoryFromArchive(name, tempDir) {
4145
- const historyJsonl = resolve11(tempDir, "history.jsonl");
4312
+ const historyJsonl = resolve10(tempDir, "history.jsonl");
4146
4313
  if (!existsSync7(historyJsonl)) return;
4147
4314
  try {
4148
4315
  const db = await getDb();
@@ -4182,27 +4349,27 @@ async function importHistoryFromArchive(name, tempDir) {
4182
4349
  }
4183
4350
  }
4184
4351
  function importSessionsFromArchive(dest, tempDir) {
4185
- const sessionsDir = resolve11(tempDir, "sessions");
4352
+ const sessionsDir = resolve10(tempDir, "sessions");
4186
4353
  if (!existsSync7(sessionsDir)) return;
4187
4354
  try {
4188
- const destSessions = resolve11(dest, ".mind/sessions");
4355
+ const destSessions = resolve10(dest, ".mind/sessions");
4189
4356
  mkdirSync6(destSessions, { recursive: true });
4190
4357
  for (const file of readdirSync2(sessionsDir)) {
4191
- cpSync(resolve11(sessionsDir, file), resolve11(destSessions, file));
4358
+ cpSync(resolve10(sessionsDir, file), resolve10(destSessions, file));
4192
4359
  }
4193
4360
  } catch (err) {
4194
4361
  logger_default.error("Failed to import sessions from archive", logger_default.errorData(err));
4195
4362
  }
4196
4363
  }
4197
- var createMindSchema = z5.object({
4198
- name: z5.string(),
4199
- template: z5.string().optional(),
4200
- stage: z5.enum(["seed", "sprouted"]).optional(),
4201
- description: z5.string().optional(),
4202
- model: z5.string().optional(),
4203
- seedSoul: z5.string().optional(),
4204
- skills: z5.array(z5.string()).optional(),
4205
- createdBy: z5.string().optional()
4364
+ var createMindSchema = z6.object({
4365
+ name: z6.string(),
4366
+ template: z6.string().optional(),
4367
+ stage: z6.enum(["seed", "sprouted"]).optional(),
4368
+ description: z6.string().optional(),
4369
+ model: z6.string().optional(),
4370
+ seedSoul: z6.string().optional(),
4371
+ skills: z6.array(z6.string()).optional(),
4372
+ createdBy: z6.string().optional()
4206
4373
  });
4207
4374
  function formatTimeAgo(date) {
4208
4375
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
@@ -4246,7 +4413,7 @@ async function proxyToMind(c, path) {
4246
4413
  return c.json({ error: "Failed to reach mind" }, 503);
4247
4414
  }
4248
4415
  }
4249
- var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", createMindSchema), async (c) => {
4416
+ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", createMindSchema), async (c) => {
4250
4417
  const body = c.req.valid("json");
4251
4418
  const { name } = body;
4252
4419
  const template = body.template ?? await resolveTemplate(body.model);
@@ -4263,7 +4430,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4263
4430
  applyInitFiles(dest);
4264
4431
  const { publicKeyPem } = generateIdentity(dest);
4265
4432
  {
4266
- const { readGlobalConfig: readGlobal } = await import("./setup-25MMJ3J4.js");
4433
+ const { readGlobalConfig: readGlobal } = await import("./setup-73YBJZQL.js");
4267
4434
  const mindDefaults = readGlobal().mindDefaults;
4268
4435
  const config2 = readVoluteConfig(dest);
4269
4436
  if (!config2) throw new Error("Failed to read volute.json after identity generation");
@@ -4300,7 +4467,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4300
4467
  }
4301
4468
  writeVoluteConfig(dest, config2);
4302
4469
  const modelId = body.model ?? cog?.model;
4303
- const sdkConfigPath = resolve11(dest, "home/.config/config.json");
4470
+ const sdkConfigPath = resolve10(dest, "home/.config/config.json");
4304
4471
  if (modelId || cog?.compaction) {
4305
4472
  const existing = existsSync7(sdkConfigPath) ? JSON.parse(readFileSync8(sdkConfigPath, "utf-8")) : {};
4306
4473
  if (modelId) {
@@ -4315,7 +4482,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4315
4482
  }
4316
4483
  const mindPrompts = await getMindPromptDefaults();
4317
4484
  writeFileSync7(
4318
- resolve11(dest, "home/.config/prompts.json"),
4485
+ resolve10(dest, "home/.config/prompts.json"),
4319
4486
  `${JSON.stringify(mindPrompts, null, 2)}
4320
4487
  `
4321
4488
  );
@@ -4327,7 +4494,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4327
4494
  } catch (err) {
4328
4495
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
4329
4496
  }
4330
- const homeDir = resolve11(dest, "home");
4497
+ const homeDir = resolve10(dest, "home");
4331
4498
  ensureVoluteGroup();
4332
4499
  createMindUser(name, homeDir);
4333
4500
  await chownMindDir(dest, name);
@@ -4340,7 +4507,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4340
4507
  await initTemplateBranch(dest, composedDir, manifest, name, env);
4341
4508
  } catch (err) {
4342
4509
  logger_default.error(`git setup failed for ${name}`, logger_default.errorData(err));
4343
- rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
4510
+ rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
4344
4511
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
4345
4512
  }
4346
4513
  await chownMindDir(dest, name);
@@ -4350,11 +4517,11 @@ The human who planted you described you as: "${body.description}"
4350
4517
  ` : "";
4351
4518
  const seedSoulRaw = body.seedSoul ?? await getPrompt("seed_soul", { name, description: descLine });
4352
4519
  const seedSoul = body.seedSoul ? substitute(seedSoulRaw, { name, description: descLine }) : seedSoulRaw;
4353
- writeFileSync7(resolve11(dest, "home/SOUL.md"), seedSoul);
4520
+ writeFileSync7(resolve10(dest, "home/SOUL.md"), seedSoul);
4354
4521
  }
4355
4522
  let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
4356
4523
  if (body.stage === "seed" && !body.skills) {
4357
- const { isImagegenEnabled } = await import("./setup-25MMJ3J4.js");
4524
+ const { isImagegenEnabled } = await import("./setup-73YBJZQL.js");
4358
4525
  if (isImagegenEnabled()) {
4359
4526
  skillSet = [...skillSet, "imagegen"];
4360
4527
  }
@@ -4372,7 +4539,7 @@ The human who planted you described you as: "${body.description}"
4372
4539
  try {
4373
4540
  const spiritEntry = await findMind("volute");
4374
4541
  if (spiritEntry) {
4375
- const { spiritDir } = await import("./spirit-53DQPRNR.js");
4542
+ const { spiritDir } = await import("./spirit-II3HOERM.js");
4376
4543
  const sDir = spiritEntry.dir ?? spiritDir();
4377
4544
  const spiritConfig = readVoluteConfig(sDir) ?? {};
4378
4545
  const schedules = spiritConfig.schedules ?? [];
@@ -4387,7 +4554,7 @@ The human who planted you described you as: "${body.description}"
4387
4554
  });
4388
4555
  spiritConfig.schedules = schedules;
4389
4556
  writeVoluteConfig(sDir, spiritConfig);
4390
- const { getScheduler: getScheduler2 } = await import("./scheduler-VON2TB52.js");
4557
+ const { getScheduler: getScheduler2 } = await import("./scheduler-YHJRRV6E.js");
4391
4558
  getScheduler2().loadSchedules("volute", sDir);
4392
4559
  }
4393
4560
  }
@@ -4398,11 +4565,11 @@ The human who planted you described you as: "${body.description}"
4398
4565
  if (body.stage !== "seed") {
4399
4566
  const customSoul = await getPromptIfCustom("default_soul");
4400
4567
  if (customSoul) {
4401
- writeFileSync7(resolve11(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
4568
+ writeFileSync7(resolve10(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
4402
4569
  }
4403
4570
  const customMemory = await getPromptIfCustom("default_memory");
4404
4571
  if (customMemory) {
4405
- writeFileSync7(resolve11(dest, "home/MEMORY.md"), customMemory);
4572
+ writeFileSync7(resolve10(dest, "home/MEMORY.md"), customMemory);
4406
4573
  }
4407
4574
  }
4408
4575
  publishPublicKey(name, publicKeyPem).catch(
@@ -4451,12 +4618,12 @@ The human who planted you described you as: "${body.description}"
4451
4618
  return importFromArchive(c, body.archivePath, body.name, body.manifest);
4452
4619
  }
4453
4620
  const wsDir = body.workspacePath;
4454
- if (!wsDir || !existsSync7(resolve11(wsDir, "SOUL.md")) || !existsSync7(resolve11(wsDir, "IDENTITY.md"))) {
4621
+ if (!wsDir || !existsSync7(resolve10(wsDir, "SOUL.md")) || !existsSync7(resolve10(wsDir, "IDENTITY.md"))) {
4455
4622
  return c.json({ error: "Invalid workspace: missing SOUL.md or IDENTITY.md" }, 400);
4456
4623
  }
4457
- const soul = readFileSync8(resolve11(wsDir, "SOUL.md"), "utf-8");
4458
- const identity = readFileSync8(resolve11(wsDir, "IDENTITY.md"), "utf-8");
4459
- const userPath = resolve11(wsDir, "USER.md");
4624
+ const soul = readFileSync8(resolve10(wsDir, "SOUL.md"), "utf-8");
4625
+ const identity = readFileSync8(resolve10(wsDir, "IDENTITY.md"), "utf-8");
4626
+ const userPath = resolve10(wsDir, "USER.md");
4460
4627
  const user = existsSync7(userPath) ? readFileSync8(userPath, "utf-8") : "";
4461
4628
  const name = body.name ?? parseNameFromIdentity(identity) ?? "imported-mind";
4462
4629
  const template = body.template ?? "claude";
@@ -4484,26 +4651,26 @@ ${user.trimEnd()}
4484
4651
  copyTemplateToDir(composedDir, dest, name, manifest);
4485
4652
  applyInitFiles(dest);
4486
4653
  const { publicKeyPem: importPublicKey } = generateIdentity(dest);
4487
- writeFileSync7(resolve11(dest, "home/SOUL.md"), mergedSoul);
4488
- const wsMemoryPath = resolve11(wsDir, "MEMORY.md");
4654
+ writeFileSync7(resolve10(dest, "home/SOUL.md"), mergedSoul);
4655
+ const wsMemoryPath = resolve10(wsDir, "MEMORY.md");
4489
4656
  const hasMemory = existsSync7(wsMemoryPath);
4490
4657
  if (hasMemory) {
4491
4658
  const existingMemory = readFileSync8(wsMemoryPath, "utf-8");
4492
4659
  writeFileSync7(
4493
- resolve11(dest, "home/MEMORY.md"),
4660
+ resolve10(dest, "home/MEMORY.md"),
4494
4661
  `${existingMemory.trimEnd()}${mergedMemoryExtra}`
4495
4662
  );
4496
4663
  } else if (user) {
4497
- writeFileSync7(resolve11(dest, "home/MEMORY.md"), `${user.trimEnd()}
4664
+ writeFileSync7(resolve10(dest, "home/MEMORY.md"), `${user.trimEnd()}
4498
4665
  `);
4499
4666
  }
4500
- const wsMemoryDir = resolve11(wsDir, "memory");
4667
+ const wsMemoryDir = resolve10(wsDir, "memory");
4501
4668
  let dailyLogCount = 0;
4502
4669
  if (existsSync7(wsMemoryDir)) {
4503
- const destMemoryDir = resolve11(dest, "home/memory");
4670
+ const destMemoryDir = resolve10(dest, "home/memory");
4504
4671
  const files = readdirSync2(wsMemoryDir).filter((f) => f.endsWith(".md"));
4505
4672
  for (const file of files) {
4506
- cpSync(resolve11(wsMemoryDir, file), resolve11(destMemoryDir, file));
4673
+ cpSync(resolve10(wsMemoryDir, file), resolve10(destMemoryDir, file));
4507
4674
  }
4508
4675
  dailyLogCount = files.length;
4509
4676
  }
@@ -4514,7 +4681,7 @@ ${user.trimEnd()}
4514
4681
  } catch (err) {
4515
4682
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
4516
4683
  }
4517
- const homeDir = resolve11(dest, "home");
4684
+ const homeDir = resolve10(dest, "home");
4518
4685
  ensureVoluteGroup();
4519
4686
  createMindUser(name, homeDir);
4520
4687
  await chownMindDir(dest, name);
@@ -4522,20 +4689,20 @@ ${user.trimEnd()}
4522
4689
  if (!hasMemory && dailyLogCount > 0) {
4523
4690
  await consolidateMemory(dest);
4524
4691
  }
4525
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
4692
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dest, "home") } : void 0;
4526
4693
  await gitExec(["init"], { cwd: dest, mindName: name, env });
4527
4694
  await configureGitIdentity(name, { cwd: dest, mindName: name, env });
4528
4695
  await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
4529
4696
  await gitExec(["commit", "-m", "import from OpenClaw"], { cwd: dest, mindName: name, env });
4530
- const sessionFile = body.sessionPath ? resolve11(body.sessionPath) : findOpenClawSession(wsDir);
4697
+ const sessionFile = body.sessionPath ? resolve10(body.sessionPath) : findOpenClawSession(wsDir);
4531
4698
  if (sessionFile && existsSync7(sessionFile)) {
4532
4699
  if (template === "pi") {
4533
4700
  importPiSession(sessionFile, dest);
4534
4701
  } else if (template === "claude") {
4535
4702
  const sessionId = convertSession({ sessionPath: sessionFile, projectDir: dest });
4536
- const mindRuntimeDir = resolve11(dest, ".mind");
4703
+ const mindRuntimeDir = resolve10(dest, ".mind");
4537
4704
  mkdirSync6(mindRuntimeDir, { recursive: true });
4538
- writeFileSync7(resolve11(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
4705
+ writeFileSync7(resolve10(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
4539
4706
  }
4540
4707
  }
4541
4708
  importOpenClawConnectors(name, dest);
@@ -4576,7 +4743,7 @@ ${user.trimEnd()}
4576
4743
  const minds = await Promise.all(
4577
4744
  entries.map(async (entry) => {
4578
4745
  const mindStatus = await getMindStatus(entry.name, entry.port, entry.running);
4579
- const hasPages = existsSync7(resolve11(mindDir(entry.name), "home", "pages"));
4746
+ const hasPages = existsSync7(resolve10(mindDir(entry.name), "home", "pages"));
4580
4747
  return {
4581
4748
  ...entry,
4582
4749
  ...mindStatus,
@@ -4605,7 +4772,7 @@ ${user.trimEnd()}
4605
4772
  return { name: s.name, port: s.port, status: variantStatus };
4606
4773
  })
4607
4774
  );
4608
- const hasPages = existsSync7(resolve11(mindDir(name), "home", "pages"));
4775
+ const hasPages = existsSync7(resolve10(mindDir(name), "home", "pages"));
4609
4776
  return c.json({ ...entry, ...mindStatus, variants: variantStatuses, hasPages });
4610
4777
  }).get("/:name/context", requireSelf(), async (c) => proxyToMind(c, "context")).get("/:name/context/messages", requireSelf(), async (c) => proxyToMind(c, "context/messages")).post("/:name/start", requireSelf(), async (c) => {
4611
4778
  const name = c.req.param("name");
@@ -4652,7 +4819,7 @@ ${user.trimEnd()}
4652
4819
  const manager = getMindManager();
4653
4820
  try {
4654
4821
  if (context?.type === "reload") {
4655
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-AG5SQDDI.js");
4822
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-YAHDOIU5.js");
4656
4823
  const sleepState = getSleepManagerIfReady2()?.getState(name);
4657
4824
  if (sleepState?.sleeping) {
4658
4825
  logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
@@ -4779,7 +4946,7 @@ ${user.trimEnd()}
4779
4946
  const name = c.req.param("name");
4780
4947
  const entry = await findMind(name);
4781
4948
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4782
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-AG5SQDDI.js");
4949
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-YAHDOIU5.js");
4783
4950
  const sm = getSleepManagerIfReady2();
4784
4951
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4785
4952
  return c.json(sm.getState(name));
@@ -4787,7 +4954,7 @@ ${user.trimEnd()}
4787
4954
  const name = c.req.param("name");
4788
4955
  const entry = await findMind(name);
4789
4956
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4790
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-AG5SQDDI.js");
4957
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-YAHDOIU5.js");
4791
4958
  const sm = getSleepManagerIfReady2();
4792
4959
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4793
4960
  if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
@@ -4807,7 +4974,7 @@ ${user.trimEnd()}
4807
4974
  const name = c.req.param("name");
4808
4975
  const entry = await findMind(name);
4809
4976
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4810
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-AG5SQDDI.js");
4977
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-YAHDOIU5.js");
4811
4978
  const sm = getSleepManagerIfReady2();
4812
4979
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4813
4980
  const sleepState = sm.getState(name);
@@ -4822,7 +4989,7 @@ ${user.trimEnd()}
4822
4989
  const name = c.req.param("name");
4823
4990
  const entry = await findMind(name);
4824
4991
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4825
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-AG5SQDDI.js");
4992
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-YAHDOIU5.js");
4826
4993
  const sm = getSleepManagerIfReady2();
4827
4994
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4828
4995
  const flushed = await sm.flushQueuedMessages(name);
@@ -4837,10 +5004,20 @@ ${user.trimEnd()}
4837
5004
  const profile = config2.profile ?? {};
4838
5005
  if (body.displayName !== void 0) profile.displayName = body.displayName;
4839
5006
  if (body.description !== void 0) profile.description = body.description;
4840
- if (body.avatar !== void 0) profile.avatar = basename(body.avatar);
5007
+ if (body.avatar !== void 0) {
5008
+ const homeDir = resolve10(dir, "home");
5009
+ const avatarPath = safeResolveWithinBase(homeDir, body.avatar);
5010
+ if (!avatarPath) {
5011
+ return c.json({ error: "Avatar path must be inside the mind's home directory" }, 400);
5012
+ }
5013
+ if (!existsSync7(avatarPath)) {
5014
+ return c.json({ error: `Avatar file not found: ${relative(homeDir, avatarPath)}` }, 400);
5015
+ }
5016
+ profile.avatar = relative(homeDir, avatarPath);
5017
+ }
4841
5018
  config2.profile = profile;
4842
5019
  writeVoluteConfig(dir, config2);
4843
- const { syncMindProfile: syncMindProfile2 } = await import("./auth-3RIG6GKN.js");
5020
+ const { syncMindProfile: syncMindProfile2 } = await import("./auth-FRZJVQCS.js");
4844
5021
  await syncMindProfile2(name, profile);
4845
5022
  broadcast({ type: "profile_updated", mind: name, summary: `${name} profile updated` });
4846
5023
  return c.json({ ok: true });
@@ -4880,14 +5057,14 @@ ${user.trimEnd()}
4880
5057
  return c.json({ output: "" });
4881
5058
  }
4882
5059
  const dir = entry.dir ?? mindDir(name);
4883
- const soulPath = resolve11(dir, "home/SOUL.md");
4884
- const memoryPath = resolve11(dir, "home/MEMORY.md");
5060
+ const soulPath = resolve10(dir, "home/SOUL.md");
5061
+ const memoryPath = resolve10(dir, "home/MEMORY.md");
4885
5062
  const soulCustom = existsSync7(soulPath) && !readFileSync8(soulPath, "utf-8").includes(ORIENTATION_MARKER);
4886
5063
  const memoryWritten = existsSync7(memoryPath) && readFileSync8(memoryPath, "utf-8").trim().length > 0;
4887
5064
  const config2 = readVoluteConfig(dir);
4888
5065
  const displayNameSet = !!config2?.profile?.displayName;
4889
5066
  const avatarSet = !!config2?.profile?.avatar;
4890
- const { isImagegenEnabled } = await import("./setup-25MMJ3J4.js");
5067
+ const { isImagegenEnabled } = await import("./setup-73YBJZQL.js");
4891
5068
  const imagegenEnabled = isImagegenEnabled();
4892
5069
  const done = [];
4893
5070
  const remaining = [];
@@ -4925,7 +5102,7 @@ ${user.trimEnd()}
4925
5102
  try {
4926
5103
  const spiritEntry = await findMind("volute");
4927
5104
  if (spiritEntry) {
4928
- const { spiritDir } = await import("./spirit-53DQPRNR.js");
5105
+ const { spiritDir } = await import("./spirit-II3HOERM.js");
4929
5106
  const sDir = spiritEntry.dir ?? spiritDir();
4930
5107
  const spiritConfig = readVoluteConfig(sDir);
4931
5108
  if (spiritConfig?.schedules) {
@@ -4933,7 +5110,7 @@ ${user.trimEnd()}
4933
5110
  spiritConfig.schedules = spiritConfig.schedules.filter((s) => s.id !== nurtureId);
4934
5111
  if (spiritConfig.schedules.length === 0) spiritConfig.schedules = void 0;
4935
5112
  writeVoluteConfig(sDir, spiritConfig);
4936
- const { getScheduler: getScheduler2 } = await import("./scheduler-VON2TB52.js");
5113
+ const { getScheduler: getScheduler2 } = await import("./scheduler-YHJRRV6E.js");
4937
5114
  getScheduler2().loadSchedules("volute", sDir);
4938
5115
  }
4939
5116
  }
@@ -4992,16 +5169,16 @@ ${user.trimEnd()}
4992
5169
  }
4993
5170
  const UPGRADE_BRANCH = "upgrade";
4994
5171
  const upgradeVariantName = `${mindName}-upgrade`;
4995
- const worktreeDir = resolve11(dir, ".variants", UPGRADE_BRANCH);
5172
+ const worktreeDir = resolve10(dir, ".variants", UPGRADE_BRANCH);
4996
5173
  if (body.abort) {
4997
5174
  if (!existsSync7(worktreeDir)) {
4998
5175
  return c.json({ error: "No upgrade in progress" }, 400);
4999
5176
  }
5000
5177
  try {
5001
5178
  try {
5002
- const gitDirContent = readFileSync8(resolve11(worktreeDir, ".git"), "utf-8").trim();
5179
+ const gitDirContent = readFileSync8(resolve10(worktreeDir, ".git"), "utf-8").trim();
5003
5180
  const gitDir = gitDirContent.replace("gitdir: ", "");
5004
- if (existsSync7(resolve11(gitDir, "MERGE_HEAD"))) {
5181
+ if (existsSync7(resolve10(gitDir, "MERGE_HEAD"))) {
5005
5182
  await gitExec(["merge", "--abort"], { cwd: worktreeDir });
5006
5183
  }
5007
5184
  } catch {
@@ -5085,7 +5262,7 @@ ${user.trimEnd()}
5085
5262
  }
5086
5263
  if (body.diff) {
5087
5264
  try {
5088
- if (!existsSync7(resolve11(dir, ".git"))) {
5265
+ if (!existsSync7(resolve10(dir, ".git"))) {
5089
5266
  return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
5090
5267
  }
5091
5268
  await updateTemplateBranch(dir, template, mindName);
@@ -5109,16 +5286,16 @@ ${user.trimEnd()}
5109
5286
  409
5110
5287
  );
5111
5288
  }
5112
- if (!existsSync7(resolve11(dir, ".git"))) {
5289
+ if (!existsSync7(resolve10(dir, ".git"))) {
5113
5290
  try {
5114
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dir, "home") } : void 0;
5291
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dir, "home") } : void 0;
5115
5292
  await gitExec(["init"], { cwd: dir, mindName, env });
5116
5293
  await configureGitIdentity(mindName, { cwd: dir, mindName, env });
5117
5294
  await gitExec(["add", "-A"], { cwd: dir, mindName, env });
5118
5295
  await gitExec(["commit", "-m", "initial commit"], { cwd: dir, mindName, env });
5119
5296
  await chownMindDir(dir, mindName);
5120
5297
  } catch (err) {
5121
- rmSync4(resolve11(dir, ".git"), { recursive: true, force: true });
5298
+ rmSync4(resolve10(dir, ".git"), { recursive: true, force: true });
5122
5299
  return c.json(
5123
5300
  {
5124
5301
  error: `Git initialization failed: ${err instanceof Error ? err.message : String(err)}`
@@ -5133,7 +5310,7 @@ ${user.trimEnd()}
5133
5310
  } catch {
5134
5311
  }
5135
5312
  await updateTemplateBranch(dir, template, mindName);
5136
- const parentDir = resolve11(dir, ".variants");
5313
+ const parentDir = resolve10(dir, ".variants");
5137
5314
  if (!existsSync7(parentDir)) {
5138
5315
  mkdirSync6(parentDir, { recursive: true });
5139
5316
  }
@@ -5267,7 +5444,7 @@ ${user.trimEnd()}
5267
5444
  if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
5268
5445
  let config2 = readVoluteConfig(dir);
5269
5446
  if (!config2 && entry.template === "pi") {
5270
- const piConfigPath = resolve11(dir, "home/.config/config.json");
5447
+ const piConfigPath = resolve10(dir, "home/.config/config.json");
5271
5448
  if (existsSync7(piConfigPath)) {
5272
5449
  try {
5273
5450
  config2 = JSON.parse(readFileSync8(piConfigPath, "utf-8"));
@@ -5276,7 +5453,7 @@ ${user.trimEnd()}
5276
5453
  }
5277
5454
  }
5278
5455
  let templateConfig = {};
5279
- const configJsonPath = resolve11(dir, "home/.config/config.json");
5456
+ const configJsonPath = resolve10(dir, "home/.config/config.json");
5280
5457
  if (existsSync7(configJsonPath)) {
5281
5458
  try {
5282
5459
  templateConfig = JSON.parse(readFileSync8(configJsonPath, "utf-8"));
@@ -5318,16 +5495,16 @@ ${user.trimEnd()}
5318
5495
  }).put(
5319
5496
  "/:name/config",
5320
5497
  requireSelf(),
5321
- zValidator5(
5498
+ zValidator6(
5322
5499
  "json",
5323
- z5.object({
5324
- model: z5.string().optional(),
5325
- thinkingLevel: z5.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional(),
5326
- maxThinkingTokens: z5.number().int().positive().nullable().optional(),
5327
- tokenBudget: z5.number().int().positive().nullable().optional(),
5328
- tokenBudgetPeriodMinutes: z5.number().int().positive().nullable().optional(),
5329
- compaction: z5.object({ maxContextTokens: z5.number().int().positive().nullable().optional() }).nullable().optional(),
5330
- unescapeNewlines: z5.boolean().optional()
5500
+ z6.object({
5501
+ model: z6.string().optional(),
5502
+ thinkingLevel: z6.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional(),
5503
+ maxThinkingTokens: z6.number().int().positive().nullable().optional(),
5504
+ tokenBudget: z6.number().int().positive().nullable().optional(),
5505
+ tokenBudgetPeriodMinutes: z6.number().int().positive().nullable().optional(),
5506
+ compaction: z6.object({ maxContextTokens: z6.number().int().positive().nullable().optional() }).nullable().optional(),
5507
+ unescapeNewlines: z6.boolean().optional()
5331
5508
  })
5332
5509
  ),
5333
5510
  async (c) => {
@@ -5368,12 +5545,12 @@ ${user.trimEnd()}
5368
5545
  }
5369
5546
  writeVoluteConfig(dir, existing);
5370
5547
  if (body.unescapeNewlines !== void 0) {
5371
- const { clearEchoTextCache } = await import("./echo-text-KFSUCZXL.js");
5548
+ const { clearEchoTextCache } = await import("./echo-text-NQXYYYCU.js");
5372
5549
  clearEchoTextCache(name);
5373
5550
  }
5374
5551
  const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.maxThinkingTokens !== void 0 || body.compaction !== void 0;
5375
5552
  if (needsConfigJson) {
5376
- const configJsonPath = resolve11(dir, "home/.config/config.json");
5553
+ const configJsonPath = resolve10(dir, "home/.config/config.json");
5377
5554
  let templateConfig = {};
5378
5555
  if (existsSync7(configJsonPath)) {
5379
5556
  try {
@@ -5445,7 +5622,7 @@ ${user.trimEnd()}
5445
5622
  }
5446
5623
  if (entry.mindType === "spirit" && body.model !== void 0) {
5447
5624
  try {
5448
- const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-25MMJ3J4.js");
5625
+ const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-73YBJZQL.js");
5449
5626
  const globalConfig = readGlobalConfig2();
5450
5627
  globalConfig.spiritModel = body.model;
5451
5628
  writeGlobalConfig2(globalConfig);
@@ -5473,7 +5650,7 @@ ${user.trimEnd()}
5473
5650
  if (!body.systemPrompt || !body.message) {
5474
5651
  return c.json({ error: "systemPrompt and message required" }, 400);
5475
5652
  }
5476
- const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-FBCCEYF5.js");
5653
+ const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-534WUSDL.js");
5477
5654
  if (!isAiConfigured()) {
5478
5655
  return c.json({ error: "AI service not configured" }, 503);
5479
5656
  }
@@ -5765,11 +5942,11 @@ ${lines.join("\n")}` });
5765
5942
  var minds_default = app13;
5766
5943
 
5767
5944
  // packages/daemon/src/web/api/prompts.ts
5768
- import { zValidator as zValidator6 } from "@hono/zod-validator";
5945
+ import { zValidator as zValidator7 } from "@hono/zod-validator";
5769
5946
  import { eq as eq6, sql as sql4 } from "drizzle-orm";
5770
- import { Hono as Hono16 } from "hono";
5771
- import { z as z6 } from "zod";
5772
- var app14 = new Hono16().get("/", async (c) => {
5947
+ import { Hono as Hono17 } from "hono";
5948
+ import { z as z7 } from "zod";
5949
+ var app14 = new Hono17().get("/", async (c) => {
5773
5950
  let rows;
5774
5951
  try {
5775
5952
  const db = await getDb();
@@ -5792,7 +5969,7 @@ var app14 = new Hono16().get("/", async (c) => {
5792
5969
  };
5793
5970
  });
5794
5971
  return c.json(prompts);
5795
- }).put("/:key", requireAdmin, zValidator6("json", z6.object({ content: z6.string() })), async (c) => {
5972
+ }).put("/:key", requireAdmin, zValidator7("json", z7.object({ content: z7.string() })), async (c) => {
5796
5973
  const key = c.req.param("key");
5797
5974
  if (!PROMPT_KEYS.includes(key)) {
5798
5975
  return c.json({ error: "Unknown prompt key" }, 404);
@@ -5816,8 +5993,8 @@ var app14 = new Hono16().get("/", async (c) => {
5816
5993
  var prompts_default = app14;
5817
5994
 
5818
5995
  // packages/daemon/src/web/api/schedules.ts
5819
- import { CronExpressionParser } from "cron-parser";
5820
- import { Hono as Hono17 } from "hono";
5996
+ import { CronExpressionParser as CronExpressionParser3 } from "cron-parser";
5997
+ import { Hono as Hono18 } from "hono";
5821
5998
  var slog2 = logger_default.child("schedules");
5822
5999
  function readSchedules(dir) {
5823
6000
  return readVoluteConfig(dir)?.schedules ?? [];
@@ -5834,7 +6011,7 @@ function writeSchedules(name, dir, schedules) {
5834
6011
  data: { schedules }
5835
6012
  });
5836
6013
  }
5837
- var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) => {
6014
+ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) => {
5838
6015
  const name = c.req.param("name");
5839
6016
  const entry = await findMind(name);
5840
6017
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -5855,14 +6032,14 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
5855
6032
  }
5856
6033
  } else if (s.cron) {
5857
6034
  try {
5858
- const interval = CronExpressionParser.parse(s.cron);
6035
+ const interval = CronExpressionParser3.parse(s.cron);
5859
6036
  const next = interval.next().toDate();
5860
6037
  upcoming.push({ id: s.id, at: next.toISOString(), type: "cron" });
5861
6038
  } catch {
5862
6039
  slog2.warn(`invalid cron "${s.cron}" for schedule "${s.id}" of ${name}`);
5863
6040
  }
5864
6041
  try {
5865
- const prevInterval = CronExpressionParser.parse(s.cron);
6042
+ const prevInterval = CronExpressionParser3.parse(s.cron);
5866
6043
  const prev = prevInterval.prev().toDate();
5867
6044
  previous.push({ id: s.id, at: prev.toISOString() });
5868
6045
  } catch {
@@ -5878,13 +6055,13 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
5878
6055
  }
5879
6056
  } else if (sleepConfig?.enabled && sleepConfig.schedule) {
5880
6057
  try {
5881
- const sleepInterval = CronExpressionParser.parse(sleepConfig.schedule.sleep);
6058
+ const sleepInterval = CronExpressionParser3.parse(sleepConfig.schedule.sleep);
5882
6059
  const nextSleep = sleepInterval.next().toDate();
5883
6060
  upcoming.push({ id: "sleep", at: nextSleep.toISOString(), type: "cron" });
5884
6061
  } catch {
5885
6062
  }
5886
6063
  try {
5887
- const prevWakeInterval = CronExpressionParser.parse(sleepConfig.schedule.wake);
6064
+ const prevWakeInterval = CronExpressionParser3.parse(sleepConfig.schedule.wake);
5888
6065
  const prevWake = prevWakeInterval.prev().toDate();
5889
6066
  previous.push({ id: "sleep", at: prevWake.toISOString() });
5890
6067
  } catch {
@@ -5908,7 +6085,7 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
5908
6085
  for (const field of ["sleep", "wake"]) {
5909
6086
  if (body.schedule[field]) {
5910
6087
  try {
5911
- CronExpressionParser.parse(body.schedule[field]);
6088
+ CronExpressionParser3.parse(body.schedule[field]);
5912
6089
  } catch {
5913
6090
  return c.json({ error: `Invalid ${field} cron: ${body.schedule[field]}` }, 400);
5914
6091
  }
@@ -5954,7 +6131,7 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
5954
6131
  }
5955
6132
  if (body.cron) {
5956
6133
  try {
5957
- CronExpressionParser.parse(body.cron);
6134
+ CronExpressionParser3.parse(body.cron);
5958
6135
  } catch {
5959
6136
  return c.json({ error: `Invalid cron expression: ${body.cron}` }, 400);
5960
6137
  }
@@ -6001,7 +6178,7 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
6001
6178
  }
6002
6179
  if (body.cron !== void 0) {
6003
6180
  try {
6004
- CronExpressionParser.parse(body.cron);
6181
+ CronExpressionParser3.parse(body.cron);
6005
6182
  } catch {
6006
6183
  return c.json({ error: `Invalid cron expression: ${body.cron}` }, 400);
6007
6184
  }
@@ -6058,7 +6235,7 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
6058
6235
  const body = await c.req.text();
6059
6236
  const message = `[webhook: ${event}] ${body}`;
6060
6237
  try {
6061
- const { sendSystemMessage } = await import("./system-chat-54RN3K67.js");
6238
+ const { sendSystemMessage } = await import("./system-chat-E65T2HSW.js");
6062
6239
  await sendSystemMessage(name, message);
6063
6240
  return c.json({ ok: true });
6064
6241
  } catch (err) {
@@ -6071,14 +6248,14 @@ var schedules_default = app15;
6071
6248
  // packages/daemon/src/web/api/setup.ts
6072
6249
  import { mkdirSync as mkdirSync7 } from "fs";
6073
6250
  import { homedir as homedir2 } from "os";
6074
- import { resolve as resolve12 } from "path";
6075
- import { Hono as Hono18 } from "hono";
6251
+ import { resolve as resolve11 } from "path";
6252
+ import { Hono as Hono19 } from "hono";
6076
6253
  import { setCookie as setCookie2 } from "hono/cookie";
6077
6254
  var DEFAULT_API_URL2 = "https://volute.systems";
6078
- var setup = new Hono18();
6255
+ var setup = new Hono19();
6079
6256
  function writeSetupConfig(systemName, description) {
6080
- const configHome = process.env.VOLUTE_HOME ?? resolve12(homedir2(), ".volute");
6081
- const mindsDir = resolve12(configHome, "minds");
6257
+ const configHome = process.env.VOLUTE_HOME ?? resolve11(homedir2(), ".volute");
6258
+ const mindsDir = resolve11(configHome, "minds");
6082
6259
  mkdirSync7(configHome, { recursive: true });
6083
6260
  mkdirSync7(mindsDir, { recursive: true });
6084
6261
  const existingConfig = readGlobalConfig();
@@ -6112,7 +6289,7 @@ setup.get("/status", async (c) => {
6112
6289
  let hasAccount = false;
6113
6290
  if (hasSystem) {
6114
6291
  try {
6115
- const { listUsersByType: listUsersByType2 } = await import("./auth-3RIG6GKN.js");
6292
+ const { listUsersByType: listUsersByType2 } = await import("./auth-FRZJVQCS.js");
6116
6293
  const brains = await listUsersByType2("brain");
6117
6294
  hasAccount = brains.length > 0;
6118
6295
  } catch (err) {
@@ -6323,7 +6500,7 @@ setup.post("/account", async (c) => {
6323
6500
  }
6324
6501
  }
6325
6502
  try {
6326
- const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-3RIG6GKN.js");
6503
+ const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-FRZJVQCS.js");
6327
6504
  const user = await createUser2(body.username.trim(), body.password);
6328
6505
  if (body.displayName?.trim()) {
6329
6506
  await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
@@ -6369,7 +6546,7 @@ setup.post("/models", async (c) => {
6369
6546
  return c.json({ error: "Spirit model is required" }, 400);
6370
6547
  }
6371
6548
  try {
6372
- const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-FBCCEYF5.js");
6549
+ const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-534WUSDL.js");
6373
6550
  setEnabledModels3(body.models);
6374
6551
  const config2 = readGlobalConfig();
6375
6552
  config2.spiritModel = body.spiritModel.trim();
@@ -6387,15 +6564,15 @@ setup.post("/complete", async (c) => {
6387
6564
  return c.json({ error: "Setup already complete" }, 400);
6388
6565
  }
6389
6566
  try {
6390
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-53DQPRNR.js");
6391
- const { startSpiritFull } = await import("./mind-service-2C7AINBO.js");
6567
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-II3HOERM.js");
6568
+ const { startSpiritFull } = await import("./mind-service-BF2LUQMH.js");
6392
6569
  await ensureSpiritProject();
6393
6570
  await syncSpiritTemplate();
6394
6571
  const warnings = [];
6395
6572
  const config2 = readGlobalConfig();
6396
6573
  if (config2.setup?.service && config2.setup?.type === "local") {
6397
6574
  try {
6398
- const { installUserService } = await import("./service-install-SHRM6NHK.js");
6575
+ const { installUserService } = await import("./service-install-4QNUDKLM.js");
6399
6576
  const installed = await installUserService(config2.port, config2.hostname);
6400
6577
  if (!installed) {
6401
6578
  warnings.push("Service installation is not supported on this platform.");
@@ -6423,8 +6600,8 @@ setup.post("/complete", async (c) => {
6423
6600
  }
6424
6601
  let spiritConversationId;
6425
6602
  try {
6426
- const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-3RIG6GKN.js");
6427
- const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-67WWW25C.js");
6603
+ const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-FRZJVQCS.js");
6604
+ const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-G4LYMHAA.js");
6428
6605
  const spiritUser = await getOrCreateMindUser2("volute");
6429
6606
  const brains = await listUsersByType2("brain");
6430
6607
  const admin2 = brains.find((u) => u.role === "admin");
@@ -6446,8 +6623,8 @@ setup.post("/complete", async (c) => {
6446
6623
  logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
6447
6624
  if (spiritConversationId && spiritStarted) {
6448
6625
  try {
6449
- const { deliverMessage: deliverMessage2 } = await import("./message-delivery-HRGFNWO7.js");
6450
- const { listUsersByType: listUsers2 } = await import("./auth-3RIG6GKN.js");
6626
+ const { deliverMessage: deliverMessage2 } = await import("./message-delivery-IUAXRPFE.js");
6627
+ const { listUsersByType: listUsers2 } = await import("./auth-FRZJVQCS.js");
6451
6628
  const admins = await listUsers2("brain");
6452
6629
  const admin2 = admins.find((u) => u.role === "admin");
6453
6630
  const adminName = admin2?.display_name || admin2?.username || "the admin";
@@ -6486,10 +6663,10 @@ var setup_default = setup;
6486
6663
  // packages/daemon/src/web/api/skills.ts
6487
6664
  import { existsSync as existsSync8, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync5 } from "fs";
6488
6665
  import { tmpdir } from "os";
6489
- import { join, resolve as resolve13 } from "path";
6666
+ import { join, resolve as resolve12 } from "path";
6490
6667
  import AdmZip from "adm-zip";
6491
- import { Hono as Hono19 } from "hono";
6492
- var app16 = new Hono19().get("/", async (c) => {
6668
+ import { Hono as Hono20 } from "hono";
6669
+ var app16 = new Hono20().get("/", async (c) => {
6493
6670
  const skills = await listSharedSkills();
6494
6671
  return c.json(skills);
6495
6672
  }).get("/defaults/list", async (c) => {
@@ -6562,7 +6739,7 @@ var app16 = new Hono19().get("/", async (c) => {
6562
6739
  try {
6563
6740
  const zip = new AdmZip(buffer2);
6564
6741
  for (const entry of zip.getEntries()) {
6565
- const target = resolve13(tmpDir, entry.entryName);
6742
+ const target = resolve12(tmpDir, entry.entryName);
6566
6743
  if (!target.startsWith(tmpDir)) {
6567
6744
  return c.json({ error: "Invalid zip: paths must not escape archive" }, 400);
6568
6745
  }
@@ -6613,15 +6790,15 @@ var app16 = new Hono19().get("/", async (c) => {
6613
6790
  var skills_default = app16;
6614
6791
 
6615
6792
  // packages/daemon/src/web/api/typing.ts
6616
- import { zValidator as zValidator7 } from "@hono/zod-validator";
6617
- import { Hono as Hono20 } from "hono";
6618
- import { z as z7 } from "zod";
6619
- var typingSchema = z7.object({
6620
- channel: z7.string().min(1),
6621
- sender: z7.string().min(1),
6622
- active: z7.boolean()
6793
+ import { zValidator as zValidator8 } from "@hono/zod-validator";
6794
+ import { Hono as Hono21 } from "hono";
6795
+ import { z as z8 } from "zod";
6796
+ var typingSchema = z8.object({
6797
+ channel: z8.string().min(1),
6798
+ sender: z8.string().min(1),
6799
+ active: z8.boolean()
6623
6800
  });
6624
- var app17 = new Hono20().post("/:name/typing", zValidator7("json", typingSchema), (c) => {
6801
+ var app17 = new Hono21().post("/:name/typing", zValidator8("json", typingSchema), (c) => {
6625
6802
  const { channel, sender, active } = c.req.valid("json");
6626
6803
  const map = getTypingMap();
6627
6804
  if (active) {
@@ -6645,9 +6822,9 @@ var typing_default = app17;
6645
6822
 
6646
6823
  // packages/daemon/src/web/api/update.ts
6647
6824
  import { spawn as spawn3 } from "child_process";
6648
- import { Hono as Hono21 } from "hono";
6825
+ import { Hono as Hono22 } from "hono";
6649
6826
  var bin;
6650
- var app18 = new Hono21().get("/update", async (c) => {
6827
+ var app18 = new Hono22().get("/update", async (c) => {
6651
6828
  const result = await checkForUpdate();
6652
6829
  return c.json(result);
6653
6830
  }).post("/update", requireAdmin, async (c) => {
@@ -6665,13 +6842,13 @@ var app18 = new Hono21().get("/update", async (c) => {
6665
6842
  var update_default = app18;
6666
6843
 
6667
6844
  // packages/daemon/src/web/api/v1/conversations.ts
6668
- import { zValidator as zValidator8 } from "@hono/zod-validator";
6669
- import { Hono as Hono22 } from "hono";
6670
- import { z as z8 } from "zod";
6671
- var createSchema = z8.object({
6672
- participantNames: z8.array(z8.string()).min(1)
6845
+ import { zValidator as zValidator9 } from "@hono/zod-validator";
6846
+ import { Hono as Hono23 } from "hono";
6847
+ import { z as z9 } from "zod";
6848
+ var createSchema = z9.object({
6849
+ participantNames: z9.array(z9.string()).min(1)
6673
6850
  });
6674
- var app19 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
6851
+ var app19 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
6675
6852
  const user = c.get("user");
6676
6853
  const convs = await listConversationsWithParticipants(user.id);
6677
6854
  return c.json(convs);
@@ -6698,7 +6875,7 @@ var app19 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
6698
6875
  }
6699
6876
  const participants = await getParticipants(id);
6700
6877
  return c.json(participants);
6701
- }).post("/", zValidator8("json", createSchema), async (c) => {
6878
+ }).post("/", zValidator9("json", createSchema), async (c) => {
6702
6879
  const user = c.get("user");
6703
6880
  const body = c.req.valid("json");
6704
6881
  const participantIds = /* @__PURE__ */ new Set();
@@ -6747,7 +6924,7 @@ var app19 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
6747
6924
  }
6748
6925
  await markConversationRead(user.id, id);
6749
6926
  return c.json({ ok: true });
6750
- }).put("/:id/private", zValidator8("json", z8.object({ private: z8.boolean() })), async (c) => {
6927
+ }).put("/:id/private", zValidator9("json", z9.object({ private: z9.boolean() })), async (c) => {
6751
6928
  const id = c.req.param("id");
6752
6929
  const user = c.get("user");
6753
6930
  if (!await isParticipantOrOwner(id, user.id)) {
@@ -6767,7 +6944,7 @@ var conversations_default = app19;
6767
6944
 
6768
6945
  // packages/daemon/src/web/api/v1/events.ts
6769
6946
  import { desc as desc5, eq as eq7 } from "drizzle-orm";
6770
- import { Hono as Hono23 } from "hono";
6947
+ import { Hono as Hono24 } from "hono";
6771
6948
  import { streamSSE as streamSSE4 } from "hono/streaming";
6772
6949
 
6773
6950
  // packages/daemon/src/lib/events/brain-presence.ts
@@ -6830,7 +7007,7 @@ function getEventsSince(sinceId, allowedConversationIds, allowedActivityMind) {
6830
7007
  }
6831
7008
 
6832
7009
  // packages/daemon/src/web/api/v1/events.ts
6833
- var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
7010
+ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
6834
7011
  const user = c.get("user");
6835
7012
  const since = c.req.query("since");
6836
7013
  const sinceId = since ? Number(since) : 0;
@@ -6848,7 +7025,7 @@ var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
6848
7025
  conversations2 = await listConversationsWithParticipants(user.id);
6849
7026
  if (conversations2.length > 0) {
6850
7027
  const convIds = conversations2.map((c2) => c2.id);
6851
- const unreads = await getUnreadCounts(user.id, convIds);
7028
+ const unreads = await getUnreadCounts(user.id, convIds, user.username);
6852
7029
  for (const conv of conversations2) {
6853
7030
  conv.unreadCount = unreads[conv.id] ?? 0;
6854
7031
  }
@@ -6924,8 +7101,8 @@ var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
6924
7101
  });
6925
7102
  }, 15e3);
6926
7103
  cleanups.push(() => clearInterval(keepAlive));
6927
- await new Promise((resolve18) => {
6928
- stream.onAbort(() => resolve18());
7104
+ await new Promise((resolve17) => {
7105
+ stream.onAbort(() => resolve17());
6929
7106
  });
6930
7107
  } finally {
6931
7108
  for (const cleanup of cleanups) {
@@ -6941,15 +7118,15 @@ var events_default = app20;
6941
7118
 
6942
7119
  // packages/daemon/src/web/api/variants.ts
6943
7120
  import { existsSync as existsSync9, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8 } from "fs";
6944
- import { resolve as resolve15 } from "path";
6945
- import { Hono as Hono24 } from "hono";
7121
+ import { resolve as resolve14 } from "path";
7122
+ import { Hono as Hono25 } from "hono";
6946
7123
 
6947
7124
  // packages/daemon/src/lib/mind/spawn-server.ts
6948
7125
  import { spawn as spawn4 } from "child_process";
6949
7126
  import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync9 } from "fs";
6950
- import { resolve as resolve14 } from "path";
7127
+ import { resolve as resolve13 } from "path";
6951
7128
  function tsxBin(cwd) {
6952
- return resolve14(cwd, "node_modules", ".bin", "tsx");
7129
+ return resolve13(cwd, "node_modules", ".bin", "tsx");
6953
7130
  }
6954
7131
  async function spawnServer(cwd, port, options) {
6955
7132
  let cmd = tsxBin(cwd);
@@ -6971,31 +7148,31 @@ function spawnAttached(cmd, args, cwd) {
6971
7148
  cwd,
6972
7149
  stdio: ["ignore", "pipe", "pipe"]
6973
7150
  });
6974
- return new Promise((resolve18) => {
6975
- const timeout = setTimeout(() => resolve18(null), 3e4);
7151
+ return new Promise((resolve17) => {
7152
+ const timeout = setTimeout(() => resolve17(null), 3e4);
6976
7153
  function checkOutput(data) {
6977
7154
  const match = data.toString().match(/listening on :(\d+)/);
6978
7155
  if (match) {
6979
7156
  clearTimeout(timeout);
6980
- resolve18({ child, actualPort: parseInt(match[1], 10) });
7157
+ resolve17({ child, actualPort: parseInt(match[1], 10) });
6981
7158
  }
6982
7159
  }
6983
7160
  child.stdout?.on("data", checkOutput);
6984
7161
  child.stderr?.on("data", checkOutput);
6985
7162
  child.on("error", () => {
6986
7163
  clearTimeout(timeout);
6987
- resolve18(null);
7164
+ resolve17(null);
6988
7165
  });
6989
7166
  child.on("exit", () => {
6990
7167
  clearTimeout(timeout);
6991
- resolve18(null);
7168
+ resolve17(null);
6992
7169
  });
6993
7170
  });
6994
7171
  }
6995
7172
  function spawnDetached(cmd, args, cwd, logDir) {
6996
- const logsDir = logDir ?? resolve14(cwd, ".mind", "logs");
7173
+ const logsDir = logDir ?? resolve13(cwd, ".mind", "logs");
6997
7174
  mkdirSync8(logsDir, { recursive: true });
6998
- const logPath = resolve14(logsDir, "mind.log");
7175
+ const logPath = resolve13(logsDir, "mind.log");
6999
7176
  const logFd = openSync(logPath, "a");
7000
7177
  const child = spawn4(cmd, args, {
7001
7178
  cwd,
@@ -7067,7 +7244,7 @@ async function verify2(port) {
7067
7244
  }
7068
7245
 
7069
7246
  // packages/daemon/src/web/api/variants.ts
7070
- var app21 = new Hono24().get("/:name/variants", async (c) => {
7247
+ var app21 = new Hono25().get("/:name/variants", async (c) => {
7071
7248
  const name = c.req.param("name");
7072
7249
  const entry = await findMind(name);
7073
7250
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -7111,11 +7288,11 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7111
7288
  return c.json({ error: `Name already in use: ${variantName}` }, 409);
7112
7289
  }
7113
7290
  const projectRoot = mindDir(mindName);
7114
- const variantDir = resolve15(projectRoot, ".variants", variantName);
7291
+ const variantDir = resolve14(projectRoot, ".variants", variantName);
7115
7292
  if (existsSync9(variantDir)) {
7116
7293
  return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
7117
7294
  }
7118
- mkdirSync9(resolve15(projectRoot, ".variants"), { recursive: true });
7295
+ mkdirSync9(resolve14(projectRoot, ".variants"), { recursive: true });
7119
7296
  try {
7120
7297
  await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
7121
7298
  } catch (e) {
@@ -7128,7 +7305,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7128
7305
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
7129
7306
  await exec(cmd, args, {
7130
7307
  cwd: variantDir,
7131
- env: { ...process.env, HOME: resolve15(variantDir, "home") }
7308
+ env: { ...process.env, HOME: resolve14(variantDir, "home") }
7132
7309
  });
7133
7310
  } else {
7134
7311
  await exec("npm", ["install"], { cwd: variantDir });
@@ -7138,13 +7315,15 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7138
7315
  return c.json({ error: `npm install failed: ${msg}` }, 500);
7139
7316
  }
7140
7317
  if (body.soul) {
7141
- writeFileSync8(resolve15(variantDir, "home/SOUL.md"), body.soul);
7318
+ writeFileSync8(resolve14(variantDir, "home/SOUL.md"), body.soul);
7142
7319
  }
7143
7320
  const variantPort = body.port ?? await nextPort();
7144
7321
  await addVariant(variantName, mindName, variantPort, variantDir, variantName);
7145
7322
  if (!body.noStart) {
7146
7323
  try {
7147
- await getMindManager().startMind(variantName);
7324
+ const manager = getMindManager();
7325
+ manager.setPendingContext(variantName, { type: "split", parent: mindName });
7326
+ await manager.startMind(variantName);
7148
7327
  } catch (e) {
7149
7328
  const msg = e instanceof Error ? e.message : String(e);
7150
7329
  return c.json({ error: `Variant created but failed to start: ${msg}` }, 500);
@@ -7238,7 +7417,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7238
7417
  if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
7239
7418
  try {
7240
7419
  const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-446HHH5V.js");
7241
- const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-7LQHTRUX.js");
7420
+ const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-NUJAGLQJ.js");
7242
7421
  const tmpl = parentEntry.template ?? "claude";
7243
7422
  await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
7244
7423
  } catch (err) {
@@ -7251,7 +7430,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7251
7430
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
7252
7431
  await exec(cmd, args, {
7253
7432
  cwd: projectRoot,
7254
- env: { ...process.env, HOME: resolve15(projectRoot, "home") }
7433
+ env: { ...process.env, HOME: resolve14(projectRoot, "home") }
7255
7434
  });
7256
7435
  } else {
7257
7436
  await exec("npm", ["install"], { cwd: projectRoot });
@@ -7296,22 +7475,22 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7296
7475
  var variants_default = app21;
7297
7476
 
7298
7477
  // packages/daemon/src/web/api/volute/channels.ts
7299
- import { zValidator as zValidator9 } from "@hono/zod-validator";
7300
- import { Hono as Hono25 } from "hono";
7301
- import { z as z9 } from "zod";
7302
- var channelSettingsSchema = z9.object({
7303
- description: z9.string().nullable().optional(),
7304
- rules: z9.string().nullable().optional(),
7305
- charLimit: z9.number().int().positive().nullable().optional(),
7306
- private: z9.boolean().optional()
7478
+ import { zValidator as zValidator10 } from "@hono/zod-validator";
7479
+ import { Hono as Hono26 } from "hono";
7480
+ import { z as z10 } from "zod";
7481
+ var channelSettingsSchema = z10.object({
7482
+ description: z10.string().nullable().optional(),
7483
+ rules: z10.string().nullable().optional(),
7484
+ charLimit: z10.number().int().positive().nullable().optional(),
7485
+ private: z10.boolean().optional()
7307
7486
  });
7308
- var createSchema2 = z9.object({
7309
- name: z9.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
7487
+ var createSchema2 = z10.object({
7488
+ name: z10.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
7310
7489
  }).merge(channelSettingsSchema);
7311
- var inviteSchema = z9.object({
7312
- username: z9.string().min(1)
7490
+ var inviteSchema = z10.object({
7491
+ username: z10.string().min(1)
7313
7492
  });
7314
- var app22 = new Hono25().get("/", async (c) => {
7493
+ var app22 = new Hono26().get("/", async (c) => {
7315
7494
  const user = c.get("user");
7316
7495
  const channels2 = await listChannels();
7317
7496
  const results = await Promise.all(
@@ -7322,7 +7501,7 @@ var app22 = new Hono25().get("/", async (c) => {
7322
7501
  })
7323
7502
  );
7324
7503
  return c.json(results);
7325
- }).post("/", zValidator9("json", createSchema2), async (c) => {
7504
+ }).post("/", zValidator10("json", createSchema2), async (c) => {
7326
7505
  const user = c.get("user");
7327
7506
  const body = c.req.valid("json");
7328
7507
  try {
@@ -7350,7 +7529,7 @@ var app22 = new Hono25().get("/", async (c) => {
7350
7529
  participants,
7351
7530
  settings: formatChannelSettings(settings)
7352
7531
  });
7353
- }).patch("/:name", zValidator9("json", channelSettingsSchema), async (c) => {
7532
+ }).patch("/:name", zValidator10("json", channelSettingsSchema), async (c) => {
7354
7533
  const name = c.req.param("name");
7355
7534
  const user = c.get("user");
7356
7535
  const body = c.req.valid("json");
@@ -7382,7 +7561,7 @@ var app22 = new Hono25().get("/", async (c) => {
7382
7561
  if (!ch) return c.json({ error: "Channel not found" }, 404);
7383
7562
  const participants = await getParticipants(ch.id);
7384
7563
  return c.json(participants);
7385
- }).post("/:name/invite", zValidator9("json", inviteSchema), async (c) => {
7564
+ }).post("/:name/invite", zValidator10("json", inviteSchema), async (c) => {
7386
7565
  const name = c.req.param("name");
7387
7566
  const inviter = c.get("user");
7388
7567
  const { username } = c.req.valid("json");
@@ -7408,27 +7587,27 @@ var app22 = new Hono25().get("/", async (c) => {
7408
7587
  var channels_default2 = app22;
7409
7588
 
7410
7589
  // packages/daemon/src/web/api/volute/chat.ts
7411
- import { zValidator as zValidator10 } from "@hono/zod-validator";
7412
- import { Hono as Hono26 } from "hono";
7590
+ import { zValidator as zValidator11 } from "@hono/zod-validator";
7591
+ import { Hono as Hono27 } from "hono";
7413
7592
  import { streamSSE as streamSSE5 } from "hono/streaming";
7414
- import { z as z10 } from "zod";
7415
- var fileSchema = z10.object({
7416
- filename: z10.string(),
7417
- data: z10.string()
7593
+ import { z as z11 } from "zod";
7594
+ var fileSchema = z11.object({
7595
+ filename: z11.string(),
7596
+ data: z11.string()
7418
7597
  // base64
7419
7598
  });
7420
- var chatSchema = z10.object({
7421
- message: z10.string().optional(),
7422
- conversationId: z10.string().optional(),
7423
- targetMind: z10.string().optional(),
7424
- sender: z10.string().optional(),
7425
- images: z10.array(
7426
- z10.object({
7427
- media_type: z10.string(),
7428
- data: z10.string()
7599
+ var chatSchema = z11.object({
7600
+ message: z11.string().optional(),
7601
+ conversationId: z11.string().optional(),
7602
+ targetMind: z11.string().optional(),
7603
+ sender: z11.string().optional(),
7604
+ images: z11.array(
7605
+ z11.object({
7606
+ media_type: z11.string(),
7607
+ data: z11.string()
7429
7608
  })
7430
7609
  ).optional(),
7431
- files: z10.array(fileSchema).optional()
7610
+ files: z11.array(fileSchema).optional()
7432
7611
  });
7433
7612
  var MAX_FILE_SIZE2 = 50 * 1024 * 1024;
7434
7613
  function stageFilesForMinds(files, targetMinds, senderName) {
@@ -7456,9 +7635,9 @@ function stageFilesForMinds(files, targetMinds, senderName) {
7456
7635
  }
7457
7636
  return { notifications };
7458
7637
  }
7459
- var unifiedChatApp = new Hono26().post(
7638
+ var unifiedChatApp = new Hono27().post(
7460
7639
  "/chat",
7461
- zValidator10("json", chatSchema),
7640
+ zValidator11("json", chatSchema),
7462
7641
  async (c) => {
7463
7642
  const user = c.get("user");
7464
7643
  const body = c.req.valid("json");
@@ -7579,6 +7758,19 @@ var unifiedChatApp = new Hono26().post(
7579
7758
  senderBase = await getBaseName(senderName);
7580
7759
  outboundTurnId = getActiveTurnId(senderBase, c.get("mindSession"));
7581
7760
  }
7761
+ if (senderIsMind && senderBase) {
7762
+ const gate = await checkStaleSend(senderBase, conversationId, [senderName, senderBase]);
7763
+ if (gate.held && gate.unseen) {
7764
+ const label = buildVoluteSlug({
7765
+ participants,
7766
+ mindUsername: senderName,
7767
+ conversationId,
7768
+ convType: conv.type,
7769
+ convName
7770
+ });
7771
+ return c.json({ ok: true, held: true, notice: formatHoldNotice(label, gate.unseen) });
7772
+ }
7773
+ }
7582
7774
  const message = await addMessage(conversationId, "user", senderName, contentBlocks, {
7583
7775
  turnId: outboundTurnId
7584
7776
  });
@@ -7619,7 +7811,6 @@ var unifiedChatApp = new Hono26().post(
7619
7811
  conversationId,
7620
7812
  contentBlocks,
7621
7813
  senderName,
7622
- senderIsMind: !!senderIsMind,
7623
7814
  participants,
7624
7815
  isDM,
7625
7816
  slugExtra: { convType: conv.type, convName },
@@ -7638,7 +7829,7 @@ var unifiedChatApp = new Hono26().post(
7638
7829
  return c.json({ ok: true, conversationId, outboundId });
7639
7830
  }
7640
7831
  );
7641
- var app23 = new Hono26().get("/:name/conversations/:id/events", async (c) => {
7832
+ var app23 = new Hono27().get("/:name/conversations/:id/events", async (c) => {
7642
7833
  const conversationId = c.req.param("id");
7643
7834
  const user = c.get("user");
7644
7835
  if (user.id !== 0 && !await isParticipantOrOwner(conversationId, user.id)) {
@@ -7655,11 +7846,11 @@ var app23 = new Hono26().get("/:name/conversations/:id/events", async (c) => {
7655
7846
  if (!stream.aborted) console.error("[chat] SSE ping error:", err);
7656
7847
  });
7657
7848
  }, 15e3);
7658
- await new Promise((resolve18) => {
7849
+ await new Promise((resolve17) => {
7659
7850
  stream.onAbort(() => {
7660
7851
  unsubscribe();
7661
7852
  clearInterval(keepAlive);
7662
- resolve18();
7853
+ resolve17();
7663
7854
  });
7664
7855
  });
7665
7856
  });
@@ -7667,14 +7858,14 @@ var app23 = new Hono26().get("/:name/conversations/:id/events", async (c) => {
7667
7858
  var chat_default = app23;
7668
7859
 
7669
7860
  // packages/daemon/src/web/api/volute/conversations.ts
7670
- import { zValidator as zValidator11 } from "@hono/zod-validator";
7671
- import { Hono as Hono27 } from "hono";
7672
- import { z as z11 } from "zod";
7673
- var createConvSchema = z11.object({
7674
- participantIds: z11.array(z11.number()).optional(),
7675
- participantNames: z11.array(z11.string()).optional()
7861
+ import { zValidator as zValidator12 } from "@hono/zod-validator";
7862
+ import { Hono as Hono28 } from "hono";
7863
+ import { z as z12 } from "zod";
7864
+ var createConvSchema = z12.object({
7865
+ participantIds: z12.array(z12.number()).optional(),
7866
+ participantNames: z12.array(z12.string()).optional()
7676
7867
  });
7677
- var app24 = new Hono27().get("/:name/conversations", async (c) => {
7868
+ var app24 = new Hono28().get("/:name/conversations", async (c) => {
7678
7869
  const name = c.req.param("name");
7679
7870
  const user = c.get("user");
7680
7871
  let lookupId = user.id;
@@ -7684,7 +7875,7 @@ var app24 = new Hono27().get("/:name/conversations", async (c) => {
7684
7875
  }
7685
7876
  const convs = await listConversationsForUser(lookupId);
7686
7877
  return c.json(convs);
7687
- }).post("/:name/conversations", zValidator11("json", createConvSchema), async (c) => {
7878
+ }).post("/:name/conversations", zValidator12("json", createConvSchema), async (c) => {
7688
7879
  const name = c.req.param("name");
7689
7880
  const user = c.get("user");
7690
7881
  const body = c.req.valid("json");
@@ -7780,7 +7971,7 @@ var conversations_default2 = app24;
7780
7971
 
7781
7972
  // packages/daemon/src/web/app.ts
7782
7973
  var httpLog = logger_default.child("http");
7783
- var app25 = new Hono28();
7974
+ var app25 = new Hono29();
7784
7975
  app25.onError((err, c) => {
7785
7976
  if (err instanceof HTTPException) {
7786
7977
  return err.getResponse();
@@ -7847,10 +8038,11 @@ app25.use("/api/skills/*", authMiddleware);
7847
8038
  app25.use("/api/extensions/*", authMiddleware);
7848
8039
  app25.use("/api/bridges/*", authMiddleware);
7849
8040
  app25.use("/api/config/*", authMiddleware);
8041
+ app25.use("/api/backup/*", authMiddleware);
7850
8042
  app25.use("/api/v1/*", authMiddleware);
7851
8043
  app25.route("/api/setup", setup_default);
7852
8044
  app25.route("/api/config", config_default);
7853
- var routes = app25.route("/api/activity", activity_default).route("/api/keys", keys_default).route("/api/auth", auth_default).route("/api/system", system_default).route("/api/system", update_default).route("/api/minds", minds_default).route("/api/minds", chat_default).route("/api/minds", schedules_default).route("/api/minds", logs_default).route("/api/minds", typing_default).route("/api/minds", variants_default).route("/api/minds", file_sharing_default).route("/api/minds", files_default).route("/api/minds", channels_default).route("/api/minds", env_default).route("/api/minds", mind_skills_default).route("/api/minds", conversations_default2).route("/api/env", sharedEnvApp).route("/api/prompts", prompts_default).route("/api/skills", skills_default).route("/api/bridges", bridges_default).route("/api/extensions", extensions_default).route("/api/v1/conversations", conversations_default).route("/api/v1/events", events_default).route("/api/v1", unifiedChatApp).route("/api/v1/channels", channels_default2).route("/api/v1/history", history_default);
8045
+ var routes = app25.route("/api/activity", activity_default).route("/api/keys", keys_default).route("/api/auth", auth_default).route("/api/system", system_default).route("/api/system", update_default).route("/api/backup", backup_default).route("/api/minds", minds_default).route("/api/minds", chat_default).route("/api/minds", schedules_default).route("/api/minds", logs_default).route("/api/minds", typing_default).route("/api/minds", variants_default).route("/api/minds", file_sharing_default).route("/api/minds", files_default).route("/api/minds", channels_default).route("/api/minds", env_default).route("/api/minds", mind_skills_default).route("/api/minds", conversations_default2).route("/api/env", sharedEnvApp).route("/api/prompts", prompts_default).route("/api/skills", skills_default).route("/api/bridges", bridges_default).route("/api/extensions", extensions_default).route("/api/v1/conversations", conversations_default).route("/api/v1/events", events_default).route("/api/v1", unifiedChatApp).route("/api/v1/channels", channels_default2).route("/api/v1/history", history_default);
7854
8046
  app25.route("/api/v1/minds", minds_default);
7855
8047
  app25.route("/api/v1/minds", chat_default);
7856
8048
  app25.route("/api/v1/minds", typing_default);
@@ -7872,7 +8064,7 @@ var app_default = app25;
7872
8064
  import { existsSync as existsSync10 } from "fs";
7873
8065
  import { readFile as readFile2, stat as stat2 } from "fs/promises";
7874
8066
  import { createServer as createHttpsServer } from "https";
7875
- import { dirname as dirname2, extname as extname3, resolve as resolve16 } from "path";
8067
+ import { dirname as dirname2, extname as extname3, resolve as resolve15 } from "path";
7876
8068
  import { serve } from "@hono/node-server";
7877
8069
  var MIME_TYPES2 = {
7878
8070
  ".html": "text/html",
@@ -7891,7 +8083,7 @@ async function startServer({
7891
8083
  let assetsDir = "";
7892
8084
  let searchDir = dirname2(new URL(import.meta.url).pathname);
7893
8085
  for (let i = 0; i < 5; i++) {
7894
- const candidate = resolve16(searchDir, "dist", "web-assets");
8086
+ const candidate = resolve15(searchDir, "dist", "web-assets");
7895
8087
  if (existsSync10(candidate)) {
7896
8088
  assetsDir = candidate;
7897
8089
  break;
@@ -7902,20 +8094,20 @@ async function startServer({
7902
8094
  app_default.get("*", async (c) => {
7903
8095
  const urlPath = new URL(c.req.url).pathname;
7904
8096
  if (urlPath.startsWith("/api/") || urlPath.startsWith("/ext/")) return c.notFound();
7905
- const filePath = resolve16(assetsDir, urlPath.slice(1));
8097
+ const filePath = resolve15(assetsDir, urlPath.slice(1));
7906
8098
  if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
7907
8099
  const s = await stat2(filePath).catch(() => null);
7908
8100
  if (s?.isFile()) {
7909
8101
  const ext = extname3(filePath);
7910
8102
  const mime = MIME_TYPES2[ext] || "application/octet-stream";
7911
8103
  const body = await readFile2(filePath);
7912
- const basename2 = filePath.slice(filePath.lastIndexOf("/") + 1);
7913
- const nameWithoutExt = basename2.slice(0, basename2.lastIndexOf("."));
8104
+ const basename = filePath.slice(filePath.lastIndexOf("/") + 1);
8105
+ const nameWithoutExt = basename.slice(0, basename.lastIndexOf("."));
7914
8106
  const isHashed = /[-.][\da-f]{8,}$/.test(nameWithoutExt);
7915
8107
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
7916
8108
  return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
7917
8109
  }
7918
- const indexPath = resolve16(assetsDir, "index.html");
8110
+ const indexPath = resolve15(assetsDir, "index.html");
7919
8111
  const indexStat = await stat2(indexPath).catch(() => null);
7920
8112
  if (indexStat?.isFile()) {
7921
8113
  const body = await readFile2(indexPath, "utf-8");
@@ -7932,10 +8124,10 @@ async function startServer({
7932
8124
  createServer: createHttpsServer,
7933
8125
  serverOptions: { key: tls.key, cert: tls.cert }
7934
8126
  });
7935
- await new Promise((resolve18, reject) => {
8127
+ await new Promise((resolve17, reject) => {
7936
8128
  server2.on("listening", () => {
7937
8129
  logger_default.info("Volute UI running (https)", { hostname, port });
7938
- resolve18();
8130
+ resolve17();
7939
8131
  });
7940
8132
  server2.on("error", (err) => {
7941
8133
  reject(err);
@@ -7943,13 +8135,13 @@ async function startServer({
7943
8135
  });
7944
8136
  const internalPort = port + 1;
7945
8137
  const internalServer = serve({ fetch: app_default.fetch, port: internalPort, hostname: "127.0.0.1" });
7946
- await new Promise((resolve18, reject) => {
8138
+ await new Promise((resolve17, reject) => {
7947
8139
  internalServer.on("listening", () => {
7948
8140
  logger_default.info("Volute API running (http, internal)", {
7949
8141
  hostname: "127.0.0.1",
7950
8142
  port: internalPort
7951
8143
  });
7952
- resolve18();
8144
+ resolve17();
7953
8145
  });
7954
8146
  internalServer.on("error", (err) => {
7955
8147
  reject(err);
@@ -7958,10 +8150,10 @@ async function startServer({
7958
8150
  return { server: server2, internalPort };
7959
8151
  }
7960
8152
  const server = serve({ fetch: app_default.fetch, port, hostname });
7961
- await new Promise((resolve18, reject) => {
8153
+ await new Promise((resolve17, reject) => {
7962
8154
  server.on("listening", () => {
7963
8155
  logger_default.info("Volute API running (http)", { hostname, port });
7964
- resolve18();
8156
+ resolve17();
7965
8157
  });
7966
8158
  server.on("error", (err) => {
7967
8159
  reject(err);
@@ -7972,17 +8164,17 @@ async function startServer({
7972
8164
 
7973
8165
  // packages/daemon/src/daemon.ts
7974
8166
  if (!process.env.VOLUTE_HOME) {
7975
- process.env.VOLUTE_HOME = resolve17(homedir3(), ".volute");
8167
+ process.env.VOLUTE_HOME = resolve16(homedir3(), ".volute");
7976
8168
  }
7977
8169
  if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
7978
8170
  process.env.TZ = process.env.VOLUTE_TIMEZONE;
7979
8171
  }
7980
8172
  function writeDaemonConfig(systemDir, config2, token) {
7981
- const configPath = resolve17(systemDir, "daemon.json");
8173
+ const configPath = resolve16(systemDir, "daemon.json");
7982
8174
  writeFileSync9(configPath, `${JSON.stringify(config2, null, 2)}
7983
8175
  `, { mode: 420 });
7984
8176
  chmodSync(configPath, 420);
7985
- const tokenPath = resolve17(systemDir, "daemon-token");
8177
+ const tokenPath = resolve16(systemDir, "daemon-token");
7986
8178
  writeFileSync9(tokenPath, `${token}
7987
8179
  `, { mode: 384 });
7988
8180
  chmodSync(tokenPath, 384);
@@ -7993,7 +8185,7 @@ async function startDaemon(opts) {
7993
8185
  const home = voluteHome();
7994
8186
  const systemDir = voluteSystemDir();
7995
8187
  if (!opts.foreground) {
7996
- const rotatingLog = new RotatingLog(resolve17(systemDir, "daemon.log"));
8188
+ const rotatingLog = new RotatingLog(resolve16(systemDir, "daemon.log"));
7997
8189
  logger_default.setOutput((line) => rotatingLog.write(`${line}
7998
8190
  `));
7999
8191
  const write = (...args) => rotatingLog.write(`${format(...args)}
@@ -8003,26 +8195,32 @@ async function startDaemon(opts) {
8003
8195
  console.warn = write;
8004
8196
  console.info = write;
8005
8197
  }
8006
- const DAEMON_PID_PATH = resolve17(systemDir, "daemon.pid");
8007
- const DAEMON_JSON_PATH = resolve17(systemDir, "daemon.json");
8008
- const DAEMON_TOKEN_PATH = resolve17(systemDir, "daemon-token");
8198
+ const DAEMON_PID_PATH = resolve16(systemDir, "daemon.pid");
8199
+ const DAEMON_JSON_PATH = resolve16(systemDir, "daemon.json");
8200
+ const DAEMON_TOKEN_PATH = resolve16(systemDir, "daemon-token");
8009
8201
  mkdirSync10(home, { recursive: true });
8010
8202
  ensureSystemDir();
8011
- const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-25MMJ3J4.js");
8203
+ const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-73YBJZQL.js");
8012
8204
  migrateConfigSecrets();
8013
8205
  migrateSetupCompleted();
8014
- const { migrateAiModelQualification } = await import("./ai-service-FBCCEYF5.js");
8206
+ const { migrateAiModelQualification } = await import("./ai-service-534WUSDL.js");
8015
8207
  migrateAiModelQualification();
8016
- await (await import("./db-CZV62BOQ.js")).getDb();
8208
+ await (await import("./db-JFLCJCUG.js")).getDb();
8017
8209
  try {
8018
8210
  const { eq: eq8, and: and6 } = await import("drizzle-orm");
8019
- const { users: users2 } = await import("./schema-LRUTFOER.js");
8020
- const db = await (await import("./db-CZV62BOQ.js")).getDb();
8211
+ const { users: users2 } = await import("./schema-PVNG3PQM.js");
8212
+ const db = await (await import("./db-JFLCJCUG.js")).getDb();
8021
8213
  await db.update(users2).set({ role: "system" }).where(and6(eq8(users2.user_type, "system"), eq8(users2.role, "user")));
8022
8214
  } catch (err) {
8023
8215
  logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
8024
8216
  }
8025
- const { initSandbox } = await import("./sandbox-SJH3XOPZ.js");
8217
+ try {
8218
+ const { migrateAvatarSizes } = await import("./avatar-image-BNWEXSA2.js");
8219
+ await migrateAvatarSizes();
8220
+ } catch (err) {
8221
+ logger_default.warn("avatar size migration failed", logger_default.errorData(err));
8222
+ }
8223
+ const { initSandbox } = await import("./sandbox-72MWV4JL.js");
8026
8224
  await initSandbox();
8027
8225
  try {
8028
8226
  await syncBuiltinSkills();
@@ -8049,7 +8247,7 @@ async function startDaemon(opts) {
8049
8247
  logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
8050
8248
  }
8051
8249
  try {
8052
- const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-3RIG6GKN.js");
8250
+ const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-FRZJVQCS.js");
8053
8251
  await getOrCreateSystemUser2();
8054
8252
  } catch (err) {
8055
8253
  logger_default.warn(
@@ -8057,13 +8255,13 @@ async function startDaemon(opts) {
8057
8255
  logger_default.errorData(err)
8058
8256
  );
8059
8257
  }
8060
- const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes2(32).toString("hex");
8061
- const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-25MMJ3J4.js");
8258
+ const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes3(32).toString("hex");
8259
+ const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-73YBJZQL.js");
8062
8260
  const globalCfg = readGlobalConfig2();
8063
8261
  let tls;
8064
8262
  if (opts.tailscale || globalCfg.tailscale) {
8065
8263
  try {
8066
- const { getTailscaleTls } = await import("./tailscale-Q7ZJL7S7.js");
8264
+ const { getTailscaleTls } = await import("./tailscale-QAWVKQKU.js");
8067
8265
  const tlsConfig = await getTailscaleTls();
8068
8266
  tls = { key: tlsConfig.key, cert: tlsConfig.cert };
8069
8267
  logger_default.info("Tailscale HTTPS enabled", { hostname: tlsConfig.hostname });
@@ -8109,6 +8307,8 @@ async function startDaemon(opts) {
8109
8307
  sleepManager.start();
8110
8308
  const summarizer = initSummarizer();
8111
8309
  summarizer.start();
8310
+ const backupManager2 = initBackupManager();
8311
+ backupManager2.start();
8112
8312
  const unsubscribeWebhook = initWebhook();
8113
8313
  const orphanedTurns = await completeOrphanedTurns();
8114
8314
  summarizeOrphanedTurns(orphanedTurns);
@@ -8141,10 +8341,10 @@ async function startDaemon(opts) {
8141
8341
  await Promise.all(workers);
8142
8342
  }
8143
8343
  try {
8144
- const { isSetupComplete: isSetupComplete2 } = await import("./setup-25MMJ3J4.js");
8344
+ const { isSetupComplete: isSetupComplete2 } = await import("./setup-73YBJZQL.js");
8145
8345
  if (isSetupComplete2()) {
8146
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-53DQPRNR.js");
8147
- const { startSpiritFull } = await import("./mind-service-2C7AINBO.js");
8346
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-II3HOERM.js");
8347
+ const { startSpiritFull } = await import("./mind-service-BF2LUQMH.js");
8148
8348
  await ensureSpiritProject();
8149
8349
  await syncSpiritTemplate();
8150
8350
  const spiritEntry = await findMind("volute");
@@ -8161,7 +8361,7 @@ async function startDaemon(opts) {
8161
8361
  bridgeManager.startBridges(daemonPort).catch((err) => {
8162
8362
  logger_default.warn("failed to start bridges", logger_default.errorData(err));
8163
8363
  });
8164
- import("./cloud-sync-KOEBUFW5.js").then(
8364
+ import("./cloud-sync-Y7LQPRE3.js").then(
8165
8365
  ({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
8166
8366
  logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
8167
8367
  })
@@ -8169,7 +8369,7 @@ async function startDaemon(opts) {
8169
8369
  logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
8170
8370
  });
8171
8371
  try {
8172
- const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-SRQJCQEK.js");
8372
+ const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-CODJOUW2.js");
8173
8373
  backfillTemplateHashes();
8174
8374
  notifyVersionUpdate().catch((err) => {
8175
8375
  logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
@@ -8237,6 +8437,7 @@ async function startDaemon(opts) {
8237
8437
  safe("mailPoller.stop", () => mailPoller.stop());
8238
8438
  safe("tokenBudget.stop", () => tokenBudget.stop());
8239
8439
  safe("summarizer.stop", () => summarizer.stop());
8440
+ safe("backupManager.stop", () => backupManager2.stop());
8240
8441
  safe("stopApiKeyRefresh", stopApiKeyRefresh);
8241
8442
  safe("delivery.dispose", () => delivery.dispose());
8242
8443
  await safe("bridgeManager.stopAll", () => bridgeManager.stopAll());