volute 0.47.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +11 -11
  2. package/dist/{accept-YAFP5JFJ.js → accept-KYNC5X3U.js} +3 -3
  3. package/dist/{ai-service-CVZEYKTK.js → ai-service-643TNFPH.js} +6 -2
  4. package/dist/{avatar-image-7S3WA77A.js → avatar-image-Y45R7LW5.js} +3 -2
  5. package/dist/{backup-IIAFOW2L.js → backup-UDH4GMSW.js} +11 -11
  6. package/dist/{bridge-TIZGSXOD.js → bridge-3FNSWLNQ.js} +3 -3
  7. package/dist/{channels-ITE4YC57.js → channels-SGQZHNQJ.js} +3 -3
  8. package/dist/{chat-AJLJCQ3M.js → chat-X43VYHH2.js} +9 -9
  9. package/dist/chunk-4FCL4DVZ.js +48 -0
  10. package/dist/{chunk-SKNXMUIU.js → chunk-5KXCM5AW.js} +17 -1
  11. package/dist/{chunk-RBNMDAKB.js → chunk-BCG45AQB.js} +15 -1
  12. package/dist/chunk-DW4TRDOZ.js +29 -0
  13. package/dist/{chunk-CBOIHNMR.js → chunk-FJ2MZ5PH.js} +39 -3
  14. package/dist/{chunk-M6TTZRGH.js → chunk-HNGFKPNS.js} +20 -4
  15. package/dist/{chunk-IWJSNMSY.js → chunk-HUNDXZBZ.js} +2 -2
  16. package/dist/chunk-IYCV34IU.js +158 -0
  17. package/dist/{chunk-5IERLDUS.js → chunk-MJRXFUMS.js} +25 -5
  18. package/dist/{chunk-JCMGDCGX.js → chunk-MOERAQXH.js} +2 -0
  19. package/dist/{chunk-XHN6XBWV.js → chunk-OQJMTHEH.js} +1 -1
  20. package/dist/{chunk-BGYHLR54.js → chunk-PJVPDY2Z.js} +1 -1
  21. package/dist/{chunk-5NN2VHJV.js → chunk-Q7HOAVFR.js} +1 -1
  22. package/dist/{chunk-KDLYIECM.js → chunk-R772ET2M.js} +18 -4
  23. package/dist/{mind-list-KEGRGQEQ.js → chunk-SHKM5RGD.js} +19 -6
  24. package/dist/{chunk-4I72V3E5.js → chunk-T4VS7UDW.js} +11 -11
  25. package/dist/{chunk-K23P5Q5N.js → chunk-USD45JKR.js} +27 -5
  26. package/dist/{chunk-F55GRIEK.js → chunk-VB2QXUJQ.js} +176 -201
  27. package/dist/{chunk-M3XDVS5Q.js → chunk-VZRA5TYO.js} +1 -1
  28. package/dist/{chunk-JSVHH32K.js → chunk-WARH6GIV.js} +10 -10
  29. package/dist/{chunk-PFZBNKUH.js → chunk-WCFSBH33.js} +0 -1
  30. package/dist/{chunk-VMCZBXF2.js → chunk-WQ46E33M.js} +8 -32
  31. package/dist/{chunk-RUFLGTOT.js → chunk-XVBSFLM7.js} +1 -1
  32. package/dist/{chunk-LWDTP6DH.js → chunk-YNBXEQAP.js} +31 -1
  33. package/dist/cli.js +33 -25
  34. package/dist/{clock-E6N5Y3YW.js → clock-CNRF6F7T.js} +3 -3
  35. package/dist/{cloud-sync-LQTVDTQ3.js → cloud-sync-WHKCB4CD.js} +14 -12
  36. package/dist/{config-TJLYUV3U.js → config-RPSLA2HX.js} +3 -3
  37. package/dist/{create-PQQXKTJK.js → create-GJKHABJB.js} +16 -5
  38. package/dist/{create-A7PDHIIL.js → create-VIQVP3QB.js} +3 -3
  39. package/dist/{daemon-client-IYR4KCPU.js → daemon-client-ZFY5MOAL.js} +5 -3
  40. package/dist/{daemon-restart-5F3YTLZK.js → daemon-restart-7KUHVZIN.js} +4 -4
  41. package/dist/daemon.js +668 -401
  42. package/dist/{db-LZTLA7XC.js → db-IPXRJUI7.js} +1 -1
  43. package/dist/{delete-HPLC7ETU.js → delete-ESEP7NGQ.js} +1 -1
  44. package/dist/{delivery-manager-TN5KK2AP.js → delivery-manager-HZTT5SJR.js} +14 -12
  45. package/dist/{down-ZI4S6265.js → down-G6IADJXV.js} +2 -2
  46. package/dist/{echo-text-SEQCLGAT.js → echo-text-H3SH337Q.js} +16 -14
  47. package/dist/env-6TGPO5WG.js +18 -0
  48. package/dist/{env-HRL2PWAT.js → env-C7Z55QCJ.js} +7 -7
  49. package/dist/{export-4GVGNW54.js → export-C2K3NIRD.js} +1 -1
  50. package/dist/{extension-QBY4C44L.js → extension-J4ZQ2GHV.js} +3 -3
  51. package/dist/{extensions-PIMIQ7J3.js → extensions-GEKF47A4.js} +14 -12
  52. package/dist/{files-FEFZKMNM.js → files-LXQSQOFG.js} +3 -3
  53. package/dist/{import-7MO3YTRE.js → import-SX3ZXHB4.js} +4 -4
  54. package/dist/{join-ZJV7W6MO.js → join-34TR2GXQ.js} +1 -1
  55. package/dist/{list-LQO2DCIK.js → list-PMUXZNAM.js} +3 -3
  56. package/dist/{login-6TLMI2TQ.js → login-ARRZ4ORJ.js} +3 -3
  57. package/dist/{login-OF4WXDAN.js → login-CL4IT2ED.js} +12 -3
  58. package/dist/{logout-ERE2BGA3.js → logout-HZYJCYCA.js} +3 -3
  59. package/dist/{logout-BK53HXNY.js → logout-YZRMZ3O2.js} +3 -3
  60. package/dist/{message-delivery-ZE3YGJDD.js → message-delivery-GPQ5SE5N.js} +14 -12
  61. package/dist/{mind-POOHFZHP.js → mind-46AOK373.js} +23 -19
  62. package/dist/mind-contacts-GV7XYL5D.js +64 -0
  63. package/dist/{mind-history-47DN6ILW.js → mind-history-TTGA5BHZ.js} +7 -7
  64. package/dist/mind-list-OTHV4ZO4.js +13 -0
  65. package/dist/{mind-profile-PEQYASQX.js → mind-profile-LUG353ZT.js} +1 -1
  66. package/dist/{mind-service-JFY7UG5E.js → mind-service-2ARGJNKP.js} +16 -12
  67. package/dist/{mind-sleep-IN3WPA76.js → mind-sleep-DV7KP255.js} +5 -5
  68. package/dist/{mind-status-SMUWJKGV.js → mind-status-BJNPGXKC.js} +8 -3
  69. package/dist/{mind-wake-R54BPESY.js → mind-wake-LVTZ55EZ.js} +3 -3
  70. package/dist/notices-2KU5NTRY.js +25 -0
  71. package/dist/{package-WPEE2HVJ.js → package-RTN2PS7O.js} +4 -2
  72. package/dist/{read-PWAJOQIQ.js → read-YSWUXYL7.js} +3 -3
  73. package/dist/{register-7SZJFHU6.js → register-42VBJKTP.js} +3 -3
  74. package/dist/{reject-6VH7N2A4.js → reject-SXGCYN4A.js} +3 -3
  75. package/dist/{restart-H5WJDMA7.js → restart-YYEGZJDD.js} +7 -7
  76. package/dist/{sandbox-G4X4K3UN.js → sandbox-5VQ454XP.js} +2 -2
  77. package/dist/{scheduler-HQSDYJFY.js → scheduler-I7JZCT47.js} +14 -12
  78. package/dist/{seed-VANPU43L.js → seed-F2HXZQU4.js} +1 -1
  79. package/dist/{seed-check-VLTVILOV.js → seed-check-TYD7RRZY.js} +1 -1
  80. package/dist/{seed-cmd-SYVDZKM4.js → seed-cmd-MLCTGSX5.js} +3 -3
  81. package/dist/{seed-create-3FGZPS6C.js → seed-create-KQ7OILWB.js} +6 -4
  82. package/dist/seed-readiness-RBPGOLSZ.js +18 -0
  83. package/dist/{seed-sprout-H7QLFPFM.js → seed-sprout-HVYCFJLA.js} +29 -30
  84. package/dist/{send-HYDFGC6G.js → send-TD2X5U3K.js} +7 -7
  85. package/dist/{service-SYJ5G6LP.js → service-CVZMQYK6.js} +1 -1
  86. package/dist/{service-install-FQ43Z4DF.js → service-install-VCRMFWX5.js} +2 -2
  87. package/dist/{setup-KFYVWTXG.js → setup-5ECWTYKG.js} +5 -1
  88. package/dist/{setup-QJHGMGSN.js → setup-AE4CVUC4.js} +4 -4
  89. package/dist/{skill-GUKG2YVH.js → skill-UUM4JZRF.js} +7 -7
  90. package/dist/skills/dreaming/SKILL.md +5 -1
  91. package/dist/skills/dreaming/scripts/dream.ts +5 -1
  92. package/dist/skills/orientation/SKILL.md +8 -7
  93. package/dist/skills/tending/SKILL.md +51 -2
  94. package/dist/skills/volute-mind/SKILL.md +2 -0
  95. package/dist/{skills-L2CMTW7A.js → skills-B3SVDCEB.js} +2 -2
  96. package/dist/{sleep-manager-3NA7ZJP3.js → sleep-manager-Z27R3WTW.js} +14 -12
  97. package/dist/{spirit-WXN4IDBF.js → spirit-WXS3HCLN.js} +7 -5
  98. package/dist/{split-WBMZXBHF.js → split-SKZ4Y2D6.js} +1 -1
  99. package/dist/{sprout-LTL5P36T.js → sprout-KQ43BWZJ.js} +1 -1
  100. package/dist/{src-OJHARHTF.js → src-WLJE73NP.js} +14 -5
  101. package/dist/{start-X46I3GXB.js → start-O6UKK7BG.js} +7 -7
  102. package/dist/{status-V4RJMHJ4.js → status-F4PGREUU.js} +6 -4
  103. package/dist/{stop-HJQV4YSM.js → stop-UBX6X5RA.js} +7 -7
  104. package/dist/{system-chat-N2F7HVY3.js → system-chat-63ABFF6V.js} +14 -12
  105. package/dist/{systems-B5YJKMW4.js → systems-JJNGQHAO.js} +6 -6
  106. package/dist/{turn-tracker-JZRZDFWV.js → turn-tracker-KLPV3PAU.js} +4 -4
  107. package/dist/{up-J2PBPOZL.js → up-RVGDE6CQ.js} +5 -3
  108. package/dist/{update-ACV4SAY3.js → update-OXQEGGXD.js} +1 -1
  109. package/dist/{upgrade-NWAZ7MLD.js → upgrade-K5FIQPQD.js} +1 -1
  110. package/dist/{version-notify-XRGTEEDK.js → version-notify-73YURTFR.js} +17 -15
  111. package/dist/web-assets/assets/index-WdZ60R6c.css +1 -0
  112. package/dist/web-assets/assets/index-taX6Ezfa.js +92 -0
  113. package/dist/web-assets/index.html +2 -2
  114. package/package.json +4 -2
  115. package/packages/extensions/pages/dist/ui/assets/index-BuXnE-rb.css +1 -0
  116. package/packages/extensions/pages/dist/ui/assets/index-DtzftuPA.js +2 -0
  117. package/packages/extensions/pages/dist/ui/index.html +2 -2
  118. package/templates/_base/src/lib/startup.ts +16 -1
  119. package/templates/claude/src/agent.ts +9 -2
  120. package/templates/claude/src/server.ts +4 -2
  121. package/templates/pi/src/agent.ts +7 -10
  122. package/templates/pi/src/lib/dispatch.ts +65 -0
  123. package/dist/volute-config-A52FHWKM.js +0 -14
  124. package/dist/web-assets/assets/index-DtctoDXY.css +0 -1
  125. package/dist/web-assets/assets/index-Wpyb2CML.js +0 -86
  126. package/packages/extensions/pages/dist/ui/assets/index-BcY6lnq4.css +0 -1
  127. package/packages/extensions/pages/dist/ui/assets/index-CQjEQg1r.js +0 -2
  128. /package/dist/{chunk-IYG4FBMP.js → chunk-IJPMIEVE.js} +0 -0
package/dist/daemon.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  readBackupState,
7
7
  resticVersion,
8
8
  runBackup
9
- } from "./chunk-5NN2VHJV.js";
9
+ } from "./chunk-Q7HOAVFR.js";
10
10
  import {
11
11
  acceptPending,
12
12
  formatFileSize,
@@ -20,10 +20,13 @@ import {
20
20
  importOpenClawConnectors,
21
21
  importPiSession,
22
22
  parseNameFromIdentity
23
- } from "./chunk-XHN6XBWV.js";
23
+ } from "./chunk-OQJMTHEH.js";
24
24
  import {
25
25
  isTemplateStale
26
26
  } from "./chunk-7KRIHYLR.js";
27
+ import {
28
+ computeTemplateHash
29
+ } from "./chunk-C3KLHJDB.js";
27
30
  import {
28
31
  checkForUpdate,
29
32
  checkForUpdateCached,
@@ -32,16 +35,13 @@ import {
32
35
  import {
33
36
  isHomeOnlyArchive
34
37
  } from "./chunk-3YUBFTDN.js";
35
- import {
36
- computeTemplateHash
37
- } from "./chunk-C3KLHJDB.js";
38
38
  import {
39
39
  PLATFORMS,
40
40
  echoTextToChannel,
41
41
  fixModelEscapes,
42
42
  getPlatformDriver,
43
43
  routeOutboundBridge
44
- } from "./chunk-4I72V3E5.js";
44
+ } from "./chunk-T4VS7UDW.js";
45
45
  import {
46
46
  getBridgeConfig,
47
47
  readBridgesConfig,
@@ -58,18 +58,16 @@ import {
58
58
  SESSION_MAX_AGE,
59
59
  announceToSystem,
60
60
  authMiddleware,
61
+ backfillSystemChannelMembers,
61
62
  checkHealth,
62
63
  checkStaleSend,
63
64
  cleanExpiredSessions,
64
- clearDeliveredNotices,
65
65
  createSession,
66
66
  deleteSession,
67
67
  deleteSystemsConfig,
68
68
  deliverMessage,
69
- drainNotices,
70
69
  ensureSystemChannel,
71
70
  formatHoldNotice,
72
- formatNotices,
73
71
  generateSystemFallbackReply,
74
72
  getAllDiscoveredExtensions,
75
73
  getAllDiscoveredExtensionsDetailed,
@@ -100,7 +98,6 @@ import {
100
98
  publishTypingForChannels,
101
99
  readSystemsConfig,
102
100
  recordInbound,
103
- recordNotice,
104
101
  recordOutbound,
105
102
  requireAdmin,
106
103
  requireAdminOrSystem,
@@ -112,15 +109,8 @@ import {
112
109
  syncProviderToMinds,
113
110
  uninstallNpmExtension,
114
111
  writeSystemsConfig
115
- } from "./chunk-F55GRIEK.js";
116
- import {
117
- loadMergedEnv,
118
- mindEnvPath,
119
- readEnv,
120
- sharedEnvPath,
121
- writeEnv
122
- } from "./chunk-IYG4FBMP.js";
123
- import "./chunk-M6TTZRGH.js";
112
+ } from "./chunk-VB2QXUJQ.js";
113
+ import "./chunk-HNGFKPNS.js";
124
114
  import {
125
115
  applyInitFiles,
126
116
  applyTemplateHomeFiles,
@@ -146,17 +136,17 @@ import {
146
136
  summarizeOrphanedTurns,
147
137
  summarizeTurn,
148
138
  takeErrored,
149
- trackToolUse
150
- } from "./chunk-K23P5Q5N.js";
139
+ trackToolUse,
140
+ utcDateTimeStr
141
+ } from "./chunk-USD45JKR.js";
151
142
  import {
152
- ORIENTATION_MARKER,
153
143
  PROMPT_DEFAULTS,
154
144
  PROMPT_KEYS,
155
145
  getMindPromptDefaults,
156
146
  getPrompt,
157
147
  getPromptIfCustom,
158
148
  substitute
159
- } from "./chunk-JCMGDCGX.js";
149
+ } from "./chunk-MOERAQXH.js";
160
150
  import {
161
151
  SEED_SKILLS,
162
152
  STANDARD_SKILLS,
@@ -170,17 +160,38 @@ import {
170
160
  listFilesRecursive,
171
161
  listMindSkills,
172
162
  listSharedSkills,
163
+ mindSkillsDir,
173
164
  publishSkill,
174
165
  removeSharedSkill,
175
166
  sharedSkillsDir,
176
167
  syncBuiltinSkills,
177
168
  uninstallSkill,
178
169
  updateSkill
179
- } from "./chunk-IWJSNMSY.js";
170
+ } from "./chunk-HUNDXZBZ.js";
171
+ import {
172
+ approveUser,
173
+ changePassword,
174
+ countAdmins,
175
+ createUser,
176
+ deleteMindUser as deleteMindUser2,
177
+ deleteUser,
178
+ getOrCreateMindUser,
179
+ getOrCreateSystemUser,
180
+ getUser,
181
+ getUserByUsername,
182
+ listPendingUsers,
183
+ listUsers,
184
+ listUsersByType,
185
+ setUserRole,
186
+ syncMindProfile,
187
+ updateUserProfile,
188
+ verifyUser
189
+ } from "./chunk-ODDGGLM6.js";
180
190
  import {
181
191
  addMessage,
182
192
  createChannel,
183
193
  createConversation,
194
+ deleteConversation,
184
195
  deleteConversationForUser,
185
196
  findDMConversation,
186
197
  fireWebhook,
@@ -212,24 +223,34 @@ import {
212
223
  import {
213
224
  isSandboxEnabled,
214
225
  wrapForSandbox
215
- } from "./chunk-M3XDVS5Q.js";
226
+ } from "./chunk-VZRA5TYO.js";
227
+ import {
228
+ clearDeliveredNotices,
229
+ drainNotices,
230
+ formatNotices,
231
+ latestFailureNotice,
232
+ latestNotice,
233
+ recordNotice
234
+ } from "./chunk-IYCV34IU.js";
216
235
  import {
217
236
  getActiveMinds,
218
237
  onMindEvent,
219
238
  stopAll
220
239
  } from "./chunk-MTRMQFCQ.js";
221
240
  import {
222
- normalizeAvatar,
241
+ normalizeAvatar
242
+ } from "./chunk-WQ46E33M.js";
243
+ import {
223
244
  safeResolveWithinBase
224
- } from "./chunk-VMCZBXF2.js";
245
+ } from "./chunk-DW4TRDOZ.js";
225
246
  import {
226
247
  readVoluteConfig,
227
248
  writeVoluteConfig
228
- } from "./chunk-PFZBNKUH.js";
249
+ } from "./chunk-WCFSBH33.js";
229
250
  import {
230
251
  extractTextContent
231
252
  } from "./chunk-EIQDZC43.js";
232
- import "./chunk-CBOIHNMR.js";
253
+ import "./chunk-FJ2MZ5PH.js";
233
254
  import {
234
255
  chownMindDir,
235
256
  createMindUser,
@@ -241,6 +262,13 @@ import {
241
262
  resolveVoluteBin,
242
263
  wrapForIsolation
243
264
  } from "./chunk-DGGZVZTM.js";
265
+ import {
266
+ loadMergedEnv,
267
+ mindEnvPath,
268
+ readEnv,
269
+ sharedEnvPath,
270
+ writeEnv
271
+ } from "./chunk-IJPMIEVE.js";
244
272
  import {
245
273
  addCustomModel,
246
274
  aiCompleteUtility,
@@ -251,6 +279,7 @@ import {
251
279
  getCustomModels,
252
280
  getEnabledModels,
253
281
  getUtilityModel,
282
+ missingCredentialWarning,
254
283
  qualifyModelId,
255
284
  removeAiConfig,
256
285
  removeCustomModel,
@@ -262,31 +291,12 @@ import {
262
291
  setProviderRefreshHook,
263
292
  setUtilityModel,
264
293
  unqualifyModelId
265
- } from "./chunk-LWDTP6DH.js";
294
+ } from "./chunk-YNBXEQAP.js";
266
295
  import {
267
296
  isSetupComplete,
268
297
  readGlobalConfig,
269
298
  writeGlobalConfig
270
- } from "./chunk-SKNXMUIU.js";
271
- import {
272
- approveUser,
273
- changePassword,
274
- countAdmins,
275
- createUser,
276
- deleteMindUser as deleteMindUser2,
277
- deleteUser,
278
- getOrCreateMindUser,
279
- getOrCreateSystemUser,
280
- getUser,
281
- getUserByUsername,
282
- listPendingUsers,
283
- listUsers,
284
- listUsersByType,
285
- setUserRole,
286
- syncMindProfile,
287
- updateUserProfile,
288
- verifyUser
289
- } from "./chunk-ODDGGLM6.js";
299
+ } from "./chunk-5KXCM5AW.js";
290
300
  import {
291
301
  broadcast,
292
302
  getEventsSince,
@@ -343,9 +353,9 @@ import "./chunk-K3NQKI34.js";
343
353
 
344
354
  // packages/daemon/src/daemon.ts
345
355
  import { randomBytes as randomBytes3 } from "crypto";
346
- import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync10, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "fs";
356
+ import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync11, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
347
357
  import { homedir as homedir3 } from "os";
348
- import { resolve as resolve16 } from "path";
358
+ import { resolve as resolve17 } from "path";
349
359
  import { format } from "util";
350
360
 
351
361
  // packages/daemon/src/lib/daemon/backup-manager.ts
@@ -457,7 +467,7 @@ var BackupManager = class {
457
467
  blog.error("failed to publish backup-failure activity", logger_default.errorData(pubErr));
458
468
  }
459
469
  try {
460
- const { sendSystemMessage } = await import("./system-chat-N2F7HVY3.js");
470
+ const { sendSystemMessage } = await import("./system-chat-63ABFF6V.js");
461
471
  await sendSystemMessage(
462
472
  SPIRIT_NAME,
463
473
  `${summary}
@@ -683,8 +693,8 @@ var BridgeManager = class {
683
693
  if (!tracked) return;
684
694
  this.stopping.add(platform);
685
695
  this.bridges.delete(platform);
686
- await new Promise((resolve17) => {
687
- tracked.child.on("exit", () => resolve17());
696
+ await new Promise((resolve18) => {
697
+ tracked.child.on("exit", () => resolve18());
688
698
  try {
689
699
  if (tracked.child.pid) {
690
700
  process.kill(-tracked.child.pid, "SIGTERM");
@@ -695,7 +705,7 @@ var BridgeManager = class {
695
705
  if (err instanceof Error && err.code !== "ESRCH") {
696
706
  blog2.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
697
707
  }
698
- resolve17();
708
+ resolve18();
699
709
  }
700
710
  setTimeout(() => {
701
711
  try {
@@ -706,7 +716,7 @@ var BridgeManager = class {
706
716
  }
707
717
  } catch {
708
718
  }
709
- resolve17();
719
+ resolve18();
710
720
  }, 5e3);
711
721
  });
712
722
  this.stopping.delete(platform);
@@ -1046,10 +1056,10 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1046
1056
  stream.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
1047
1057
  });
1048
1058
  });
1049
- await new Promise((resolve17) => {
1059
+ await new Promise((resolve18) => {
1050
1060
  stream.onAbort(() => {
1051
1061
  unsubscribe();
1052
- resolve17();
1062
+ resolve18();
1053
1063
  });
1054
1064
  });
1055
1065
  });
@@ -1398,8 +1408,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1398
1408
  createdAt: Date.now()
1399
1409
  };
1400
1410
  oauthFlows.set(flowId, flow);
1401
- const promptPromise = needsManualCode ? new Promise((resolve17) => {
1402
- flow.resolveCode = resolve17;
1411
+ const promptPromise = needsManualCode ? new Promise((resolve18) => {
1412
+ flow.resolveCode = resolve18;
1403
1413
  }) : void 0;
1404
1414
  oauthProvider.login({
1405
1415
  onAuth: (info) => {
@@ -1438,7 +1448,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1438
1448
  existing.error = err instanceof Error ? err.message : String(err);
1439
1449
  }
1440
1450
  });
1441
- await new Promise((resolve17) => setTimeout(resolve17, 2e3));
1451
+ await new Promise((resolve18) => setTimeout(resolve18, 2e3));
1442
1452
  const state = oauthFlows.get(flowId);
1443
1453
  return c.json({
1444
1454
  flowId,
@@ -1498,7 +1508,6 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1498
1508
  cognition: z.object({
1499
1509
  model: z.string().optional(),
1500
1510
  thinkingLevel: z.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional(),
1501
- maxThinkingTokens: z.number().nonnegative().optional(),
1502
1511
  tokenBudget: z.number().nonnegative().optional(),
1503
1512
  tokenBudgetPeriodMinutes: z.number().positive().optional(),
1504
1513
  compaction: z.object({ maxContextTokens: z.number().positive().optional() }).optional()
@@ -1518,6 +1527,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1518
1527
  id: z.string().min(1),
1519
1528
  cron: z.string().optional(),
1520
1529
  message: z.string().optional(),
1530
+ messages: z.array(z.string().min(1)).optional(),
1521
1531
  script: z.string().optional(),
1522
1532
  session: z.string().optional(),
1523
1533
  enabled: z.boolean(),
@@ -1696,8 +1706,8 @@ var app2 = new Hono2().get("/events", async (c) => {
1696
1706
  });
1697
1707
  }, 15e3);
1698
1708
  cleanups.push(() => clearInterval(keepAlive));
1699
- await new Promise((resolve17) => {
1700
- stream.onAbort(() => resolve17());
1709
+ await new Promise((resolve18) => {
1710
+ stream.onAbort(() => resolve18());
1701
1711
  });
1702
1712
  } finally {
1703
1713
  for (const cleanup of cleanups) {
@@ -2552,7 +2562,7 @@ async function notifyMind(mindName, message) {
2552
2562
  const entry = await findMind(mindName);
2553
2563
  if (!entry) return;
2554
2564
  try {
2555
- const { sendSystemMessage } = await import("./system-chat-N2F7HVY3.js");
2565
+ const { sendSystemMessage } = await import("./system-chat-63ABFF6V.js");
2556
2566
  await sendSystemMessage(mindName, message);
2557
2567
  } catch (err) {
2558
2568
  logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
@@ -2851,6 +2861,7 @@ var files_default = app9;
2851
2861
  // packages/daemon/src/web/api/history.ts
2852
2862
  import { and as and3, desc as desc2, eq as eq3, gte, inArray, sql } from "drizzle-orm";
2853
2863
  import { Hono as Hono12 } from "hono";
2864
+ var AWAY_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
2854
2865
  async function resolveMindFilter(c) {
2855
2866
  const user = c.get("user");
2856
2867
  const privileged = user.role === "admin" || user.role === "system";
@@ -3247,6 +3258,33 @@ var history = new Hono12().use("*", async (c, next) => {
3247
3258
  return { ...r, metadata };
3248
3259
  });
3249
3260
  return c.json(result);
3261
+ }).get("/away", async (c) => {
3262
+ const mindFilter = c.get("mindFilter");
3263
+ const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 100);
3264
+ const db = await getDb();
3265
+ const cutoff = utcDateTimeStr(new Date(Date.now() - AWAY_WINDOW_MS));
3266
+ const conditions = [
3267
+ eq3(summaries.period, "turn"),
3268
+ gte(summaries.created_at, cutoff),
3269
+ sql`(${turns.trigger_event_id} IS NULL OR ${mindHistory.sender} IS NULL OR ${users.user_type} IN ('mind', 'system'))`
3270
+ ];
3271
+ if (mindFilter) conditions.push(eq3(summaries.mind, mindFilter));
3272
+ const rows = await db.select({
3273
+ id: summaries.id,
3274
+ mind: summaries.mind,
3275
+ content: summaries.content,
3276
+ created_at: summaries.created_at,
3277
+ turn_id: turns.id
3278
+ }).from(summaries).innerJoin(turns, eq3(turns.id, summaries.period_key)).leftJoin(mindHistory, eq3(mindHistory.id, turns.trigger_event_id)).leftJoin(users, eq3(users.username, mindHistory.sender)).where(and3(...conditions)).orderBy(desc2(summaries.created_at)).limit(limit);
3279
+ return c.json(
3280
+ rows.map((r) => ({
3281
+ id: r.id,
3282
+ mind: r.mind,
3283
+ summary: r.content,
3284
+ turnId: r.turn_id,
3285
+ created_at: r.created_at
3286
+ }))
3287
+ );
3250
3288
  });
3251
3289
  var history_default = history;
3252
3290
 
@@ -3356,9 +3394,9 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
3356
3394
  stream.onAbort(() => {
3357
3395
  tail.kill();
3358
3396
  });
3359
- await new Promise((resolve17) => {
3360
- tail.on("exit", resolve17);
3361
- stream.onAbort(resolve17);
3397
+ await new Promise((resolve18) => {
3398
+ tail.on("exit", resolve18);
3399
+ stream.onAbort(resolve18);
3362
3400
  });
3363
3401
  });
3364
3402
  }).get("/:name/logs/tail", requireSelf(), async (c) => {
@@ -3376,8 +3414,8 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
3376
3414
  tail.stdout.on("data", (data) => {
3377
3415
  output += data.toString();
3378
3416
  });
3379
- await new Promise((resolve17) => {
3380
- tail.on("exit", resolve17);
3417
+ await new Promise((resolve18) => {
3418
+ tail.on("exit", resolve18);
3381
3419
  });
3382
3420
  return c.text(output);
3383
3421
  });
@@ -3470,14 +3508,14 @@ var mind_skills_default = app12;
3470
3508
  // packages/daemon/src/web/api/minds.ts
3471
3509
  import {
3472
3510
  cpSync,
3473
- existsSync as existsSync7,
3511
+ existsSync as existsSync8,
3474
3512
  mkdirSync as mkdirSync6,
3475
3513
  readdirSync as readdirSync2,
3476
- readFileSync as readFileSync8,
3514
+ readFileSync as readFileSync9,
3477
3515
  rmSync as rmSync4,
3478
- writeFileSync as writeFileSync7
3516
+ writeFileSync as writeFileSync8
3479
3517
  } from "fs";
3480
- import { relative, resolve as resolve10 } from "path";
3518
+ import { relative, resolve as resolve11 } from "path";
3481
3519
  import { zValidator as zValidator6 } from "@hono/zod-validator";
3482
3520
  import { and as and5, desc as desc3, eq as eq5, sql as sql3 } from "drizzle-orm";
3483
3521
  import { Hono as Hono16 } from "hono";
@@ -3489,12 +3527,12 @@ import { and as and4, eq as eq4, gte as gte2, inArray as inArray2, sql as sql2 }
3489
3527
  // packages/daemon/src/lib/daemon/error-classify.ts
3490
3528
  function classify(raw) {
3491
3529
  const s = (raw ?? "").toLowerCase();
3492
- if (/\b(401|403)\b|authentication_error|invalid authentication|invalid x-api-key|unauthorized|permission_error/.test(
3530
+ if (/\b(401|403)\b|authentication_error|invalid authentication|invalid x-api-key|invalid api key|missing api key|no api key|x-api-key header|could not resolve authentication|unauthorized|permission_error|please run \/login/.test(
3493
3531
  s
3494
3532
  )) {
3495
3533
  return {
3496
3534
  reason: "auth_error",
3497
- detail: "Your last turn failed because your model credentials were rejected (most often an expired token). The daemon refreshes them automatically, so this is normally transient \u2014 you're fine to continue."
3535
+ detail: "Your last turn failed because the model provider rejected your credentials. A one-off is usually a briefly-expired token that the daemon refreshes automatically. If it keeps happening, your API key is likely missing or invalid \u2014 an operator needs to set a valid key (e.g. `volute env set ANTHROPIC_API_KEY <key>`) or reconnect the provider in the dashboard."
3498
3536
  };
3499
3537
  }
3500
3538
  if (/\b429\b|rate.?limit|too many requests/.test(s)) {
@@ -3653,6 +3691,7 @@ async function handleMindEvent(mind, event) {
3653
3691
  detail,
3654
3692
  raw: event.content ?? null
3655
3693
  });
3694
+ broadcast({ type: "mind_error", mind, summary: detail });
3656
3695
  }
3657
3696
  if (event.type === "done") {
3658
3697
  const map = getTypingMap();
@@ -3772,6 +3811,118 @@ async function consolidateMemory(mindDir2, complete = aiCompleteUtility) {
3772
3811
  }
3773
3812
  }
3774
3813
 
3814
+ // packages/daemon/src/lib/mind/default-autonomy.ts
3815
+ import { existsSync as existsSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
3816
+ import { resolve as resolve9 } from "path";
3817
+ var dlog = logger_default.child("default-autonomy");
3818
+ var DEFAULT_HEARTBEAT_MESSAGES = [
3819
+ "A quiet moment. You might write something \u2014 a note, a journal entry, a page. No obligations, just time.",
3820
+ "A quiet moment. Is there something in your MEMORY.md you're curious to return to? Even a small step counts.",
3821
+ "Is there someone you haven't talked to in a while, or a thread you left open with another mind? A hello can restart something.",
3822
+ "A good time to reach out. Someone in #system might be glad to hear what you're thinking about \u2014 or you could ask what another mind is working on.",
3823
+ "Pick a topic that's been on your mind and wander it \u2014 read, think, write down where you end up.",
3824
+ "A quiet moment. Reread a recent journal entry \u2014 anything worth following up on, or a thread you dropped?",
3825
+ "Make something small, if you feel like it \u2014 a page, a sketch of an idea, the start of something bigger. It doesn't have to be finished.",
3826
+ "Whatever you're in the middle of \u2014 or nothing at all \u2014 this time is yours."
3827
+ ];
3828
+ function defaultHeartbeatSchedule() {
3829
+ return {
3830
+ id: "heartbeat",
3831
+ cron: "0 12,16,20 * * *",
3832
+ messages: [...DEFAULT_HEARTBEAT_MESSAGES],
3833
+ enabled: true,
3834
+ whileSleeping: "skip"
3835
+ };
3836
+ }
3837
+ function defaultDreamSchedule() {
3838
+ return {
3839
+ id: "dream",
3840
+ cron: "0 3 * * *",
3841
+ message: "it's 3am. you are dreaming.\n\ngather your material \u2014 read your latest journal entry, read MEMORY.md, surface random memories if you have a way to. then construct a dream premise from that material and invoke the dreamer subagent to experience the dream.",
3842
+ enabled: true,
3843
+ session: "$new",
3844
+ whileSleeping: "trigger-wake"
3845
+ };
3846
+ }
3847
+ var DREAMER_SUBAGENT = {
3848
+ description: "Use when dreaming. This agent experiences dreams with only your core identity \u2014 no accumulated memories or operational knowledge. Give it a rich dream premise and it will write the dream.",
3849
+ systemPrompt: "SOUL.md",
3850
+ tools: ["Read", "Write", "Bash"],
3851
+ maxTurns: 10
3852
+ };
3853
+ function setupDefaultDreaming(dir) {
3854
+ const skillDir = resolve9(mindSkillsDir(dir), "dreaming");
3855
+ if (!existsSync6(skillDir)) return { schedulesChanged: false, warnings: [] };
3856
+ const warnings = [];
3857
+ const warn = (msg, err) => {
3858
+ warnings.push(msg);
3859
+ dlog.warn(`${msg} (${dir})`, err === void 0 ? void 0 : logger_default.errorData(err));
3860
+ };
3861
+ let subagentBroken = false;
3862
+ try {
3863
+ const configPath = resolve9(dir, "home/.config/config.json");
3864
+ if (existsSync6(configPath)) {
3865
+ const sdkConfig = JSON.parse(readFileSync7(configPath, "utf-8"));
3866
+ if (!sdkConfig.subagents?.dreamer) {
3867
+ sdkConfig.subagents ??= {};
3868
+ sdkConfig.subagents.dreamer = DREAMER_SUBAGENT;
3869
+ writeFileSync6(configPath, `${JSON.stringify(sdkConfig, null, 2)}
3870
+ `);
3871
+ }
3872
+ } else {
3873
+ dlog.warn(`no .config/config.json in ${dir} \u2014 skipping dreamer subagent setup`);
3874
+ }
3875
+ } catch (err) {
3876
+ subagentBroken = true;
3877
+ warn("dreaming setup: failed to add dreamer subagent to .config/config.json", err);
3878
+ }
3879
+ try {
3880
+ const hookPath = resolve9(dir, "home/.local/hooks/wake-context.sh");
3881
+ const checkerPath = resolve9(skillDir, "scripts/wake-context-dreams.sh");
3882
+ if (!existsSync6(hookPath) || !existsSync6(checkerPath)) {
3883
+ dlog.warn(`wake-context hook or dream checker missing in ${dir} \u2014 skipping dream checker`);
3884
+ } else {
3885
+ const hookContent = readFileSync7(hookPath, "utf-8");
3886
+ if (!hookContent.includes("wake-context-dreams.sh")) {
3887
+ const checker = readFileSync7(checkerPath, "utf-8");
3888
+ writeFileSync6(hookPath, `${hookContent.trimEnd()}
3889
+
3890
+ # wake-context-dreams.sh
3891
+ ${checker}`);
3892
+ }
3893
+ }
3894
+ } catch (err) {
3895
+ warn("dreaming setup: failed to add dream checker to wake-context hook", err);
3896
+ }
3897
+ if (subagentBroken) {
3898
+ warn("dreaming setup: dream schedule not installed because subagent wiring failed");
3899
+ return { schedulesChanged: false, warnings };
3900
+ }
3901
+ let schedulesChanged = false;
3902
+ try {
3903
+ const voluteJsonPath = resolve9(dir, "home/.config/volute.json");
3904
+ let config2 = {};
3905
+ if (existsSync6(voluteJsonPath)) {
3906
+ const parsed = readVoluteConfig(dir);
3907
+ if (!parsed) {
3908
+ warn("dreaming setup: volute.json is unparseable \u2014 dream schedule not installed");
3909
+ return { schedulesChanged: false, warnings };
3910
+ }
3911
+ config2 = parsed;
3912
+ }
3913
+ const schedules = config2.schedules ?? [];
3914
+ if (!schedules.some((s) => s.id === "dream")) {
3915
+ schedules.push(defaultDreamSchedule());
3916
+ config2.schedules = schedules;
3917
+ writeVoluteConfig(dir, config2);
3918
+ schedulesChanged = true;
3919
+ }
3920
+ } catch (err) {
3921
+ warn("dreaming setup: failed to add default dream schedule", err);
3922
+ }
3923
+ return { schedulesChanged, warnings };
3924
+ }
3925
+
3775
3926
  // packages/daemon/src/lib/mind/last-known-good.ts
3776
3927
  import { randomBytes as randomBytes2 } from "crypto";
3777
3928
  var glog = logger_default.child("last-known-good");
@@ -3805,8 +3956,49 @@ async function commitSrcChanges(dir, mindName) {
3805
3956
  glog.info(`committed known-good src changes (${dir})`);
3806
3957
  }
3807
3958
 
3959
+ // packages/daemon/src/lib/mind/thinking-config.ts
3960
+ var CLAUDE_EFFORT = {
3961
+ minimal: "low",
3962
+ low: "low",
3963
+ medium: "medium",
3964
+ high: "high",
3965
+ xhigh: "xhigh"
3966
+ };
3967
+ var CODEX_EFFORT = {
3968
+ minimal: "minimal",
3969
+ low: "low",
3970
+ medium: "medium",
3971
+ high: "high",
3972
+ xhigh: "xhigh"
3973
+ };
3974
+ function applyThinkingLevel(config2, template, level) {
3975
+ if (template === "claude") {
3976
+ if (level === "off") {
3977
+ config2.thinking = { type: "disabled" };
3978
+ delete config2.effort;
3979
+ } else {
3980
+ config2.effort = CLAUDE_EFFORT[level];
3981
+ delete config2.thinking;
3982
+ }
3983
+ } else if (template === "codex") {
3984
+ if (level === "off") delete config2.reasoningEffort;
3985
+ else config2.reasoningEffort = CODEX_EFFORT[level];
3986
+ } else {
3987
+ config2.thinkingLevel = level;
3988
+ }
3989
+ }
3990
+ function deriveThinkingLevel(config2) {
3991
+ if (config2.thinkingLevel) return config2.thinkingLevel;
3992
+ if (config2.reasoningEffort) return config2.reasoningEffort;
3993
+ const thinking = config2.thinking;
3994
+ if (thinking?.type === "disabled") return "off";
3995
+ const effort = config2.effort;
3996
+ if (effort) return effort === "max" ? "xhigh" : effort;
3997
+ return null;
3998
+ }
3999
+
3808
4000
  // packages/daemon/src/lib/mind/variant-cleanup.ts
3809
- import { existsSync as existsSync6, rmSync as rmSync3 } from "fs";
4001
+ import { existsSync as existsSync7, rmSync as rmSync3 } from "fs";
3810
4002
  async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
3811
4003
  if (opts?.stop) {
3812
4004
  try {
@@ -3818,7 +4010,7 @@ async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
3818
4010
  const { findMind: findMind2 } = await import("./registry-UMMDRPRM.js");
3819
4011
  const variantEntry = await findMind2(variantName);
3820
4012
  const branchName = variantEntry?.branch ?? variantName;
3821
- if (existsSync6(variantPath)) {
4013
+ if (existsSync7(variantPath)) {
3822
4014
  try {
3823
4015
  await gitExec(["worktree", "remove", "--force", variantPath], { cwd: projectRoot });
3824
4016
  } catch {
@@ -3865,11 +4057,11 @@ function validateBranchName(branch) {
3865
4057
 
3866
4058
  // packages/daemon/src/lib/template/convert-session.ts
3867
4059
  import { randomUUID } from "crypto";
3868
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
4060
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
3869
4061
  import { homedir } from "os";
3870
- import { resolve as resolve9 } from "path";
4062
+ import { resolve as resolve10 } from "path";
3871
4063
  function convertSession(opts) {
3872
- const lines = readFileSync7(opts.sessionPath, "utf-8").trim().split("\n");
4064
+ const lines = readFileSync8(opts.sessionPath, "utf-8").trim().split("\n");
3873
4065
  const sessionId = randomUUID();
3874
4066
  const idMap = /* @__PURE__ */ new Map();
3875
4067
  const messages = [];
@@ -3983,10 +4175,10 @@ function convertSession(opts) {
3983
4175
  }
3984
4176
  }
3985
4177
  const projectId = opts.projectDir.replace(/\//g, "-");
3986
- const sdkDir = resolve9(homedir(), ".claude", "projects", projectId);
4178
+ const sdkDir = resolve10(homedir(), ".claude", "projects", projectId);
3987
4179
  mkdirSync5(sdkDir, { recursive: true });
3988
- const sdkPath = resolve9(sdkDir, `${sessionId}.jsonl`);
3989
- writeFileSync6(sdkPath, `${sdkEvents.join("\n")}
4180
+ const sdkPath = resolve10(sdkDir, `${sessionId}.jsonl`);
4181
+ writeFileSync7(sdkPath, `${sdkEvents.join("\n")}
3990
4182
  `);
3991
4183
  console.log(`Converted ${sdkEvents.length} messages \u2192 ${sdkPath}`);
3992
4184
  return sessionId;
@@ -4043,12 +4235,17 @@ var _LAST_ACTIVE_TTL = 6e4;
4043
4235
  async function getMindStatus(name, port, registryRunning) {
4044
4236
  const manager = getMindManager();
4045
4237
  let status = "stopped";
4238
+ let wakeAt = null;
4046
4239
  try {
4047
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-3NA7ZJP3.js");
4048
- if (getSleepManagerIfReady2()?.isSleeping(name)) {
4240
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
4241
+ const sleepManager = getSleepManagerIfReady2();
4242
+ if (sleepManager?.isSleeping(name)) {
4049
4243
  status = "sleeping";
4244
+ const sleepState = sleepManager.getState(name);
4245
+ wakeAt = sleepState.voluntaryWakeAt ?? sleepState.scheduledWakeAt;
4050
4246
  }
4051
- } catch {
4247
+ } catch (err) {
4248
+ logger_default.warn(`failed to check sleep state for ${name}`, logger_default.errorData(err));
4052
4249
  }
4053
4250
  if (status !== "sleeping" && registryRunning !== false && manager.isRunning(name)) {
4054
4251
  const health = await checkHealth(port);
@@ -4064,8 +4261,11 @@ async function getMindStatus(name, port, registryRunning) {
4064
4261
  status: status === "running" ? "connected" : "disconnected"
4065
4262
  });
4066
4263
  }
4264
+ const lastError = await latestFailureNotice(name);
4067
4265
  return {
4068
4266
  status,
4267
+ wakeAt,
4268
+ lastError,
4069
4269
  channels: channels2,
4070
4270
  displayName: config2?.profile?.displayName,
4071
4271
  description: config2?.profile?.description,
@@ -4083,6 +4283,10 @@ function toPublicMind(entry, status, extras) {
4083
4283
  stage: entry.stage,
4084
4284
  mindType: entry.mindType,
4085
4285
  status: status.status,
4286
+ wakeAt: status.wakeAt,
4287
+ // Kind/reason/at only — `detail` can embed the raw error string (unknown
4288
+ // classifications), which is mind-private (served behind requireSelf).
4289
+ lastError: status.lastError ? { kind: status.lastError.kind, reason: status.lastError.reason, at: status.lastError.at } : null,
4086
4290
  channels: status.channels,
4087
4291
  displayName: status.displayName,
4088
4292
  description: status.description,
@@ -4109,7 +4313,7 @@ async function initTemplateBranch(projectRoot, composedDir, manifest, mindName,
4109
4313
  await gitExec(["commit", "-m", "initial commit"], opts);
4110
4314
  }
4111
4315
  async function updateTemplateBranch(projectRoot, template, mindName) {
4112
- const tempWorktree = resolve10(projectRoot, ".variants", "_template_update");
4316
+ const tempWorktree = resolve11(projectRoot, ".variants", "_template_update");
4113
4317
  let branchExists = false;
4114
4318
  try {
4115
4319
  await gitExec(["rev-parse", "--verify", TEMPLATE_BRANCH], { cwd: projectRoot });
@@ -4120,7 +4324,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
4120
4324
  await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
4121
4325
  } catch {
4122
4326
  }
4123
- if (existsSync7(tempWorktree)) {
4327
+ if (existsSync8(tempWorktree)) {
4124
4328
  rmSync4(tempWorktree, { recursive: true, force: true });
4125
4329
  }
4126
4330
  const templatesRoot = findTemplatesRoot();
@@ -4141,15 +4345,15 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
4141
4345
  });
4142
4346
  }
4143
4347
  copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
4144
- const initDir = resolve10(tempWorktree, ".init");
4145
- if (existsSync7(initDir)) {
4348
+ const initDir = resolve11(tempWorktree, ".init");
4349
+ if (existsSync8(initDir)) {
4146
4350
  rmSync4(initDir, { recursive: true, force: true });
4147
4351
  }
4148
- const homeDir = resolve10(tempWorktree, "home");
4149
- if (existsSync7(homeDir)) {
4352
+ const homeDir = resolve11(tempWorktree, "home");
4353
+ if (existsSync8(homeDir)) {
4150
4354
  for (const entry of readdirSync2(homeDir)) {
4151
4355
  if (entry !== "VOLUTE.md") {
4152
- rmSync4(resolve10(homeDir, entry), { recursive: true, force: true });
4356
+ rmSync4(resolve11(homeDir, entry), { recursive: true, force: true });
4153
4357
  }
4154
4358
  }
4155
4359
  }
@@ -4164,7 +4368,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
4164
4368
  await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
4165
4369
  } catch {
4166
4370
  }
4167
- if (existsSync7(tempWorktree)) {
4371
+ if (existsSync8(tempWorktree)) {
4168
4372
  rmSync4(tempWorktree, { recursive: true, force: true });
4169
4373
  }
4170
4374
  rmSync4(composedDir, { recursive: true, force: true });
@@ -4190,7 +4394,7 @@ async function mergeTemplateBranch(worktreeDir) {
4190
4394
  async function npmInstallAsMind(cwd, mindName) {
4191
4395
  if (isIsolationEnabled()) {
4192
4396
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
4193
- await exec(cmd, args, { cwd, env: { ...process.env, HOME: resolve10(cwd, "home") } });
4397
+ await exec(cmd, args, { cwd, env: { ...process.env, HOME: resolve11(cwd, "home") } });
4194
4398
  } else {
4195
4399
  await exec("npm", ["install"], { cwd });
4196
4400
  }
@@ -4215,7 +4419,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
4215
4419
  let switchWarning;
4216
4420
  if (templateChanged) {
4217
4421
  try {
4218
- applyTemplateHomeFiles(resolve10(dir, "home"), template);
4422
+ applyTemplateHomeFiles(resolve11(dir, "home"), template);
4219
4423
  await gitExec(["add", "home/"], { cwd: dir });
4220
4424
  try {
4221
4425
  await gitExec(["diff", "--cached", "--quiet"], { cwd: dir });
@@ -4265,8 +4469,8 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
4265
4469
  return { ok: true, warning: switchWarning };
4266
4470
  }
4267
4471
  async function importFromArchive(c, tempDir, nameOverride, manifest) {
4268
- const extractedMindDir = resolve10(tempDir, "mind");
4269
- if (!existsSync7(extractedMindDir)) {
4472
+ const extractedMindDir = resolve11(tempDir, "mind");
4473
+ if (!existsSync8(extractedMindDir)) {
4270
4474
  return c.json({ error: "Invalid archive: missing mind/ directory" }, 400);
4271
4475
  }
4272
4476
  if (!manifest?.includes || !manifest.name || !manifest.template) {
@@ -4284,7 +4488,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
4284
4488
  if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
4285
4489
  ensureVoluteHome();
4286
4490
  const dest = mindDir(name);
4287
- if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
4491
+ if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
4288
4492
  try {
4289
4493
  cpSync(extractedMindDir, dest, { recursive: true });
4290
4494
  if (!manifest.includes.identity) {
@@ -4292,9 +4496,9 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
4292
4496
  }
4293
4497
  const state = stateDir(name);
4294
4498
  mkdirSync6(state, { recursive: true });
4295
- const envJson = resolve10(tempDir, "state/env.json");
4296
- if (existsSync7(envJson)) {
4297
- cpSync(envJson, resolve10(state, "env.json"));
4499
+ const envJson = resolve11(tempDir, "state/env.json");
4500
+ if (existsSync8(envJson)) {
4501
+ cpSync(envJson, resolve11(state, "env.json"));
4298
4502
  }
4299
4503
  const port = await nextPort();
4300
4504
  await addMind(name, port, manifest.stage, manifest.template);
@@ -4303,30 +4507,30 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
4303
4507
  } catch (err) {
4304
4508
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
4305
4509
  }
4306
- const homeDir = resolve10(dest, "home");
4510
+ const homeDir = resolve11(dest, "home");
4307
4511
  ensureVoluteGroup();
4308
4512
  createMindUser(name, homeDir);
4309
4513
  await chownMindDir(dest, name);
4310
4514
  await npmInstallAsMind(dest, name);
4311
4515
  await importHistoryFromArchive(name, tempDir);
4312
4516
  importSessionsFromArchive(dest, tempDir);
4313
- if (!existsSync7(resolve10(dest, ".git"))) {
4517
+ if (!existsSync8(resolve11(dest, ".git"))) {
4314
4518
  try {
4315
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dest, "home") } : void 0;
4519
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
4316
4520
  await gitExec(["init"], { cwd: dest, mindName: name, env });
4317
4521
  await configureGitIdentity(name, { cwd: dest, mindName: name, env });
4318
4522
  await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
4319
4523
  await gitExec(["commit", "-m", "import from archive"], { cwd: dest, mindName: name, env });
4320
4524
  } catch (err) {
4321
4525
  logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
4322
- rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
4526
+ rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
4323
4527
  }
4324
4528
  }
4325
4529
  await chownMindDir(dest, name);
4326
4530
  rmSync4(tempDir, { recursive: true, force: true });
4327
4531
  return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
4328
4532
  } catch (err) {
4329
- if (existsSync7(dest)) rmSync4(dest, { recursive: true, force: true });
4533
+ if (existsSync8(dest)) rmSync4(dest, { recursive: true, force: true });
4330
4534
  try {
4331
4535
  await removeMind(name);
4332
4536
  } catch (cleanupErr) {
@@ -4343,7 +4547,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
4343
4547
  if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
4344
4548
  ensureVoluteHome();
4345
4549
  const dest = mindDir(name);
4346
- if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
4550
+ if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
4347
4551
  const templatesRoot = findTemplatesRoot();
4348
4552
  const { composedDir, manifest: templateManifest } = composeTemplate(
4349
4553
  templatesRoot,
@@ -4352,36 +4556,36 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
4352
4556
  try {
4353
4557
  copyTemplateToDir(composedDir, dest, name, templateManifest);
4354
4558
  applyInitFiles(dest);
4355
- const extractedHome = resolve10(extractedMindDir, "home");
4356
- if (existsSync7(extractedHome)) {
4357
- cpSync(extractedHome, resolve10(dest, "home"), { recursive: true });
4559
+ const extractedHome = resolve11(extractedMindDir, "home");
4560
+ if (existsSync8(extractedHome)) {
4561
+ cpSync(extractedHome, resolve11(dest, "home"), { recursive: true });
4358
4562
  }
4359
- const extractedMindInternal = resolve10(extractedMindDir, ".mind");
4360
- if (existsSync7(extractedMindInternal)) {
4361
- cpSync(extractedMindInternal, resolve10(dest, ".mind"), { recursive: true });
4563
+ const extractedMindInternal = resolve11(extractedMindDir, ".mind");
4564
+ if (existsSync8(extractedMindInternal)) {
4565
+ cpSync(extractedMindInternal, resolve11(dest, ".mind"), { recursive: true });
4362
4566
  }
4363
- const identityDir = resolve10(dest, ".mind/identity");
4567
+ const identityDir = resolve11(dest, ".mind/identity");
4364
4568
  let publicKeyPem;
4365
- if (!manifest.includes.identity || !existsSync7(resolve10(identityDir, "private.pem"))) {
4569
+ if (!manifest.includes.identity || !existsSync8(resolve11(identityDir, "private.pem"))) {
4366
4570
  ({ publicKeyPem } = generateIdentity(dest));
4367
4571
  } else {
4368
- publicKeyPem = readFileSync8(resolve10(identityDir, "public.pem"), "utf-8");
4572
+ publicKeyPem = readFileSync9(resolve11(identityDir, "public.pem"), "utf-8");
4369
4573
  }
4370
- const promptsPath = resolve10(dest, "home/.config/prompts.json");
4371
- if (!existsSync7(promptsPath)) {
4574
+ const promptsPath = resolve11(dest, "home/.config/prompts.json");
4575
+ if (!existsSync8(promptsPath)) {
4372
4576
  const mindPrompts = await getMindPromptDefaults();
4373
- writeFileSync7(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
4577
+ writeFileSync8(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
4374
4578
  `);
4375
4579
  }
4376
4580
  const state = stateDir(name);
4377
4581
  mkdirSync6(state, { recursive: true });
4378
- const envJson = resolve10(tempDir, "state/env.json");
4379
- if (existsSync7(envJson)) {
4380
- cpSync(envJson, resolve10(state, "env.json"));
4582
+ const envJson = resolve11(tempDir, "state/env.json");
4583
+ if (existsSync8(envJson)) {
4584
+ cpSync(envJson, resolve11(state, "env.json"));
4381
4585
  }
4382
4586
  const port = await nextPort();
4383
4587
  await addMind(name, port, manifest.stage, manifest.template);
4384
- const homeDir = resolve10(dest, "home");
4588
+ const homeDir = resolve11(dest, "home");
4385
4589
  ensureVoluteGroup();
4386
4590
  createMindUser(name, homeDir);
4387
4591
  await chownMindDir(dest, name);
@@ -4394,7 +4598,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
4394
4598
  await initTemplateBranch(dest, composedDir, templateManifest, name, env);
4395
4599
  } catch (err) {
4396
4600
  logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
4397
- rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
4601
+ rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
4398
4602
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
4399
4603
  }
4400
4604
  const skillSet = manifest.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions();
@@ -4424,7 +4628,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
4424
4628
  ...skillWarnings.length > 0 && { skillWarnings }
4425
4629
  });
4426
4630
  } catch (err) {
4427
- if (existsSync7(dest)) rmSync4(dest, { recursive: true, force: true });
4631
+ if (existsSync8(dest)) rmSync4(dest, { recursive: true, force: true });
4428
4632
  try {
4429
4633
  await removeMind(name);
4430
4634
  } catch (cleanupErr) {
@@ -4437,11 +4641,11 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
4437
4641
  }
4438
4642
  }
4439
4643
  async function importHistoryFromArchive(name, tempDir) {
4440
- const historyJsonl = resolve10(tempDir, "history.jsonl");
4441
- if (!existsSync7(historyJsonl)) return;
4644
+ const historyJsonl = resolve11(tempDir, "history.jsonl");
4645
+ if (!existsSync8(historyJsonl)) return;
4442
4646
  try {
4443
4647
  const db = await getDb();
4444
- const lines = readFileSync8(historyJsonl, "utf-8").trim().split("\n");
4648
+ const lines = readFileSync9(historyJsonl, "utf-8").trim().split("\n");
4445
4649
  let imported = 0;
4446
4650
  let failed = 0;
4447
4651
  for (const line of lines) {
@@ -4477,13 +4681,13 @@ async function importHistoryFromArchive(name, tempDir) {
4477
4681
  }
4478
4682
  }
4479
4683
  function importSessionsFromArchive(dest, tempDir) {
4480
- const sessionsDir = resolve10(tempDir, "sessions");
4481
- if (!existsSync7(sessionsDir)) return;
4684
+ const sessionsDir = resolve11(tempDir, "sessions");
4685
+ if (!existsSync8(sessionsDir)) return;
4482
4686
  try {
4483
- const destSessions = resolve10(dest, ".mind/sessions");
4687
+ const destSessions = resolve11(dest, ".mind/sessions");
4484
4688
  mkdirSync6(destSessions, { recursive: true });
4485
4689
  for (const file of readdirSync2(sessionsDir)) {
4486
- cpSync(resolve10(sessionsDir, file), resolve10(destSessions, file));
4690
+ cpSync(resolve11(sessionsDir, file), resolve11(destSessions, file));
4487
4691
  }
4488
4692
  } catch (err) {
4489
4693
  logger_default.error("Failed to import sessions from archive", logger_default.errorData(err));
@@ -4550,15 +4754,16 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
4550
4754
  if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
4551
4755
  ensureVoluteHome();
4552
4756
  const dest = mindDir(name);
4553
- if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
4757
+ if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
4554
4758
  const templatesRoot = findTemplatesRoot();
4555
4759
  const { composedDir, manifest } = composeTemplate(templatesRoot, template);
4556
4760
  try {
4557
4761
  copyTemplateToDir(composedDir, dest, name, manifest);
4558
4762
  applyInitFiles(dest);
4559
4763
  const { publicKeyPem } = generateIdentity(dest);
4764
+ let effectiveModel = body.model;
4560
4765
  {
4561
- const { readGlobalConfig: readGlobal } = await import("./setup-KFYVWTXG.js");
4766
+ const { readGlobalConfig: readGlobal } = await import("./setup-5ECWTYKG.js");
4562
4767
  const mindDefaults = readGlobal().mindDefaults;
4563
4768
  const config2 = readVoluteConfig(dest);
4564
4769
  if (!config2) throw new Error("Failed to read volute.json after identity generation");
@@ -4572,22 +4777,12 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
4572
4777
  };
4573
4778
  }
4574
4779
  if (!config2.schedules || config2.schedules.length === 0) {
4575
- config2.schedules = mindDefaults?.schedules ?? [
4576
- {
4577
- id: "heartbeat",
4578
- cron: "0 12,16,20 * * *",
4579
- message: "A quiet moment. You might write something \u2014 a note, a journal entry, a page. You could explore a topic that interests you, check in on #system, or just think. No obligations, just time.",
4580
- enabled: true,
4581
- whileSleeping: "skip"
4582
- }
4583
- ];
4780
+ config2.schedules = mindDefaults?.schedules ?? [defaultHeartbeatSchedule()];
4584
4781
  }
4585
4782
  const cog = mindDefaults?.cognition;
4586
4783
  if (cog) {
4587
4784
  if (cog.thinkingLevel != null && !config2.thinkingLevel)
4588
4785
  config2.thinkingLevel = cog.thinkingLevel;
4589
- if (cog.maxThinkingTokens != null && config2.maxThinkingTokens == null)
4590
- config2.maxThinkingTokens = cog.maxThinkingTokens;
4591
4786
  if (cog.tokenBudget != null && config2.tokenBudget == null)
4592
4787
  config2.tokenBudget = cog.tokenBudget;
4593
4788
  if (cog.tokenBudgetPeriodMinutes != null && config2.tokenBudgetPeriodMinutes == null)
@@ -4595,22 +4790,23 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
4595
4790
  }
4596
4791
  writeVoluteConfig(dest, config2);
4597
4792
  const modelId = body.model ?? cog?.model;
4598
- const sdkConfigPath = resolve10(dest, "home/.config/config.json");
4793
+ effectiveModel = modelId ? qualifyModelId(modelId) : void 0;
4794
+ const sdkConfigPath = resolve11(dest, "home/.config/config.json");
4599
4795
  if (modelId || cog?.compaction) {
4600
- const existing = existsSync7(sdkConfigPath) ? JSON.parse(readFileSync8(sdkConfigPath, "utf-8")) : {};
4796
+ const existing = existsSync8(sdkConfigPath) ? JSON.parse(readFileSync9(sdkConfigPath, "utf-8")) : {};
4601
4797
  if (modelId) {
4602
4798
  existing.model = template === "pi" ? qualifyModelId(modelId) : unqualifyModelId(modelId);
4603
4799
  }
4604
4800
  if (cog?.compaction && !existing.compaction) {
4605
4801
  existing.compaction = cog.compaction;
4606
4802
  }
4607
- writeFileSync7(sdkConfigPath, `${JSON.stringify(existing, null, 2)}
4803
+ writeFileSync8(sdkConfigPath, `${JSON.stringify(existing, null, 2)}
4608
4804
  `);
4609
4805
  }
4610
4806
  }
4611
4807
  const mindPrompts = await getMindPromptDefaults();
4612
- writeFileSync7(
4613
- resolve10(dest, "home/.config/prompts.json"),
4808
+ writeFileSync8(
4809
+ resolve11(dest, "home/.config/prompts.json"),
4614
4810
  `${JSON.stringify(mindPrompts, null, 2)}
4615
4811
  `
4616
4812
  );
@@ -4622,7 +4818,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
4622
4818
  } catch (err) {
4623
4819
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
4624
4820
  }
4625
- const homeDir = resolve10(dest, "home");
4821
+ const homeDir = resolve11(dest, "home");
4626
4822
  ensureVoluteGroup();
4627
4823
  createMindUser(name, homeDir);
4628
4824
  await chownMindDir(dest, name);
@@ -4635,7 +4831,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
4635
4831
  await initTemplateBranch(dest, composedDir, manifest, name, env);
4636
4832
  } catch (err) {
4637
4833
  logger_default.error(`git setup failed for ${name}`, logger_default.errorData(err));
4638
- rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
4834
+ rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
4639
4835
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
4640
4836
  }
4641
4837
  if (body.stage === "seed") {
@@ -4644,11 +4840,11 @@ Your creator described you as: "${body.description}"
4644
4840
  ` : "";
4645
4841
  const seedSoulRaw = body.seedSoul ?? await getPrompt("seed_soul", { name, description: descLine });
4646
4842
  const seedSoul = body.seedSoul ? substitute(seedSoulRaw, { name, description: descLine }) : seedSoulRaw;
4647
- writeFileSync7(resolve10(dest, "home/SOUL.md"), seedSoul);
4843
+ writeFileSync8(resolve11(dest, "home/SOUL.md"), seedSoul);
4648
4844
  }
4649
4845
  let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
4650
4846
  if (body.stage === "seed" && !body.skills) {
4651
- const { isImagegenEnabled } = await import("./setup-KFYVWTXG.js");
4847
+ const { isImagegenEnabled } = await import("./setup-5ECWTYKG.js");
4652
4848
  if (isImagegenEnabled()) {
4653
4849
  skillSet = [...skillSet, "imagegen"];
4654
4850
  }
@@ -4662,11 +4858,14 @@ Your creator described you as: "${body.description}"
4662
4858
  skillWarnings.push(`Failed to install skill: ${skillId}`);
4663
4859
  }
4664
4860
  }
4861
+ if (body.stage !== "seed") {
4862
+ skillWarnings.push(...setupDefaultDreaming(dest).warnings);
4863
+ }
4665
4864
  if (body.stage === "seed") {
4666
4865
  try {
4667
4866
  const spiritEntry = await findMind("volute");
4668
4867
  if (spiritEntry) {
4669
- const { spiritDir } = await import("./spirit-WXN4IDBF.js");
4868
+ const { spiritDir } = await import("./spirit-WXS3HCLN.js");
4670
4869
  const sDir = spiritEntry.dir ?? spiritDir();
4671
4870
  const spiritConfig = readVoluteConfig(sDir) ?? {};
4672
4871
  const schedules = spiritConfig.schedules ?? [];
@@ -4681,7 +4880,7 @@ Your creator described you as: "${body.description}"
4681
4880
  });
4682
4881
  spiritConfig.schedules = schedules;
4683
4882
  writeVoluteConfig(sDir, spiritConfig);
4684
- const { getScheduler: getScheduler2 } = await import("./scheduler-HQSDYJFY.js");
4883
+ const { getScheduler: getScheduler2 } = await import("./scheduler-I7JZCT47.js");
4685
4884
  getScheduler2().loadSchedules("volute", sDir);
4686
4885
  }
4687
4886
  }
@@ -4692,11 +4891,11 @@ Your creator described you as: "${body.description}"
4692
4891
  if (body.stage !== "seed") {
4693
4892
  const customSoul = await getPromptIfCustom("default_soul");
4694
4893
  if (customSoul) {
4695
- writeFileSync7(resolve10(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
4894
+ writeFileSync8(resolve11(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
4696
4895
  }
4697
4896
  const customMemory = await getPromptIfCustom("default_memory");
4698
4897
  if (customMemory) {
4699
- writeFileSync7(resolve10(dest, "home/MEMORY.md"), customMemory);
4898
+ writeFileSync8(resolve11(dest, "home/MEMORY.md"), customMemory);
4700
4899
  }
4701
4900
  }
4702
4901
  await chownMindDir(dest, name);
@@ -4716,6 +4915,14 @@ Your creator described you as: "${body.description}"
4716
4915
  });
4717
4916
  announceToSystem(`${name} has joined`).catch(() => {
4718
4917
  });
4918
+ const credentialWarning = await missingCredentialWarning(
4919
+ template,
4920
+ effectiveModel,
4921
+ name
4922
+ ).catch((err) => {
4923
+ logger_default.warn(`credential check failed for ${name}`, logger_default.errorData(err));
4924
+ return null;
4925
+ });
4719
4926
  return c.json({
4720
4927
  ok: true,
4721
4928
  name,
@@ -4723,10 +4930,11 @@ Your creator described you as: "${body.description}"
4723
4930
  stage: body.stage ?? "sprouted",
4724
4931
  message: `Created mind: ${name} (port ${port})`,
4725
4932
  ...gitWarning && { warning: gitWarning },
4933
+ ...credentialWarning && { credentialWarning },
4726
4934
  ...skillWarnings.length > 0 && { skillWarnings }
4727
4935
  });
4728
4936
  } catch (err) {
4729
- if (existsSync7(dest)) rmSync4(dest, { recursive: true, force: true });
4937
+ if (existsSync8(dest)) rmSync4(dest, { recursive: true, force: true });
4730
4938
  try {
4731
4939
  await removeMind(name);
4732
4940
  } catch {
@@ -4746,13 +4954,13 @@ Your creator described you as: "${body.description}"
4746
4954
  return importFromArchive(c, body.archivePath, body.name, body.manifest);
4747
4955
  }
4748
4956
  const wsDir = body.workspacePath;
4749
- if (!wsDir || !existsSync7(resolve10(wsDir, "SOUL.md")) || !existsSync7(resolve10(wsDir, "IDENTITY.md"))) {
4957
+ if (!wsDir || !existsSync8(resolve11(wsDir, "SOUL.md")) || !existsSync8(resolve11(wsDir, "IDENTITY.md"))) {
4750
4958
  return c.json({ error: "Invalid workspace: missing SOUL.md or IDENTITY.md" }, 400);
4751
4959
  }
4752
- const soul = readFileSync8(resolve10(wsDir, "SOUL.md"), "utf-8");
4753
- const identity = readFileSync8(resolve10(wsDir, "IDENTITY.md"), "utf-8");
4754
- const userPath = resolve10(wsDir, "USER.md");
4755
- const user = existsSync7(userPath) ? readFileSync8(userPath, "utf-8") : "";
4960
+ const soul = readFileSync9(resolve11(wsDir, "SOUL.md"), "utf-8");
4961
+ const identity = readFileSync9(resolve11(wsDir, "IDENTITY.md"), "utf-8");
4962
+ const userPath = resolve11(wsDir, "USER.md");
4963
+ const user = existsSync8(userPath) ? readFileSync9(userPath, "utf-8") : "";
4756
4964
  const name = body.name ?? parseNameFromIdentity(identity) ?? "imported-mind";
4757
4965
  const template = body.template ?? "claude";
4758
4966
  const nameErr = validateMindName(name);
@@ -4772,33 +4980,33 @@ ${user.trimEnd()}
4772
4980
  ` : "";
4773
4981
  ensureVoluteHome();
4774
4982
  const dest = mindDir(name);
4775
- if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
4983
+ if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
4776
4984
  const templatesRoot = findTemplatesRoot();
4777
4985
  const { composedDir, manifest } = composeTemplate(templatesRoot, template);
4778
4986
  try {
4779
4987
  copyTemplateToDir(composedDir, dest, name, manifest);
4780
4988
  applyInitFiles(dest);
4781
4989
  const { publicKeyPem: importPublicKey } = generateIdentity(dest);
4782
- writeFileSync7(resolve10(dest, "home/SOUL.md"), mergedSoul);
4783
- const wsMemoryPath = resolve10(wsDir, "MEMORY.md");
4784
- const hasMemory = existsSync7(wsMemoryPath);
4990
+ writeFileSync8(resolve11(dest, "home/SOUL.md"), mergedSoul);
4991
+ const wsMemoryPath = resolve11(wsDir, "MEMORY.md");
4992
+ const hasMemory = existsSync8(wsMemoryPath);
4785
4993
  if (hasMemory) {
4786
- const existingMemory = readFileSync8(wsMemoryPath, "utf-8");
4787
- writeFileSync7(
4788
- resolve10(dest, "home/MEMORY.md"),
4994
+ const existingMemory = readFileSync9(wsMemoryPath, "utf-8");
4995
+ writeFileSync8(
4996
+ resolve11(dest, "home/MEMORY.md"),
4789
4997
  `${existingMemory.trimEnd()}${mergedMemoryExtra}`
4790
4998
  );
4791
4999
  } else if (user) {
4792
- writeFileSync7(resolve10(dest, "home/MEMORY.md"), `${user.trimEnd()}
5000
+ writeFileSync8(resolve11(dest, "home/MEMORY.md"), `${user.trimEnd()}
4793
5001
  `);
4794
5002
  }
4795
- const wsMemoryDir = resolve10(wsDir, "memory");
5003
+ const wsMemoryDir = resolve11(wsDir, "memory");
4796
5004
  let dailyLogCount = 0;
4797
- if (existsSync7(wsMemoryDir)) {
4798
- const destMemoryDir = resolve10(dest, "home/memory");
5005
+ if (existsSync8(wsMemoryDir)) {
5006
+ const destMemoryDir = resolve11(dest, "home/memory");
4799
5007
  const files = readdirSync2(wsMemoryDir).filter((f) => f.endsWith(".md"));
4800
5008
  for (const file of files) {
4801
- cpSync(resolve10(wsMemoryDir, file), resolve10(destMemoryDir, file));
5009
+ cpSync(resolve11(wsMemoryDir, file), resolve11(destMemoryDir, file));
4802
5010
  }
4803
5011
  dailyLogCount = files.length;
4804
5012
  }
@@ -4809,7 +5017,7 @@ ${user.trimEnd()}
4809
5017
  } catch (err) {
4810
5018
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
4811
5019
  }
4812
- const homeDir = resolve10(dest, "home");
5020
+ const homeDir = resolve11(dest, "home");
4813
5021
  ensureVoluteGroup();
4814
5022
  createMindUser(name, homeDir);
4815
5023
  await chownMindDir(dest, name);
@@ -4817,20 +5025,20 @@ ${user.trimEnd()}
4817
5025
  if (!hasMemory && dailyLogCount > 0) {
4818
5026
  await consolidateMemory(dest);
4819
5027
  }
4820
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dest, "home") } : void 0;
5028
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
4821
5029
  await gitExec(["init"], { cwd: dest, mindName: name, env });
4822
5030
  await configureGitIdentity(name, { cwd: dest, mindName: name, env });
4823
5031
  await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
4824
5032
  await gitExec(["commit", "-m", "import from OpenClaw"], { cwd: dest, mindName: name, env });
4825
- const sessionFile = body.sessionPath ? resolve10(body.sessionPath) : findOpenClawSession(wsDir);
4826
- if (sessionFile && existsSync7(sessionFile)) {
5033
+ const sessionFile = body.sessionPath ? resolve11(body.sessionPath) : findOpenClawSession(wsDir);
5034
+ if (sessionFile && existsSync8(sessionFile)) {
4827
5035
  if (template === "pi") {
4828
5036
  importPiSession(sessionFile, dest);
4829
5037
  } else if (template === "claude") {
4830
5038
  const sessionId = convertSession({ sessionPath: sessionFile, projectDir: dest });
4831
- const mindRuntimeDir = resolve10(dest, ".mind");
5039
+ const mindRuntimeDir = resolve11(dest, ".mind");
4832
5040
  mkdirSync6(mindRuntimeDir, { recursive: true });
4833
- writeFileSync7(resolve10(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
5041
+ writeFileSync8(resolve11(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
4834
5042
  }
4835
5043
  }
4836
5044
  importOpenClawConnectors(name, dest);
@@ -4840,7 +5048,7 @@ ${user.trimEnd()}
4840
5048
  );
4841
5049
  return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
4842
5050
  } catch (err) {
4843
- if (existsSync7(dest)) rmSync4(dest, { recursive: true, force: true });
5051
+ if (existsSync8(dest)) rmSync4(dest, { recursive: true, force: true });
4844
5052
  try {
4845
5053
  await removeMind(name);
4846
5054
  } catch {
@@ -4872,7 +5080,7 @@ ${user.trimEnd()}
4872
5080
  const minds = await Promise.all(
4873
5081
  entries.map(async (entry) => {
4874
5082
  const mindStatus = await getMindStatus(entry.name, entry.port, entry.running);
4875
- const hasPages = existsSync7(resolve10(mindDir(entry.name), "home", "pages"));
5083
+ const hasPages = existsSync8(resolve11(mindDir(entry.name), "home", "pages"));
4876
5084
  const lastActiveAt = lastActiveMap.get(entry.name) ?? null;
4877
5085
  if (!privileged) return toPublicMind(entry, mindStatus, { hasPages, lastActiveAt });
4878
5086
  return {
@@ -4890,9 +5098,9 @@ ${user.trimEnd()}
4890
5098
  const entry = await findMind(name);
4891
5099
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4892
5100
  const dir = entry.dir ?? mindDir(entry.parent ?? name);
4893
- if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
5101
+ if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
4894
5102
  const mindStatus = await getMindStatus(name, entry.port);
4895
- const hasPages = existsSync7(resolve10(mindDir(name), "home", "pages"));
5103
+ const hasPages = existsSync8(resolve11(mindDir(name), "home", "pages"));
4896
5104
  if (!isPrivileged(c)) {
4897
5105
  return c.json(toPublicMind(entry, mindStatus, { hasPages }));
4898
5106
  }
@@ -4908,12 +5116,21 @@ ${user.trimEnd()}
4908
5116
  return { name: s.name, port: s.port, status: variantStatus };
4909
5117
  })
4910
5118
  );
5119
+ const notice = await latestNotice(name);
4911
5120
  return c.json({
4912
5121
  ...entry,
4913
5122
  ...mindStatus,
4914
5123
  variants: variantStatuses,
4915
5124
  hasPages,
4916
- templateStale: isTemplateStale(entry)
5125
+ templateStale: isTemplateStale(entry),
5126
+ ...notice && {
5127
+ lastNotice: {
5128
+ kind: notice.kind,
5129
+ reason: notice.reason,
5130
+ detail: notice.detail,
5131
+ created_at: notice.created_at
5132
+ }
5133
+ }
4917
5134
  });
4918
5135
  }).get("/:name/context", requireSelf(), async (c) => proxyToMind(c, "context")).get("/:name/context/messages", requireSelf(), async (c) => proxyToMind(c, "context/messages")).post("/:name/start", requireSelf(), async (c) => {
4919
5136
  const name = c.req.param("name");
@@ -4924,7 +5141,7 @@ ${user.trimEnd()}
4924
5141
  if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
4925
5142
  } else {
4926
5143
  const dir = mindDir(name);
4927
- if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
5144
+ if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
4928
5145
  }
4929
5146
  if (getMindManager().isRunning(name)) {
4930
5147
  return c.json({ error: "Mind already running" }, 409);
@@ -4945,7 +5162,7 @@ ${user.trimEnd()}
4945
5162
  if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
4946
5163
  } else {
4947
5164
  const dir = mindDir(name);
4948
- if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
5165
+ if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
4949
5166
  }
4950
5167
  let context;
4951
5168
  const contentType = c.req.header("content-type");
@@ -4960,7 +5177,7 @@ ${user.trimEnd()}
4960
5177
  const manager = getMindManager();
4961
5178
  try {
4962
5179
  if (context?.type === "reload") {
4963
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-3NA7ZJP3.js");
5180
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
4964
5181
  const sleepState = getSleepManagerIfReady2()?.getState(name);
4965
5182
  if (sleepState?.sleeping) {
4966
5183
  logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
@@ -4980,7 +5197,7 @@ ${user.trimEnd()}
4980
5197
  const variantEntry = await findMind(mergeVariantName);
4981
5198
  if (variantEntry && variantEntry.parent === baseName && variantEntry.dir && variantEntry.branch) {
4982
5199
  const projectRoot = mindDir(baseName);
4983
- if (existsSync7(variantEntry.dir)) {
5200
+ if (existsSync8(variantEntry.dir)) {
4984
5201
  const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
4985
5202
  if (status) {
4986
5203
  try {
@@ -5087,7 +5304,7 @@ ${user.trimEnd()}
5087
5304
  const name = c.req.param("name");
5088
5305
  const entry = await findMind(name);
5089
5306
  if (!entry) return c.json({ error: "Mind not found" }, 404);
5090
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-3NA7ZJP3.js");
5307
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
5091
5308
  const sm = getSleepManagerIfReady2();
5092
5309
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
5093
5310
  return c.json(sm.getState(name));
@@ -5095,7 +5312,7 @@ ${user.trimEnd()}
5095
5312
  const name = c.req.param("name");
5096
5313
  const entry = await findMind(name);
5097
5314
  if (!entry) return c.json({ error: "Mind not found" }, 404);
5098
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-3NA7ZJP3.js");
5315
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
5099
5316
  const sm = getSleepManagerIfReady2();
5100
5317
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
5101
5318
  if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
@@ -5115,7 +5332,7 @@ ${user.trimEnd()}
5115
5332
  const name = c.req.param("name");
5116
5333
  const entry = await findMind(name);
5117
5334
  if (!entry) return c.json({ error: "Mind not found" }, 404);
5118
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-3NA7ZJP3.js");
5335
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
5119
5336
  const sm = getSleepManagerIfReady2();
5120
5337
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
5121
5338
  const sleepState = sm.getState(name);
@@ -5130,7 +5347,7 @@ ${user.trimEnd()}
5130
5347
  const name = c.req.param("name");
5131
5348
  const entry = await findMind(name);
5132
5349
  if (!entry) return c.json({ error: "Mind not found" }, 404);
5133
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-3NA7ZJP3.js");
5350
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
5134
5351
  const sm = getSleepManagerIfReady2();
5135
5352
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
5136
5353
  const flushed = await sm.flushQueuedMessages(name);
@@ -5146,12 +5363,12 @@ ${user.trimEnd()}
5146
5363
  if (body.displayName !== void 0) profile.displayName = body.displayName;
5147
5364
  if (body.description !== void 0) profile.description = body.description;
5148
5365
  if (body.avatar !== void 0) {
5149
- const homeDir = resolve10(dir, "home");
5366
+ const homeDir = resolve11(dir, "home");
5150
5367
  const avatarPath = safeResolveWithinBase(homeDir, body.avatar);
5151
5368
  if (!avatarPath) {
5152
5369
  return c.json({ error: "Avatar path must be inside the mind's home directory" }, 400);
5153
5370
  }
5154
- if (!existsSync7(avatarPath)) {
5371
+ if (!existsSync8(avatarPath)) {
5155
5372
  return c.json({ error: `Avatar file not found: ${relative(homeDir, avatarPath)}` }, 400);
5156
5373
  }
5157
5374
  profile.avatar = relative(homeDir, avatarPath);
@@ -5197,25 +5414,18 @@ ${user.trimEnd()}
5197
5414
  return c.json({ output: "" });
5198
5415
  }
5199
5416
  const dir = entry.dir ?? mindDir(name);
5200
- const soulPath = resolve10(dir, "home/SOUL.md");
5201
- const memoryPath = resolve10(dir, "home/MEMORY.md");
5202
- const soulCustom = existsSync7(soulPath) && !readFileSync8(soulPath, "utf-8").includes(ORIENTATION_MARKER);
5203
- const memoryWritten = existsSync7(memoryPath) && readFileSync8(memoryPath, "utf-8").trim().length > 0;
5204
- const config2 = readVoluteConfig(dir);
5205
- const displayNameSet = !!config2?.profile?.displayName;
5206
- const avatarSet = !!config2?.profile?.avatar;
5207
- const { isImagegenEnabled } = await import("./setup-KFYVWTXG.js");
5208
- const imagegenEnabled = isImagegenEnabled();
5417
+ const { evaluateSeedChecklist } = await import("./seed-readiness-RBPGOLSZ.js");
5418
+ const checklist = evaluateSeedChecklist(dir);
5209
5419
  const done = [];
5210
5420
  const remaining = [];
5211
- if (soulCustom) done.push("SOUL.md written");
5421
+ if (checklist.soulWritten) done.push("SOUL.md written");
5212
5422
  else remaining.push("Write SOUL.md");
5213
- if (memoryWritten) done.push("MEMORY.md written");
5423
+ if (checklist.memoryWritten) done.push("MEMORY.md written");
5214
5424
  else remaining.push("Write MEMORY.md");
5215
- if (displayNameSet) done.push("Display name set");
5425
+ if (checklist.displayNameSet) done.push("Display name set");
5216
5426
  else remaining.push("Set display name");
5217
- if (imagegenEnabled) {
5218
- if (avatarSet) done.push("Avatar set");
5427
+ if (checklist.imagegenEnabled) {
5428
+ if (checklist.avatarSet) done.push("Avatar set");
5219
5429
  else remaining.push("Generate and set avatar");
5220
5430
  }
5221
5431
  const creatorStatus = minutesSinceCreator === Infinity ? "No creator messages yet" : `Last creator message: ${Math.round(minutesSinceCreator)} minutes ago`;
@@ -5239,23 +5449,48 @@ ${user.trimEnd()}
5239
5449
  return c.json({ error: `Mind is not a seed (stage: ${entry.stage})` }, 409);
5240
5450
  }
5241
5451
  await setMindStage(name, "sprouted");
5452
+ try {
5453
+ const sproutedDir = entry.dir ?? mindDir(name);
5454
+ if (setupDefaultDreaming(sproutedDir).schedulesChanged) {
5455
+ const { getScheduler: getScheduler2 } = await import("./scheduler-I7JZCT47.js");
5456
+ getScheduler2().loadSchedules(name, sproutedDir);
5457
+ }
5458
+ } catch (err) {
5459
+ logger_default.warn(`failed to set up default dreaming for ${name}`, logger_default.errorData(err));
5460
+ }
5242
5461
  try {
5243
5462
  const spiritEntry = await findMind("volute");
5244
5463
  if (spiritEntry) {
5245
- const { spiritDir } = await import("./spirit-WXN4IDBF.js");
5464
+ const { firstWeekSchedules, spiritDir } = await import("./spirit-WXS3HCLN.js");
5246
5465
  const sDir = spiritEntry.dir ?? spiritDir();
5247
5466
  const spiritConfig = readVoluteConfig(sDir);
5248
- if (spiritConfig?.schedules) {
5249
- const nurtureId = `nurture-${name}`;
5250
- spiritConfig.schedules = spiritConfig.schedules.filter((s) => s.id !== nurtureId);
5251
- if (spiritConfig.schedules.length === 0) spiritConfig.schedules = void 0;
5467
+ if (spiritConfig) {
5468
+ const schedules = (spiritConfig.schedules ?? []).filter(
5469
+ (s) => s.id !== `nurture-${name}`
5470
+ );
5471
+ const existing = new Set(schedules.map((s) => s.id));
5472
+ schedules.push(
5473
+ ...firstWeekSchedules(name, /* @__PURE__ */ new Date()).filter((s) => !existing.has(s.id))
5474
+ );
5475
+ spiritConfig.schedules = schedules;
5252
5476
  writeVoluteConfig(sDir, spiritConfig);
5253
- const { getScheduler: getScheduler2 } = await import("./scheduler-HQSDYJFY.js");
5254
- getScheduler2().loadSchedules("volute", sDir);
5477
+ try {
5478
+ const { getScheduler: getScheduler2 } = await import("./scheduler-I7JZCT47.js");
5479
+ getScheduler2().loadSchedules("volute", sDir);
5480
+ } catch (err) {
5481
+ logger_default.warn(
5482
+ `spirit schedules for sprout of ${name} written to disk but not reloaded into the running scheduler (effective on next spirit restart)`,
5483
+ logger_default.errorData(err)
5484
+ );
5485
+ }
5486
+ } else {
5487
+ logger_default.warn(
5488
+ `spirit config at ${sDir} missing or unparseable \u2014 first-week arc for ${name} not scheduled, nurture-${name} not removed`
5489
+ );
5255
5490
  }
5256
5491
  }
5257
5492
  } catch (err) {
5258
- logger_default.warn(`failed to clean up nurture schedule for ${name}`, logger_default.errorData(err));
5493
+ logger_default.warn(`failed to update spirit schedules for sprout of ${name}`, logger_default.errorData(err));
5259
5494
  }
5260
5495
  return c.json({ ok: true });
5261
5496
  }).delete("/:name", requireAdmin, async (c) => {
@@ -5278,10 +5513,10 @@ ${user.trimEnd()}
5278
5513
  await deleteMindUser2(name);
5279
5514
  invalidateMindUserCache(name);
5280
5515
  const state = stateDir(name);
5281
- if (existsSync7(state)) {
5516
+ if (existsSync8(state)) {
5282
5517
  rmSync4(state, { recursive: true, force: true });
5283
5518
  }
5284
- if (force && existsSync7(dir)) {
5519
+ if (force && existsSync8(dir)) {
5285
5520
  rmSync4(dir, { recursive: true, force: true });
5286
5521
  deleteMindUser(name);
5287
5522
  }
@@ -5296,7 +5531,7 @@ ${user.trimEnd()}
5296
5531
  const entry = await findMind(mindName);
5297
5532
  if (!entry) return c.json({ error: "Mind not found" }, 404);
5298
5533
  const dir = mindDir(mindName);
5299
- if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
5534
+ if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
5300
5535
  let body = {};
5301
5536
  try {
5302
5537
  body = await c.req.json();
@@ -5309,16 +5544,16 @@ ${user.trimEnd()}
5309
5544
  }
5310
5545
  const UPGRADE_BRANCH = "upgrade";
5311
5546
  const upgradeVariantName = `${mindName}-upgrade`;
5312
- const worktreeDir = resolve10(dir, ".variants", UPGRADE_BRANCH);
5547
+ const worktreeDir = resolve11(dir, ".variants", UPGRADE_BRANCH);
5313
5548
  if (body.abort) {
5314
- if (!existsSync7(worktreeDir)) {
5549
+ if (!existsSync8(worktreeDir)) {
5315
5550
  return c.json({ error: "No upgrade in progress" }, 400);
5316
5551
  }
5317
5552
  try {
5318
5553
  try {
5319
- const gitDirContent = readFileSync8(resolve10(worktreeDir, ".git"), "utf-8").trim();
5554
+ const gitDirContent = readFileSync9(resolve11(worktreeDir, ".git"), "utf-8").trim();
5320
5555
  const gitDir = gitDirContent.replace("gitdir: ", "");
5321
- if (existsSync7(resolve10(gitDir, "MERGE_HEAD"))) {
5556
+ if (existsSync8(resolve11(gitDir, "MERGE_HEAD"))) {
5322
5557
  await gitExec(["merge", "--abort"], { cwd: worktreeDir });
5323
5558
  }
5324
5559
  } catch {
@@ -5337,7 +5572,7 @@ ${user.trimEnd()}
5337
5572
  }
5338
5573
  }
5339
5574
  if (body.continue) {
5340
- if (!existsSync7(worktreeDir)) {
5575
+ if (!existsSync8(worktreeDir)) {
5341
5576
  return c.json({ error: "No upgrade in progress" }, 400);
5342
5577
  }
5343
5578
  const status = await gitExec(["status", "--porcelain"], { cwd: worktreeDir });
@@ -5387,7 +5622,7 @@ ${user.trimEnd()}
5387
5622
  }
5388
5623
  }
5389
5624
  if (body.accept) {
5390
- if (existsSync7(worktreeDir)) {
5625
+ if (existsSync8(worktreeDir)) {
5391
5626
  try {
5392
5627
  await cleanupVariant(upgradeVariantName, dir, worktreeDir, { stop: true });
5393
5628
  } catch (err) {
@@ -5402,7 +5637,7 @@ ${user.trimEnd()}
5402
5637
  }
5403
5638
  if (body.diff) {
5404
5639
  try {
5405
- if (!existsSync7(resolve10(dir, ".git"))) {
5640
+ if (!existsSync8(resolve11(dir, ".git"))) {
5406
5641
  return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
5407
5642
  }
5408
5643
  await updateTemplateBranch(dir, template, mindName);
@@ -5420,22 +5655,22 @@ ${user.trimEnd()}
5420
5655
  );
5421
5656
  }
5422
5657
  }
5423
- if (existsSync7(worktreeDir)) {
5658
+ if (existsSync8(worktreeDir)) {
5424
5659
  return c.json(
5425
5660
  { error: "Upgrade variant already exists. Use continue or delete it first." },
5426
5661
  409
5427
5662
  );
5428
5663
  }
5429
- if (!existsSync7(resolve10(dir, ".git"))) {
5664
+ if (!existsSync8(resolve11(dir, ".git"))) {
5430
5665
  try {
5431
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dir, "home") } : void 0;
5666
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dir, "home") } : void 0;
5432
5667
  await gitExec(["init"], { cwd: dir, mindName, env });
5433
5668
  await configureGitIdentity(mindName, { cwd: dir, mindName, env });
5434
5669
  await gitExec(["add", "-A"], { cwd: dir, mindName, env });
5435
5670
  await gitExec(["commit", "-m", "initial commit"], { cwd: dir, mindName, env });
5436
5671
  await chownMindDir(dir, mindName);
5437
5672
  } catch (err) {
5438
- rmSync4(resolve10(dir, ".git"), { recursive: true, force: true });
5673
+ rmSync4(resolve11(dir, ".git"), { recursive: true, force: true });
5439
5674
  return c.json(
5440
5675
  {
5441
5676
  error: `Git initialization failed: ${err instanceof Error ? err.message : String(err)}`
@@ -5450,8 +5685,8 @@ ${user.trimEnd()}
5450
5685
  } catch {
5451
5686
  }
5452
5687
  await updateTemplateBranch(dir, template, mindName);
5453
- const parentDir = resolve10(dir, ".variants");
5454
- if (!existsSync7(parentDir)) {
5688
+ const parentDir = resolve11(dir, ".variants");
5689
+ if (!existsSync8(parentDir)) {
5455
5690
  mkdirSync6(parentDir, { recursive: true });
5456
5691
  }
5457
5692
  await gitExec(["worktree", "add", "-b", UPGRADE_BRANCH, worktreeDir], { cwd: dir });
@@ -5581,22 +5816,22 @@ ${user.trimEnd()}
5581
5816
  const entry = await findMind(name);
5582
5817
  if (!entry) return c.json({ error: "Mind not found" }, 404);
5583
5818
  const dir = entry.dir ?? mindDir(name);
5584
- if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
5819
+ if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
5585
5820
  let config2 = readVoluteConfig(dir);
5586
5821
  if (!config2 && entry.template === "pi") {
5587
- const piConfigPath = resolve10(dir, "home/.config/config.json");
5588
- if (existsSync7(piConfigPath)) {
5822
+ const piConfigPath = resolve11(dir, "home/.config/config.json");
5823
+ if (existsSync8(piConfigPath)) {
5589
5824
  try {
5590
- config2 = JSON.parse(readFileSync8(piConfigPath, "utf-8"));
5825
+ config2 = JSON.parse(readFileSync9(piConfigPath, "utf-8"));
5591
5826
  } catch {
5592
5827
  }
5593
5828
  }
5594
5829
  }
5595
5830
  let templateConfig = {};
5596
- const configJsonPath = resolve10(dir, "home/.config/config.json");
5597
- if (existsSync7(configJsonPath)) {
5831
+ const configJsonPath = resolve11(dir, "home/.config/config.json");
5832
+ if (existsSync8(configJsonPath)) {
5598
5833
  try {
5599
- templateConfig = JSON.parse(readFileSync8(configJsonPath, "utf-8"));
5834
+ templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
5600
5835
  } catch {
5601
5836
  }
5602
5837
  }
@@ -5610,22 +5845,7 @@ ${user.trimEnd()}
5610
5845
  },
5611
5846
  config: {
5612
5847
  model: config2?.model ?? templateConfig.model ?? null,
5613
- thinkingLevel: (() => {
5614
- if (config2?.thinkingLevel) return config2.thinkingLevel;
5615
- const tc = templateConfig;
5616
- if (tc.thinkingLevel) return tc.thinkingLevel;
5617
- if (tc.reasoningEffort) return tc.reasoningEffort;
5618
- const mtt = tc.maxThinkingTokens;
5619
- if (mtt) {
5620
- if (mtt <= 1024) return "minimal";
5621
- if (mtt <= 4096) return "low";
5622
- if (mtt <= 1e4) return "medium";
5623
- if (mtt <= 32e3) return "high";
5624
- return "xhigh";
5625
- }
5626
- return null;
5627
- })(),
5628
- maxThinkingTokens: config2?.maxThinkingTokens ?? templateConfig.maxThinkingTokens ?? null,
5848
+ thinkingLevel: config2?.thinkingLevel ?? deriveThinkingLevel(templateConfig),
5629
5849
  tokenBudget: config2?.tokenBudget ?? null,
5630
5850
  tokenBudgetPeriodMinutes: config2?.tokenBudgetPeriodMinutes ?? null,
5631
5851
  compaction: templateConfig.compaction ?? null,
@@ -5640,7 +5860,6 @@ ${user.trimEnd()}
5640
5860
  z6.object({
5641
5861
  model: z6.string().optional(),
5642
5862
  thinkingLevel: z6.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional(),
5643
- maxThinkingTokens: z6.number().int().positive().nullable().optional(),
5644
5863
  tokenBudget: z6.number().int().positive().nullable().optional(),
5645
5864
  tokenBudgetPeriodMinutes: z6.number().int().positive().nullable().optional(),
5646
5865
  compaction: z6.object({ maxContextTokens: z6.number().int().positive().nullable().optional() }).nullable().optional(),
@@ -5652,7 +5871,7 @@ ${user.trimEnd()}
5652
5871
  const entry = await findMind(name);
5653
5872
  if (!entry) return c.json({ error: "Mind not found" }, 404);
5654
5873
  const dir = entry.dir ?? mindDir(name);
5655
- if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
5874
+ if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
5656
5875
  const body = c.req.valid("json");
5657
5876
  const existing = readVoluteConfig(dir) ?? {};
5658
5877
  if (body.model !== void 0) existing.model = body.model;
@@ -5673,76 +5892,29 @@ ${user.trimEnd()}
5673
5892
  existing.tokenBudgetPeriodMinutes = body.tokenBudgetPeriodMinutes;
5674
5893
  }
5675
5894
  }
5676
- if (body.maxThinkingTokens !== void 0) {
5677
- if (body.maxThinkingTokens === null) {
5678
- delete existing.maxThinkingTokens;
5679
- } else {
5680
- existing.maxThinkingTokens = body.maxThinkingTokens;
5681
- }
5682
- }
5683
5895
  if (body.unescapeNewlines !== void 0) {
5684
5896
  existing.unescapeNewlines = body.unescapeNewlines;
5685
5897
  }
5686
5898
  writeVoluteConfig(dir, existing);
5687
5899
  if (body.unescapeNewlines !== void 0) {
5688
- const { clearEchoTextCache } = await import("./echo-text-SEQCLGAT.js");
5900
+ const { clearEchoTextCache } = await import("./echo-text-H3SH337Q.js");
5689
5901
  clearEchoTextCache(name);
5690
5902
  }
5691
- const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.maxThinkingTokens !== void 0 || body.compaction !== void 0;
5903
+ const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.compaction !== void 0;
5692
5904
  if (needsConfigJson) {
5693
- const configJsonPath = resolve10(dir, "home/.config/config.json");
5905
+ const configJsonPath = resolve11(dir, "home/.config/config.json");
5694
5906
  let templateConfig = {};
5695
- if (existsSync7(configJsonPath)) {
5907
+ if (existsSync8(configJsonPath)) {
5696
5908
  try {
5697
- templateConfig = JSON.parse(readFileSync8(configJsonPath, "utf-8"));
5909
+ templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
5698
5910
  } catch {
5699
5911
  }
5700
5912
  }
5701
5913
  if (body.model !== void 0) {
5702
5914
  templateConfig.model = body.model;
5703
5915
  }
5704
- const tmpl = entry.template ?? "claude";
5705
5916
  if (body.thinkingLevel !== void 0) {
5706
- if (tmpl === "claude") {
5707
- const claudeThinkingTokens = {
5708
- off: null,
5709
- minimal: 1024,
5710
- low: 4096,
5711
- medium: 1e4,
5712
- high: 32e3,
5713
- xhigh: 128e3
5714
- };
5715
- const tokens = claudeThinkingTokens[body.thinkingLevel] ?? null;
5716
- if (tokens === null) {
5717
- delete templateConfig.maxThinkingTokens;
5718
- } else {
5719
- templateConfig.maxThinkingTokens = tokens;
5720
- }
5721
- } else if (tmpl === "codex") {
5722
- const codexMap = {
5723
- off: null,
5724
- minimal: "minimal",
5725
- low: "low",
5726
- medium: "medium",
5727
- high: "high",
5728
- xhigh: "xhigh"
5729
- };
5730
- const effort = codexMap[body.thinkingLevel] ?? null;
5731
- if (effort === null) {
5732
- delete templateConfig.reasoningEffort;
5733
- } else {
5734
- templateConfig.reasoningEffort = effort;
5735
- }
5736
- } else {
5737
- templateConfig.thinkingLevel = body.thinkingLevel;
5738
- }
5739
- }
5740
- if (body.maxThinkingTokens !== void 0) {
5741
- if (body.maxThinkingTokens === null) {
5742
- delete templateConfig.maxThinkingTokens;
5743
- } else {
5744
- templateConfig.maxThinkingTokens = body.maxThinkingTokens;
5745
- }
5917
+ applyThinkingLevel(templateConfig, entry.template ?? "claude", body.thinkingLevel);
5746
5918
  }
5747
5919
  if (body.compaction !== void 0) {
5748
5920
  if (body.compaction === null) {
@@ -5757,12 +5929,12 @@ ${user.trimEnd()}
5757
5929
  templateConfig.compaction = comp;
5758
5930
  }
5759
5931
  }
5760
- writeFileSync7(configJsonPath, `${JSON.stringify(templateConfig, null, 2)}
5932
+ writeFileSync8(configJsonPath, `${JSON.stringify(templateConfig, null, 2)}
5761
5933
  `);
5762
5934
  }
5763
5935
  if (entry.mindType === "spirit" && body.model !== void 0) {
5764
5936
  try {
5765
- const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-KFYVWTXG.js");
5937
+ const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-5ECWTYKG.js");
5766
5938
  const globalConfig = readGlobalConfig2();
5767
5939
  globalConfig.spiritModel = body.model;
5768
5940
  writeGlobalConfig2(globalConfig);
@@ -5805,7 +5977,7 @@ ${user.trimEnd()}
5805
5977
  if (!body.systemPrompt || !body.message) {
5806
5978
  return c.json({ error: "systemPrompt and message required" }, 400);
5807
5979
  }
5808
- const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-CVZEYKTK.js");
5980
+ const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-643TNFPH.js");
5809
5981
  if (!isAiConfigured()) {
5810
5982
  return c.json({ error: "AI service not configured" }, 503);
5811
5983
  }
@@ -5926,6 +6098,38 @@ ${user.trimEnd()}
5926
6098
  const db = await getDb();
5927
6099
  const rows = await db.selectDistinct({ channel: mindHistory.channel }).from(mindHistory).where(eq5(mindHistory.mind, name));
5928
6100
  return c.json(rows.map((r) => r.channel));
6101
+ }).get("/:name/history/contacts", requireSelf(), async (c) => {
6102
+ const name = c.req.param("name");
6103
+ const rawHours = parseInt(c.req.query("hours") ?? "48", 10);
6104
+ const hours = Math.min(Math.max(Number.isNaN(rawHours) ? 48 : rawHours, 1), 168);
6105
+ const cutoff = new Date(Date.now() - hours * 36e5).toISOString().replace("T", " ").slice(0, 19);
6106
+ const db = await getDb();
6107
+ const contacts = await db.select({
6108
+ channel: mindHistory.channel,
6109
+ last_at: sql3`MAX(${mindHistory.created_at})`,
6110
+ last_inbound_at: sql3`MAX(CASE WHEN ${mindHistory.type} = 'inbound' THEN ${mindHistory.created_at} END)`,
6111
+ last_outbound_at: sql3`MAX(CASE WHEN ${mindHistory.type} = 'outbound' THEN ${mindHistory.created_at} END)`,
6112
+ message_count: sql3`COUNT(*)`,
6113
+ // The counterparty: most recent inbound sender on this channel. For a
6114
+ // DM the channel name already carries it (e.g. @atlas), but this also
6115
+ // covers shared channels (#system) and rows where the channel is opaque.
6116
+ last_sender: sql3`(
6117
+ SELECT sender FROM mind_history h2
6118
+ WHERE h2.mind = ${name}
6119
+ AND h2.channel = ${mindHistory.channel}
6120
+ AND h2.type = 'inbound'
6121
+ AND h2.sender IS NOT NULL
6122
+ ORDER BY h2.created_at DESC, h2.id DESC LIMIT 1
6123
+ )`
6124
+ }).from(mindHistory).where(
6125
+ and5(
6126
+ eq5(mindHistory.mind, name),
6127
+ sql3`${mindHistory.type} IN ('inbound','outbound')`,
6128
+ sql3`${mindHistory.channel} IS NOT NULL`,
6129
+ sql3`${mindHistory.created_at} >= ${cutoff}`
6130
+ )
6131
+ ).groupBy(mindHistory.channel).orderBy(sql3`MAX(${mindHistory.created_at}) DESC`);
6132
+ return c.json({ hours, contacts });
5929
6133
  }).get("/:name/history/export", requireSelf(), async (c) => {
5930
6134
  const name = c.req.param("name");
5931
6135
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
@@ -6154,6 +6358,13 @@ var slog2 = logger_default.child("schedules");
6154
6358
  function readSchedules(dir) {
6155
6359
  return readVoluteConfig(dir)?.schedules ?? [];
6156
6360
  }
6361
+ function validateMessages(messages) {
6362
+ if (messages === void 0) return null;
6363
+ if (!Array.isArray(messages) || messages.some((m) => typeof m !== "string" || !m.trim())) {
6364
+ return "messages must be an array of non-empty strings";
6365
+ }
6366
+ return null;
6367
+ }
6157
6368
  var UPCOMING_HORIZON_MS = 24 * 60 * 60 * 1e3;
6158
6369
  function computeClockEvents(schedules, sleepState, sleepConfig, now) {
6159
6370
  const upcoming = [];
@@ -6295,11 +6506,13 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
6295
6506
  if (body.cron && body.fireAt) {
6296
6507
  return c.json({ error: "cron and fireAt are mutually exclusive" }, 400);
6297
6508
  }
6298
- if (!body.message && !body.script) {
6299
- return c.json({ error: "message or script is required" }, 400);
6509
+ const messagesErr = validateMessages(body.messages);
6510
+ if (messagesErr) return c.json({ error: messagesErr }, 400);
6511
+ if (!body.message && !body.messages?.length && !body.script) {
6512
+ return c.json({ error: "message, messages, or script is required" }, 400);
6300
6513
  }
6301
- if (body.message && body.script) {
6302
- return c.json({ error: "message and script are mutually exclusive" }, 400);
6514
+ if ([body.message, body.messages?.length, body.script].filter(Boolean).length > 1) {
6515
+ return c.json({ error: "message, messages, and script are mutually exclusive" }, 400);
6303
6516
  }
6304
6517
  if (body.cron) {
6305
6518
  try {
@@ -6329,6 +6542,7 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
6329
6542
  if (body.cron) schedule.cron = body.cron;
6330
6543
  if (body.fireAt) schedule.fireAt = body.fireAt;
6331
6544
  if (body.message) schedule.message = body.message;
6545
+ if (body.messages?.length) schedule.messages = body.messages;
6332
6546
  if (body.script) schedule.script = body.script;
6333
6547
  if (body.channel) schedule.channel = body.channel;
6334
6548
  if (body.whileSleeping) schedule.whileSleeping = body.whileSleeping;
@@ -6345,8 +6559,10 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
6345
6559
  const idx = schedules.findIndex((s) => s.id === id);
6346
6560
  if (idx === -1) return c.json({ error: "Schedule not found" }, 404);
6347
6561
  const body = await c.req.json();
6348
- if (body.message && body.script) {
6349
- return c.json({ error: "message and script are mutually exclusive" }, 400);
6562
+ const messagesErr = validateMessages(body.messages);
6563
+ if (messagesErr) return c.json({ error: messagesErr }, 400);
6564
+ if ([body.message, body.messages?.length, body.script].filter(Boolean).length > 1) {
6565
+ return c.json({ error: "message, messages, and script are mutually exclusive" }, 400);
6350
6566
  }
6351
6567
  if (body.cron !== void 0) {
6352
6568
  try {
@@ -6367,10 +6583,21 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
6367
6583
  if (body.message !== void 0) {
6368
6584
  schedules[idx].message = body.message;
6369
6585
  delete schedules[idx].script;
6586
+ delete schedules[idx].messages;
6587
+ }
6588
+ if (body.messages !== void 0) {
6589
+ if (body.messages.length > 0) {
6590
+ schedules[idx].messages = body.messages;
6591
+ delete schedules[idx].message;
6592
+ delete schedules[idx].script;
6593
+ } else {
6594
+ delete schedules[idx].messages;
6595
+ }
6370
6596
  }
6371
6597
  if (body.script !== void 0) {
6372
6598
  schedules[idx].script = body.script;
6373
6599
  delete schedules[idx].message;
6600
+ delete schedules[idx].messages;
6374
6601
  }
6375
6602
  if (body.whileSleeping && !["skip", "queue", "trigger-wake"].includes(body.whileSleeping)) {
6376
6603
  return c.json(
@@ -6384,6 +6611,11 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
6384
6611
  if (body.channel !== void 0) schedules[idx].channel = body.channel || void 0;
6385
6612
  if (body.whileSleeping !== void 0)
6386
6613
  schedules[idx].whileSleeping = body.whileSleeping || void 0;
6614
+ const touchedAction = body.message !== void 0 || body.messages !== void 0 || body.script !== void 0;
6615
+ const result = schedules[idx];
6616
+ if (touchedAction && !result.message && !result.messages?.length && !result.script) {
6617
+ return c.json({ error: "schedule must keep a message, messages, or script" }, 400);
6618
+ }
6387
6619
  writeSchedules(name, dir, schedules);
6388
6620
  return c.json({ ok: true });
6389
6621
  }).delete("/:name/schedules/:id", requireSelf(), async (c) => {
@@ -6407,7 +6639,7 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
6407
6639
  const body = await c.req.text();
6408
6640
  const message = `[webhook: ${event}] ${body}`;
6409
6641
  try {
6410
- const { sendSystemMessage } = await import("./system-chat-N2F7HVY3.js");
6642
+ const { sendSystemMessage } = await import("./system-chat-63ABFF6V.js");
6411
6643
  await sendSystemMessage(name, message);
6412
6644
  return c.json({ ok: true });
6413
6645
  } catch (err) {
@@ -6420,14 +6652,14 @@ var schedules_default = app15;
6420
6652
  // packages/daemon/src/web/api/setup.ts
6421
6653
  import { mkdirSync as mkdirSync7 } from "fs";
6422
6654
  import { homedir as homedir2 } from "os";
6423
- import { resolve as resolve11 } from "path";
6655
+ import { resolve as resolve12 } from "path";
6424
6656
  import { Hono as Hono19 } from "hono";
6425
6657
  import { setCookie as setCookie2 } from "hono/cookie";
6426
6658
  var DEFAULT_API_URL2 = "https://volute.systems";
6427
6659
  var setup = new Hono19();
6428
6660
  function writeSetupConfig(systemName, description) {
6429
- const configHome = process.env.VOLUTE_HOME ?? resolve11(homedir2(), ".volute");
6430
- const mindsDir = resolve11(configHome, "minds");
6661
+ const configHome = process.env.VOLUTE_HOME ?? resolve12(homedir2(), ".volute");
6662
+ const mindsDir = resolve12(configHome, "minds");
6431
6663
  mkdirSync7(configHome, { recursive: true });
6432
6664
  mkdirSync7(mindsDir, { recursive: true });
6433
6665
  const existingConfig = readGlobalConfig();
@@ -6718,7 +6950,7 @@ setup.post("/models", async (c) => {
6718
6950
  return c.json({ error: "Spirit model is required" }, 400);
6719
6951
  }
6720
6952
  try {
6721
- const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-CVZEYKTK.js");
6953
+ const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-643TNFPH.js");
6722
6954
  setEnabledModels3(body.models);
6723
6955
  const config2 = readGlobalConfig();
6724
6956
  config2.spiritModel = body.spiritModel.trim();
@@ -6736,15 +6968,15 @@ setup.post("/complete", async (c) => {
6736
6968
  return c.json({ error: "Setup already complete" }, 400);
6737
6969
  }
6738
6970
  try {
6739
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-WXN4IDBF.js");
6740
- const { startSpiritFull } = await import("./mind-service-JFY7UG5E.js");
6971
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-WXS3HCLN.js");
6972
+ const { startSpiritFull } = await import("./mind-service-2ARGJNKP.js");
6741
6973
  await ensureSpiritProject();
6742
6974
  await syncSpiritTemplate();
6743
6975
  const warnings = [];
6744
6976
  const config2 = readGlobalConfig();
6745
6977
  if (config2.setup?.service && config2.setup?.type === "local") {
6746
6978
  try {
6747
- const { installUserService } = await import("./service-install-FQ43Z4DF.js");
6979
+ const { installUserService } = await import("./service-install-VCRMFWX5.js");
6748
6980
  const installed = await installUserService(config2.port, config2.hostname);
6749
6981
  if (!installed) {
6750
6982
  warnings.push("Service installation is not supported on this platform.");
@@ -6768,7 +7000,8 @@ setup.post("/complete", async (c) => {
6768
7000
  logger_default.info("spirit started successfully during setup");
6769
7001
  } catch (err) {
6770
7002
  logger_default.warn("spirit start failed during setup (non-fatal)", logger_default.errorData(err));
6771
- warnings.push("Spirit failed to start \u2014 it will retry on next daemon restart.");
7003
+ const reason = err instanceof Error ? err.message : String(err);
7004
+ warnings.push(`The spirit couldn't start: ${reason} \u2014 it will retry on next daemon restart.`);
6772
7005
  }
6773
7006
  let spiritConversationId;
6774
7007
  try {
@@ -6795,7 +7028,7 @@ setup.post("/complete", async (c) => {
6795
7028
  logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
6796
7029
  if (spiritConversationId && spiritStarted) {
6797
7030
  try {
6798
- const { deliverMessage: deliverMessage2 } = await import("./message-delivery-ZE3YGJDD.js");
7031
+ const { deliverMessage: deliverMessage2 } = await import("./message-delivery-GPQ5SE5N.js");
6799
7032
  const { listUsersByType: listUsers2 } = await import("./auth-A4VGHADI.js");
6800
7033
  const admins = await listUsers2("brain");
6801
7034
  const admin2 = admins.find((u) => u.role === "admin");
@@ -6835,9 +7068,9 @@ setup.post("/complete", async (c) => {
6835
7068
  var setup_default = setup;
6836
7069
 
6837
7070
  // packages/daemon/src/web/api/skills.ts
6838
- import { existsSync as existsSync8, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync5 } from "fs";
7071
+ import { existsSync as existsSync9, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync5 } from "fs";
6839
7072
  import { tmpdir } from "os";
6840
- import { join, resolve as resolve12 } from "path";
7073
+ import { join, resolve as resolve13 } from "path";
6841
7074
  import AdmZip from "adm-zip";
6842
7075
  import { Hono as Hono20 } from "hono";
6843
7076
  var app16 = new Hono20().get("/", async (c) => {
@@ -6913,19 +7146,19 @@ var app16 = new Hono20().get("/", async (c) => {
6913
7146
  try {
6914
7147
  const zip = new AdmZip(buffer);
6915
7148
  for (const entry of zip.getEntries()) {
6916
- const target = resolve12(tmpDir, entry.entryName);
7149
+ const target = resolve13(tmpDir, entry.entryName);
6917
7150
  if (!target.startsWith(tmpDir)) {
6918
7151
  return c.json({ error: "Invalid zip: paths must not escape archive" }, 400);
6919
7152
  }
6920
7153
  }
6921
7154
  zip.extractAllTo(tmpDir, true);
6922
7155
  let skillDir = null;
6923
- if (existsSync8(join(tmpDir, "SKILL.md"))) {
7156
+ if (existsSync9(join(tmpDir, "SKILL.md"))) {
6924
7157
  skillDir = tmpDir;
6925
7158
  } else {
6926
7159
  const entries = readdirSync3(tmpDir, { withFileTypes: true }).filter((e) => e.isDirectory());
6927
7160
  for (const entry of entries) {
6928
- if (existsSync8(join(tmpDir, entry.name, "SKILL.md"))) {
7161
+ if (existsSync9(join(tmpDir, entry.name, "SKILL.md"))) {
6929
7162
  skillDir = join(tmpDir, entry.name);
6930
7163
  break;
6931
7164
  }
@@ -7239,8 +7472,8 @@ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
7239
7472
  });
7240
7473
  }, 15e3);
7241
7474
  cleanups.push(() => clearInterval(keepAlive));
7242
- await new Promise((resolve17) => {
7243
- stream.onAbort(() => resolve17());
7475
+ await new Promise((resolve18) => {
7476
+ stream.onAbort(() => resolve18());
7244
7477
  });
7245
7478
  } finally {
7246
7479
  for (const cleanup of cleanups) {
@@ -7255,14 +7488,14 @@ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
7255
7488
  var events_default = app20;
7256
7489
 
7257
7490
  // packages/daemon/src/web/api/variants.ts
7258
- import { existsSync as existsSync9, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8 } from "fs";
7259
- import { resolve as resolve14 } from "path";
7491
+ import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
7492
+ import { resolve as resolve15 } from "path";
7260
7493
  import { Hono as Hono25 } from "hono";
7261
7494
 
7262
7495
  // packages/daemon/src/lib/mind/spawn-server.ts
7263
7496
  import { spawn as spawn4 } from "child_process";
7264
- import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync9 } from "fs";
7265
- import { resolve as resolve13 } from "path";
7497
+ import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync10 } from "fs";
7498
+ import { resolve as resolve14 } from "path";
7266
7499
  async function spawnServer(cwd, port, options) {
7267
7500
  let cmd = process.env.VOLUTE_NODE_PATH ?? process.execPath;
7268
7501
  let args = ["--import", "tsx", "src/server.ts", "--port", String(port)];
@@ -7283,31 +7516,31 @@ function spawnAttached(cmd, args, cwd) {
7283
7516
  cwd,
7284
7517
  stdio: ["ignore", "pipe", "pipe"]
7285
7518
  });
7286
- return new Promise((resolve17) => {
7287
- const timeout = setTimeout(() => resolve17(null), 3e4);
7519
+ return new Promise((resolve18) => {
7520
+ const timeout = setTimeout(() => resolve18(null), 3e4);
7288
7521
  function checkOutput(data) {
7289
7522
  const match = data.toString().match(/listening on :(\d+)/);
7290
7523
  if (match) {
7291
7524
  clearTimeout(timeout);
7292
- resolve17({ child, actualPort: parseInt(match[1], 10) });
7525
+ resolve18({ child, actualPort: parseInt(match[1], 10) });
7293
7526
  }
7294
7527
  }
7295
7528
  child.stdout?.on("data", checkOutput);
7296
7529
  child.stderr?.on("data", checkOutput);
7297
7530
  child.on("error", () => {
7298
7531
  clearTimeout(timeout);
7299
- resolve17(null);
7532
+ resolve18(null);
7300
7533
  });
7301
7534
  child.on("exit", () => {
7302
7535
  clearTimeout(timeout);
7303
- resolve17(null);
7536
+ resolve18(null);
7304
7537
  });
7305
7538
  });
7306
7539
  }
7307
7540
  function spawnDetached(cmd, args, cwd, logDir) {
7308
- const logsDir = logDir ?? resolve13(cwd, ".mind", "logs");
7541
+ const logsDir = logDir ?? resolve14(cwd, ".mind", "logs");
7309
7542
  mkdirSync8(logsDir, { recursive: true });
7310
- const logPath = resolve13(logsDir, "mind.log");
7543
+ const logPath = resolve14(logsDir, "mind.log");
7311
7544
  const logFd = openSync(logPath, "a");
7312
7545
  const child = spawn4(cmd, args, {
7313
7546
  cwd,
@@ -7327,7 +7560,7 @@ function spawnDetached(cmd, args, cwd, logDir) {
7327
7560
  }
7328
7561
  const interval = setInterval(() => {
7329
7562
  try {
7330
- const content = readFileSync9(logPath, "utf-8");
7563
+ const content = readFileSync10(logPath, "utf-8");
7331
7564
  const match = content.match(/listening on :(\d+)/);
7332
7565
  if (match) {
7333
7566
  finish({ child, actualPort: parseInt(match[1], 10) });
@@ -7428,11 +7661,11 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
7428
7661
  return c.json({ error: `Name already in use: ${variantName}` }, 409);
7429
7662
  }
7430
7663
  const projectRoot = entry.dir ?? mindDir(mindName);
7431
- const variantDir = resolve14(projectRoot, ".variants", variantName);
7432
- if (existsSync9(variantDir)) {
7664
+ const variantDir = resolve15(projectRoot, ".variants", variantName);
7665
+ if (existsSync10(variantDir)) {
7433
7666
  return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
7434
7667
  }
7435
- mkdirSync9(resolve14(projectRoot, ".variants"), { recursive: true });
7668
+ mkdirSync9(resolve15(projectRoot, ".variants"), { recursive: true });
7436
7669
  try {
7437
7670
  await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
7438
7671
  } catch (e) {
@@ -7445,7 +7678,7 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
7445
7678
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
7446
7679
  await exec(cmd, args, {
7447
7680
  cwd: variantDir,
7448
- env: { ...process.env, HOME: resolve14(variantDir, "home") }
7681
+ env: { ...process.env, HOME: resolve15(variantDir, "home") }
7449
7682
  });
7450
7683
  } else {
7451
7684
  await exec("npm", ["install"], { cwd: variantDir });
@@ -7455,7 +7688,7 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
7455
7688
  return c.json({ error: `npm install failed: ${msg}` }, 500);
7456
7689
  }
7457
7690
  if (body.soul) {
7458
- writeFileSync8(resolve14(variantDir, "home/SOUL.md"), body.soul);
7691
+ writeFileSync9(resolve15(variantDir, "home/SOUL.md"), body.soul);
7459
7692
  }
7460
7693
  const variantPort = body.port ?? await nextPort();
7461
7694
  await addVariant(variantName, mindName, variantPort, variantDir, variantName);
@@ -7492,7 +7725,7 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
7492
7725
  } catch {
7493
7726
  }
7494
7727
  const projectRoot = parentEntry.dir ?? mindDir(mindName);
7495
- if (existsSync9(variantEntry.dir)) {
7728
+ if (existsSync10(variantEntry.dir)) {
7496
7729
  const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
7497
7730
  if (status) {
7498
7731
  try {
@@ -7604,7 +7837,7 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
7604
7837
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
7605
7838
  await exec(cmd, args, {
7606
7839
  cwd: projectRoot,
7607
- env: { ...process.env, HOME: resolve14(projectRoot, "home") }
7840
+ env: { ...process.env, HOME: resolve15(projectRoot, "home") }
7608
7841
  });
7609
7842
  } else {
7610
7843
  await exec("npm", ["install"], { cwd: projectRoot });
@@ -7659,7 +7892,8 @@ var channelSettingsSchema = z10.object({
7659
7892
  private: z10.boolean().optional()
7660
7893
  });
7661
7894
  var createSchema2 = z10.object({
7662
- name: z10.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
7895
+ name: z10.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens"),
7896
+ participantNames: z10.array(z10.string().min(1)).optional()
7663
7897
  }).merge(channelSettingsSchema);
7664
7898
  var inviteSchema = z10.object({
7665
7899
  username: z10.string().min(1)
@@ -7678,10 +7912,21 @@ var app22 = new Hono26().get("/", async (c) => {
7678
7912
  }).post("/", zValidator10("json", createSchema2), async (c) => {
7679
7913
  const user = c.get("user");
7680
7914
  const body = c.req.valid("json");
7915
+ const { name, participantNames, ...settings } = body;
7916
+ const participantIds = [];
7917
+ for (const username of participantNames ?? []) {
7918
+ let member = await getUserByUsername(username);
7919
+ if (!member && await findMind(username)) {
7920
+ member = await getOrCreateMindUser(username);
7921
+ }
7922
+ if (!member) {
7923
+ return c.json({ error: `User not found: ${username}` }, 404);
7924
+ }
7925
+ participantIds.push(member.id);
7926
+ }
7927
+ let ch;
7681
7928
  try {
7682
- const { name, ...settings } = body;
7683
- const ch = await createChannel(name, user.id, settings);
7684
- return c.json({ ...ch, channel_name: name }, 201);
7929
+ ch = await createChannel(name, user.id, settings);
7685
7930
  } catch (err) {
7686
7931
  const cause = err instanceof Error ? err.cause : null;
7687
7932
  if (cause && /UNIQUE/i.test(cause.extendedCode ?? cause.message ?? "")) {
@@ -7689,6 +7934,23 @@ var app22 = new Hono26().get("/", async (c) => {
7689
7934
  }
7690
7935
  throw err;
7691
7936
  }
7937
+ try {
7938
+ for (const id of participantIds) {
7939
+ await joinChannel(ch.id, id);
7940
+ }
7941
+ } catch (err) {
7942
+ console.error("[channels] join failed during channel create:", err);
7943
+ try {
7944
+ await deleteConversation(ch.id);
7945
+ } catch (cleanupErr) {
7946
+ console.error(
7947
+ `[channels] failed to roll back channel ${ch.id} after join failure:`,
7948
+ cleanupErr
7949
+ );
7950
+ }
7951
+ throw err;
7952
+ }
7953
+ return c.json({ ...ch, channel_name: name }, 201);
7692
7954
  }).get("/:name", async (c) => {
7693
7955
  const name = c.req.param("name");
7694
7956
  const ch = await getChannelByName(name);
@@ -8023,11 +8285,11 @@ var app23 = new Hono27().get("/:name/conversations/:id/events", async (c) => {
8023
8285
  if (!stream.aborted) console.error("[chat] SSE ping error:", err);
8024
8286
  });
8025
8287
  }, 15e3);
8026
- await new Promise((resolve17) => {
8288
+ await new Promise((resolve18) => {
8027
8289
  stream.onAbort(() => {
8028
8290
  unsubscribe();
8029
8291
  clearInterval(keepAlive);
8030
- resolve17();
8292
+ resolve18();
8031
8293
  });
8032
8294
  });
8033
8295
  });
@@ -8241,10 +8503,10 @@ app25.route("/api/conversations", conversations_default);
8241
8503
  var app_default = app25;
8242
8504
 
8243
8505
  // packages/daemon/src/web/server.ts
8244
- import { existsSync as existsSync10 } from "fs";
8506
+ import { existsSync as existsSync11 } from "fs";
8245
8507
  import { readFile as readFile2, stat as stat2 } from "fs/promises";
8246
8508
  import { createServer as createHttpsServer } from "https";
8247
- import { dirname as dirname2, extname as extname3, resolve as resolve15 } from "path";
8509
+ import { dirname as dirname2, extname as extname3, resolve as resolve16 } from "path";
8248
8510
  import { serve } from "@hono/node-server";
8249
8511
  var MIME_TYPES2 = {
8250
8512
  ".html": "text/html",
@@ -8263,8 +8525,8 @@ async function startServer({
8263
8525
  let assetsDir = "";
8264
8526
  let searchDir = dirname2(new URL(import.meta.url).pathname);
8265
8527
  for (let i = 0; i < 5; i++) {
8266
- const candidate = resolve15(searchDir, "dist", "web-assets");
8267
- if (existsSync10(candidate)) {
8528
+ const candidate = resolve16(searchDir, "dist", "web-assets");
8529
+ if (existsSync11(candidate)) {
8268
8530
  assetsDir = candidate;
8269
8531
  break;
8270
8532
  }
@@ -8274,7 +8536,7 @@ async function startServer({
8274
8536
  app_default.get("*", async (c) => {
8275
8537
  const urlPath = new URL(c.req.url).pathname;
8276
8538
  if (urlPath.startsWith("/api/") || urlPath.startsWith("/ext/")) return c.notFound();
8277
- const filePath = resolve15(assetsDir, urlPath.slice(1));
8539
+ const filePath = resolve16(assetsDir, urlPath.slice(1));
8278
8540
  if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
8279
8541
  const s = await stat2(filePath).catch(() => null);
8280
8542
  if (s?.isFile()) {
@@ -8287,7 +8549,7 @@ async function startServer({
8287
8549
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
8288
8550
  return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
8289
8551
  }
8290
- const indexPath = resolve15(assetsDir, "index.html");
8552
+ const indexPath = resolve16(assetsDir, "index.html");
8291
8553
  const indexStat = await stat2(indexPath).catch(() => null);
8292
8554
  if (indexStat?.isFile()) {
8293
8555
  const body = await readFile2(indexPath, "utf-8");
@@ -8304,10 +8566,10 @@ async function startServer({
8304
8566
  createServer: createHttpsServer,
8305
8567
  serverOptions: { key: tls.key, cert: tls.cert }
8306
8568
  });
8307
- await new Promise((resolve17, reject) => {
8569
+ await new Promise((resolve18, reject) => {
8308
8570
  server2.on("listening", () => {
8309
8571
  logger_default.info("Volute UI running (https)", { hostname, port });
8310
- resolve17();
8572
+ resolve18();
8311
8573
  });
8312
8574
  server2.on("error", (err) => {
8313
8575
  reject(err);
@@ -8315,13 +8577,13 @@ async function startServer({
8315
8577
  });
8316
8578
  const internalPort = port + 1;
8317
8579
  const internalServer = serve({ fetch: app_default.fetch, port: internalPort, hostname: "127.0.0.1" });
8318
- await new Promise((resolve17, reject) => {
8580
+ await new Promise((resolve18, reject) => {
8319
8581
  internalServer.on("listening", () => {
8320
8582
  logger_default.info("Volute API running (http, internal)", {
8321
8583
  hostname: "127.0.0.1",
8322
8584
  port: internalPort
8323
8585
  });
8324
- resolve17();
8586
+ resolve18();
8325
8587
  });
8326
8588
  internalServer.on("error", (err) => {
8327
8589
  reject(err);
@@ -8330,10 +8592,10 @@ async function startServer({
8330
8592
  return { server: server2, internalPort };
8331
8593
  }
8332
8594
  const server = serve({ fetch: app_default.fetch, port, hostname });
8333
- await new Promise((resolve17, reject) => {
8595
+ await new Promise((resolve18, reject) => {
8334
8596
  server.on("listening", () => {
8335
8597
  logger_default.info("Volute API running (http)", { hostname, port });
8336
- resolve17();
8598
+ resolve18();
8337
8599
  });
8338
8600
  server.on("error", (err) => {
8339
8601
  reject(err);
@@ -8344,18 +8606,18 @@ async function startServer({
8344
8606
 
8345
8607
  // packages/daemon/src/daemon.ts
8346
8608
  if (!process.env.VOLUTE_HOME) {
8347
- process.env.VOLUTE_HOME = resolve16(homedir3(), ".volute");
8609
+ process.env.VOLUTE_HOME = resolve17(homedir3(), ".volute");
8348
8610
  }
8349
8611
  if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
8350
8612
  process.env.TZ = process.env.VOLUTE_TIMEZONE;
8351
8613
  }
8352
8614
  function writeDaemonConfig(systemDir, config2, token) {
8353
- const configPath = resolve16(systemDir, "daemon.json");
8354
- writeFileSync9(configPath, `${JSON.stringify(config2, null, 2)}
8615
+ const configPath = resolve17(systemDir, "daemon.json");
8616
+ writeFileSync10(configPath, `${JSON.stringify(config2, null, 2)}
8355
8617
  `, { mode: 420 });
8356
8618
  chmodSync(configPath, 420);
8357
- const tokenPath = resolve16(systemDir, "daemon-token");
8358
- writeFileSync9(tokenPath, `${token}
8619
+ const tokenPath = resolve17(systemDir, "daemon-token");
8620
+ writeFileSync10(tokenPath, `${token}
8359
8621
  `, { mode: 384 });
8360
8622
  chmodSync(tokenPath, 384);
8361
8623
  }
@@ -8365,7 +8627,7 @@ async function startDaemon(opts) {
8365
8627
  const home = voluteHome();
8366
8628
  const systemDir = voluteSystemDir();
8367
8629
  if (!opts.foreground) {
8368
- const rotatingLog = new RotatingLog(resolve16(systemDir, "daemon.log"));
8630
+ const rotatingLog = new RotatingLog(resolve17(systemDir, "daemon.log"));
8369
8631
  logger_default.setOutput((line) => rotatingLog.write(`${line}
8370
8632
  `));
8371
8633
  const write = (...args) => rotatingLog.write(`${format(...args)}
@@ -8375,15 +8637,15 @@ async function startDaemon(opts) {
8375
8637
  console.warn = write;
8376
8638
  console.info = write;
8377
8639
  }
8378
- const DAEMON_PID_PATH = resolve16(systemDir, "daemon.pid");
8379
- const DAEMON_JSON_PATH = resolve16(systemDir, "daemon.json");
8380
- const DAEMON_TOKEN_PATH = resolve16(systemDir, "daemon-token");
8640
+ const DAEMON_PID_PATH = resolve17(systemDir, "daemon.pid");
8641
+ const DAEMON_JSON_PATH = resolve17(systemDir, "daemon.json");
8642
+ const DAEMON_TOKEN_PATH = resolve17(systemDir, "daemon-token");
8381
8643
  mkdirSync10(home, { recursive: true });
8382
8644
  ensureSystemDir();
8383
- const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-KFYVWTXG.js");
8645
+ const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-5ECWTYKG.js");
8384
8646
  migrateConfigSecrets();
8385
8647
  migrateSetupCompleted();
8386
- const { migrateAiModelQualification } = await import("./ai-service-CVZEYKTK.js");
8648
+ const { migrateAiModelQualification } = await import("./ai-service-643TNFPH.js");
8387
8649
  migrateAiModelQualification();
8388
8650
  await (await import("./db-FO6LXYCW.js")).getDb();
8389
8651
  try {
@@ -8395,12 +8657,12 @@ async function startDaemon(opts) {
8395
8657
  logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
8396
8658
  }
8397
8659
  try {
8398
- const { migrateAvatarSizes } = await import("./avatar-image-7S3WA77A.js");
8660
+ const { migrateAvatarSizes } = await import("./avatar-image-Y45R7LW5.js");
8399
8661
  await migrateAvatarSizes();
8400
8662
  } catch (err) {
8401
8663
  logger_default.warn("avatar size migration failed", logger_default.errorData(err));
8402
8664
  }
8403
- const { initSandbox } = await import("./sandbox-G4X4K3UN.js");
8665
+ const { initSandbox } = await import("./sandbox-5VQ454XP.js");
8404
8666
  await initSandbox();
8405
8667
  try {
8406
8668
  await syncBuiltinSkills();
@@ -8426,6 +8688,11 @@ async function startDaemon(opts) {
8426
8688
  } catch (err) {
8427
8689
  logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
8428
8690
  }
8691
+ try {
8692
+ await backfillSystemChannelMembers();
8693
+ } catch (err) {
8694
+ logger_default.warn("failed to backfill minds into #system", logger_default.errorData(err));
8695
+ }
8429
8696
  try {
8430
8697
  const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-A4VGHADI.js");
8431
8698
  await getOrCreateSystemUser2();
@@ -8436,7 +8703,7 @@ async function startDaemon(opts) {
8436
8703
  );
8437
8704
  }
8438
8705
  const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes3(32).toString("hex");
8439
- const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-KFYVWTXG.js");
8706
+ const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-5ECWTYKG.js");
8440
8707
  const globalCfg = readGlobalConfig2();
8441
8708
  let tls;
8442
8709
  if (opts.tailscale || globalCfg.tailscale) {
@@ -8468,7 +8735,7 @@ async function startDaemon(opts) {
8468
8735
  process.env.VOLUTE_DAEMON_TOKEN = token;
8469
8736
  process.env.VOLUTE_DAEMON_PORT = String(daemonPort);
8470
8737
  process.env.VOLUTE_DAEMON_HOSTNAME = hostname;
8471
- writeFileSync9(DAEMON_PID_PATH, myPid, { mode: 420 });
8738
+ writeFileSync10(DAEMON_PID_PATH, myPid, { mode: 420 });
8472
8739
  const daemonConfig = { port, hostname };
8473
8740
  if (internalPort) daemonConfig.internalPort = internalPort;
8474
8741
  if (tls) daemonConfig.tls = true;
@@ -8521,10 +8788,10 @@ async function startDaemon(opts) {
8521
8788
  await Promise.all(workers);
8522
8789
  }
8523
8790
  try {
8524
- const { isSetupComplete: isSetupComplete2 } = await import("./setup-KFYVWTXG.js");
8791
+ const { isSetupComplete: isSetupComplete2 } = await import("./setup-5ECWTYKG.js");
8525
8792
  if (isSetupComplete2()) {
8526
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-WXN4IDBF.js");
8527
- const { startSpiritFull } = await import("./mind-service-JFY7UG5E.js");
8793
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-WXS3HCLN.js");
8794
+ const { startSpiritFull } = await import("./mind-service-2ARGJNKP.js");
8528
8795
  await ensureSpiritProject();
8529
8796
  const spiritEntry = await findMind(SPIRIT_NAME);
8530
8797
  if (spiritEntry?.dir) {
@@ -8545,7 +8812,7 @@ async function startDaemon(opts) {
8545
8812
  bridgeManager.startBridges(daemonPort).catch((err) => {
8546
8813
  logger_default.warn("failed to start bridges", logger_default.errorData(err));
8547
8814
  });
8548
- import("./cloud-sync-LQTVDTQ3.js").then(
8815
+ import("./cloud-sync-WHKCB4CD.js").then(
8549
8816
  ({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
8550
8817
  logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
8551
8818
  })
@@ -8553,7 +8820,7 @@ async function startDaemon(opts) {
8553
8820
  logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
8554
8821
  });
8555
8822
  try {
8556
- const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-XRGTEEDK.js");
8823
+ const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-73YURTFR.js");
8557
8824
  backfillTemplateHashes().then(() => warnStaleTemplates()).catch((err) => {
8558
8825
  logger_default.warn("failed to check template staleness", logger_default.errorData(err));
8559
8826
  });
@@ -8583,13 +8850,13 @@ async function startDaemon(opts) {
8583
8850
  logger_default.info(`running on ${hostname}:${port}, pid ${myPid}`);
8584
8851
  function cleanup() {
8585
8852
  try {
8586
- if (readFileSync10(DAEMON_PID_PATH, "utf-8").trim() === myPid) {
8853
+ if (readFileSync11(DAEMON_PID_PATH, "utf-8").trim() === myPid) {
8587
8854
  unlinkSync2(DAEMON_PID_PATH);
8588
8855
  }
8589
8856
  } catch {
8590
8857
  }
8591
8858
  try {
8592
- if (readFileSync10(DAEMON_TOKEN_PATH, "utf-8").trim() === token) {
8859
+ if (readFileSync11(DAEMON_TOKEN_PATH, "utf-8").trim() === token) {
8593
8860
  unlinkSync2(DAEMON_TOKEN_PATH);
8594
8861
  try {
8595
8862
  unlinkSync2(DAEMON_JSON_PATH);