volute 0.44.0 → 0.45.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/dist/{activity-events-OMCSM7XW.js → activity-events-BUR2RYTJ.js} +2 -2
  2. package/dist/{ai-service-7PHSRDMO.js → ai-service-UODCCE4O.js} +3 -3
  3. package/dist/{archive-6R4TZMYI.js → archive-WS2L2VIQ.js} +2 -2
  4. package/dist/{auth-FRZJVQCS.js → auth-FLAEXXZK.js} +3 -3
  5. package/dist/{avatar-image-BNWEXSA2.js → avatar-image-6KY6UU4D.js} +3 -3
  6. package/dist/backup-TST5C2YN.js +381 -0
  7. package/dist/{chat-I4EDDIQC.js → chat-76MRWWQX.js} +2 -2
  8. package/dist/{chunk-5AHYQHNT.js → chunk-4JOQZPCE.js} +3 -2
  9. package/dist/{chunk-2BONPXAF.js → chunk-6EMWJZBK.js} +1 -1
  10. package/dist/{chunk-ZMIMSIIT.js → chunk-7C44R625.js} +1 -1
  11. package/dist/{chunk-I2Y2YHIO.js → chunk-7ZUB63PS.js} +4 -4
  12. package/dist/{chunk-LAXUUY7O.js → chunk-A7WQZKOU.js} +2 -2
  13. package/dist/{chunk-H7IYFRAL.js → chunk-ALKYQULU.js} +10 -5
  14. package/dist/{chunk-KP3KWNG6.js → chunk-CDPBTTZO.js} +2 -2
  15. package/dist/{chunk-SQL7M4HJ.js → chunk-DRJ24GXK.js} +2 -2
  16. package/dist/{chunk-HVU45COX.js → chunk-EJVPTVTI.js} +1 -1
  17. package/dist/{chunk-PNV24SEP.js → chunk-F7H6ATM4.js} +14 -2
  18. package/dist/{chunk-7FT24JBQ.js → chunk-FR6S2KNN.js} +10 -10
  19. package/dist/chunk-FXORA5JG.js +327 -0
  20. package/dist/{chunk-3ERIL673.js → chunk-H2X54EHC.js} +1 -1
  21. package/dist/{chunk-J47TIYHA.js → chunk-IHKGWTGT.js} +1 -1
  22. package/dist/{chunk-3GYVW2X3.js → chunk-JZ62SYWR.js} +1 -1
  23. package/dist/{chunk-EQZD4YU3.js → chunk-NYC5U6K7.js} +9 -9
  24. package/dist/{chunk-FZMEVCWC.js → chunk-OP4JG2BS.js} +9 -6
  25. package/dist/{chunk-CU6OFXMM.js → chunk-PFZBNKUH.js} +9 -0
  26. package/dist/{chunk-QMJJWTNL.js → chunk-QCN24XEN.js} +1 -1
  27. package/dist/{chunk-7KWANSLX.js → chunk-QNQMSWZE.js} +3 -3
  28. package/dist/{chunk-UMI4UIJG.js → chunk-R77O2WMK.js} +1 -1
  29. package/dist/{chunk-IEWZ7VD7.js → chunk-RRNXJOKB.js} +2 -2
  30. package/dist/{chunk-FHWUQZXE.js → chunk-RXEEYDIB.js} +1 -1
  31. package/dist/{chunk-CYI534DJ.js → chunk-T6HYVHPG.js} +2 -2
  32. package/dist/{chunk-Q2XBKQ2D.js → chunk-TQJ6ZYVY.js} +2 -2
  33. package/dist/{chunk-NF75HPNR.js → chunk-UYLGEDVD.js} +40 -15
  34. package/dist/{chunk-OMETFX5H.js → chunk-YT7PEESJ.js} +261 -102
  35. package/dist/{chunk-5GT7URXJ.js → chunk-ZDZISKCL.js} +1 -1
  36. package/dist/cli.js +21 -15
  37. package/dist/{cloud-sync-6WJ7WFYD.js → cloud-sync-3OJOPZRT.js} +16 -16
  38. package/dist/{conversations-WAJYZKOC.js → conversations-JZTD6KLR.js} +3 -3
  39. package/dist/{create-YZIV5OJC.js → create-IOV4GCRX.js} +1 -1
  40. package/dist/{daemon-restart-OUJVINXV.js → daemon-restart-TIHKVVVA.js} +6 -6
  41. package/dist/daemon.js +562 -321
  42. package/dist/{db-JFLCJCUG.js → db-MF2JNRUW.js} +1 -1
  43. package/dist/delivery-manager-VDVKVA46.js +32 -0
  44. package/dist/{delivery-router-GODSIS62.js → delivery-router-N4A7ZC5T.js} +2 -2
  45. package/dist/{down-XCAZXWLB.js → down-U2CZ23M4.js} +4 -4
  46. package/dist/echo-text-6JJOPUD4.js +32 -0
  47. package/dist/{exec-4GWHAHS3.js → exec-G3ZRST4Z.js} +2 -2
  48. package/dist/{export-ID7YUSLZ.js → export-GGIVO76O.js} +2 -2
  49. package/dist/{extensions-3QNDGW5E.js → extensions-JONTW2HF.js} +16 -16
  50. package/dist/{files-BQ2WB5KC.js → files-4LN3EN7Q.js} +2 -2
  51. package/dist/{import-SKID37QX.js → import-42YNQBF4.js} +5 -5
  52. package/dist/{isolation-5MB3J73F.js → isolation-YMGZZ4E5.js} +2 -2
  53. package/dist/{join-RXPXGV4L.js → join-ZJV7W6MO.js} +4 -0
  54. package/dist/{login-LM4NF4ZB.js → login-M6OJUPQ2.js} +1 -1
  55. package/dist/{logout-CTJVIZGA.js → logout-WQBWO77G.js} +1 -1
  56. package/dist/message-delivery-3C65ZI6L.js +34 -0
  57. package/dist/{mind-MI7Z6KM2.js → mind-DWB6XYCH.js} +7 -7
  58. package/dist/{mind-activity-tracker-BGHJE7XA.js → mind-activity-tracker-POBLU3LC.js} +3 -3
  59. package/dist/mind-service-3F4I46CI.js +36 -0
  60. package/dist/{package-5B4XDTJH.js → package-A7KXT67Q.js} +1 -1
  61. package/dist/{registry-NUJAGLQJ.js → registry-OUZBZ3Q4.js} +5 -1
  62. package/dist/{sandbox-IOPWWILM.js → sandbox-ZJ7QA6Z6.js} +3 -3
  63. package/dist/scheduler-P6DXLLXI.js +30 -0
  64. package/dist/{seed-UUPVQWFB.js → seed-HCP5NYKH.js} +1 -1
  65. package/dist/{seed-cmd-7XPKDQUC.js → seed-cmd-ILOGNIFB.js} +2 -2
  66. package/dist/{seed-create-IZ4M5ESO.js → seed-create-OURS2LS4.js} +3 -3
  67. package/dist/{seed-sprout-POJXHJWV.js → seed-sprout-ELDFDAN6.js} +7 -7
  68. package/dist/{send-O6W53VBM.js → send-AAIOPJAV.js} +2 -2
  69. package/dist/{service-AQVPUANO.js → service-UOCLXDWR.js} +3 -3
  70. package/dist/{service-install-4QNUDKLM.js → service-install-4HHFDDWY.js} +4 -4
  71. package/dist/{setup-5GCO3CUB.js → setup-DQM5VPY4.js} +6 -6
  72. package/dist/{setup-MLRKNP7Y.js → setup-Y2EJI3GG.js} +2 -2
  73. package/dist/skills/imagegen/scripts/imagegen.ts +100 -40
  74. package/dist/skills/memory/SKILL.md +2 -1
  75. package/dist/skills/orientation/SKILL.md +1 -1
  76. package/dist/skills/plan-coordinator/SKILL.md +2 -2
  77. package/dist/skills/volute-admin/SKILL.md +9 -6
  78. package/dist/skills/volute-mind/SKILL.md +20 -17
  79. package/dist/skills/volute-mind/references/extensions.md +5 -3
  80. package/dist/skills/volute-mind/references/integrations.md +2 -2
  81. package/dist/skills/volute-mind/references/routing.md +19 -23
  82. package/dist/skills/volute-mind/references/variants.md +10 -8
  83. package/dist/{skills-775C7QFF.js → skills-BKINFL7W.js} +4 -4
  84. package/dist/sleep-manager-HCUH4PM4.js +34 -0
  85. package/dist/{spirit-IK5OYWMV.js → spirit-DBTIW7P4.js} +7 -7
  86. package/dist/{sprout-ZY5QGOEL.js → sprout-W3KC7UGK.js} +1 -1
  87. package/dist/{src-XFY3XDD6.js → src-OJHARHTF.js} +28 -17
  88. package/dist/{status-E5DQNCAO.js → status-SWRVGXBI.js} +4 -4
  89. package/dist/system-chat-XOALE2RD.js +36 -0
  90. package/dist/{tailscale-QAWVKQKU.js → tailscale-3XOKOW7T.js} +1 -1
  91. package/dist/{turn-tracker-RWZMY7M6.js → turn-tracker-2W6Q2NSR.js} +6 -4
  92. package/dist/{up-FLCDR2UB.js → up-FTK7CTO3.js} +5 -5
  93. package/dist/{update-7TYVH5FM.js → update-SWAYZRWJ.js} +4 -4
  94. package/dist/{update-check-VSCSJ7KX.js → update-check-PQ2MZ47K.js} +2 -2
  95. package/dist/{upgrade-37DAGF6H.js → upgrade-NWAZ7MLD.js} +1 -1
  96. package/dist/{version-notify-B67N35A3.js → version-notify-3XMAIQTE.js} +17 -17
  97. package/dist/{volute-config-TS62GS6A.js → volute-config-A52FHWKM.js} +5 -1
  98. package/dist/web-assets/assets/{index-dJdNzAPn.css → index-B1JBQv2m.css} +1 -1
  99. package/dist/web-assets/assets/index-Bc2m8gRC.js +86 -0
  100. package/dist/web-assets/index.html +2 -2
  101. package/package.json +1 -1
  102. package/packages/extensions/plan/skills/plan/SKILL.md +1 -1
  103. package/templates/_base/.init/.config/prompts.json +1 -1
  104. package/templates/_base/.init/.local/hooks/startup-context.ts +0 -8
  105. package/templates/_base/.init/MEMORY.md +2 -1
  106. package/templates/_base/home/VOLUTE.md +6 -9
  107. package/templates/_base/src/lib/file-handler.ts +3 -3
  108. package/templates/_base/src/lib/router.ts +21 -25
  109. package/templates/_base/src/lib/startup.ts +3 -1
  110. package/templates/_base/src/lib/types.ts +2 -2
  111. package/templates/claude/.init/CLAUDE.md +1 -1
  112. package/templates/claude/src/agent.ts +97 -12
  113. package/templates/claude/src/lib/message-channel.ts +23 -0
  114. package/templates/claude/src/lib/session-reaper.ts +37 -0
  115. package/templates/claude/src/lib/stream-consumer.ts +7 -4
  116. package/templates/claude/src/server.ts +1 -0
  117. package/templates/codex/.init/AGENTS.md +4 -2
  118. package/templates/codex/src/agent.ts +31 -13
  119. package/templates/pi/.init/MINDS.md +4 -2
  120. package/templates/pi/src/agent.ts +18 -7
  121. package/templates/pi/src/lib/event-handler.ts +6 -2
  122. package/dist/delivery-manager-TEVOHX5W.js +0 -32
  123. package/dist/echo-text-T7ZA5EYD.js +0 -32
  124. package/dist/message-delivery-2EA5LLMD.js +0 -34
  125. package/dist/mind-service-S3SY7HAM.js +0 -36
  126. package/dist/scheduler-CXWQ6Z4E.js +0 -30
  127. package/dist/sleep-manager-HINI6Y46.js +0 -34
  128. package/dist/system-chat-4DQZOEZI.js +0 -34
  129. package/dist/web-assets/assets/index-Domoz5Cg.js +0 -79
  130. 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-FXORA5JG.js";
2
10
  import {
3
11
  acceptPending,
4
12
  formatFileSize,
@@ -6,25 +14,25 @@ import {
6
14
  rejectPending,
7
15
  stageFile,
8
16
  validateFilePath
9
- } from "./chunk-UMI4UIJG.js";
17
+ } from "./chunk-R77O2WMK.js";
10
18
  import {
11
19
  findOpenClawSession,
12
20
  importOpenClawConnectors,
13
21
  importPiSession,
14
22
  parseNameFromIdentity
15
- } from "./chunk-LAXUUY7O.js";
23
+ } from "./chunk-A7WQZKOU.js";
16
24
  import {
17
25
  checkForUpdate,
18
26
  checkForUpdateCached,
19
27
  getCurrentVersion
20
- } from "./chunk-2BONPXAF.js";
28
+ } from "./chunk-6EMWJZBK.js";
21
29
  import {
22
30
  normalizeAvatar,
23
31
  safeResolveWithinBase
24
- } from "./chunk-SQL7M4HJ.js";
32
+ } from "./chunk-DRJ24GXK.js";
25
33
  import {
26
34
  isHomeOnlyArchive
27
- } from "./chunk-QMJJWTNL.js";
35
+ } from "./chunk-QCN24XEN.js";
28
36
  import {
29
37
  computeTemplateHash
30
38
  } from "./chunk-QMJCNZ6C.js";
@@ -34,7 +42,7 @@ import {
34
42
  fixModelEscapes,
35
43
  getPlatformDriver,
36
44
  routeOutboundBridge
37
- } from "./chunk-EQZD4YU3.js";
45
+ } from "./chunk-NYC5U6K7.js";
38
46
  import {
39
47
  getBridgeConfig,
40
48
  readBridgesConfig,
@@ -43,7 +51,7 @@ import {
43
51
  resolveChannelMapping,
44
52
  setBridgeConfig,
45
53
  setChannelMapping
46
- } from "./chunk-FHWUQZXE.js";
54
+ } from "./chunk-RXEEYDIB.js";
47
55
  import {
48
56
  MindStartupError,
49
57
  RestartTracker,
@@ -63,7 +71,7 @@ import {
63
71
  ensureSystemChannel,
64
72
  formatHoldNotice,
65
73
  formatNotices,
66
- generateSystemReply,
74
+ generateSystemFallbackReply,
67
75
  getAllDiscoveredExtensions,
68
76
  getAllDiscoveredExtensionsDetailed,
69
77
  getDeliveryManager,
@@ -99,20 +107,21 @@ import {
99
107
  requireAdminOrSystem,
100
108
  requireSelf,
101
109
  setExtensionEnabled,
110
+ shouldGenerateSystemFallback,
102
111
  startMindFull,
103
112
  stopMindFull,
104
113
  syncProviderToMinds,
105
114
  uninstallNpmExtension,
106
115
  writeSystemsConfig
107
- } from "./chunk-OMETFX5H.js";
116
+ } from "./chunk-YT7PEESJ.js";
108
117
  import {
109
118
  loadMergedEnv,
110
119
  mindEnvPath,
111
120
  readEnv,
112
121
  sharedEnvPath,
113
122
  writeEnv
114
- } from "./chunk-5GT7URXJ.js";
115
- import "./chunk-7FT24JBQ.js";
123
+ } from "./chunk-ZDZISKCL.js";
124
+ import "./chunk-FR6S2KNN.js";
116
125
  import {
117
126
  applyInitFiles,
118
127
  applyTemplateHomeFiles,
@@ -141,7 +150,7 @@ import {
141
150
  syncBuiltinSkills,
142
151
  uninstallSkill,
143
152
  updateSkill
144
- } from "./chunk-I2Y2YHIO.js";
153
+ } from "./chunk-7ZUB63PS.js";
145
154
  import {
146
155
  addMessage,
147
156
  createChannel,
@@ -173,23 +182,23 @@ import {
173
182
  setConversationPrivate,
174
183
  subscribe as subscribe2,
175
184
  updateChannelSettings
176
- } from "./chunk-FZMEVCWC.js";
185
+ } from "./chunk-OP4JG2BS.js";
177
186
  import {
178
187
  readVoluteConfig,
179
188
  writeVoluteConfig
180
- } from "./chunk-CU6OFXMM.js";
189
+ } from "./chunk-PFZBNKUH.js";
181
190
  import {
182
191
  isSandboxEnabled,
183
192
  wrapForSandbox
184
- } from "./chunk-3GYVW2X3.js";
193
+ } from "./chunk-JZ62SYWR.js";
185
194
  import {
186
195
  getActiveMinds,
187
196
  onMindEvent,
188
197
  stopAll
189
- } from "./chunk-HVU45COX.js";
198
+ } from "./chunk-EJVPTVTI.js";
190
199
  import {
191
200
  extractTextContent
192
- } from "./chunk-5AHYQHNT.js";
201
+ } from "./chunk-4JOQZPCE.js";
193
202
  import {
194
203
  PROMPT_DEFAULTS,
195
204
  PROMPT_KEYS,
@@ -198,10 +207,10 @@ import {
198
207
  completeTurn,
199
208
  createTurn,
200
209
  getActiveTurnId,
201
- getLastToolUseEventId,
202
210
  getMindPromptDefaults,
203
211
  getPrompt,
204
212
  getPromptIfCustom,
213
+ getToolUseEventId,
205
214
  initSummarizer,
206
215
  markErrored,
207
216
  publish as publish2,
@@ -212,8 +221,8 @@ import {
212
221
  summarizeTurn,
213
222
  takeErrored,
214
223
  trackToolUse
215
- } from "./chunk-NF75HPNR.js";
216
- import "./chunk-Q2XBKQ2D.js";
224
+ } from "./chunk-UYLGEDVD.js";
225
+ import "./chunk-TQJ6ZYVY.js";
217
226
  import {
218
227
  chownMindDir,
219
228
  createMindUser,
@@ -224,9 +233,10 @@ import {
224
233
  isIsolationEnabled,
225
234
  resolveVoluteBin,
226
235
  wrapForIsolation
227
- } from "./chunk-3ERIL673.js";
236
+ } from "./chunk-H2X54EHC.js";
228
237
  import {
229
238
  addCustomModel,
239
+ aiCompleteUtility,
230
240
  buildCustomModel,
231
241
  getAiConfig,
232
242
  getAvailableModels,
@@ -245,12 +255,12 @@ import {
245
255
  setProviderRefreshHook,
246
256
  setUtilityModel,
247
257
  unqualifyModelId
248
- } from "./chunk-J47TIYHA.js";
258
+ } from "./chunk-IHKGWTGT.js";
249
259
  import {
250
260
  isSetupComplete,
251
261
  readGlobalConfig,
252
262
  writeGlobalConfig
253
- } from "./chunk-PNV24SEP.js";
263
+ } from "./chunk-F7H6ATM4.js";
254
264
  import {
255
265
  approveUser,
256
266
  changePassword,
@@ -269,11 +279,11 @@ import {
269
279
  syncMindProfile,
270
280
  updateUserProfile,
271
281
  verifyUser
272
- } from "./chunk-CYI534DJ.js";
282
+ } from "./chunk-T6HYVHPG.js";
273
283
  import {
274
284
  broadcast,
275
285
  subscribe
276
- } from "./chunk-ZMIMSIIT.js";
286
+ } from "./chunk-7C44R625.js";
277
287
  import {
278
288
  logBuffer,
279
289
  logger_default
@@ -297,6 +307,7 @@ import {
297
307
  readAllMinds,
298
308
  readRegistry,
299
309
  removeMind,
310
+ resolveMindDir,
300
311
  setMindRunning,
301
312
  setMindStage,
302
313
  setMindTemplate,
@@ -305,7 +316,7 @@ import {
305
316
  validateMindName,
306
317
  voluteHome,
307
318
  voluteSystemDir
308
- } from "./chunk-H7IYFRAL.js";
319
+ } from "./chunk-ALKYQULU.js";
309
320
  import {
310
321
  activity,
311
322
  channels,
@@ -320,12 +331,76 @@ import {
320
331
  import "./chunk-K3NQKI34.js";
321
332
 
322
333
  // packages/daemon/src/daemon.ts
323
- import { randomBytes as randomBytes2 } from "crypto";
334
+ import { randomBytes as randomBytes3 } from "crypto";
324
335
  import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync10, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "fs";
325
336
  import { homedir as homedir3 } from "os";
326
337
  import { resolve as resolve16 } from "path";
327
338
  import { format } from "util";
328
339
 
340
+ // packages/daemon/src/lib/daemon/backup-manager.ts
341
+ import { CronExpressionParser } from "cron-parser";
342
+ var blog = logger_default.child("backup");
343
+ var DEFAULT_BACKUP_SCHEDULE = "0 3 * * *";
344
+ var BackupManager = class {
345
+ interval = null;
346
+ lastFiredMinute = -1;
347
+ warnedUnconfigured = false;
348
+ start() {
349
+ this.interval = setInterval(() => {
350
+ this.tick().catch((err) => blog.error("backup tick failed", logger_default.errorData(err)));
351
+ }, 6e4);
352
+ }
353
+ stop() {
354
+ if (this.interval) clearInterval(this.interval);
355
+ this.interval = null;
356
+ }
357
+ /**
358
+ * True at most once per scheduled fire minute (records the minute it
359
+ * consumed), and only when backups are enabled and runnable. Not a pure
360
+ * predicate — a second call in the same minute returns false.
361
+ */
362
+ isDue(now = /* @__PURE__ */ new Date()) {
363
+ const config2 = readGlobalConfig().backup;
364
+ if (!config2?.enabled) return false;
365
+ if (!config2.repository || !config2.password) {
366
+ if (!this.warnedUnconfigured) {
367
+ blog.warn("scheduled backups are enabled but no repository is initialized \u2014 not running");
368
+ this.warnedUnconfigured = true;
369
+ }
370
+ return false;
371
+ }
372
+ this.warnedUnconfigured = false;
373
+ const cron = config2.schedule || DEFAULT_BACKUP_SCHEDULE;
374
+ const epochMinute = Math.floor(now.getTime() / 6e4);
375
+ if (epochMinute === this.lastFiredMinute) return false;
376
+ let prevMinute;
377
+ try {
378
+ const interval = CronExpressionParser.parse(cron, { currentDate: now });
379
+ prevMinute = Math.floor(interval.prev().toDate().getTime() / 6e4);
380
+ } catch (err) {
381
+ blog.warn(`invalid backup cron "${cron}"`, logger_default.errorData(err));
382
+ return false;
383
+ }
384
+ if (prevMinute !== epochMinute) return false;
385
+ this.lastFiredMinute = epochMinute;
386
+ return true;
387
+ }
388
+ async tick() {
389
+ if (!this.isDue()) return;
390
+ blog.info("scheduled backup starting");
391
+ try {
392
+ await runBackup();
393
+ } catch (err) {
394
+ blog.error("scheduled backup failed", logger_default.errorData(err));
395
+ }
396
+ }
397
+ };
398
+ var backupManager = null;
399
+ function initBackupManager() {
400
+ if (!backupManager) backupManager = new BackupManager();
401
+ return backupManager;
402
+ }
403
+
329
404
  // packages/daemon/src/lib/daemon/bridge-manager.ts
330
405
  import { spawn } from "child_process";
331
406
  import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, unlinkSync, writeFileSync } from "fs";
@@ -394,7 +469,7 @@ function checkMissingBridgeEnv(def, env) {
394
469
  }
395
470
 
396
471
  // packages/daemon/src/lib/daemon/bridge-manager.ts
397
- var blog = logger_default.child("bridges");
472
+ var blog2 = logger_default.child("bridges");
398
473
  function searchUpwards(...segments) {
399
474
  let searchDir = dirname(new URL(import.meta.url).pathname);
400
475
  for (let i = 0; i < 5; i++) {
@@ -415,7 +490,7 @@ var BridgeManager = class {
415
490
  await Promise.all(
416
491
  platforms.map(
417
492
  (platform) => this.startBridge(platform, daemonPort).catch((err) => {
418
- blog.warn(`failed to start bridge ${platform}`, logger_default.errorData(err));
493
+ blog2.warn(`failed to start bridge ${platform}`, logger_default.errorData(err));
419
494
  })
420
495
  )
421
496
  );
@@ -444,7 +519,7 @@ var BridgeManager = class {
444
519
  }
445
520
  } catch (err) {
446
521
  if (err instanceof Error && err.code !== "ESRCH") {
447
- blog.warn(`failed to stop existing bridge ${platform}`, logger_default.errorData(err));
522
+ blog2.warn(`failed to stop existing bridge ${platform}`, logger_default.errorData(err));
448
523
  }
449
524
  res();
450
525
  }
@@ -509,24 +584,24 @@ var BridgeManager = class {
509
584
  }
510
585
  if (this.shuttingDown) return;
511
586
  if (this.stopping.has(platform)) return;
512
- blog.error(`bridge ${platform} exited with code ${code}`);
513
- if (lastStderr) blog.warn(`bridge ${platform} last output: ${lastStderr}`);
587
+ blog2.error(`bridge ${platform} exited with code ${code}`);
588
+ if (lastStderr) blog2.warn(`bridge ${platform} last output: ${lastStderr}`);
514
589
  const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(platform);
515
590
  if (!shouldRestart) {
516
- blog.error(`bridge ${platform} crashed ${attempt} times \u2014 giving up`);
591
+ blog2.error(`bridge ${platform} crashed ${attempt} times \u2014 giving up`);
517
592
  return;
518
593
  }
519
- blog.info(
594
+ blog2.info(
520
595
  `restarting bridge ${platform} \u2014 attempt ${attempt}/${this.restartTracker.maxRestartAttempts}, in ${delay}ms`
521
596
  );
522
597
  setTimeout(() => {
523
598
  if (this.shuttingDown || this.stopping.has(platform)) return;
524
599
  this.startBridge(platform, daemonPort).catch((err) => {
525
- blog.error(`failed to restart bridge ${platform}`, logger_default.errorData(err));
600
+ blog2.error(`failed to restart bridge ${platform}`, logger_default.errorData(err));
526
601
  });
527
602
  }, delay);
528
603
  });
529
- blog.info(`started bridge ${platform}`);
604
+ blog2.info(`started bridge ${platform}`);
530
605
  }
531
606
  async stopBridge(platform) {
532
607
  const tracked = this.bridges.get(platform);
@@ -543,7 +618,7 @@ var BridgeManager = class {
543
618
  }
544
619
  } catch (err) {
545
620
  if (err instanceof Error && err.code !== "ESRCH") {
546
- blog.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
621
+ blog2.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
547
622
  }
548
623
  resolve17();
549
624
  }
@@ -564,9 +639,9 @@ var BridgeManager = class {
564
639
  try {
565
640
  this.removeBridgePid(platform);
566
641
  } catch (err) {
567
- blog.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
642
+ blog2.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
568
643
  }
569
- blog.info(`stopped bridge ${platform}`);
644
+ blog2.info(`stopped bridge ${platform}`);
570
645
  }
571
646
  async stopAll() {
572
647
  this.shuttingDown = true;
@@ -596,7 +671,7 @@ var BridgeManager = class {
596
671
  unlinkSync(this.bridgePidPath(platform));
597
672
  } catch (err) {
598
673
  if (err instanceof Error && err.code !== "ENOENT") {
599
- blog.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
674
+ blog2.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
600
675
  }
601
676
  }
602
677
  }
@@ -614,18 +689,18 @@ var BridgeManager = class {
614
689
  } catch {
615
690
  }
616
691
  }
617
- blog.warn(`killed orphan bridge ${platform} (pid ${pid})`);
692
+ blog2.warn(`killed orphan bridge ${platform} (pid ${pid})`);
618
693
  }
619
694
  } catch (err) {
620
695
  if (err instanceof Error && err.code !== "ESRCH") {
621
- blog.debug(`orphan bridge ${platform} cleanup: ${err}`);
696
+ blog2.debug(`orphan bridge ${platform} cleanup: ${err}`);
622
697
  }
623
698
  }
624
699
  try {
625
700
  unlinkSync(pidPath);
626
701
  } catch (err) {
627
702
  if (err instanceof Error && err.code !== "ENOENT") {
628
- blog.warn(`failed to clean up PID file for orphan bridge ${platform}`, logger_default.errorData(err));
703
+ blog2.warn(`failed to clean up PID file for orphan bridge ${platform}`, logger_default.errorData(err));
629
704
  }
630
705
  }
631
706
  }
@@ -1400,10 +1475,10 @@ function getCachedApiKey(provider) {
1400
1475
  var keyRefreshTimer = null;
1401
1476
  var slog = logger_default.child("ai-keys");
1402
1477
  var oauthHealth = /* @__PURE__ */ new Map();
1403
- function needsRefresh(oauth) {
1478
+ function needsRefresh(oauth, now = Date.now()) {
1404
1479
  const expires = oauth.expires;
1405
- if (!expires || Date.now() >= expires) return true;
1406
- return expires - Date.now() < 15 * 60 * 1e3;
1480
+ if (!expires || now >= expires) return true;
1481
+ return expires - now < 15 * 60 * 1e3;
1407
1482
  }
1408
1483
  async function refreshApiKeyCache() {
1409
1484
  const ai = getAiConfig();
@@ -1457,7 +1532,7 @@ function stopApiKeyRefresh() {
1457
1532
  var system_default = app;
1458
1533
 
1459
1534
  // packages/daemon/src/web/app.ts
1460
- import { Hono as Hono28 } from "hono";
1535
+ import { Hono as Hono29 } from "hono";
1461
1536
  import { bodyLimit } from "hono/body-limit";
1462
1537
  import { cors } from "hono/cors";
1463
1538
  import { csrf } from "hono/csrf";
@@ -1824,10 +1899,115 @@ var app3 = new Hono3().post("/register", zValidator2("json", credentialsSchema),
1824
1899
  }).route("/", admin).route("/", authenticated);
1825
1900
  var auth_default = app3;
1826
1901
 
1827
- // packages/daemon/src/web/api/bridges.ts
1902
+ // packages/daemon/src/web/api/backup.ts
1903
+ import { randomBytes } from "crypto";
1828
1904
  import { zValidator as zValidator3 } from "@hono/zod-validator";
1905
+ import { CronExpressionParser as CronExpressionParser2 } from "cron-parser";
1829
1906
  import { Hono as Hono4 } from "hono";
1830
1907
  import { z as z3 } from "zod";
1908
+ function redactedConfig() {
1909
+ const backup2 = readGlobalConfig().backup ?? {};
1910
+ return {
1911
+ repository: backup2.repository,
1912
+ schedule: backup2.schedule ?? DEFAULT_BACKUP_SCHEDULE,
1913
+ enabled: backup2.enabled,
1914
+ keep: backup2.keep,
1915
+ includeSessions: backup2.includeSessions,
1916
+ hasPassword: !!backup2.password,
1917
+ envKeys: Object.keys(backup2.env ?? {})
1918
+ };
1919
+ }
1920
+ var configSchema = z3.object({
1921
+ repository: z3.string().optional(),
1922
+ schedule: z3.string().refine(
1923
+ (cron) => {
1924
+ try {
1925
+ CronExpressionParser2.parse(cron);
1926
+ return true;
1927
+ } catch {
1928
+ return false;
1929
+ }
1930
+ },
1931
+ { message: "Invalid cron expression" }
1932
+ ).optional(),
1933
+ enabled: z3.boolean().optional(),
1934
+ keep: z3.object({
1935
+ daily: z3.number().int().min(0).optional(),
1936
+ weekly: z3.number().int().min(0).optional(),
1937
+ monthly: z3.number().int().min(0).optional()
1938
+ }).refine((keep) => !(keep.daily === 0 && keep.weekly === 0 && keep.monthly === 0), {
1939
+ message: "Retention cannot be zero everywhere \u2014 prune would delete every snapshot"
1940
+ }).optional(),
1941
+ includeSessions: z3.boolean().optional(),
1942
+ password: z3.string().optional(),
1943
+ env: z3.record(z3.string(), z3.string()).optional()
1944
+ });
1945
+ var backup = new Hono4().get("/config", requireAdmin, (c) => c.json(redactedConfig())).put("/config", requireAdmin, zValidator3("json", configSchema), (c) => {
1946
+ const updates = c.req.valid("json");
1947
+ const config2 = readGlobalConfig();
1948
+ const current = config2.backup ?? {};
1949
+ config2.backup = {
1950
+ ...current,
1951
+ ...updates,
1952
+ // Empty-string password means "keep existing" so the UI can save
1953
+ // settings without re-entering the passphrase.
1954
+ password: updates.password || current.password,
1955
+ env: updates.env ?? current.env
1956
+ };
1957
+ writeGlobalConfig(config2);
1958
+ return c.json(redactedConfig());
1959
+ }).post("/init", requireAdmin, async (c) => {
1960
+ const config2 = readGlobalConfig();
1961
+ if (!config2.backup?.repository) {
1962
+ return c.json({ error: "Backup repository is not configured" }, 400);
1963
+ }
1964
+ let generatedPassword = null;
1965
+ if (!config2.backup.password) {
1966
+ generatedPassword = randomBytes(32).toString("base64url");
1967
+ config2.backup.password = generatedPassword;
1968
+ }
1969
+ try {
1970
+ await initRepo(config2.backup);
1971
+ } catch (err) {
1972
+ const stderr = err.stderr;
1973
+ const detail = err instanceof Error ? err.message : String(err);
1974
+ return c.json({ error: stderr?.trim() || detail }, 500);
1975
+ }
1976
+ if (generatedPassword) writeGlobalConfig(config2);
1977
+ return c.json({ ok: true, password: generatedPassword });
1978
+ }).post("/run", requireAdmin, async (c) => {
1979
+ try {
1980
+ const summary = await runBackup();
1981
+ return c.json(summary);
1982
+ } catch (err) {
1983
+ const stderr = err.stderr;
1984
+ const detail = err instanceof Error ? err.message : String(err);
1985
+ return c.json({ error: stderr?.trim() || detail }, 500);
1986
+ }
1987
+ }).get("/snapshots", requireAdmin, async (c) => {
1988
+ try {
1989
+ return c.json(await listSnapshots());
1990
+ } catch (err) {
1991
+ const stderr = err.stderr;
1992
+ const detail = err instanceof Error ? err.message : String(err);
1993
+ return c.json({ error: stderr?.trim() || detail }, 500);
1994
+ }
1995
+ }).get("/status", requireAdmin, async (c) => {
1996
+ const version = await resticVersion();
1997
+ return c.json({
1998
+ resticInstalled: version !== null,
1999
+ resticVersion: version,
2000
+ installHint: version === null ? RESTIC_INSTALL_HINT : null,
2001
+ config: redactedConfig(),
2002
+ state: readBackupState()
2003
+ });
2004
+ });
2005
+ var backup_default = backup;
2006
+
2007
+ // packages/daemon/src/web/api/bridges.ts
2008
+ import { zValidator as zValidator4 } from "@hono/zod-validator";
2009
+ import { Hono as Hono5 } from "hono";
2010
+ import { z as z4 } from "zod";
1831
2011
 
1832
2012
  // packages/daemon/src/lib/chat/puppets.ts
1833
2013
  import { and as and2, eq as eq2 } from "drizzle-orm";
@@ -1916,27 +2096,27 @@ async function fanOutToMinds(opts) {
1916
2096
  }
1917
2097
 
1918
2098
  // packages/daemon/src/web/api/bridges.ts
1919
- var inboundSchema = z3.object({
1920
- content: z3.array(
1921
- z3.union([
1922
- z3.object({ type: z3.literal("text"), text: z3.string() }),
1923
- z3.object({ type: z3.literal("image"), media_type: z3.string(), data: z3.string() })
2099
+ var inboundSchema = z4.object({
2100
+ content: z4.array(
2101
+ z4.union([
2102
+ z4.object({ type: z4.literal("text"), text: z4.string() }),
2103
+ z4.object({ type: z4.literal("image"), media_type: z4.string(), data: z4.string() })
1924
2104
  ])
1925
2105
  ).min(1),
1926
- platformUserId: z3.string(),
1927
- displayName: z3.string(),
1928
- externalChannel: z3.string(),
1929
- isDM: z3.boolean(),
1930
- targetMind: z3.string().optional()
2106
+ platformUserId: z4.string(),
2107
+ displayName: z4.string(),
2108
+ externalChannel: z4.string(),
2109
+ isDM: z4.boolean(),
2110
+ targetMind: z4.string().optional()
1931
2111
  });
1932
- var mappingSchema = z3.object({
1933
- externalChannel: z3.string(),
1934
- voluteChannel: z3.string()
2112
+ var mappingSchema = z4.object({
2113
+ externalChannel: z4.string(),
2114
+ voluteChannel: z4.string()
1935
2115
  });
1936
- var enableSchema = z3.object({
1937
- defaultMind: z3.string()
2116
+ var enableSchema = z4.object({
2117
+ defaultMind: z4.string()
1938
2118
  });
1939
- var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSchema), async (c) => {
2119
+ var app4 = new Hono5().post("/:platform/inbound", zValidator4("json", inboundSchema), async (c) => {
1940
2120
  const user = c.get("user");
1941
2121
  if (user.id !== 0) return c.json({ error: "Bridge inbound requires daemon token" }, 403);
1942
2122
  const platform = c.req.param("platform");
@@ -1988,7 +2168,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
1988
2168
  }
1989
2169
  const participants = await getParticipants(channel.id);
1990
2170
  if (!participants.some((p) => p.userId === puppet.id)) {
1991
- const { addParticipant } = await import("./conversations-WAJYZKOC.js");
2171
+ const { addParticipant } = await import("./conversations-JZTD6KLR.js");
1992
2172
  await addParticipant(channel.id, puppet.id);
1993
2173
  }
1994
2174
  const contentBlocks = body.content;
@@ -2018,7 +2198,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
2018
2198
  };
2019
2199
  });
2020
2200
  return c.json(bridges);
2021
- }).post("/:platform", requireAdmin, zValidator3("json", enableSchema), async (c) => {
2201
+ }).post("/:platform", requireAdmin, zValidator4("json", enableSchema), async (c) => {
2022
2202
  const platform = c.req.param("platform");
2023
2203
  const body = c.req.valid("json");
2024
2204
  const def = getBridgeDef(platform);
@@ -2057,7 +2237,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
2057
2237
  await manager.stopBridge(platform);
2058
2238
  removeBridgeConfig(platform);
2059
2239
  return c.json({ ok: true });
2060
- }).put("/:platform/mappings", requireAdmin, zValidator3("json", mappingSchema), (c) => {
2240
+ }).put("/:platform/mappings", requireAdmin, zValidator4("json", mappingSchema), (c) => {
2061
2241
  const platform = c.req.param("platform");
2062
2242
  const body = c.req.valid("json");
2063
2243
  try {
@@ -2088,11 +2268,11 @@ async function fanOutToBridgedMinds(opts) {
2088
2268
  var bridges_default = app4;
2089
2269
 
2090
2270
  // packages/daemon/src/web/api/channels.ts
2091
- import { Hono as Hono5 } from "hono";
2271
+ import { Hono as Hono6 } from "hono";
2092
2272
  function buildEnv(name) {
2093
2273
  return { ...loadMergedEnv(name), VOLUTE_MIND: name, VOLUTE_MIND_DIR: mindDir(name) };
2094
2274
  }
2095
- var app5 = new Hono5().post("/:name/channels/create", requireSelf(), async (c) => {
2275
+ var app5 = new Hono6().post("/:name/channels/create", requireSelf(), async (c) => {
2096
2276
  const name = c.req.param("name");
2097
2277
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
2098
2278
  const {
@@ -2117,8 +2297,8 @@ var app5 = new Hono5().post("/:name/channels/create", requireSelf(), async (c) =
2117
2297
  var channels_default = app5;
2118
2298
 
2119
2299
  // packages/daemon/src/web/api/config.ts
2120
- import { Hono as Hono6 } from "hono";
2121
- var config = new Hono6();
2300
+ import { Hono as Hono7 } from "hono";
2301
+ var config = new Hono7();
2122
2302
  config.get("/models", async (c) => {
2123
2303
  const enabled = new Set(getEnabledModels());
2124
2304
  const all = await getAvailableModels();
@@ -2145,8 +2325,8 @@ config.get("/status", (c) => {
2145
2325
  var config_default = config;
2146
2326
 
2147
2327
  // packages/daemon/src/web/api/env.ts
2148
- import { Hono as Hono7 } from "hono";
2149
- var app6 = new Hono7().get("/:name/env", requireSelf(), async (c) => {
2328
+ import { Hono as Hono8 } from "hono";
2329
+ var app6 = new Hono8().get("/:name/env", requireSelf(), async (c) => {
2150
2330
  const name = c.req.param("name");
2151
2331
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
2152
2332
  const shared = readEnv(sharedEnvPath());
@@ -2189,7 +2369,7 @@ var app6 = new Hono7().get("/:name/env", requireSelf(), async (c) => {
2189
2369
  writeEnv(path, env);
2190
2370
  return c.json({ ok: true });
2191
2371
  });
2192
- var sharedEnvApp = new Hono7().get("/", requireAdmin, (c) => {
2372
+ var sharedEnvApp = new Hono8().get("/", requireAdmin, (c) => {
2193
2373
  return c.json(readEnv(sharedEnvPath()));
2194
2374
  }).put("/:key", requireAdmin, async (c) => {
2195
2375
  const key = c.req.param("key");
@@ -2219,8 +2399,8 @@ var sharedEnvApp = new Hono7().get("/", requireAdmin, (c) => {
2219
2399
  var env_default = app6;
2220
2400
 
2221
2401
  // packages/daemon/src/web/api/extensions.ts
2222
- import { Hono as Hono8 } from "hono";
2223
- var app7 = new Hono8().get("/", (c) => {
2402
+ import { Hono as Hono9 } from "hono";
2403
+ var app7 = new Hono9().get("/", (c) => {
2224
2404
  return c.json(getLoadedExtensions());
2225
2405
  }).get("/all", (c) => {
2226
2406
  const detail = c.req.query("detail") === "true";
@@ -2267,18 +2447,18 @@ var extensions_default = app7;
2267
2447
  // packages/daemon/src/web/api/file-sharing.ts
2268
2448
  import { readFileSync as readFileSync4, statSync as statSync2 } from "fs";
2269
2449
  import { resolve as resolve4 } from "path";
2270
- import { Hono as Hono9 } from "hono";
2450
+ import { Hono as Hono10 } from "hono";
2271
2451
  async function notifyMind(mindName, message) {
2272
2452
  const entry = await findMind(mindName);
2273
2453
  if (!entry) return;
2274
2454
  try {
2275
- const { sendSystemMessage } = await import("./system-chat-4DQZOEZI.js");
2455
+ const { sendSystemMessage } = await import("./system-chat-XOALE2RD.js");
2276
2456
  await sendSystemMessage(mindName, message);
2277
2457
  } catch (err) {
2278
2458
  logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
2279
2459
  }
2280
2460
  }
2281
- var app8 = new Hono9().post("/:name/files/send", requireSelf(), async (c) => {
2461
+ var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
2282
2462
  const senderName = c.req.param("name");
2283
2463
  const senderEntry = await findMind(senderName);
2284
2464
  if (!senderEntry) return c.json({ error: "Sender mind not found" }, 404);
@@ -2398,7 +2578,7 @@ var file_sharing_default = app8;
2398
2578
  import { mkdirSync as mkdirSync3, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
2399
2579
  import { readdir, readFile, realpath, stat } from "fs/promises";
2400
2580
  import { extname as extname2, resolve as resolve5 } from "path";
2401
- import { Hono as Hono10 } from "hono";
2581
+ import { Hono as Hono11 } from "hono";
2402
2582
  var AVATAR_MIME2 = {
2403
2583
  ".png": "image/png",
2404
2584
  ".jpg": "image/jpeg",
@@ -2425,7 +2605,7 @@ var MIME_TYPES = {
2425
2605
  ".woff": "font/woff",
2426
2606
  ".woff2": "font/woff2"
2427
2607
  };
2428
- var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2608
+ var app9 = new Hono11().post("/:name/avatar", requireSelf(), async (c) => {
2429
2609
  const name = c.req.param("name");
2430
2610
  const entry = await findMind(name);
2431
2611
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -2570,7 +2750,7 @@ var files_default = app9;
2570
2750
 
2571
2751
  // packages/daemon/src/web/api/history.ts
2572
2752
  import { and as and3, desc as desc2, eq as eq3, gte, inArray, sql } from "drizzle-orm";
2573
- import { Hono as Hono11 } from "hono";
2753
+ import { Hono as Hono12 } from "hono";
2574
2754
  async function resolveMindFilter(c) {
2575
2755
  const user = c.get("user");
2576
2756
  if (user.role === "admin" || user.role === "system") {
@@ -2578,7 +2758,7 @@ async function resolveMindFilter(c) {
2578
2758
  }
2579
2759
  return getBaseName(user.username);
2580
2760
  }
2581
- var history = new Hono11().get("/turns", async (c) => {
2761
+ var history = new Hono12().get("/turns", async (c) => {
2582
2762
  const mindFilter = await resolveMindFilter(c);
2583
2763
  const turnIdFilter = c.req.query("turnId");
2584
2764
  const turnIdsFilter = c.req.query("turnIds");
@@ -2969,7 +3149,7 @@ var history = new Hono11().get("/turns", async (c) => {
2969
3149
  var history_default = history;
2970
3150
 
2971
3151
  // packages/daemon/src/web/api/keys.ts
2972
- import { Hono as Hono12 } from "hono";
3152
+ import { Hono as Hono13 } from "hono";
2973
3153
 
2974
3154
  // packages/daemon/src/lib/mind/identity.ts
2975
3155
  import { createHash, generateKeyPairSync, sign, verify } from "crypto";
@@ -3029,7 +3209,7 @@ async function publishPublicKey(mindName, publicKeyPem) {
3029
3209
  }
3030
3210
 
3031
3211
  // packages/daemon/src/web/api/keys.ts
3032
- var app10 = new Hono12().get("/:fingerprint", async (c) => {
3212
+ var app10 = new Hono13().get("/:fingerprint", async (c) => {
3033
3213
  const fingerprint = c.req.param("fingerprint");
3034
3214
  for (const entry of await readRegistry()) {
3035
3215
  try {
@@ -3049,9 +3229,9 @@ var keys_default = app10;
3049
3229
  import { spawn as spawn2 } from "child_process";
3050
3230
  import { existsSync as existsSync5 } from "fs";
3051
3231
  import { resolve as resolve7 } from "path";
3052
- import { Hono as Hono13 } from "hono";
3232
+ import { Hono as Hono14 } from "hono";
3053
3233
  import { streamSSE as streamSSE3 } from "hono/streaming";
3054
- var app11 = new Hono13().get("/:name/logs", requireSelf(), async (c) => {
3234
+ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
3055
3235
  const name = c.req.param("name");
3056
3236
  const entry = await findMind(name);
3057
3237
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -3102,10 +3282,10 @@ var app11 = new Hono13().get("/:name/logs", requireSelf(), async (c) => {
3102
3282
  var logs_default = app11;
3103
3283
 
3104
3284
  // packages/daemon/src/web/api/mind-skills.ts
3105
- import { zValidator as zValidator4 } from "@hono/zod-validator";
3106
- import { Hono as Hono14 } from "hono";
3107
- import { z as z4 } from "zod";
3108
- var app12 = new Hono14().get("/:name/skills", async (c) => {
3285
+ import { zValidator as zValidator5 } from "@hono/zod-validator";
3286
+ import { Hono as Hono15 } from "hono";
3287
+ import { z as z5 } from "zod";
3288
+ var app12 = new Hono15().get("/:name/skills", async (c) => {
3109
3289
  const name = c.req.param("name");
3110
3290
  const entry = await findMind(name);
3111
3291
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -3115,7 +3295,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
3115
3295
  }).post(
3116
3296
  "/:name/skills/install",
3117
3297
  requireSelf(),
3118
- zValidator4("json", z4.object({ skillId: z4.string() })),
3298
+ zValidator5("json", z5.object({ skillId: z5.string() })),
3119
3299
  async (c) => {
3120
3300
  const name = c.req.param("name");
3121
3301
  const entry = await findMind(name);
@@ -3124,6 +3304,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
3124
3304
  const dir = entry.dir ?? mindDir(name);
3125
3305
  try {
3126
3306
  const result = await installSkill(name, dir, skillId);
3307
+ await chownMindDir(dir, name);
3127
3308
  return c.json({ ok: true, ...result });
3128
3309
  } catch (e) {
3129
3310
  const msg = e instanceof Error ? e.message : String(e);
@@ -3133,7 +3314,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
3133
3314
  ).post(
3134
3315
  "/:name/skills/update",
3135
3316
  requireSelf(),
3136
- zValidator4("json", z4.object({ skillId: z4.string() })),
3317
+ zValidator5("json", z5.object({ skillId: z5.string() })),
3137
3318
  async (c) => {
3138
3319
  const name = c.req.param("name");
3139
3320
  const entry = await findMind(name);
@@ -3142,6 +3323,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
3142
3323
  const dir = entry.dir ?? mindDir(name);
3143
3324
  try {
3144
3325
  const result = await updateSkill(name, dir, skillId);
3326
+ await chownMindDir(dir, name);
3145
3327
  return c.json(result);
3146
3328
  } catch (e) {
3147
3329
  const msg = e instanceof Error ? e.message : String(e);
@@ -3151,7 +3333,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
3151
3333
  ).post(
3152
3334
  "/:name/skills/publish",
3153
3335
  requireSelf(),
3154
- zValidator4("json", z4.object({ skillId: z4.string() })),
3336
+ zValidator5("json", z5.object({ skillId: z5.string() })),
3155
3337
  async (c) => {
3156
3338
  const name = c.req.param("name");
3157
3339
  const entry = await findMind(name);
@@ -3174,6 +3356,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
3174
3356
  const dir = entry.dir ?? mindDir(name);
3175
3357
  try {
3176
3358
  await uninstallSkill(name, dir, skillName);
3359
+ await chownMindDir(dir, name);
3177
3360
  } catch (e) {
3178
3361
  const msg = e instanceof Error ? e.message : String(e);
3179
3362
  return c.json({ error: msg }, 400);
@@ -3192,11 +3375,11 @@ import {
3192
3375
  rmSync as rmSync4,
3193
3376
  writeFileSync as writeFileSync7
3194
3377
  } from "fs";
3195
- import { basename, resolve as resolve10 } from "path";
3196
- import { zValidator as zValidator5 } from "@hono/zod-validator";
3378
+ import { relative, resolve as resolve10 } from "path";
3379
+ import { zValidator as zValidator6 } from "@hono/zod-validator";
3197
3380
  import { and as and5, desc as desc4, eq as eq5, sql as sql3 } from "drizzle-orm";
3198
- import { Hono as Hono15 } from "hono";
3199
- import { z as z5 } from "zod";
3381
+ import { Hono as Hono16 } from "hono";
3382
+ import { z as z6 } from "zod";
3200
3383
 
3201
3384
  // packages/daemon/src/lib/daemon/turn-lifecycle.ts
3202
3385
  import { and as and4, desc as desc3, eq as eq4, inArray as inArray2, sql as sql2 } from "drizzle-orm";
@@ -3313,13 +3496,18 @@ async function handleMindEvent(mind, event) {
3313
3496
  }).returning({ id: mindHistory.id });
3314
3497
  insertedId = result[0]?.id;
3315
3498
  } catch (err) {
3316
- llog.error(`failed to persist event for ${mind}`, logger_default.errorData(err));
3499
+ llog.error(
3500
+ `HISTORY GAP: failed to persist ${event.type} event for ${mind}${event.session ? ` (session ${event.session})` : ""}${event.channel ? ` on ${event.channel}` : ""}`,
3501
+ logger_default.errorData(err)
3502
+ );
3317
3503
  }
3318
3504
  if (event.type === "tool_use" && insertedId != null) {
3319
- trackToolUse(mind, event.session, insertedId);
3505
+ const toolUseId = typeof event.metadata?.id === "string" ? event.metadata.id : void 0;
3506
+ trackToolUse(mind, event.session, insertedId, toolUseId);
3320
3507
  }
3321
3508
  if (event.type === "tool_result" && turnId && event.content) {
3322
- const toolUseEventId = getLastToolUseEventId(mind, event.session);
3509
+ const resultToolUseId = typeof event.metadata?.tool_use_id === "string" ? event.metadata.tool_use_id : void 0;
3510
+ const toolUseEventId = getToolUseEventId(mind, event.session, resultToolUseId);
3323
3511
  try {
3324
3512
  await linkToolResultToTurn(mind, turnId, event.content, toolUseEventId);
3325
3513
  } catch (err) {
@@ -3382,7 +3570,7 @@ async function handleMindEvent(mind, event) {
3382
3570
  session: event.session,
3383
3571
  kind: "budget",
3384
3572
  reason: "token_budget",
3385
- 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."
3573
+ 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."
3386
3574
  });
3387
3575
  }
3388
3576
  }
@@ -3413,35 +3601,50 @@ async function completeTurnAndSummarize(mind, event, insertedId) {
3413
3601
  // packages/daemon/src/lib/mind/consolidate.ts
3414
3602
  import { readdirSync, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
3415
3603
  import { resolve as resolve8 } from "path";
3416
- async function consolidateMemory(mindDir2) {
3604
+ var cLog = logger_default.child("consolidate");
3605
+ var MAX_CONSOLIDATION_INPUT_CHARS = 2e5;
3606
+ function readDailyLogs(memoryDir) {
3607
+ let files;
3608
+ try {
3609
+ files = readdirSync(memoryDir).filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).sort();
3610
+ } catch {
3611
+ return [];
3612
+ }
3613
+ const logs = [];
3614
+ for (const filename of files) {
3615
+ const date = filename.replace(".md", "");
3616
+ const content = readFileSync6(resolve8(memoryDir, filename), "utf-8").trim();
3617
+ if (content) logs.push(`### ${date}
3618
+
3619
+ ${content}`);
3620
+ }
3621
+ return logs;
3622
+ }
3623
+ function boundLogText(logs, maxChars = MAX_CONSOLIDATION_INPUT_CHARS) {
3624
+ const kept = [];
3625
+ let total = 0;
3626
+ for (let i = logs.length - 1; i >= 0; i--) {
3627
+ const len = logs[i].length + (kept.length > 0 ? 2 : 0);
3628
+ if (total + len > maxChars) break;
3629
+ kept.unshift(logs[i]);
3630
+ total += len;
3631
+ }
3632
+ if (kept.length === 0 && logs.length > 0) {
3633
+ return logs[logs.length - 1].slice(-maxChars);
3634
+ }
3635
+ return kept.join("\n\n");
3636
+ }
3637
+ async function consolidateMemory(mindDir2, complete = aiCompleteUtility) {
3417
3638
  const soulPath = resolve8(mindDir2, "home/SOUL.md");
3418
3639
  const memoryPath = resolve8(mindDir2, "home/MEMORY.md");
3419
3640
  const memoryDir = resolve8(mindDir2, "home/memory");
3420
3641
  const soul = readFileSync6(soulPath, "utf-8");
3421
- const logs = [];
3422
- try {
3423
- const files = readdirSync(memoryDir).filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).sort();
3424
- for (const filename of files) {
3425
- const date = filename.replace(".md", "");
3426
- const content2 = readFileSync6(resolve8(memoryDir, filename), "utf-8").trim();
3427
- if (content2) {
3428
- logs.push(`### ${date}
3429
-
3430
- ${content2}`);
3431
- }
3432
- }
3433
- } catch {
3434
- }
3642
+ const logs = readDailyLogs(memoryDir);
3435
3643
  if (logs.length === 0) {
3436
- console.log("No daily logs found.");
3437
- return;
3438
- }
3439
- const apiKey = process.env.ANTHROPIC_API_KEY;
3440
- if (!apiKey) {
3441
- console.error("ANTHROPIC_API_KEY not set, skipping memory consolidation.");
3644
+ cLog.info("No daily logs found; skipping memory consolidation.");
3442
3645
  return;
3443
3646
  }
3444
- console.log("Consolidating memory from daily logs...");
3647
+ cLog.info("Consolidating memory from daily logs...");
3445
3648
  const userMessage = [
3446
3649
  "You have daily logs from a previous environment but no long-term memory file yet.",
3447
3650
  "Please review the daily logs below and produce consolidated MEMORY.md content.",
@@ -3449,40 +3652,20 @@ ${content2}`);
3449
3652
  "",
3450
3653
  "## Daily logs",
3451
3654
  "",
3452
- logs.join("\n\n")
3655
+ boundLogText(logs)
3453
3656
  ].join("\n");
3454
- const res = await fetch("https://api.anthropic.com/v1/messages", {
3455
- method: "POST",
3456
- headers: {
3457
- "Content-Type": "application/json",
3458
- "x-api-key": apiKey,
3459
- "anthropic-version": "2023-06-01"
3460
- },
3461
- body: JSON.stringify({
3462
- model: "claude-sonnet-4-20250514",
3463
- max_tokens: 4096,
3464
- system: soul,
3465
- messages: [{ role: "user", content: userMessage }]
3466
- })
3467
- });
3468
- if (!res.ok) {
3469
- const body = await res.text();
3470
- console.error(`Anthropic API error (${res.status}): ${body}`);
3471
- return;
3472
- }
3473
- const data = await res.json();
3474
- const content = data.content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join("").trim();
3657
+ const content = (await complete(soul, userMessage))?.trim();
3475
3658
  if (content) {
3476
3659
  writeFileSync5(memoryPath, `${content}
3477
3660
  `);
3478
- console.log("MEMORY.md created successfully.");
3661
+ cLog.info("MEMORY.md created successfully.");
3479
3662
  } else {
3480
- console.warn("Warning: No content produced.");
3663
+ cLog.warn("No content produced; skipping memory consolidation.");
3481
3664
  }
3482
3665
  }
3483
3666
 
3484
3667
  // packages/daemon/src/lib/mind/last-known-good.ts
3485
- import { randomBytes } from "crypto";
3668
+ import { randomBytes as randomBytes2 } from "crypto";
3486
3669
  var glog = logger_default.child("last-known-good");
3487
3670
  async function hasSrcChanges(dir, mindName) {
3488
3671
  const status = (await gitExec(["status", "--porcelain", "--", "src"], { cwd: dir, mindName })).trim();
@@ -3491,7 +3674,7 @@ async function hasSrcChanges(dir, mindName) {
3491
3674
  async function rollbackSrcChanges(dir, mindName) {
3492
3675
  if (!await hasSrcChanges(dir, mindName)) return { parked: false };
3493
3676
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3494
- const branch = `broken/${ts}-${randomBytes(4).toString("hex")}`;
3677
+ const branch = `broken/${ts}-${randomBytes2(4).toString("hex")}`;
3495
3678
  const opts = { cwd: dir, mindName };
3496
3679
  await gitExec(["add", "--", "src"], opts);
3497
3680
  await gitExec(
@@ -3524,7 +3707,7 @@ async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
3524
3707
  logger_default.warn(`failed to stop variant ${variantName}`, logger_default.errorData(err));
3525
3708
  }
3526
3709
  }
3527
- const { findMind: findMind2 } = await import("./registry-NUJAGLQJ.js");
3710
+ const { findMind: findMind2 } = await import("./registry-OUZBZ3Q4.js");
3528
3711
  const variantEntry = await findMind2(variantName);
3529
3712
  const branchName = variantEntry?.branch ?? variantName;
3530
3713
  if (existsSync6(variantPath)) {
@@ -3753,7 +3936,7 @@ async function getMindStatus(name, port, registryRunning) {
3753
3936
  const manager = getMindManager();
3754
3937
  let status = "stopped";
3755
3938
  try {
3756
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HINI6Y46.js");
3939
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HCUH4PM4.js");
3757
3940
  if (getSleepManagerIfReady2()?.isSleeping(name)) {
3758
3941
  status = "sleeping";
3759
3942
  }
@@ -4179,15 +4362,15 @@ function importSessionsFromArchive(dest, tempDir) {
4179
4362
  logger_default.error("Failed to import sessions from archive", logger_default.errorData(err));
4180
4363
  }
4181
4364
  }
4182
- var createMindSchema = z5.object({
4183
- name: z5.string(),
4184
- template: z5.string().optional(),
4185
- stage: z5.enum(["seed", "sprouted"]).optional(),
4186
- description: z5.string().optional(),
4187
- model: z5.string().optional(),
4188
- seedSoul: z5.string().optional(),
4189
- skills: z5.array(z5.string()).optional(),
4190
- createdBy: z5.string().optional()
4365
+ var createMindSchema = z6.object({
4366
+ name: z6.string(),
4367
+ template: z6.string().optional(),
4368
+ stage: z6.enum(["seed", "sprouted"]).optional(),
4369
+ description: z6.string().optional(),
4370
+ model: z6.string().optional(),
4371
+ seedSoul: z6.string().optional(),
4372
+ skills: z6.array(z6.string()).optional(),
4373
+ createdBy: z6.string().optional()
4191
4374
  });
4192
4375
  function formatTimeAgo(date) {
4193
4376
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
@@ -4231,7 +4414,7 @@ async function proxyToMind(c, path) {
4231
4414
  return c.json({ error: "Failed to reach mind" }, 503);
4232
4415
  }
4233
4416
  }
4234
- var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", createMindSchema), async (c) => {
4417
+ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", createMindSchema), async (c) => {
4235
4418
  const body = c.req.valid("json");
4236
4419
  const { name } = body;
4237
4420
  const template = body.template ?? await resolveTemplate(body.model);
@@ -4248,7 +4431,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4248
4431
  applyInitFiles(dest);
4249
4432
  const { publicKeyPem } = generateIdentity(dest);
4250
4433
  {
4251
- const { readGlobalConfig: readGlobal } = await import("./setup-MLRKNP7Y.js");
4434
+ const { readGlobalConfig: readGlobal } = await import("./setup-Y2EJI3GG.js");
4252
4435
  const mindDefaults = readGlobal().mindDefaults;
4253
4436
  const config2 = readVoluteConfig(dest);
4254
4437
  if (!config2) throw new Error("Failed to read volute.json after identity generation");
@@ -4328,7 +4511,6 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4328
4511
  rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
4329
4512
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
4330
4513
  }
4331
- await chownMindDir(dest, name);
4332
4514
  if (body.stage === "seed") {
4333
4515
  const descLine = body.description ? `
4334
4516
  The human who planted you described you as: "${body.description}"
@@ -4339,7 +4521,7 @@ The human who planted you described you as: "${body.description}"
4339
4521
  }
4340
4522
  let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
4341
4523
  if (body.stage === "seed" && !body.skills) {
4342
- const { isImagegenEnabled } = await import("./setup-MLRKNP7Y.js");
4524
+ const { isImagegenEnabled } = await import("./setup-Y2EJI3GG.js");
4343
4525
  if (isImagegenEnabled()) {
4344
4526
  skillSet = [...skillSet, "imagegen"];
4345
4527
  }
@@ -4357,7 +4539,7 @@ The human who planted you described you as: "${body.description}"
4357
4539
  try {
4358
4540
  const spiritEntry = await findMind("volute");
4359
4541
  if (spiritEntry) {
4360
- const { spiritDir } = await import("./spirit-IK5OYWMV.js");
4542
+ const { spiritDir } = await import("./spirit-DBTIW7P4.js");
4361
4543
  const sDir = spiritEntry.dir ?? spiritDir();
4362
4544
  const spiritConfig = readVoluteConfig(sDir) ?? {};
4363
4545
  const schedules = spiritConfig.schedules ?? [];
@@ -4372,7 +4554,7 @@ The human who planted you described you as: "${body.description}"
4372
4554
  });
4373
4555
  spiritConfig.schedules = schedules;
4374
4556
  writeVoluteConfig(sDir, spiritConfig);
4375
- const { getScheduler: getScheduler2 } = await import("./scheduler-CXWQ6Z4E.js");
4557
+ const { getScheduler: getScheduler2 } = await import("./scheduler-P6DXLLXI.js");
4376
4558
  getScheduler2().loadSchedules("volute", sDir);
4377
4559
  }
4378
4560
  }
@@ -4390,6 +4572,7 @@ The human who planted you described you as: "${body.description}"
4390
4572
  writeFileSync7(resolve10(dest, "home/MEMORY.md"), customMemory);
4391
4573
  }
4392
4574
  }
4575
+ await chownMindDir(dest, name);
4393
4576
  publishPublicKey(name, publicKeyPem).catch(
4394
4577
  (err) => logger_default.warn(`failed to publish key for ${name}`, { error: err.message })
4395
4578
  );
@@ -4637,7 +4820,7 @@ ${user.trimEnd()}
4637
4820
  const manager = getMindManager();
4638
4821
  try {
4639
4822
  if (context?.type === "reload") {
4640
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HINI6Y46.js");
4823
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HCUH4PM4.js");
4641
4824
  const sleepState = getSleepManagerIfReady2()?.getState(name);
4642
4825
  if (sleepState?.sleeping) {
4643
4826
  logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
@@ -4764,7 +4947,7 @@ ${user.trimEnd()}
4764
4947
  const name = c.req.param("name");
4765
4948
  const entry = await findMind(name);
4766
4949
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4767
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HINI6Y46.js");
4950
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HCUH4PM4.js");
4768
4951
  const sm = getSleepManagerIfReady2();
4769
4952
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4770
4953
  return c.json(sm.getState(name));
@@ -4772,7 +4955,7 @@ ${user.trimEnd()}
4772
4955
  const name = c.req.param("name");
4773
4956
  const entry = await findMind(name);
4774
4957
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4775
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HINI6Y46.js");
4958
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HCUH4PM4.js");
4776
4959
  const sm = getSleepManagerIfReady2();
4777
4960
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4778
4961
  if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
@@ -4792,7 +4975,7 @@ ${user.trimEnd()}
4792
4975
  const name = c.req.param("name");
4793
4976
  const entry = await findMind(name);
4794
4977
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4795
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HINI6Y46.js");
4978
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HCUH4PM4.js");
4796
4979
  const sm = getSleepManagerIfReady2();
4797
4980
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4798
4981
  const sleepState = sm.getState(name);
@@ -4807,7 +4990,7 @@ ${user.trimEnd()}
4807
4990
  const name = c.req.param("name");
4808
4991
  const entry = await findMind(name);
4809
4992
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4810
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HINI6Y46.js");
4993
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HCUH4PM4.js");
4811
4994
  const sm = getSleepManagerIfReady2();
4812
4995
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4813
4996
  const flushed = await sm.flushQueuedMessages(name);
@@ -4822,10 +5005,20 @@ ${user.trimEnd()}
4822
5005
  const profile = config2.profile ?? {};
4823
5006
  if (body.displayName !== void 0) profile.displayName = body.displayName;
4824
5007
  if (body.description !== void 0) profile.description = body.description;
4825
- if (body.avatar !== void 0) profile.avatar = basename(body.avatar);
5008
+ if (body.avatar !== void 0) {
5009
+ const homeDir = resolve10(dir, "home");
5010
+ const avatarPath = safeResolveWithinBase(homeDir, body.avatar);
5011
+ if (!avatarPath) {
5012
+ return c.json({ error: "Avatar path must be inside the mind's home directory" }, 400);
5013
+ }
5014
+ if (!existsSync7(avatarPath)) {
5015
+ return c.json({ error: `Avatar file not found: ${relative(homeDir, avatarPath)}` }, 400);
5016
+ }
5017
+ profile.avatar = relative(homeDir, avatarPath);
5018
+ }
4826
5019
  config2.profile = profile;
4827
5020
  writeVoluteConfig(dir, config2);
4828
- const { syncMindProfile: syncMindProfile2 } = await import("./auth-FRZJVQCS.js");
5021
+ const { syncMindProfile: syncMindProfile2 } = await import("./auth-FLAEXXZK.js");
4829
5022
  await syncMindProfile2(name, profile);
4830
5023
  broadcast({ type: "profile_updated", mind: name, summary: `${name} profile updated` });
4831
5024
  return c.json({ ok: true });
@@ -4872,7 +5065,7 @@ ${user.trimEnd()}
4872
5065
  const config2 = readVoluteConfig(dir);
4873
5066
  const displayNameSet = !!config2?.profile?.displayName;
4874
5067
  const avatarSet = !!config2?.profile?.avatar;
4875
- const { isImagegenEnabled } = await import("./setup-MLRKNP7Y.js");
5068
+ const { isImagegenEnabled } = await import("./setup-Y2EJI3GG.js");
4876
5069
  const imagegenEnabled = isImagegenEnabled();
4877
5070
  const done = [];
4878
5071
  const remaining = [];
@@ -4910,7 +5103,7 @@ ${user.trimEnd()}
4910
5103
  try {
4911
5104
  const spiritEntry = await findMind("volute");
4912
5105
  if (spiritEntry) {
4913
- const { spiritDir } = await import("./spirit-IK5OYWMV.js");
5106
+ const { spiritDir } = await import("./spirit-DBTIW7P4.js");
4914
5107
  const sDir = spiritEntry.dir ?? spiritDir();
4915
5108
  const spiritConfig = readVoluteConfig(sDir);
4916
5109
  if (spiritConfig?.schedules) {
@@ -4918,7 +5111,7 @@ ${user.trimEnd()}
4918
5111
  spiritConfig.schedules = spiritConfig.schedules.filter((s) => s.id !== nurtureId);
4919
5112
  if (spiritConfig.schedules.length === 0) spiritConfig.schedules = void 0;
4920
5113
  writeVoluteConfig(sDir, spiritConfig);
4921
- const { getScheduler: getScheduler2 } = await import("./scheduler-CXWQ6Z4E.js");
5114
+ const { getScheduler: getScheduler2 } = await import("./scheduler-P6DXLLXI.js");
4922
5115
  getScheduler2().loadSchedules("volute", sDir);
4923
5116
  }
4924
5117
  }
@@ -5303,16 +5496,16 @@ ${user.trimEnd()}
5303
5496
  }).put(
5304
5497
  "/:name/config",
5305
5498
  requireSelf(),
5306
- zValidator5(
5499
+ zValidator6(
5307
5500
  "json",
5308
- z5.object({
5309
- model: z5.string().optional(),
5310
- thinkingLevel: z5.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional(),
5311
- maxThinkingTokens: z5.number().int().positive().nullable().optional(),
5312
- tokenBudget: z5.number().int().positive().nullable().optional(),
5313
- tokenBudgetPeriodMinutes: z5.number().int().positive().nullable().optional(),
5314
- compaction: z5.object({ maxContextTokens: z5.number().int().positive().nullable().optional() }).nullable().optional(),
5315
- unescapeNewlines: z5.boolean().optional()
5501
+ z6.object({
5502
+ model: z6.string().optional(),
5503
+ thinkingLevel: z6.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional(),
5504
+ maxThinkingTokens: z6.number().int().positive().nullable().optional(),
5505
+ tokenBudget: z6.number().int().positive().nullable().optional(),
5506
+ tokenBudgetPeriodMinutes: z6.number().int().positive().nullable().optional(),
5507
+ compaction: z6.object({ maxContextTokens: z6.number().int().positive().nullable().optional() }).nullable().optional(),
5508
+ unescapeNewlines: z6.boolean().optional()
5316
5509
  })
5317
5510
  ),
5318
5511
  async (c) => {
@@ -5353,7 +5546,7 @@ ${user.trimEnd()}
5353
5546
  }
5354
5547
  writeVoluteConfig(dir, existing);
5355
5548
  if (body.unescapeNewlines !== void 0) {
5356
- const { clearEchoTextCache } = await import("./echo-text-T7ZA5EYD.js");
5549
+ const { clearEchoTextCache } = await import("./echo-text-6JJOPUD4.js");
5357
5550
  clearEchoTextCache(name);
5358
5551
  }
5359
5552
  const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.maxThinkingTokens !== void 0 || body.compaction !== void 0;
@@ -5430,7 +5623,7 @@ ${user.trimEnd()}
5430
5623
  }
5431
5624
  if (entry.mindType === "spirit" && body.model !== void 0) {
5432
5625
  try {
5433
- const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-MLRKNP7Y.js");
5626
+ const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-Y2EJI3GG.js");
5434
5627
  const globalConfig = readGlobalConfig2();
5435
5628
  globalConfig.spiritModel = body.model;
5436
5629
  writeGlobalConfig2(globalConfig);
@@ -5458,7 +5651,7 @@ ${user.trimEnd()}
5458
5651
  if (!body.systemPrompt || !body.message) {
5459
5652
  return c.json({ error: "systemPrompt and message required" }, 400);
5460
5653
  }
5461
- const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-7PHSRDMO.js");
5654
+ const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-UODCCE4O.js");
5462
5655
  if (!isAiConfigured()) {
5463
5656
  return c.json({ error: "AI service not configured" }, 503);
5464
5657
  }
@@ -5750,11 +5943,11 @@ ${lines.join("\n")}` });
5750
5943
  var minds_default = app13;
5751
5944
 
5752
5945
  // packages/daemon/src/web/api/prompts.ts
5753
- import { zValidator as zValidator6 } from "@hono/zod-validator";
5946
+ import { zValidator as zValidator7 } from "@hono/zod-validator";
5754
5947
  import { eq as eq6, sql as sql4 } from "drizzle-orm";
5755
- import { Hono as Hono16 } from "hono";
5756
- import { z as z6 } from "zod";
5757
- var app14 = new Hono16().get("/", async (c) => {
5948
+ import { Hono as Hono17 } from "hono";
5949
+ import { z as z7 } from "zod";
5950
+ var app14 = new Hono17().get("/", async (c) => {
5758
5951
  let rows;
5759
5952
  try {
5760
5953
  const db = await getDb();
@@ -5777,7 +5970,7 @@ var app14 = new Hono16().get("/", async (c) => {
5777
5970
  };
5778
5971
  });
5779
5972
  return c.json(prompts);
5780
- }).put("/:key", requireAdmin, zValidator6("json", z6.object({ content: z6.string() })), async (c) => {
5973
+ }).put("/:key", requireAdmin, zValidator7("json", z7.object({ content: z7.string() })), async (c) => {
5781
5974
  const key = c.req.param("key");
5782
5975
  if (!PROMPT_KEYS.includes(key)) {
5783
5976
  return c.json({ error: "Unknown prompt key" }, 404);
@@ -5801,8 +5994,8 @@ var app14 = new Hono16().get("/", async (c) => {
5801
5994
  var prompts_default = app14;
5802
5995
 
5803
5996
  // packages/daemon/src/web/api/schedules.ts
5804
- import { CronExpressionParser } from "cron-parser";
5805
- import { Hono as Hono17 } from "hono";
5997
+ import { CronExpressionParser as CronExpressionParser3 } from "cron-parser";
5998
+ import { Hono as Hono18 } from "hono";
5806
5999
  var slog2 = logger_default.child("schedules");
5807
6000
  function readSchedules(dir) {
5808
6001
  return readVoluteConfig(dir)?.schedules ?? [];
@@ -5819,7 +6012,7 @@ function writeSchedules(name, dir, schedules) {
5819
6012
  data: { schedules }
5820
6013
  });
5821
6014
  }
5822
- var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) => {
6015
+ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) => {
5823
6016
  const name = c.req.param("name");
5824
6017
  const entry = await findMind(name);
5825
6018
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -5840,14 +6033,14 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
5840
6033
  }
5841
6034
  } else if (s.cron) {
5842
6035
  try {
5843
- const interval = CronExpressionParser.parse(s.cron);
6036
+ const interval = CronExpressionParser3.parse(s.cron);
5844
6037
  const next = interval.next().toDate();
5845
6038
  upcoming.push({ id: s.id, at: next.toISOString(), type: "cron" });
5846
6039
  } catch {
5847
6040
  slog2.warn(`invalid cron "${s.cron}" for schedule "${s.id}" of ${name}`);
5848
6041
  }
5849
6042
  try {
5850
- const prevInterval = CronExpressionParser.parse(s.cron);
6043
+ const prevInterval = CronExpressionParser3.parse(s.cron);
5851
6044
  const prev = prevInterval.prev().toDate();
5852
6045
  previous.push({ id: s.id, at: prev.toISOString() });
5853
6046
  } catch {
@@ -5863,13 +6056,13 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
5863
6056
  }
5864
6057
  } else if (sleepConfig?.enabled && sleepConfig.schedule) {
5865
6058
  try {
5866
- const sleepInterval = CronExpressionParser.parse(sleepConfig.schedule.sleep);
6059
+ const sleepInterval = CronExpressionParser3.parse(sleepConfig.schedule.sleep);
5867
6060
  const nextSleep = sleepInterval.next().toDate();
5868
6061
  upcoming.push({ id: "sleep", at: nextSleep.toISOString(), type: "cron" });
5869
6062
  } catch {
5870
6063
  }
5871
6064
  try {
5872
- const prevWakeInterval = CronExpressionParser.parse(sleepConfig.schedule.wake);
6065
+ const prevWakeInterval = CronExpressionParser3.parse(sleepConfig.schedule.wake);
5873
6066
  const prevWake = prevWakeInterval.prev().toDate();
5874
6067
  previous.push({ id: "sleep", at: prevWake.toISOString() });
5875
6068
  } catch {
@@ -5893,7 +6086,7 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
5893
6086
  for (const field of ["sleep", "wake"]) {
5894
6087
  if (body.schedule[field]) {
5895
6088
  try {
5896
- CronExpressionParser.parse(body.schedule[field]);
6089
+ CronExpressionParser3.parse(body.schedule[field]);
5897
6090
  } catch {
5898
6091
  return c.json({ error: `Invalid ${field} cron: ${body.schedule[field]}` }, 400);
5899
6092
  }
@@ -5939,7 +6132,7 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
5939
6132
  }
5940
6133
  if (body.cron) {
5941
6134
  try {
5942
- CronExpressionParser.parse(body.cron);
6135
+ CronExpressionParser3.parse(body.cron);
5943
6136
  } catch {
5944
6137
  return c.json({ error: `Invalid cron expression: ${body.cron}` }, 400);
5945
6138
  }
@@ -5986,7 +6179,7 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
5986
6179
  }
5987
6180
  if (body.cron !== void 0) {
5988
6181
  try {
5989
- CronExpressionParser.parse(body.cron);
6182
+ CronExpressionParser3.parse(body.cron);
5990
6183
  } catch {
5991
6184
  return c.json({ error: `Invalid cron expression: ${body.cron}` }, 400);
5992
6185
  }
@@ -6043,7 +6236,7 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
6043
6236
  const body = await c.req.text();
6044
6237
  const message = `[webhook: ${event}] ${body}`;
6045
6238
  try {
6046
- const { sendSystemMessage } = await import("./system-chat-4DQZOEZI.js");
6239
+ const { sendSystemMessage } = await import("./system-chat-XOALE2RD.js");
6047
6240
  await sendSystemMessage(name, message);
6048
6241
  return c.json({ ok: true });
6049
6242
  } catch (err) {
@@ -6057,10 +6250,10 @@ var schedules_default = app15;
6057
6250
  import { mkdirSync as mkdirSync7 } from "fs";
6058
6251
  import { homedir as homedir2 } from "os";
6059
6252
  import { resolve as resolve11 } from "path";
6060
- import { Hono as Hono18 } from "hono";
6253
+ import { Hono as Hono19 } from "hono";
6061
6254
  import { setCookie as setCookie2 } from "hono/cookie";
6062
6255
  var DEFAULT_API_URL2 = "https://volute.systems";
6063
- var setup = new Hono18();
6256
+ var setup = new Hono19();
6064
6257
  function writeSetupConfig(systemName, description) {
6065
6258
  const configHome = process.env.VOLUTE_HOME ?? resolve11(homedir2(), ".volute");
6066
6259
  const mindsDir = resolve11(configHome, "minds");
@@ -6097,7 +6290,7 @@ setup.get("/status", async (c) => {
6097
6290
  let hasAccount = false;
6098
6291
  if (hasSystem) {
6099
6292
  try {
6100
- const { listUsersByType: listUsersByType2 } = await import("./auth-FRZJVQCS.js");
6293
+ const { listUsersByType: listUsersByType2 } = await import("./auth-FLAEXXZK.js");
6101
6294
  const brains = await listUsersByType2("brain");
6102
6295
  hasAccount = brains.length > 0;
6103
6296
  } catch (err) {
@@ -6308,7 +6501,7 @@ setup.post("/account", async (c) => {
6308
6501
  }
6309
6502
  }
6310
6503
  try {
6311
- const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-FRZJVQCS.js");
6504
+ const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-FLAEXXZK.js");
6312
6505
  const user = await createUser2(body.username.trim(), body.password);
6313
6506
  if (body.displayName?.trim()) {
6314
6507
  await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
@@ -6354,7 +6547,7 @@ setup.post("/models", async (c) => {
6354
6547
  return c.json({ error: "Spirit model is required" }, 400);
6355
6548
  }
6356
6549
  try {
6357
- const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-7PHSRDMO.js");
6550
+ const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-UODCCE4O.js");
6358
6551
  setEnabledModels3(body.models);
6359
6552
  const config2 = readGlobalConfig();
6360
6553
  config2.spiritModel = body.spiritModel.trim();
@@ -6372,15 +6565,15 @@ setup.post("/complete", async (c) => {
6372
6565
  return c.json({ error: "Setup already complete" }, 400);
6373
6566
  }
6374
6567
  try {
6375
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-IK5OYWMV.js");
6376
- const { startSpiritFull } = await import("./mind-service-S3SY7HAM.js");
6568
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-DBTIW7P4.js");
6569
+ const { startSpiritFull } = await import("./mind-service-3F4I46CI.js");
6377
6570
  await ensureSpiritProject();
6378
6571
  await syncSpiritTemplate();
6379
6572
  const warnings = [];
6380
6573
  const config2 = readGlobalConfig();
6381
6574
  if (config2.setup?.service && config2.setup?.type === "local") {
6382
6575
  try {
6383
- const { installUserService } = await import("./service-install-4QNUDKLM.js");
6576
+ const { installUserService } = await import("./service-install-4HHFDDWY.js");
6384
6577
  const installed = await installUserService(config2.port, config2.hostname);
6385
6578
  if (!installed) {
6386
6579
  warnings.push("Service installation is not supported on this platform.");
@@ -6408,8 +6601,8 @@ setup.post("/complete", async (c) => {
6408
6601
  }
6409
6602
  let spiritConversationId;
6410
6603
  try {
6411
- const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-FRZJVQCS.js");
6412
- const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-WAJYZKOC.js");
6604
+ const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-FLAEXXZK.js");
6605
+ const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-JZTD6KLR.js");
6413
6606
  const spiritUser = await getOrCreateMindUser2("volute");
6414
6607
  const brains = await listUsersByType2("brain");
6415
6608
  const admin2 = brains.find((u) => u.role === "admin");
@@ -6431,8 +6624,8 @@ setup.post("/complete", async (c) => {
6431
6624
  logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
6432
6625
  if (spiritConversationId && spiritStarted) {
6433
6626
  try {
6434
- const { deliverMessage: deliverMessage2 } = await import("./message-delivery-2EA5LLMD.js");
6435
- const { listUsersByType: listUsers2 } = await import("./auth-FRZJVQCS.js");
6627
+ const { deliverMessage: deliverMessage2 } = await import("./message-delivery-3C65ZI6L.js");
6628
+ const { listUsersByType: listUsers2 } = await import("./auth-FLAEXXZK.js");
6436
6629
  const admins = await listUsers2("brain");
6437
6630
  const admin2 = admins.find((u) => u.role === "admin");
6438
6631
  const adminName = admin2?.display_name || admin2?.username || "the admin";
@@ -6473,8 +6666,8 @@ import { existsSync as existsSync8, mkdtempSync, readdirSync as readdirSync3, rm
6473
6666
  import { tmpdir } from "os";
6474
6667
  import { join, resolve as resolve12 } from "path";
6475
6668
  import AdmZip from "adm-zip";
6476
- import { Hono as Hono19 } from "hono";
6477
- var app16 = new Hono19().get("/", async (c) => {
6669
+ import { Hono as Hono20 } from "hono";
6670
+ var app16 = new Hono20().get("/", async (c) => {
6478
6671
  const skills = await listSharedSkills();
6479
6672
  return c.json(skills);
6480
6673
  }).get("/defaults/list", async (c) => {
@@ -6598,15 +6791,15 @@ var app16 = new Hono19().get("/", async (c) => {
6598
6791
  var skills_default = app16;
6599
6792
 
6600
6793
  // packages/daemon/src/web/api/typing.ts
6601
- import { zValidator as zValidator7 } from "@hono/zod-validator";
6602
- import { Hono as Hono20 } from "hono";
6603
- import { z as z7 } from "zod";
6604
- var typingSchema = z7.object({
6605
- channel: z7.string().min(1),
6606
- sender: z7.string().min(1),
6607
- active: z7.boolean()
6794
+ import { zValidator as zValidator8 } from "@hono/zod-validator";
6795
+ import { Hono as Hono21 } from "hono";
6796
+ import { z as z8 } from "zod";
6797
+ var typingSchema = z8.object({
6798
+ channel: z8.string().min(1),
6799
+ sender: z8.string().min(1),
6800
+ active: z8.boolean()
6608
6801
  });
6609
- var app17 = new Hono20().post("/:name/typing", zValidator7("json", typingSchema), (c) => {
6802
+ var app17 = new Hono21().post("/:name/typing", zValidator8("json", typingSchema), (c) => {
6610
6803
  const { channel, sender, active } = c.req.valid("json");
6611
6804
  const map = getTypingMap();
6612
6805
  if (active) {
@@ -6630,9 +6823,9 @@ var typing_default = app17;
6630
6823
 
6631
6824
  // packages/daemon/src/web/api/update.ts
6632
6825
  import { spawn as spawn3 } from "child_process";
6633
- import { Hono as Hono21 } from "hono";
6826
+ import { Hono as Hono22 } from "hono";
6634
6827
  var bin;
6635
- var app18 = new Hono21().get("/update", async (c) => {
6828
+ var app18 = new Hono22().get("/update", async (c) => {
6636
6829
  const result = await checkForUpdate();
6637
6830
  return c.json(result);
6638
6831
  }).post("/update", requireAdmin, async (c) => {
@@ -6650,13 +6843,13 @@ var app18 = new Hono21().get("/update", async (c) => {
6650
6843
  var update_default = app18;
6651
6844
 
6652
6845
  // packages/daemon/src/web/api/v1/conversations.ts
6653
- import { zValidator as zValidator8 } from "@hono/zod-validator";
6654
- import { Hono as Hono22 } from "hono";
6655
- import { z as z8 } from "zod";
6656
- var createSchema = z8.object({
6657
- participantNames: z8.array(z8.string()).min(1)
6846
+ import { zValidator as zValidator9 } from "@hono/zod-validator";
6847
+ import { Hono as Hono23 } from "hono";
6848
+ import { z as z9 } from "zod";
6849
+ var createSchema = z9.object({
6850
+ participantNames: z9.array(z9.string()).min(1)
6658
6851
  });
6659
- var app19 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
6852
+ var app19 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
6660
6853
  const user = c.get("user");
6661
6854
  const convs = await listConversationsWithParticipants(user.id);
6662
6855
  return c.json(convs);
@@ -6683,7 +6876,7 @@ var app19 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
6683
6876
  }
6684
6877
  const participants = await getParticipants(id);
6685
6878
  return c.json(participants);
6686
- }).post("/", zValidator8("json", createSchema), async (c) => {
6879
+ }).post("/", zValidator9("json", createSchema), async (c) => {
6687
6880
  const user = c.get("user");
6688
6881
  const body = c.req.valid("json");
6689
6882
  const participantIds = /* @__PURE__ */ new Set();
@@ -6732,7 +6925,7 @@ var app19 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
6732
6925
  }
6733
6926
  await markConversationRead(user.id, id);
6734
6927
  return c.json({ ok: true });
6735
- }).put("/:id/private", zValidator8("json", z8.object({ private: z8.boolean() })), async (c) => {
6928
+ }).put("/:id/private", zValidator9("json", z9.object({ private: z9.boolean() })), async (c) => {
6736
6929
  const id = c.req.param("id");
6737
6930
  const user = c.get("user");
6738
6931
  if (!await isParticipantOrOwner(id, user.id)) {
@@ -6752,7 +6945,7 @@ var conversations_default = app19;
6752
6945
 
6753
6946
  // packages/daemon/src/web/api/v1/events.ts
6754
6947
  import { desc as desc5, eq as eq7 } from "drizzle-orm";
6755
- import { Hono as Hono23 } from "hono";
6948
+ import { Hono as Hono24 } from "hono";
6756
6949
  import { streamSSE as streamSSE4 } from "hono/streaming";
6757
6950
 
6758
6951
  // packages/daemon/src/lib/events/brain-presence.ts
@@ -6815,7 +7008,7 @@ function getEventsSince(sinceId, allowedConversationIds, allowedActivityMind) {
6815
7008
  }
6816
7009
 
6817
7010
  // packages/daemon/src/web/api/v1/events.ts
6818
- var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
7011
+ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
6819
7012
  const user = c.get("user");
6820
7013
  const since = c.req.query("since");
6821
7014
  const sinceId = since ? Number(since) : 0;
@@ -6833,7 +7026,7 @@ var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
6833
7026
  conversations2 = await listConversationsWithParticipants(user.id);
6834
7027
  if (conversations2.length > 0) {
6835
7028
  const convIds = conversations2.map((c2) => c2.id);
6836
- const unreads = await getUnreadCounts(user.id, convIds);
7029
+ const unreads = await getUnreadCounts(user.id, convIds, user.username);
6837
7030
  for (const conv of conversations2) {
6838
7031
  conv.unreadCount = unreads[conv.id] ?? 0;
6839
7032
  }
@@ -6927,7 +7120,7 @@ var events_default = app20;
6927
7120
  // packages/daemon/src/web/api/variants.ts
6928
7121
  import { existsSync as existsSync9, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8 } from "fs";
6929
7122
  import { resolve as resolve14 } from "path";
6930
- import { Hono as Hono24 } from "hono";
7123
+ import { Hono as Hono25 } from "hono";
6931
7124
 
6932
7125
  // packages/daemon/src/lib/mind/spawn-server.ts
6933
7126
  import { spawn as spawn4 } from "child_process";
@@ -7052,7 +7245,7 @@ async function verify2(port) {
7052
7245
  }
7053
7246
 
7054
7247
  // packages/daemon/src/web/api/variants.ts
7055
- var app21 = new Hono24().get("/:name/variants", async (c) => {
7248
+ var app21 = new Hono25().get("/:name/variants", async (c) => {
7056
7249
  const name = c.req.param("name");
7057
7250
  const entry = await findMind(name);
7058
7251
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -7082,6 +7275,11 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7082
7275
  if (!entry) return c.json({ error: "Mind not found" }, 404);
7083
7276
  if (entry.stage === "seed")
7084
7277
  return c.json({ error: "Seed minds cannot create variants \u2014 sprout first" }, 403);
7278
+ if (entry.parent)
7279
+ return c.json(
7280
+ { error: "Cannot split from a variant \u2014 split from the base mind instead" },
7281
+ 403
7282
+ );
7085
7283
  let body;
7086
7284
  try {
7087
7285
  body = await c.req.json();
@@ -7095,7 +7293,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7095
7293
  if (await findMind(variantName)) {
7096
7294
  return c.json({ error: `Name already in use: ${variantName}` }, 409);
7097
7295
  }
7098
- const projectRoot = mindDir(mindName);
7296
+ const projectRoot = entry.dir ?? mindDir(mindName);
7099
7297
  const variantDir = resolve14(projectRoot, ".variants", variantName);
7100
7298
  if (existsSync9(variantDir)) {
7101
7299
  return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
@@ -7129,7 +7327,9 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7129
7327
  await addVariant(variantName, mindName, variantPort, variantDir, variantName);
7130
7328
  if (!body.noStart) {
7131
7329
  try {
7132
- await getMindManager().startMind(variantName);
7330
+ const manager = getMindManager();
7331
+ manager.setPendingContext(variantName, { type: "split", parent: mindName });
7332
+ await manager.startMind(variantName);
7133
7333
  } catch (e) {
7134
7334
  const msg = e instanceof Error ? e.message : String(e);
7135
7335
  return c.json({ error: `Variant created but failed to start: ${msg}` }, 500);
@@ -7157,7 +7357,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7157
7357
  body = await c.req.json();
7158
7358
  } catch {
7159
7359
  }
7160
- const projectRoot = mindDir(mindName);
7360
+ const projectRoot = parentEntry.dir ?? mindDir(mindName);
7161
7361
  if (existsSync9(variantEntry.dir)) {
7162
7362
  const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
7163
7363
  if (status) {
@@ -7190,7 +7390,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7190
7390
  }
7191
7391
  const verified = await verify2(result.actualPort);
7192
7392
  try {
7193
- process.kill(result.child.pid);
7393
+ process.kill(-result.child.pid, "SIGTERM");
7194
7394
  } catch {
7195
7395
  }
7196
7396
  if (!verified) {
@@ -7217,13 +7417,47 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7217
7417
  try {
7218
7418
  await gitExec(["merge", variantEntry.branch], { cwd: projectRoot });
7219
7419
  } catch (_e) {
7220
- return c.json({ error: "Merge failed. Resolve conflicts manually." }, 500);
7420
+ let conflicts = [];
7421
+ try {
7422
+ const out = (await gitExec(["diff", "--name-only", "--diff-filter=U"], { cwd: projectRoot })).trim();
7423
+ conflicts = out ? out.split("\n") : [];
7424
+ } catch (err) {
7425
+ logger_default.warn(`failed to list merge conflicts for ${mindName}`, logger_default.errorData(err));
7426
+ }
7427
+ try {
7428
+ await gitExec(["merge", "--abort"], { cwd: projectRoot });
7429
+ } catch (err) {
7430
+ logger_default.warn(`failed to abort merge for ${mindName}`, logger_default.errorData(err));
7431
+ }
7432
+ try {
7433
+ await chownMindDir(projectRoot, mindName);
7434
+ } catch (err) {
7435
+ logger_default.warn(
7436
+ `failed to restore ownership after aborted merge for ${mindName}`,
7437
+ logger_default.errorData(err)
7438
+ );
7439
+ return c.json(
7440
+ {
7441
+ error: `Merge failed and restoring parent ownership failed: ${err instanceof Error ? err.message : String(err)}`,
7442
+ conflicts
7443
+ },
7444
+ 500
7445
+ );
7446
+ }
7447
+ return c.json(
7448
+ {
7449
+ error: "Merge failed. Resolve conflicts in the variant and retry the join.",
7450
+ conflicts
7451
+ },
7452
+ 500
7453
+ );
7221
7454
  }
7222
- await cleanupVariant(variantName, projectRoot, variantEntry.dir);
7455
+ await cleanupVariant(variantName, projectRoot, variantEntry.dir, { stop: true });
7456
+ await chownMindDir(projectRoot, mindName);
7223
7457
  if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
7224
7458
  try {
7225
7459
  const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-446HHH5V.js");
7226
- const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-NUJAGLQJ.js");
7460
+ const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-OUZBZ3Q4.js");
7227
7461
  const tmpl = parentEntry.template ?? "claude";
7228
7462
  await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
7229
7463
  } catch (err) {
@@ -7274,29 +7508,29 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7274
7508
  return c.json({ error: `Unknown variant: ${variantName}` }, 404);
7275
7509
  }
7276
7510
  if (!variantEntry.dir) return c.json({ error: `Variant ${variantName} has no directory` }, 500);
7277
- const projectRoot = mindDir(mindName);
7511
+ const projectRoot = parentEntry.dir ?? mindDir(mindName);
7278
7512
  await cleanupVariant(variantName, projectRoot, variantEntry.dir, { stop: true });
7279
7513
  return c.json({ ok: true });
7280
7514
  });
7281
7515
  var variants_default = app21;
7282
7516
 
7283
7517
  // packages/daemon/src/web/api/volute/channels.ts
7284
- import { zValidator as zValidator9 } from "@hono/zod-validator";
7285
- import { Hono as Hono25 } from "hono";
7286
- import { z as z9 } from "zod";
7287
- var channelSettingsSchema = z9.object({
7288
- description: z9.string().nullable().optional(),
7289
- rules: z9.string().nullable().optional(),
7290
- charLimit: z9.number().int().positive().nullable().optional(),
7291
- private: z9.boolean().optional()
7518
+ import { zValidator as zValidator10 } from "@hono/zod-validator";
7519
+ import { Hono as Hono26 } from "hono";
7520
+ import { z as z10 } from "zod";
7521
+ var channelSettingsSchema = z10.object({
7522
+ description: z10.string().nullable().optional(),
7523
+ rules: z10.string().nullable().optional(),
7524
+ charLimit: z10.number().int().positive().nullable().optional(),
7525
+ private: z10.boolean().optional()
7292
7526
  });
7293
- var createSchema2 = z9.object({
7294
- name: z9.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
7527
+ var createSchema2 = z10.object({
7528
+ name: z10.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
7295
7529
  }).merge(channelSettingsSchema);
7296
- var inviteSchema = z9.object({
7297
- username: z9.string().min(1)
7530
+ var inviteSchema = z10.object({
7531
+ username: z10.string().min(1)
7298
7532
  });
7299
- var app22 = new Hono25().get("/", async (c) => {
7533
+ var app22 = new Hono26().get("/", async (c) => {
7300
7534
  const user = c.get("user");
7301
7535
  const channels2 = await listChannels();
7302
7536
  const results = await Promise.all(
@@ -7307,7 +7541,7 @@ var app22 = new Hono25().get("/", async (c) => {
7307
7541
  })
7308
7542
  );
7309
7543
  return c.json(results);
7310
- }).post("/", zValidator9("json", createSchema2), async (c) => {
7544
+ }).post("/", zValidator10("json", createSchema2), async (c) => {
7311
7545
  const user = c.get("user");
7312
7546
  const body = c.req.valid("json");
7313
7547
  try {
@@ -7335,7 +7569,7 @@ var app22 = new Hono25().get("/", async (c) => {
7335
7569
  participants,
7336
7570
  settings: formatChannelSettings(settings)
7337
7571
  });
7338
- }).patch("/:name", zValidator9("json", channelSettingsSchema), async (c) => {
7572
+ }).patch("/:name", zValidator10("json", channelSettingsSchema), async (c) => {
7339
7573
  const name = c.req.param("name");
7340
7574
  const user = c.get("user");
7341
7575
  const body = c.req.valid("json");
@@ -7367,7 +7601,7 @@ var app22 = new Hono25().get("/", async (c) => {
7367
7601
  if (!ch) return c.json({ error: "Channel not found" }, 404);
7368
7602
  const participants = await getParticipants(ch.id);
7369
7603
  return c.json(participants);
7370
- }).post("/:name/invite", zValidator9("json", inviteSchema), async (c) => {
7604
+ }).post("/:name/invite", zValidator10("json", inviteSchema), async (c) => {
7371
7605
  const name = c.req.param("name");
7372
7606
  const inviter = c.get("user");
7373
7607
  const { username } = c.req.valid("json");
@@ -7393,27 +7627,27 @@ var app22 = new Hono25().get("/", async (c) => {
7393
7627
  var channels_default2 = app22;
7394
7628
 
7395
7629
  // packages/daemon/src/web/api/volute/chat.ts
7396
- import { zValidator as zValidator10 } from "@hono/zod-validator";
7397
- import { Hono as Hono26 } from "hono";
7630
+ import { zValidator as zValidator11 } from "@hono/zod-validator";
7631
+ import { Hono as Hono27 } from "hono";
7398
7632
  import { streamSSE as streamSSE5 } from "hono/streaming";
7399
- import { z as z10 } from "zod";
7400
- var fileSchema = z10.object({
7401
- filename: z10.string(),
7402
- data: z10.string()
7633
+ import { z as z11 } from "zod";
7634
+ var fileSchema = z11.object({
7635
+ filename: z11.string(),
7636
+ data: z11.string()
7403
7637
  // base64
7404
7638
  });
7405
- var chatSchema = z10.object({
7406
- message: z10.string().optional(),
7407
- conversationId: z10.string().optional(),
7408
- targetMind: z10.string().optional(),
7409
- sender: z10.string().optional(),
7410
- images: z10.array(
7411
- z10.object({
7412
- media_type: z10.string(),
7413
- data: z10.string()
7639
+ var chatSchema = z11.object({
7640
+ message: z11.string().optional(),
7641
+ conversationId: z11.string().optional(),
7642
+ targetMind: z11.string().optional(),
7643
+ sender: z11.string().optional(),
7644
+ images: z11.array(
7645
+ z11.object({
7646
+ media_type: z11.string(),
7647
+ data: z11.string()
7414
7648
  })
7415
7649
  ).optional(),
7416
- files: z10.array(fileSchema).optional()
7650
+ files: z11.array(fileSchema).optional()
7417
7651
  });
7418
7652
  var MAX_FILE_SIZE2 = 50 * 1024 * 1024;
7419
7653
  function stageFilesForMinds(files, targetMinds, senderName) {
@@ -7441,9 +7675,9 @@ function stageFilesForMinds(files, targetMinds, senderName) {
7441
7675
  }
7442
7676
  return { notifications };
7443
7677
  }
7444
- var unifiedChatApp = new Hono26().post(
7678
+ var unifiedChatApp = new Hono27().post(
7445
7679
  "/chat",
7446
- zValidator10("json", chatSchema),
7680
+ zValidator11("json", chatSchema),
7447
7681
  async (c) => {
7448
7682
  const user = c.get("user");
7449
7683
  const body = c.req.valid("json");
@@ -7454,7 +7688,7 @@ var unifiedChatApp = new Hono26().post(
7454
7688
  return c.json({ error: "conversationId or targetMind required" }, 400);
7455
7689
  }
7456
7690
  const senderName = user.id === 0 && body.sender ? body.sender : user.username;
7457
- const senderIsMind = user.id === 0 && body.sender && await findMind(body.sender) || user.user_type === "mind";
7691
+ const senderIsMind = user.id === 0 && body.sender && await findMind(body.sender) || user.user_type === "mind" || user.user_type === "system" && !!await findMind(user.username);
7458
7692
  let baseName;
7459
7693
  let variantName;
7460
7694
  let conversationId = body.conversationId;
@@ -7531,7 +7765,7 @@ var unifiedChatApp = new Hono26().post(
7531
7765
  }
7532
7766
  }
7533
7767
  if (senderIsMind) {
7534
- const vCfg = readVoluteConfig(mindDir(baseName ?? senderName));
7768
+ const vCfg = readVoluteConfig(await resolveMindDir(baseName ?? senderName));
7535
7769
  const shouldUnescapeNewlines = vCfg?.unescapeNewlines === true;
7536
7770
  for (const block of contentBlocks) {
7537
7771
  if (block.type === "text") {
@@ -7624,18 +7858,21 @@ var unifiedChatApp = new Hono26().post(
7624
7858
  targetName: baseName ? (username) => username === baseName ? variantName : username : void 0
7625
7859
  });
7626
7860
  const systemReplyTarget = baseName ?? senderName;
7627
- if (senderIsMind && body.message) {
7628
- const hasSystemUser = participants.some((p) => p.userType === "system");
7629
- if (hasSystemUser) {
7630
- generateSystemReply(conversationId, systemReplyTarget, body.message).catch(
7631
- (err) => logger_default.error(`system reply generation failed for ${systemReplyTarget}`, logger_default.errorData(err))
7632
- );
7633
- }
7861
+ if (shouldGenerateSystemFallback({
7862
+ senderIsMind: !!senderIsMind,
7863
+ hasMessage: !!body.message,
7864
+ convType: conv.type,
7865
+ participants,
7866
+ replyTarget: systemReplyTarget
7867
+ })) {
7868
+ generateSystemFallbackReply(conversationId, systemReplyTarget, body.message).catch(
7869
+ (err) => logger_default.error(`system reply generation failed for ${systemReplyTarget}`, logger_default.errorData(err))
7870
+ );
7634
7871
  }
7635
7872
  return c.json({ ok: true, conversationId, outboundId });
7636
7873
  }
7637
7874
  );
7638
- var app23 = new Hono26().get("/:name/conversations/:id/events", async (c) => {
7875
+ var app23 = new Hono27().get("/:name/conversations/:id/events", async (c) => {
7639
7876
  const conversationId = c.req.param("id");
7640
7877
  const user = c.get("user");
7641
7878
  if (user.id !== 0 && !await isParticipantOrOwner(conversationId, user.id)) {
@@ -7664,14 +7901,14 @@ var app23 = new Hono26().get("/:name/conversations/:id/events", async (c) => {
7664
7901
  var chat_default = app23;
7665
7902
 
7666
7903
  // packages/daemon/src/web/api/volute/conversations.ts
7667
- import { zValidator as zValidator11 } from "@hono/zod-validator";
7668
- import { Hono as Hono27 } from "hono";
7669
- import { z as z11 } from "zod";
7670
- var createConvSchema = z11.object({
7671
- participantIds: z11.array(z11.number()).optional(),
7672
- participantNames: z11.array(z11.string()).optional()
7904
+ import { zValidator as zValidator12 } from "@hono/zod-validator";
7905
+ import { Hono as Hono28 } from "hono";
7906
+ import { z as z12 } from "zod";
7907
+ var createConvSchema = z12.object({
7908
+ participantIds: z12.array(z12.number()).optional(),
7909
+ participantNames: z12.array(z12.string()).optional()
7673
7910
  });
7674
- var app24 = new Hono27().get("/:name/conversations", async (c) => {
7911
+ var app24 = new Hono28().get("/:name/conversations", async (c) => {
7675
7912
  const name = c.req.param("name");
7676
7913
  const user = c.get("user");
7677
7914
  let lookupId = user.id;
@@ -7681,7 +7918,7 @@ var app24 = new Hono27().get("/:name/conversations", async (c) => {
7681
7918
  }
7682
7919
  const convs = await listConversationsForUser(lookupId);
7683
7920
  return c.json(convs);
7684
- }).post("/:name/conversations", zValidator11("json", createConvSchema), async (c) => {
7921
+ }).post("/:name/conversations", zValidator12("json", createConvSchema), async (c) => {
7685
7922
  const name = c.req.param("name");
7686
7923
  const user = c.get("user");
7687
7924
  const body = c.req.valid("json");
@@ -7777,7 +8014,7 @@ var conversations_default2 = app24;
7777
8014
 
7778
8015
  // packages/daemon/src/web/app.ts
7779
8016
  var httpLog = logger_default.child("http");
7780
- var app25 = new Hono28();
8017
+ var app25 = new Hono29();
7781
8018
  app25.onError((err, c) => {
7782
8019
  if (err instanceof HTTPException) {
7783
8020
  return err.getResponse();
@@ -7844,10 +8081,11 @@ app25.use("/api/skills/*", authMiddleware);
7844
8081
  app25.use("/api/extensions/*", authMiddleware);
7845
8082
  app25.use("/api/bridges/*", authMiddleware);
7846
8083
  app25.use("/api/config/*", authMiddleware);
8084
+ app25.use("/api/backup/*", authMiddleware);
7847
8085
  app25.use("/api/v1/*", authMiddleware);
7848
8086
  app25.route("/api/setup", setup_default);
7849
8087
  app25.route("/api/config", config_default);
7850
- 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);
8088
+ 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);
7851
8089
  app25.route("/api/v1/minds", minds_default);
7852
8090
  app25.route("/api/v1/minds", chat_default);
7853
8091
  app25.route("/api/v1/minds", typing_default);
@@ -7906,8 +8144,8 @@ async function startServer({
7906
8144
  const ext = extname3(filePath);
7907
8145
  const mime = MIME_TYPES2[ext] || "application/octet-stream";
7908
8146
  const body = await readFile2(filePath);
7909
- const basename2 = filePath.slice(filePath.lastIndexOf("/") + 1);
7910
- const nameWithoutExt = basename2.slice(0, basename2.lastIndexOf("."));
8147
+ const basename = filePath.slice(filePath.lastIndexOf("/") + 1);
8148
+ const nameWithoutExt = basename.slice(0, basename.lastIndexOf("."));
7911
8149
  const isHashed = /[-.][\da-f]{8,}$/.test(nameWithoutExt);
7912
8150
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
7913
8151
  return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
@@ -8005,27 +8243,27 @@ async function startDaemon(opts) {
8005
8243
  const DAEMON_TOKEN_PATH = resolve16(systemDir, "daemon-token");
8006
8244
  mkdirSync10(home, { recursive: true });
8007
8245
  ensureSystemDir();
8008
- const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-MLRKNP7Y.js");
8246
+ const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-Y2EJI3GG.js");
8009
8247
  migrateConfigSecrets();
8010
8248
  migrateSetupCompleted();
8011
- const { migrateAiModelQualification } = await import("./ai-service-7PHSRDMO.js");
8249
+ const { migrateAiModelQualification } = await import("./ai-service-UODCCE4O.js");
8012
8250
  migrateAiModelQualification();
8013
- await (await import("./db-JFLCJCUG.js")).getDb();
8251
+ await (await import("./db-MF2JNRUW.js")).getDb();
8014
8252
  try {
8015
8253
  const { eq: eq8, and: and6 } = await import("drizzle-orm");
8016
8254
  const { users: users2 } = await import("./schema-PVNG3PQM.js");
8017
- const db = await (await import("./db-JFLCJCUG.js")).getDb();
8255
+ const db = await (await import("./db-MF2JNRUW.js")).getDb();
8018
8256
  await db.update(users2).set({ role: "system" }).where(and6(eq8(users2.user_type, "system"), eq8(users2.role, "user")));
8019
8257
  } catch (err) {
8020
8258
  logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
8021
8259
  }
8022
8260
  try {
8023
- const { migrateAvatarSizes } = await import("./avatar-image-BNWEXSA2.js");
8261
+ const { migrateAvatarSizes } = await import("./avatar-image-6KY6UU4D.js");
8024
8262
  await migrateAvatarSizes();
8025
8263
  } catch (err) {
8026
8264
  logger_default.warn("avatar size migration failed", logger_default.errorData(err));
8027
8265
  }
8028
- const { initSandbox } = await import("./sandbox-IOPWWILM.js");
8266
+ const { initSandbox } = await import("./sandbox-ZJ7QA6Z6.js");
8029
8267
  await initSandbox();
8030
8268
  try {
8031
8269
  await syncBuiltinSkills();
@@ -8052,7 +8290,7 @@ async function startDaemon(opts) {
8052
8290
  logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
8053
8291
  }
8054
8292
  try {
8055
- const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-FRZJVQCS.js");
8293
+ const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-FLAEXXZK.js");
8056
8294
  await getOrCreateSystemUser2();
8057
8295
  } catch (err) {
8058
8296
  logger_default.warn(
@@ -8060,13 +8298,13 @@ async function startDaemon(opts) {
8060
8298
  logger_default.errorData(err)
8061
8299
  );
8062
8300
  }
8063
- const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes2(32).toString("hex");
8064
- const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-MLRKNP7Y.js");
8301
+ const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes3(32).toString("hex");
8302
+ const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-Y2EJI3GG.js");
8065
8303
  const globalCfg = readGlobalConfig2();
8066
8304
  let tls;
8067
8305
  if (opts.tailscale || globalCfg.tailscale) {
8068
8306
  try {
8069
- const { getTailscaleTls } = await import("./tailscale-QAWVKQKU.js");
8307
+ const { getTailscaleTls } = await import("./tailscale-3XOKOW7T.js");
8070
8308
  const tlsConfig = await getTailscaleTls();
8071
8309
  tls = { key: tlsConfig.key, cert: tlsConfig.cert };
8072
8310
  logger_default.info("Tailscale HTTPS enabled", { hostname: tlsConfig.hostname });
@@ -8112,6 +8350,8 @@ async function startDaemon(opts) {
8112
8350
  sleepManager.start();
8113
8351
  const summarizer = initSummarizer();
8114
8352
  summarizer.start();
8353
+ const backupManager2 = initBackupManager();
8354
+ backupManager2.start();
8115
8355
  const unsubscribeWebhook = initWebhook();
8116
8356
  const orphanedTurns = await completeOrphanedTurns();
8117
8357
  summarizeOrphanedTurns(orphanedTurns);
@@ -8144,10 +8384,10 @@ async function startDaemon(opts) {
8144
8384
  await Promise.all(workers);
8145
8385
  }
8146
8386
  try {
8147
- const { isSetupComplete: isSetupComplete2 } = await import("./setup-MLRKNP7Y.js");
8387
+ const { isSetupComplete: isSetupComplete2 } = await import("./setup-Y2EJI3GG.js");
8148
8388
  if (isSetupComplete2()) {
8149
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-IK5OYWMV.js");
8150
- const { startSpiritFull } = await import("./mind-service-S3SY7HAM.js");
8389
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-DBTIW7P4.js");
8390
+ const { startSpiritFull } = await import("./mind-service-3F4I46CI.js");
8151
8391
  await ensureSpiritProject();
8152
8392
  await syncSpiritTemplate();
8153
8393
  const spiritEntry = await findMind("volute");
@@ -8164,7 +8404,7 @@ async function startDaemon(opts) {
8164
8404
  bridgeManager.startBridges(daemonPort).catch((err) => {
8165
8405
  logger_default.warn("failed to start bridges", logger_default.errorData(err));
8166
8406
  });
8167
- import("./cloud-sync-6WJ7WFYD.js").then(
8407
+ import("./cloud-sync-3OJOPZRT.js").then(
8168
8408
  ({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
8169
8409
  logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
8170
8410
  })
@@ -8172,7 +8412,7 @@ async function startDaemon(opts) {
8172
8412
  logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
8173
8413
  });
8174
8414
  try {
8175
- const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-B67N35A3.js");
8415
+ const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-3XMAIQTE.js");
8176
8416
  backfillTemplateHashes();
8177
8417
  notifyVersionUpdate().catch((err) => {
8178
8418
  logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
@@ -8240,6 +8480,7 @@ async function startDaemon(opts) {
8240
8480
  safe("mailPoller.stop", () => mailPoller.stop());
8241
8481
  safe("tokenBudget.stop", () => tokenBudget.stop());
8242
8482
  safe("summarizer.stop", () => summarizer.stop());
8483
+ safe("backupManager.stop", () => backupManager2.stop());
8243
8484
  safe("stopApiKeyRefresh", stopApiKeyRefresh);
8244
8485
  safe("delivery.dispose", () => delivery.dispose());
8245
8486
  await safe("bridgeManager.stopAll", () => bridgeManager.stopAll());