volute 0.40.2 → 0.41.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/{accept-IVHOHXQS.js → accept-7YVHZKRD.js} +2 -2
  2. package/dist/{activity-events-DS4QRWBY.js → activity-events-KFKVRZE3.js} +4 -4
  3. package/dist/{ai-service-EVLKMAJD.js → ai-service-XCLE3MQP.js} +5 -5
  4. package/dist/{api-client-NFM6GX2N.js → api-client-LC5YRA32.js} +1 -1
  5. package/dist/{archive-UDHFZN4G.js → archive-4PPYF7LL.js} +4 -4
  6. package/dist/{auth-X6ZITZ7D.js → auth-EAASQPTN.js} +5 -5
  7. package/dist/{bridge-MSZC4HUT.js → bridge-WPYSOQKR.js} +2 -2
  8. package/dist/{chat-F2EEN76G.js → chat-7DOENBY2.js} +9 -9
  9. package/dist/{chunk-E25SO3QW.js → chunk-5QG36RV7.js} +3 -3
  10. package/dist/{chunk-NERYUSER.js → chunk-62ICA2FF.js} +1 -1
  11. package/dist/{chunk-KMHC36CA.js → chunk-763WUVJQ.js} +43 -10
  12. package/dist/{chunk-ITH5ZLZJ.js → chunk-BLOAJLGI.js} +1 -1
  13. package/dist/{chunk-4UMXOMZ6.js → chunk-CGPESELY.js} +2 -2
  14. package/dist/{chunk-MNUXL4XN.js → chunk-E7XWFDZL.js} +1 -1
  15. package/dist/{chunk-PEKG3GNZ.js → chunk-EKLRS2SX.js} +3 -3
  16. package/dist/{chunk-ZOI6D2YH.js → chunk-F44AEQAW.js} +292 -73
  17. package/dist/{chunk-JYQQDI3M.js → chunk-G777ME4L.js} +2 -2
  18. package/dist/{chunk-YMMYN2V3.js → chunk-GCS64EAD.js} +5 -5
  19. package/dist/{chunk-AEAZRTEV.js → chunk-GN52E2DP.js} +1 -1
  20. package/dist/{chunk-ZX7EAV5J.js → chunk-IFNSAOA4.js} +9 -2
  21. package/dist/{chunk-ZXPWTH4I.js → chunk-IJCZAYGT.js} +1 -1
  22. package/dist/{chunk-B4WPXYPI.js → chunk-IUZ3EV2D.js} +10 -1
  23. package/dist/chunk-K3NQKI34.js +10 -0
  24. package/dist/{chunk-QYI65HCL.js → chunk-K547QOCM.js} +2 -2
  25. package/dist/{chunk-SVXOBKQY.js → chunk-KUJVCDWT.js} +2 -2
  26. package/dist/{chunk-YHWGN4FX.js → chunk-M2YMNTHK.js} +1 -1
  27. package/dist/{chunk-DNU6XLE2.js → chunk-MA7MYEOK.js} +4 -3
  28. package/dist/{chunk-2HZRJ35V.js → chunk-MHFAWJCC.js} +1 -1
  29. package/dist/{chunk-UX7FPDDO.js → chunk-MJIJFCAH.js} +44 -15
  30. package/dist/{chunk-NRJ3ZYFP.js → chunk-MYJSKXGH.js} +15 -14
  31. package/dist/{chunk-I57LLNAQ.js → chunk-OEJFZHZZ.js} +1 -1
  32. package/dist/{chunk-TOANT6FD.js → chunk-OSUF75I7.js} +2 -2
  33. package/dist/{chunk-46DYYHN6.js → chunk-QLWG3C2Z.js} +44 -0
  34. package/dist/{chunk-KAB6UGOL.js → chunk-QMJCNZ6C.js} +1 -1
  35. package/dist/{chunk-PKGA23XM.js → chunk-QPTQKGGF.js} +1 -1
  36. package/dist/{chunk-6SYHHEQ7.js → chunk-TFBQESH7.js} +1 -1
  37. package/dist/{chunk-WOWRLBL2.js → chunk-ULNQ6OC4.js} +8 -8
  38. package/dist/{chunk-42UMLIQR.js → chunk-VBKRZCR7.js} +1 -1
  39. package/dist/{chunk-3Y7UDHO7.js → chunk-YLTIEEVL.js} +3 -3
  40. package/dist/cli.js +24 -24
  41. package/dist/{clock-YLDJUKBW.js → clock-HP2TGMG5.js} +4 -4
  42. package/dist/{cloud-sync-GOSJZIHH.js → cloud-sync-2XVXEOSU.js} +19 -19
  43. package/dist/{config-PO4EZLIK.js → config-W7MS3PWY.js} +4 -4
  44. package/dist/connectors/discord-bridge.js +1 -1
  45. package/dist/connectors/slack-bridge.js +1 -1
  46. package/dist/connectors/telegram-bridge.js +1 -1
  47. package/dist/{conversations-AYLXPOGC.js → conversations-FSZCUUYO.js} +5 -5
  48. package/dist/{create-ZMTGINV3.js → create-CJ2SR4EU.js} +2 -2
  49. package/dist/{create-Y3RGU2GI.js → create-OTM46ZUM.js} +4 -4
  50. package/dist/{daemon-client-H6MEKK2W.js → daemon-client-EWDPOOHC.js} +4 -2
  51. package/dist/{daemon-restart-FSWVXPUE.js → daemon-restart-HDVGTYH7.js} +9 -9
  52. package/dist/daemon.js +260 -309
  53. package/dist/{db-FSYOTHSN.js → db-IJL6B26S.js} +1 -1
  54. package/dist/db-ZJJJYJBU.js +9 -0
  55. package/dist/{delete-TXVOH2OC.js → delete-4ND5PLE7.js} +3 -3
  56. package/dist/delivery-manager-CPADWRV2.js +33 -0
  57. package/dist/{delivery-router-T6CYTS3M.js → delivery-router-FDBZJQOY.js} +4 -4
  58. package/dist/down-DS6WCT34.js +17 -0
  59. package/dist/echo-text-GEDEEY7M.js +32 -0
  60. package/dist/{env-77IOWG4U.js → env-XX2MBZCZ.js} +2 -2
  61. package/dist/exec-ZDD7NEB4.js +17 -0
  62. package/dist/{export-TZKOCSCE.js → export-5DOQV2WM.js} +6 -6
  63. package/dist/{extension-35NB6GHW.js → extension-BCFYXI7A.js} +5 -2
  64. package/dist/{extensions-MD757RFY.js → extensions-SU3N4COT.js} +19 -19
  65. package/dist/{files-WNNVJWJB.js → files-K2MEMV3W.js} +5 -5
  66. package/dist/{import-BNNFCQ7U.js → import-V6QEHMPQ.js} +11 -11
  67. package/dist/{isolation-4Q4P7HRV.js → isolation-F7ABZMDA.js} +4 -4
  68. package/dist/{join-E2EJEXZO.js → join-4S3KT7NE.js} +3 -3
  69. package/dist/{list-BYCEDASJ.js → list-XJB5WII6.js} +2 -2
  70. package/dist/{login-Y6UAYQVO.js → login-PHMTLNUF.js} +4 -4
  71. package/dist/{login-JNSIYFVH.js → login-YWD6PUOT.js} +2 -2
  72. package/dist/{logout-VHGWVH63.js → logout-BP3R3CAA.js} +4 -4
  73. package/dist/{logout-M6FI62BL.js → logout-Q2WICH4V.js} +2 -2
  74. package/dist/message-delivery-HPMELC4Q.js +41 -0
  75. package/dist/{mind-OOB2LEVC.js → mind-APS4URT7.js} +19 -19
  76. package/dist/{mind-activity-tracker-GJ5RJS32.js → mind-activity-tracker-HWVFE533.js} +5 -5
  77. package/dist/{mind-history-W4JPTPTV.js → mind-history-TDUQFYAG.js} +2 -2
  78. package/dist/{mind-list-QROHCLGT.js → mind-list-2T353Q5G.js} +2 -2
  79. package/dist/mind-manager-74XQZEGX.js +33 -0
  80. package/dist/{mind-profile-3LNKXNPA.js → mind-profile-2HHR7LZ7.js} +2 -2
  81. package/dist/mind-service-XGXSMQP6.js +37 -0
  82. package/dist/{mind-sleep-PVCMLTAH.js → mind-sleep-4NXV4J4U.js} +2 -2
  83. package/dist/{mind-status-RAJFLRCN.js → mind-status-CG66OXDK.js} +2 -2
  84. package/dist/{mind-wake-HZUOVE7J.js → mind-wake-TNB54DBR.js} +2 -2
  85. package/dist/{package-PPA3VWS2.js → package-MVFX22K5.js} +4 -2
  86. package/dist/{read-OOINVR2H.js → read-JLR4NQXU.js} +2 -2
  87. package/dist/{read-stdin-P6HCZUAA.js → read-stdin-4B5UYPPM.js} +1 -1
  88. package/dist/{register-ISOH34RF.js → register-IQ2M4UO6.js} +2 -2
  89. package/dist/{registry-GV35XFT7.js → registry-MDLNPTTI.js} +7 -3
  90. package/dist/{reject-ZBWP62X5.js → reject-N2D4CZND.js} +2 -2
  91. package/dist/{restart-QBJV5455.js → restart-43A5MBGV.js} +2 -2
  92. package/dist/{sandbox-5R32QKWQ.js → sandbox-ND53WZVU.js} +9 -5
  93. package/dist/scheduler-MEBQF5MW.js +31 -0
  94. package/dist/{schema-LYQUDL7G.js → schema-HHYJDG7B.js} +2 -2
  95. package/dist/{seed-BTAHXCO5.js → seed-L4XFZ3VX.js} +2 -2
  96. package/dist/{seed-check-3WXXRHTC.js → seed-check-N5ALJBT6.js} +2 -2
  97. package/dist/{seed-cmd-VEJNJBAQ.js → seed-cmd-NSTPYJFC.js} +4 -4
  98. package/dist/{seed-create-LOU5RALI.js → seed-create-ZYCZC46W.js} +6 -6
  99. package/dist/{seed-sprout-BXF5TBXD.js → seed-sprout-YXHU73XA.js} +12 -12
  100. package/dist/{send-WO3CVG73.js → send-KQECN2EL.js} +5 -5
  101. package/dist/{service-WMV6R6VJ.js → service-Q5OVY5AK.js} +6 -6
  102. package/dist/service-install-GTDUHP6R.js +17 -0
  103. package/dist/{setup-OTEC3ZPM.js → setup-FPFWDMXD.js} +4 -4
  104. package/dist/{setup-W3545462.js → setup-RMR3TKCR.js} +9 -9
  105. package/dist/{skill-QHACP7EU.js → skill-E43BI34Y.js} +2 -2
  106. package/dist/skills/imagegen/scripts/imagegen.ts +1 -1
  107. package/dist/{skills-3P7VQA4U.js → skills-AOZF6U2B.js} +7 -7
  108. package/dist/sleep-manager-OHM3TO62.js +35 -0
  109. package/dist/spirit-ONLRFATY.js +24 -0
  110. package/dist/{split-7AO4IO42.js → split-5IBUODEE.js} +3 -3
  111. package/dist/{sprout-AQICF7WZ.js → sprout-2KJOQZCL.js} +2 -2
  112. package/dist/{src-2IMB3V27.js → src-L2Z7X5UT.js} +6 -9
  113. package/dist/{src-XNUXP2FP.js → src-O4PRLMKM.js} +1 -1
  114. package/dist/src-TJ7RBU5H.js +2191 -0
  115. package/dist/{start-2U57BBK7.js → start-5AYFGNS7.js} +2 -2
  116. package/dist/{status-BRYYYO7C.js → status-ECZHHSY5.js} +7 -7
  117. package/dist/{stop-QILBDUAR.js → stop-WJ6IG6OK.js} +2 -2
  118. package/dist/system-chat-HZUKBIKJ.js +35 -0
  119. package/dist/{systems-3XTAHA35.js → systems-5MA57Q7G.js} +5 -5
  120. package/dist/{tailscale-X4HRKRTW.js → tailscale-TIRTGM6E.js} +3 -3
  121. package/dist/template-hash-446HHH5V.js +9 -0
  122. package/dist/{turn-tracker-AI6WWEBA.js → turn-tracker-TIX4DY2W.js} +6 -6
  123. package/dist/up-7KVNER6V.js +19 -0
  124. package/dist/{update-OY2JYXYK.js → update-OPR4KU4M.js} +7 -7
  125. package/dist/{update-check-IUB7QHAF.js → update-check-OG27AL4Z.js} +4 -4
  126. package/dist/{upgrade-25J6AE47.js → upgrade-QB7AHIKX.js} +3 -3
  127. package/dist/{variant-5LQOPCQA.js → variant-HHDTW74J.js} +1 -1
  128. package/dist/{version-notify-DK6AHWX7.js → version-notify-UFFDUPCX.js} +21 -21
  129. package/dist/{volute-config-7FO6QKWU.js → volute-config-TS62GS6A.js} +1 -1
  130. package/package.json +3 -1
  131. package/packages/extensions/plan/skills/plan/scripts/plan-hook.sh +2 -2
  132. package/templates/_base/.init/.config/hooks/pre-prompt/session-activity.ts +3 -3
  133. package/templates/_base/.init/.local/hooks/pre-prompt/notices.ts +3 -3
  134. package/templates/_base/.init/.local/hooks/pre-prompt/session-activity.ts +3 -3
  135. package/templates/_base/src/lib/daemon-client.ts +1 -1
  136. package/templates/_base/src/lib/volute-server.ts +1 -1
  137. package/dist/chunk-LMMQX4CK.js +0 -49
  138. package/dist/db-ZEPKEJJD.js +0 -9
  139. package/dist/delivery-manager-3NTCDKHR.js +0 -33
  140. package/dist/down-6DYO2QV7.js +0 -17
  141. package/dist/echo-text-JUNRP4ER.js +0 -32
  142. package/dist/exec-5DGKQ5V3.js +0 -17
  143. package/dist/message-delivery-Q7TU24IA.js +0 -41
  144. package/dist/mind-manager-4NFK4GEU.js +0 -31
  145. package/dist/mind-service-X7FH3NA4.js +0 -37
  146. package/dist/scheduler-PDARH4CE.js +0 -31
  147. package/dist/service-install-W3FQXJKB.js +0 -17
  148. package/dist/sleep-manager-TTNOLIX5.js +0 -35
  149. package/dist/spirit-T6GK5GEP.js +0 -24
  150. package/dist/src-OS75U2O7.js +0 -241910
  151. package/dist/system-chat-7CA2PP6A.js +0 -35
  152. package/dist/template-hash-DMHSLRDX.js +0 -9
  153. package/dist/up-PKNNDN6M.js +0 -19
package/dist/daemon.js CHANGED
@@ -6,31 +6,31 @@ import {
6
6
  rejectPending,
7
7
  stageFile,
8
8
  validateFilePath
9
- } from "./chunk-YHWGN4FX.js";
9
+ } from "./chunk-M2YMNTHK.js";
10
10
  import {
11
11
  findOpenClawSession,
12
12
  importOpenClawConnectors,
13
13
  importPiSession,
14
14
  parseNameFromIdentity
15
- } from "./chunk-SVXOBKQY.js";
15
+ } from "./chunk-KUJVCDWT.js";
16
16
  import {
17
17
  checkForUpdate,
18
18
  checkForUpdateCached,
19
19
  getCurrentVersion
20
- } from "./chunk-MNUXL4XN.js";
20
+ } from "./chunk-E7XWFDZL.js";
21
21
  import {
22
22
  isHomeOnlyArchive
23
- } from "./chunk-I57LLNAQ.js";
23
+ } from "./chunk-OEJFZHZZ.js";
24
24
  import {
25
25
  computeTemplateHash
26
- } from "./chunk-KAB6UGOL.js";
26
+ } from "./chunk-QMJCNZ6C.js";
27
27
  import {
28
28
  PLATFORMS,
29
29
  echoTextToChannel,
30
30
  fixModelEscapes,
31
31
  getPlatformDriver,
32
32
  routeOutboundBridge
33
- } from "./chunk-WOWRLBL2.js";
33
+ } from "./chunk-ULNQ6OC4.js";
34
34
  import {
35
35
  getBridgeConfig,
36
36
  readBridgesConfig,
@@ -39,12 +39,17 @@ import {
39
39
  resolveChannelMapping,
40
40
  setBridgeConfig,
41
41
  setChannelMapping
42
- } from "./chunk-PKGA23XM.js";
42
+ } from "./chunk-QPTQKGGF.js";
43
43
  import {
44
44
  RestartTracker,
45
45
  RotatingLog,
46
+ SESSION_MAX_AGE,
46
47
  announceToSystem,
48
+ authMiddleware,
49
+ cleanExpiredSessions,
47
50
  clearDeliveredNotices,
51
+ createSession,
52
+ deleteSession,
48
53
  deleteSystemsConfig,
49
54
  deliverMessage,
50
55
  drainNotices,
@@ -58,6 +63,7 @@ import {
58
63
  getLoadedExtensions,
59
64
  getMindManager,
60
65
  getScheduler,
66
+ getSessionUserId,
61
67
  getSleepManagerIfReady,
62
68
  getTokenBudget,
63
69
  getTypingMap,
@@ -68,6 +74,8 @@ import {
68
74
  initSleepManager,
69
75
  initTokenBudget,
70
76
  installNpmExtension,
77
+ invalidateMindUserCache,
78
+ invalidateSessionCache,
71
79
  isConversationId,
72
80
  joinSystemChannel,
73
81
  linkToolResultToTurn,
@@ -79,7 +87,9 @@ import {
79
87
  recordInbound,
80
88
  recordNotice,
81
89
  recordOutbound,
82
- resolveMindToken,
90
+ requireAdmin,
91
+ requireAdminOrSystem,
92
+ requireSelf,
83
93
  setExtensionEnabled,
84
94
  startMindFull,
85
95
  stopMindFull,
@@ -88,22 +98,24 @@ import {
88
98
  tagUntaggedOutbound,
89
99
  uninstallNpmExtension,
90
100
  writeSystemsConfig
91
- } from "./chunk-ZOI6D2YH.js";
101
+ } from "./chunk-F44AEQAW.js";
92
102
  import {
93
103
  loadMergedEnv,
94
104
  mindEnvPath,
95
105
  readEnv,
96
106
  sharedEnvPath,
97
107
  writeEnv
98
- } from "./chunk-ITH5ZLZJ.js";
99
- import "./chunk-NRJ3ZYFP.js";
108
+ } from "./chunk-BLOAJLGI.js";
109
+ import "./chunk-MYJSKXGH.js";
100
110
  import {
101
111
  applyInitFiles,
112
+ applyTemplateHomeFiles,
102
113
  composeTemplate,
103
114
  copyTemplateToDir,
104
115
  findTemplatesRoot,
116
+ isKnownTemplate,
105
117
  listFiles
106
- } from "./chunk-46DYYHN6.js";
118
+ } from "./chunk-QLWG3C2Z.js";
107
119
  import {
108
120
  SEED_SKILLS,
109
121
  STANDARD_SKILLS,
@@ -123,7 +135,7 @@ import {
123
135
  syncBuiltinSkills,
124
136
  uninstallSkill,
125
137
  updateSkill
126
- } from "./chunk-UX7FPDDO.js";
138
+ } from "./chunk-MJIJFCAH.js";
127
139
  import {
128
140
  addMessage,
129
141
  createChannel,
@@ -155,20 +167,23 @@ import {
155
167
  setConversationPrivate,
156
168
  subscribe as subscribe2,
157
169
  updateChannelSettings
158
- } from "./chunk-3Y7UDHO7.js";
170
+ } from "./chunk-YLTIEEVL.js";
159
171
  import {
160
172
  readVoluteConfig,
161
173
  writeVoluteConfig
162
174
  } from "./chunk-CU6OFXMM.js";
163
- import "./chunk-KMHC36CA.js";
175
+ import {
176
+ isSandboxEnabled,
177
+ wrapForSandbox
178
+ } from "./chunk-763WUVJQ.js";
164
179
  import {
165
180
  getActiveMinds,
166
181
  onMindEvent,
167
182
  stopAll
168
- } from "./chunk-42UMLIQR.js";
183
+ } from "./chunk-VBKRZCR7.js";
169
184
  import {
170
185
  extractTextContent
171
- } from "./chunk-NERYUSER.js";
186
+ } from "./chunk-62ICA2FF.js";
172
187
  import {
173
188
  PROMPT_DEFAULTS,
174
189
  PROMPT_KEYS,
@@ -191,12 +206,12 @@ import {
191
206
  summarizeTurn,
192
207
  takeErrored,
193
208
  trackToolUse
194
- } from "./chunk-YMMYN2V3.js";
209
+ } from "./chunk-GCS64EAD.js";
195
210
  import {
196
211
  exec,
197
212
  gitExec,
198
213
  resolveVoluteBin
199
- } from "./chunk-AEAZRTEV.js";
214
+ } from "./chunk-GN52E2DP.js";
200
215
  import {
201
216
  chownMindDir,
202
217
  createMindUser,
@@ -204,7 +219,7 @@ import {
204
219
  ensureVoluteGroup,
205
220
  isIsolationEnabled,
206
221
  wrapForIsolation
207
- } from "./chunk-6SYHHEQ7.js";
222
+ } from "./chunk-TFBQESH7.js";
208
223
  import {
209
224
  getAiConfig,
210
225
  getAvailableModels,
@@ -221,12 +236,12 @@ import {
221
236
  setProviderRefreshHook,
222
237
  setUtilityModel,
223
238
  unqualifyModelId
224
- } from "./chunk-ZXPWTH4I.js";
239
+ } from "./chunk-IJCZAYGT.js";
225
240
  import {
226
241
  isSetupComplete,
227
242
  readGlobalConfig,
228
243
  writeGlobalConfig
229
- } from "./chunk-DNU6XLE2.js";
244
+ } from "./chunk-MA7MYEOK.js";
230
245
  import {
231
246
  approveUser,
232
247
  changePassword,
@@ -245,11 +260,11 @@ import {
245
260
  syncMindProfile,
246
261
  updateUserProfile,
247
262
  verifyUser
248
- } from "./chunk-E25SO3QW.js";
263
+ } from "./chunk-5QG36RV7.js";
249
264
  import {
250
265
  broadcast,
251
266
  subscribe
252
- } from "./chunk-QYI65HCL.js";
267
+ } from "./chunk-K547QOCM.js";
253
268
  import {
254
269
  logBuffer,
255
270
  logger_default
@@ -268,35 +283,36 @@ import {
268
283
  getBaseName,
269
284
  getDb,
270
285
  mindDir,
286
+ mindTmpDir,
271
287
  nextPort,
272
288
  readAllMinds,
273
289
  readRegistry,
274
290
  removeMind,
275
291
  setMindRunning,
276
292
  setMindStage,
293
+ setMindTemplate,
277
294
  setMindTemplateHash,
278
295
  stateDir,
279
296
  validateMindName,
280
297
  voluteHome,
281
298
  voluteSystemDir
282
- } from "./chunk-B4WPXYPI.js";
299
+ } from "./chunk-IUZ3EV2D.js";
283
300
  import {
284
301
  activity,
285
302
  channels,
286
303
  conversationParticipants,
287
304
  conversations,
288
305
  mindHistory,
289
- sessions,
290
306
  summaries,
291
307
  systemPrompts,
292
308
  turns,
293
309
  users
294
- } from "./chunk-2HZRJ35V.js";
295
- import "./chunk-LMMQX4CK.js";
310
+ } from "./chunk-MHFAWJCC.js";
311
+ import "./chunk-K3NQKI34.js";
296
312
 
297
313
  // packages/daemon/src/daemon.ts
298
314
  import { randomBytes } from "crypto";
299
- import { mkdirSync as mkdirSync10, readFileSync as readFileSync10, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "fs";
315
+ import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync10, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "fs";
300
316
  import { homedir as homedir3 } from "os";
301
317
  import { resolve as resolve17 } from "path";
302
318
  import { format } from "util";
@@ -831,150 +847,6 @@ async function generateImage(model, prompt) {
831
847
  return PROVIDERS[providerId].generate(modelId, prompt, apiKey);
832
848
  }
833
849
 
834
- // packages/daemon/src/web/middleware/auth.ts
835
- import { timingSafeEqual } from "crypto";
836
- import { eq as eq2, lt as lt2 } from "drizzle-orm";
837
- import { getCookie } from "hono/cookie";
838
- import { createMiddleware } from "hono/factory";
839
- var MIND_USER_CACHE_TTL = 5 * 60 * 1e3;
840
- var mindUserCache = /* @__PURE__ */ new Map();
841
- function invalidateMindUserCache(mindName) {
842
- mindUserCache.delete(mindName);
843
- }
844
- function isValidDaemonToken(token) {
845
- const expected = process.env.VOLUTE_DAEMON_TOKEN;
846
- if (!expected || token.length !== expected.length) return false;
847
- return timingSafeEqual(Buffer.from(token), Buffer.from(expected));
848
- }
849
- var SESSION_MAX_AGE = 365 * 24 * 60 * 60 * 1e3;
850
- var SESSION_CACHE_TTL = 5 * 60 * 1e3;
851
- var sessionCache = /* @__PURE__ */ new Map();
852
- function invalidateSessionCache(sessionId) {
853
- sessionCache.delete(sessionId);
854
- }
855
- async function createSession(userId) {
856
- const db = await getDb();
857
- const sessionId = crypto.randomUUID();
858
- await db.insert(sessions).values({ id: sessionId, userId, createdAt: Date.now() });
859
- return sessionId;
860
- }
861
- async function deleteSession(sessionId) {
862
- sessionCache.delete(sessionId);
863
- const db = await getDb();
864
- await db.delete(sessions).where(eq2(sessions.id, sessionId));
865
- }
866
- async function getSessionUserId(sessionId) {
867
- const db = await getDb();
868
- const row = await db.select().from(sessions).where(eq2(sessions.id, sessionId)).get();
869
- if (!row) return void 0;
870
- if (Date.now() - row.createdAt > SESSION_MAX_AGE) {
871
- await db.delete(sessions).where(eq2(sessions.id, sessionId));
872
- return void 0;
873
- }
874
- return row.userId;
875
- }
876
- async function cleanExpiredSessions() {
877
- const db = await getDb();
878
- const cutoff = Date.now() - SESSION_MAX_AGE;
879
- await db.delete(sessions).where(lt2(sessions.createdAt, cutoff));
880
- }
881
- var requireAdmin = createMiddleware(async (c, next) => {
882
- const user = c.get("user");
883
- if (user.role !== "admin") {
884
- return c.json({ error: "Forbidden" }, 403);
885
- }
886
- await next();
887
- });
888
- var requireAdminOrSystem = createMiddleware(async (c, next) => {
889
- const user = c.get("user");
890
- if (user.role !== "admin" && user.role !== "system") {
891
- return c.json({ error: "Forbidden" }, 403);
892
- }
893
- await next();
894
- });
895
- async function resolveSession(sessionId) {
896
- const cached = sessionCache.get(sessionId);
897
- if (cached && cached.expires > Date.now()) {
898
- return cached.user;
899
- }
900
- const userId = await getSessionUserId(sessionId);
901
- if (userId == null) {
902
- sessionCache.delete(sessionId);
903
- return null;
904
- }
905
- const user = await getUser(userId);
906
- if (!user) {
907
- sessionCache.delete(sessionId);
908
- return null;
909
- }
910
- sessionCache.set(sessionId, { userId, user, expires: Date.now() + SESSION_CACHE_TTL });
911
- return user;
912
- }
913
- var authMiddleware = createMiddleware(async (c, next) => {
914
- const authHeader = c.req.header("Authorization");
915
- if (authHeader?.startsWith("Bearer ")) {
916
- const token = authHeader.slice(7);
917
- if (token && isValidDaemonToken(token)) {
918
- c.set("user", {
919
- id: 0,
920
- username: "daemon",
921
- role: "admin",
922
- user_type: "brain",
923
- display_name: null,
924
- description: null,
925
- avatar: null
926
- });
927
- const mindSessionHeader = c.req.header("X-Volute-Session");
928
- if (mindSessionHeader) c.set("mindSession", mindSessionHeader);
929
- await next();
930
- return;
931
- }
932
- const mindName = resolveMindToken(token);
933
- if (mindName) {
934
- const cached = mindUserCache.get(mindName);
935
- let mindUser;
936
- if (cached && Date.now() - cached.ts < MIND_USER_CACHE_TTL) {
937
- mindUser = cached.user;
938
- } else {
939
- mindUser = await getOrCreateMindUser(mindName);
940
- mindUserCache.set(mindName, { user: mindUser, ts: Date.now() });
941
- }
942
- c.set("user", mindUser);
943
- const mindSessionHeader = c.req.header("X-Volute-Session");
944
- if (mindSessionHeader) c.set("mindSession", mindSessionHeader);
945
- await next();
946
- return;
947
- }
948
- if (token) {
949
- const user2 = await resolveSession(token);
950
- if (user2) {
951
- if (user2.role === "pending") return c.json({ error: "Account pending approval" }, 403);
952
- c.set("user", user2);
953
- await next();
954
- return;
955
- }
956
- }
957
- }
958
- const sessionId = getCookie(c, "volute_session");
959
- if (!sessionId) return c.json({ error: "Unauthorized" }, 401);
960
- const user = await resolveSession(sessionId);
961
- if (!user) return c.json({ error: "Unauthorized" }, 401);
962
- if (user.role === "pending") return c.json({ error: "Account pending approval" }, 403);
963
- c.set("user", user);
964
- await next();
965
- });
966
- var requireSelf = (paramName = "name") => createMiddleware(async (c, next) => {
967
- const user = c.get("user");
968
- if (user.role !== "admin" && user.role !== "system") {
969
- const target = c.req.param(paramName) ?? "";
970
- const baseName = await getBaseName(target);
971
- if (user.username !== baseName) {
972
- return c.json({ error: "Forbidden" }, 403);
973
- }
974
- }
975
- await next();
976
- });
977
-
978
850
  // packages/daemon/src/web/api/system.ts
979
851
  var DEFAULT_API_URL = "https://volute.systems";
980
852
  var igLog = logger_default.child("imagegen");
@@ -1629,7 +1501,7 @@ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as rea
1629
1501
  import { extname, resolve as resolve3 } from "path";
1630
1502
  import { zValidator as zValidator2 } from "@hono/zod-validator";
1631
1503
  import { Hono as Hono3 } from "hono";
1632
- import { deleteCookie, getCookie as getCookie2, setCookie } from "hono/cookie";
1504
+ import { deleteCookie, getCookie, setCookie } from "hono/cookie";
1633
1505
  import { z as z2 } from "zod";
1634
1506
  function tryJoinSystem(userId) {
1635
1507
  if (!process.env.VOLUTE_DAEMON_TOKEN) return;
@@ -1675,7 +1547,7 @@ var authenticated = new Hono3().use(authMiddleware).post("/change-password", zVa
1675
1547
  const user = c.get("user");
1676
1548
  const body = c.req.valid("json");
1677
1549
  await updateUserProfile(user.id, body);
1678
- const sessionId = getCookie2(c, "volute_session");
1550
+ const sessionId = getCookie(c, "volute_session");
1679
1551
  if (sessionId) invalidateSessionCache(sessionId);
1680
1552
  broadcast({
1681
1553
  type: "profile_updated",
@@ -1707,7 +1579,7 @@ var authenticated = new Hono3().use(authMiddleware).post("/change-password", zVa
1707
1579
  rmSync(oldPath, { force: true });
1708
1580
  }
1709
1581
  await updateUserProfile(user.id, { avatar: filename });
1710
- const sessionId = getCookie2(c, "volute_session");
1582
+ const sessionId = getCookie(c, "volute_session");
1711
1583
  if (sessionId) invalidateSessionCache(sessionId);
1712
1584
  broadcast({
1713
1585
  type: "profile_updated",
@@ -1722,7 +1594,7 @@ var authenticated = new Hono3().use(authMiddleware).post("/change-password", zVa
1722
1594
  rmSync(path, { force: true });
1723
1595
  }
1724
1596
  await updateUserProfile(user.id, { avatar: null });
1725
- const sessionId = getCookie2(c, "volute_session");
1597
+ const sessionId = getCookie(c, "volute_session");
1726
1598
  if (sessionId) invalidateSessionCache(sessionId);
1727
1599
  broadcast({
1728
1600
  type: "profile_updated",
@@ -1833,7 +1705,7 @@ var app3 = new Hono3().post("/register", zValidator2("json", credentialsSchema),
1833
1705
  tryJoinSystem(user.id);
1834
1706
  return c.json({ id: user.id, username: user.username, role: user.role, sessionId });
1835
1707
  }).post("/logout", async (c) => {
1836
- const cookieSession = getCookie2(c, "volute_session");
1708
+ const cookieSession = getCookie(c, "volute_session");
1837
1709
  if (cookieSession) {
1838
1710
  await deleteSession(cookieSession);
1839
1711
  deleteCookie(c, "volute_session", { path: "/" });
@@ -1848,7 +1720,7 @@ var app3 = new Hono3().post("/register", zValidator2("json", credentialsSchema),
1848
1720
  }
1849
1721
  return c.json({ ok: true });
1850
1722
  }).get("/me", async (c) => {
1851
- let sessionId = getCookie2(c, "volute_session");
1723
+ let sessionId = getCookie(c, "volute_session");
1852
1724
  if (!sessionId) {
1853
1725
  const authHeader = c.req.header("Authorization");
1854
1726
  if (authHeader?.startsWith("Bearer ")) {
@@ -1895,7 +1767,7 @@ import { Hono as Hono4 } from "hono";
1895
1767
  import { z as z3 } from "zod";
1896
1768
 
1897
1769
  // packages/daemon/src/lib/chat/puppets.ts
1898
- import { and as and2, eq as eq3 } from "drizzle-orm";
1770
+ import { and as and2, eq as eq2 } from "drizzle-orm";
1899
1771
  async function findOrCreatePuppet(platform, platformId, displayName) {
1900
1772
  const username = `${platform}:${platformId}`;
1901
1773
  const db = await getDb();
@@ -1904,10 +1776,10 @@ async function findOrCreatePuppet(platform, platformId, displayName) {
1904
1776
  username: users.username,
1905
1777
  display_name: users.display_name,
1906
1778
  avatar: users.avatar
1907
- }).from(users).where(and2(eq3(users.username, username), eq3(users.user_type, "puppet"))).get();
1779
+ }).from(users).where(and2(eq2(users.username, username), eq2(users.user_type, "puppet"))).get();
1908
1780
  if (existing) {
1909
1781
  if (existing.display_name !== displayName) {
1910
- await db.update(users).set({ display_name: displayName }).where(eq3(users.id, existing.id));
1782
+ await db.update(users).set({ display_name: displayName }).where(eq2(users.id, existing.id));
1911
1783
  existing.display_name = displayName;
1912
1784
  }
1913
1785
  return existing;
@@ -1933,7 +1805,7 @@ async function findOrCreatePuppet(platform, platformId, displayName) {
1933
1805
  username: users.username,
1934
1806
  display_name: users.display_name,
1935
1807
  avatar: users.avatar
1936
- }).from(users).where(and2(eq3(users.username, username), eq3(users.user_type, "puppet"))).get();
1808
+ }).from(users).where(and2(eq2(users.username, username), eq2(users.user_type, "puppet"))).get();
1937
1809
  if (retried) return retried;
1938
1810
  }
1939
1811
  throw err;
@@ -2013,7 +1885,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
2013
1885
  }
2014
1886
  const participants = await getParticipants(channel.id);
2015
1887
  if (!participants.some((p) => p.userId === puppet.id)) {
2016
- const { addParticipant } = await import("./conversations-AYLXPOGC.js");
1888
+ const { addParticipant } = await import("./conversations-FSZCUUYO.js");
2017
1889
  await addParticipant(channel.id, puppet.id);
2018
1890
  }
2019
1891
  const contentBlocks = body.content;
@@ -2106,8 +1978,8 @@ async function fanOutToBridgedMinds(opts) {
2106
1978
  const participants = await getParticipants(opts.conversationId);
2107
1979
  const mindParticipants = participants.filter((p) => p.userType === "mind");
2108
1980
  const participantNames = participants.map((p) => p.username);
2109
- const { getMindManager: getMindManager2 } = await import("./mind-manager-4NFK4GEU.js");
2110
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TTNOLIX5.js");
1981
+ const { getMindManager: getMindManager2 } = await import("./mind-manager-74XQZEGX.js");
1982
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OHM3TO62.js");
2111
1983
  const manager = getMindManager2();
2112
1984
  const sm = getSleepManagerIfReady2();
2113
1985
  const targetMinds = mindParticipants.filter((ap) => {
@@ -2319,7 +2191,7 @@ async function notifyMind(mindName, message) {
2319
2191
  const entry = await findMind(mindName);
2320
2192
  if (!entry) return;
2321
2193
  try {
2322
- const { sendSystemMessage } = await import("./system-chat-7CA2PP6A.js");
2194
+ const { sendSystemMessage } = await import("./system-chat-HZUKBIKJ.js");
2323
2195
  await sendSystemMessage(mindName, message);
2324
2196
  } catch (err) {
2325
2197
  logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
@@ -2629,18 +2501,25 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2629
2501
  var files_default = app9;
2630
2502
 
2631
2503
  // packages/daemon/src/web/api/history.ts
2632
- import { and as and3, desc as desc2, eq as eq4, gte, inArray, sql } from "drizzle-orm";
2504
+ import { and as and3, desc as desc2, eq as eq3, gte, inArray, sql } from "drizzle-orm";
2633
2505
  import { Hono as Hono11 } from "hono";
2506
+ async function resolveMindFilter(c) {
2507
+ const user = c.get("user");
2508
+ if (user.role === "admin" || user.role === "system") {
2509
+ return c.req.query("mind") ?? void 0;
2510
+ }
2511
+ return getBaseName(user.username);
2512
+ }
2634
2513
  var history = new Hono11().get("/turns", async (c) => {
2635
- const mindFilter = c.req.query("mind");
2514
+ const mindFilter = await resolveMindFilter(c);
2636
2515
  const turnIdFilter = c.req.query("turnId");
2637
2516
  const turnIdsFilter = c.req.query("turnIds");
2638
2517
  const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 200);
2639
2518
  const offset = Math.max(parseInt(c.req.query("offset") ?? "0", 10) || 0, 0);
2640
2519
  const db = await getDb();
2641
2520
  const conditions = [];
2642
- if (mindFilter) conditions.push(eq4(turns.mind, mindFilter));
2643
- if (turnIdFilter) conditions.push(eq4(turns.id, turnIdFilter));
2521
+ if (mindFilter) conditions.push(eq3(turns.mind, mindFilter));
2522
+ if (turnIdFilter) conditions.push(eq3(turns.id, turnIdFilter));
2644
2523
  if (turnIdsFilter) {
2645
2524
  const ids = turnIdsFilter.split(",").filter(Boolean);
2646
2525
  if (ids.length > 0) conditions.push(inArray(turns.id, ids));
@@ -2648,7 +2527,7 @@ var history = new Hono11().get("/turns", async (c) => {
2648
2527
  const turnRows = await db.select().from(turns).where(conditions.length > 0 ? and3(...conditions) : void 0).orderBy(desc2(turns.created_at)).limit(limit).offset(offset);
2649
2528
  if (turnRows.length === 0) return c.json([]);
2650
2529
  const turnIds = turnRows.map((t) => t.id);
2651
- const summaryRows = await db.select().from(summaries).where(and3(eq4(summaries.period, "turn"), inArray(summaries.period_key, turnIds)));
2530
+ const summaryRows = await db.select().from(summaries).where(and3(eq3(summaries.period, "turn"), inArray(summaries.period_key, turnIds)));
2652
2531
  const summaryByTurn = /* @__PURE__ */ new Map();
2653
2532
  for (const s of summaryRows) {
2654
2533
  summaryByTurn.set(s.period_key, { content: s.content, metadata: s.metadata });
@@ -2773,15 +2652,15 @@ var history = new Hono11().get("/turns", async (c) => {
2773
2652
  db.select({
2774
2653
  conversation_id: conversationParticipants.conversation_id,
2775
2654
  username: users.username
2776
- }).from(conversationParticipants).innerJoin(users, eq4(conversationParticipants.user_id, users.id))
2655
+ }).from(conversationParticipants).innerJoin(users, eq3(conversationParticipants.user_id, users.id))
2777
2656
  );
2778
2657
  const dmRows = await db.with(cp2).select({
2779
2658
  id: conversations.id,
2780
2659
  targetUsername: users.username
2781
2660
  }).from(conversations).innerJoin(
2782
2661
  conversationParticipants,
2783
- eq4(conversations.id, conversationParticipants.conversation_id)
2784
- ).innerJoin(users, eq4(conversationParticipants.user_id, users.id)).where(and3(eq4(conversations.type, "dm"), inArray(users.username, targetNames)));
2662
+ eq3(conversations.id, conversationParticipants.conversation_id)
2663
+ ).innerJoin(users, eq3(conversationParticipants.user_id, users.id)).where(and3(eq3(conversations.type, "dm"), inArray(users.username, targetNames)));
2785
2664
  const dmCandidates = [];
2786
2665
  for (const row of dmRows) {
2787
2666
  const slug = `@${row.targetUsername}`;
@@ -2796,7 +2675,7 @@ var history = new Hono11().get("/turns", async (c) => {
2796
2675
  const verifyRows = await db.select({
2797
2676
  conversation_id: conversationParticipants.conversation_id,
2798
2677
  username: users.username
2799
- }).from(conversationParticipants).innerJoin(users, eq4(conversationParticipants.user_id, users.id)).where(
2678
+ }).from(conversationParticipants).innerJoin(users, eq3(conversationParticipants.user_id, users.id)).where(
2800
2679
  and3(
2801
2680
  inArray(conversationParticipants.conversation_id, candidateConvIds),
2802
2681
  inArray(users.username, allMindNames)
@@ -2874,7 +2753,7 @@ var history = new Hono11().get("/turns", async (c) => {
2874
2753
  });
2875
2754
  return c.json(result);
2876
2755
  }).get("/events", async (c) => {
2877
- const mindFilter = c.req.query("mind");
2756
+ const mindFilter = await resolveMindFilter(c);
2878
2757
  const stream = new ReadableStream({
2879
2758
  start(controller) {
2880
2759
  const encoder = new TextEncoder();
@@ -2929,7 +2808,9 @@ var history = new Hono11().get("/turns", async (c) => {
2929
2808
  }
2930
2809
  });
2931
2810
  }).get("/summaries", async (c) => {
2932
- const mind = c.req.query("mind") ?? "_system";
2811
+ const user = c.get("user");
2812
+ const privileged = user.role === "admin" || user.role === "system";
2813
+ const mind = privileged ? c.req.query("mind") ?? "_system" : await getBaseName(user.username);
2933
2814
  const period = c.req.query("period");
2934
2815
  const ids = c.req.query("ids");
2935
2816
  const from = c.req.query("from");
@@ -2939,7 +2820,9 @@ var history = new Hono11().get("/turns", async (c) => {
2939
2820
  const db2 = await getDb();
2940
2821
  const idList = ids.split(",").map((s) => parseInt(s, 10)).filter((n) => !Number.isNaN(n));
2941
2822
  if (idList.length === 0) return c.json([]);
2942
- const rows2 = await db2.select().from(summaries).where(inArray(summaries.id, idList));
2823
+ const idConditions = [inArray(summaries.id, idList)];
2824
+ if (!privileged) idConditions.push(eq3(summaries.mind, mind));
2825
+ const rows2 = await db2.select().from(summaries).where(and3(...idConditions));
2943
2826
  const result2 = rows2.map((r) => {
2944
2827
  let metadata = null;
2945
2828
  if (r.metadata) {
@@ -2957,7 +2840,7 @@ var history = new Hono11().get("/turns", async (c) => {
2957
2840
  return c.json({ error: "period is required (turn, hour, day, week, month)" }, 400);
2958
2841
  }
2959
2842
  const db = await getDb();
2960
- const conditions = [eq4(summaries.mind, mind), eq4(summaries.period, period)];
2843
+ const conditions = [eq3(summaries.mind, mind), eq3(summaries.period, period)];
2961
2844
  if (from) conditions.push(gte(summaries.period_key, from));
2962
2845
  if (to) conditions.push(sql`${summaries.period_key} <= ${to}`);
2963
2846
  const rows = await db.select({
@@ -2982,13 +2865,13 @@ var history = new Hono11().get("/turns", async (c) => {
2982
2865
  });
2983
2866
  return c.json(result);
2984
2867
  }).get("/activity", async (c) => {
2985
- const mind = c.req.query("mind");
2868
+ const mind = await resolveMindFilter(c);
2986
2869
  const from = c.req.query("from");
2987
2870
  const to = c.req.query("to");
2988
2871
  const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "100", 10) || 100, 1), 500);
2989
2872
  const db = await getDb();
2990
2873
  const conditions = [];
2991
- if (mind) conditions.push(eq4(activity.mind, mind));
2874
+ if (mind) conditions.push(eq3(activity.mind, mind));
2992
2875
  if (from) conditions.push(gte(activity.created_at, from));
2993
2876
  if (to) conditions.push(sql`${activity.created_at} <= ${to}`);
2994
2877
  conditions.push(
@@ -3243,7 +3126,7 @@ import {
3243
3126
  } from "fs";
3244
3127
  import { basename, resolve as resolve11 } from "path";
3245
3128
  import { zValidator as zValidator5 } from "@hono/zod-validator";
3246
- import { and as and4, desc as desc3, eq as eq5, sql as sql2 } from "drizzle-orm";
3129
+ import { and as and4, desc as desc3, eq as eq4, sql as sql2 } from "drizzle-orm";
3247
3130
  import { Hono as Hono15 } from "hono";
3248
3131
  import { z as z5 } from "zod";
3249
3132
 
@@ -3365,7 +3248,7 @@ async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
3365
3248
  logger_default.warn(`failed to stop variant ${variantName}`, logger_default.errorData(err));
3366
3249
  }
3367
3250
  }
3368
- const { findMind: findMind2 } = await import("./registry-GV35XFT7.js");
3251
+ const { findMind: findMind2 } = await import("./registry-MDLNPTTI.js");
3369
3252
  const variantEntry = await findMind2(variantName);
3370
3253
  const branchName = variantEntry?.branch ?? variantName;
3371
3254
  if (existsSync6(variantPath)) {
@@ -3622,7 +3505,7 @@ async function getMindStatus(name, port, registryRunning) {
3622
3505
  const manager = getMindManager();
3623
3506
  let status = "stopped";
3624
3507
  try {
3625
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TTNOLIX5.js");
3508
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OHM3TO62.js");
3626
3509
  if (getSleepManagerIfReady2()?.isSleeping(name)) {
3627
3510
  status = "sleeping";
3628
3511
  }
@@ -3754,7 +3637,8 @@ async function npmInstallAsMind(cwd, mindName) {
3754
3637
  await exec("npm", ["install"], { cwd });
3755
3638
  }
3756
3639
  }
3757
- async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariantName, upgradeBranch, template) {
3640
+ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariantName, upgradeBranch, template, oldTemplate) {
3641
+ const templateChanged = template !== oldTemplate;
3758
3642
  const mainStatus = (await gitExec(["status", "--porcelain"], { cwd: dir })).trim();
3759
3643
  if (mainStatus) {
3760
3644
  await gitExec(["add", "-A"], { cwd: dir });
@@ -3770,10 +3654,33 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
3770
3654
  await gitExec(["branch", "-D", upgradeBranch], { cwd: dir });
3771
3655
  } catch {
3772
3656
  }
3657
+ let switchWarning;
3658
+ if (templateChanged) {
3659
+ try {
3660
+ applyTemplateHomeFiles(resolve11(dir, "home"), template);
3661
+ await gitExec(["add", "home/"], { cwd: dir });
3662
+ try {
3663
+ await gitExec(["diff", "--cached", "--quiet"], { cwd: dir });
3664
+ } catch {
3665
+ await gitExec(["commit", "-m", `swap template-owned home files for ${template}`], {
3666
+ cwd: dir
3667
+ });
3668
+ }
3669
+ chownMindDir(dir, mindName);
3670
+ switchWarning = `Switched ${oldTemplate}\u2192${template}: config reset to ${template} defaults, mechanics doc replaced, conversation starts fresh (sessions aren't portable across runtimes).`;
3671
+ } catch (err) {
3672
+ logger_default.warn(`failed to swap template home files for ${mindName}`, logger_default.errorData(err));
3673
+ return {
3674
+ ok: true,
3675
+ warning: `Upgrade merged but template switch ${oldTemplate}\u2192${template} failed: ${err instanceof Error ? err.message : String(err)}. The mind is still registered as ${oldTemplate}; re-run the switch or fix home/ manually.`
3676
+ };
3677
+ }
3678
+ }
3773
3679
  try {
3774
3680
  await setMindTemplateHash(mindName, computeTemplateHash(template));
3681
+ await setMindTemplate(mindName, template);
3775
3682
  } catch (err) {
3776
- logger_default.warn(`failed to update template hash for ${mindName}`, logger_default.errorData(err));
3683
+ logger_default.warn(`failed to update template for ${mindName}`, logger_default.errorData(err));
3777
3684
  }
3778
3685
  try {
3779
3686
  await npmInstallAsMind(dir, mindName);
@@ -3797,7 +3704,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
3797
3704
  warning: `Upgrade merged but mind restart failed: ${e instanceof Error ? e.message : String(e)}`
3798
3705
  };
3799
3706
  }
3800
- return { ok: true };
3707
+ return { ok: true, warning: switchWarning };
3801
3708
  }
3802
3709
  async function importFromArchive(c, tempDir, nameOverride, manifest) {
3803
3710
  const extractedMindDir = resolve11(tempDir, "mind");
@@ -4093,7 +4000,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4093
4000
  applyInitFiles(dest);
4094
4001
  const { publicKeyPem } = generateIdentity(dest);
4095
4002
  {
4096
- const { readGlobalConfig: readGlobal } = await import("./setup-OTEC3ZPM.js");
4003
+ const { readGlobalConfig: readGlobal } = await import("./setup-FPFWDMXD.js");
4097
4004
  const mindDefaults = readGlobal().mindDefaults;
4098
4005
  const config2 = readVoluteConfig(dest);
4099
4006
  if (!config2) throw new Error("Failed to read volute.json after identity generation");
@@ -4184,7 +4091,7 @@ The human who planted you described you as: "${body.description}"
4184
4091
  }
4185
4092
  let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
4186
4093
  if (body.stage === "seed" && !body.skills) {
4187
- const { isImagegenEnabled } = await import("./setup-OTEC3ZPM.js");
4094
+ const { isImagegenEnabled } = await import("./setup-FPFWDMXD.js");
4188
4095
  if (isImagegenEnabled()) {
4189
4096
  skillSet = [...skillSet, "imagegen"];
4190
4097
  }
@@ -4202,7 +4109,7 @@ The human who planted you described you as: "${body.description}"
4202
4109
  try {
4203
4110
  const spiritEntry = await findMind("volute");
4204
4111
  if (spiritEntry) {
4205
- const { spiritDir } = await import("./spirit-T6GK5GEP.js");
4112
+ const { spiritDir } = await import("./spirit-ONLRFATY.js");
4206
4113
  const sDir = spiritEntry.dir ?? spiritDir();
4207
4114
  const spiritConfig = readVoluteConfig(sDir) ?? {};
4208
4115
  const schedules = spiritConfig.schedules ?? [];
@@ -4217,7 +4124,7 @@ The human who planted you described you as: "${body.description}"
4217
4124
  });
4218
4125
  spiritConfig.schedules = schedules;
4219
4126
  writeVoluteConfig(sDir, spiritConfig);
4220
- const { getScheduler: getScheduler2 } = await import("./scheduler-PDARH4CE.js");
4127
+ const { getScheduler: getScheduler2 } = await import("./scheduler-MEBQF5MW.js");
4221
4128
  getScheduler2().loadSchedules("volute", sDir);
4222
4129
  }
4223
4130
  }
@@ -4482,7 +4389,7 @@ ${user.trimEnd()}
4482
4389
  const manager = getMindManager();
4483
4390
  try {
4484
4391
  if (context?.type === "reload") {
4485
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TTNOLIX5.js");
4392
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OHM3TO62.js");
4486
4393
  const sleepState = getSleepManagerIfReady2()?.getState(name);
4487
4394
  if (sleepState?.sleeping) {
4488
4395
  logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
@@ -4577,7 +4484,7 @@ ${user.trimEnd()}
4577
4484
  const name = c.req.param("name");
4578
4485
  const entry = await findMind(name);
4579
4486
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4580
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TTNOLIX5.js");
4487
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OHM3TO62.js");
4581
4488
  const sm = getSleepManagerIfReady2();
4582
4489
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4583
4490
  return c.json(sm.getState(name));
@@ -4585,7 +4492,7 @@ ${user.trimEnd()}
4585
4492
  const name = c.req.param("name");
4586
4493
  const entry = await findMind(name);
4587
4494
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4588
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TTNOLIX5.js");
4495
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OHM3TO62.js");
4589
4496
  const sm = getSleepManagerIfReady2();
4590
4497
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4591
4498
  if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
@@ -4605,7 +4512,7 @@ ${user.trimEnd()}
4605
4512
  const name = c.req.param("name");
4606
4513
  const entry = await findMind(name);
4607
4514
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4608
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TTNOLIX5.js");
4515
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OHM3TO62.js");
4609
4516
  const sm = getSleepManagerIfReady2();
4610
4517
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4611
4518
  const sleepState = sm.getState(name);
@@ -4620,7 +4527,7 @@ ${user.trimEnd()}
4620
4527
  const name = c.req.param("name");
4621
4528
  const entry = await findMind(name);
4622
4529
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4623
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TTNOLIX5.js");
4530
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OHM3TO62.js");
4624
4531
  const sm = getSleepManagerIfReady2();
4625
4532
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4626
4533
  const flushed = await sm.flushQueuedMessages(name);
@@ -4638,7 +4545,7 @@ ${user.trimEnd()}
4638
4545
  if (body.avatar !== void 0) profile.avatar = basename(body.avatar);
4639
4546
  config2.profile = profile;
4640
4547
  writeVoluteConfig(dir, config2);
4641
- const { syncMindProfile: syncMindProfile2 } = await import("./auth-X6ZITZ7D.js");
4548
+ const { syncMindProfile: syncMindProfile2 } = await import("./auth-EAASQPTN.js");
4642
4549
  await syncMindProfile2(name, profile);
4643
4550
  broadcast({ type: "profile_updated", mind: name, summary: `${name} profile updated` });
4644
4551
  return c.json({ ok: true });
@@ -4655,8 +4562,8 @@ ${user.trimEnd()}
4655
4562
  const spiritThreshold = Number.isNaN(rawSpirit) ? 15 : rawSpirit;
4656
4563
  const lastCreatorMsg = await db.select({ created_at: mindHistory.created_at }).from(mindHistory).where(
4657
4564
  and4(
4658
- eq5(mindHistory.mind, name),
4659
- eq5(mindHistory.type, "inbound"),
4565
+ eq4(mindHistory.mind, name),
4566
+ eq4(mindHistory.type, "inbound"),
4660
4567
  sql2`${mindHistory.sender} != 'volute'`,
4661
4568
  sql2`${mindHistory.sender} != ${name}`,
4662
4569
  sql2`${mindHistory.sender} IS NOT NULL`
@@ -4664,9 +4571,9 @@ ${user.trimEnd()}
4664
4571
  ).orderBy(desc3(mindHistory.created_at)).limit(1);
4665
4572
  const lastSpiritMsg = await db.select({ created_at: mindHistory.created_at }).from(mindHistory).where(
4666
4573
  and4(
4667
- eq5(mindHistory.mind, name),
4668
- eq5(mindHistory.type, "inbound"),
4669
- eq5(mindHistory.sender, "volute")
4574
+ eq4(mindHistory.mind, name),
4575
+ eq4(mindHistory.type, "inbound"),
4576
+ eq4(mindHistory.sender, "volute")
4670
4577
  )
4671
4578
  ).orderBy(desc3(mindHistory.created_at)).limit(1);
4672
4579
  const now = Date.now();
@@ -4685,7 +4592,7 @@ ${user.trimEnd()}
4685
4592
  const config2 = readVoluteConfig(dir);
4686
4593
  const displayNameSet = !!config2?.profile?.displayName;
4687
4594
  const avatarSet = !!config2?.profile?.avatar;
4688
- const { isImagegenEnabled } = await import("./setup-OTEC3ZPM.js");
4595
+ const { isImagegenEnabled } = await import("./setup-FPFWDMXD.js");
4689
4596
  const imagegenEnabled = isImagegenEnabled();
4690
4597
  const done = [];
4691
4598
  const remaining = [];
@@ -4723,7 +4630,7 @@ ${user.trimEnd()}
4723
4630
  try {
4724
4631
  const spiritEntry = await findMind("volute");
4725
4632
  if (spiritEntry) {
4726
- const { spiritDir } = await import("./spirit-T6GK5GEP.js");
4633
+ const { spiritDir } = await import("./spirit-ONLRFATY.js");
4727
4634
  const sDir = spiritEntry.dir ?? spiritDir();
4728
4635
  const spiritConfig = readVoluteConfig(sDir);
4729
4636
  if (spiritConfig?.schedules) {
@@ -4731,7 +4638,7 @@ ${user.trimEnd()}
4731
4638
  spiritConfig.schedules = spiritConfig.schedules.filter((s) => s.id !== nurtureId);
4732
4639
  if (spiritConfig.schedules.length === 0) spiritConfig.schedules = void 0;
4733
4640
  writeVoluteConfig(sDir, spiritConfig);
4734
- const { getScheduler: getScheduler2 } = await import("./scheduler-PDARH4CE.js");
4641
+ const { getScheduler: getScheduler2 } = await import("./scheduler-MEBQF5MW.js");
4735
4642
  getScheduler2().loadSchedules("volute", sDir);
4736
4643
  }
4737
4644
  }
@@ -4783,7 +4690,11 @@ ${user.trimEnd()}
4783
4690
  body = await c.req.json();
4784
4691
  } catch {
4785
4692
  }
4786
- const template = body.template ?? entry.template ?? "claude";
4693
+ const oldTemplate = entry.template ?? "claude";
4694
+ const template = body.template ?? oldTemplate;
4695
+ if (!isKnownTemplate(template)) {
4696
+ return c.json({ error: `Unknown template: ${template}` }, 400);
4697
+ }
4787
4698
  const UPGRADE_BRANCH = "upgrade";
4788
4699
  const upgradeVariantName = `${mindName}-upgrade`;
4789
4700
  const worktreeDir = resolve11(dir, ".variants", UPGRADE_BRANCH);
@@ -4852,7 +4763,8 @@ ${user.trimEnd()}
4852
4763
  worktreeDir,
4853
4764
  upgradeVariantName,
4854
4765
  UPGRADE_BRANCH,
4855
- template
4766
+ template,
4767
+ oldTemplate
4856
4768
  );
4857
4769
  return c.json(result);
4858
4770
  } catch (err) {
@@ -4984,7 +4896,8 @@ ${user.trimEnd()}
4984
4896
  worktreeDir,
4985
4897
  upgradeVariantName,
4986
4898
  UPGRADE_BRANCH,
4987
- template
4899
+ template,
4900
+ oldTemplate
4988
4901
  );
4989
4902
  return c.json(result);
4990
4903
  } catch (err) {
@@ -5160,7 +5073,7 @@ ${user.trimEnd()}
5160
5073
  }
5161
5074
  writeVoluteConfig(dir, existing);
5162
5075
  if (body.unescapeNewlines !== void 0) {
5163
- const { clearEchoTextCache } = await import("./echo-text-JUNRP4ER.js");
5076
+ const { clearEchoTextCache } = await import("./echo-text-GEDEEY7M.js");
5164
5077
  clearEchoTextCache(name);
5165
5078
  }
5166
5079
  const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.maxThinkingTokens !== void 0 || body.compaction !== void 0;
@@ -5237,7 +5150,7 @@ ${user.trimEnd()}
5237
5150
  }
5238
5151
  if (entry.mindType === "spirit" && body.model !== void 0) {
5239
5152
  try {
5240
- const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-OTEC3ZPM.js");
5153
+ const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-FPFWDMXD.js");
5241
5154
  const globalConfig = readGlobalConfig2();
5242
5155
  globalConfig.spiritModel = body.model;
5243
5156
  writeGlobalConfig2(globalConfig);
@@ -5265,7 +5178,7 @@ ${user.trimEnd()}
5265
5178
  if (!body.systemPrompt || !body.message) {
5266
5179
  return c.json({ error: "systemPrompt and message required" }, 400);
5267
5180
  }
5268
- const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-EVLKMAJD.js");
5181
+ const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-XCLE3MQP.js");
5269
5182
  if (!isAiConfigured()) {
5270
5183
  return c.json({ error: "AI service not configured" }, 503);
5271
5184
  }
@@ -5538,18 +5451,18 @@ ${user.trimEnd()}
5538
5451
  event_count: sql2`COUNT(*)`,
5539
5452
  message_count: sql2`SUM(CASE WHEN ${mindHistory.type} IN ('inbound','outbound') THEN 1 ELSE 0 END)`,
5540
5453
  tool_count: sql2`SUM(CASE WHEN ${mindHistory.type}='tool_use' THEN 1 ELSE 0 END)`
5541
- }).from(mindHistory).where(and4(eq5(mindHistory.mind, name), sql2`${mindHistory.session} IS NOT NULL`)).groupBy(mindHistory.session).orderBy(sql2`MIN(${mindHistory.created_at}) DESC`);
5454
+ }).from(mindHistory).where(and4(eq4(mindHistory.mind, name), sql2`${mindHistory.session} IS NOT NULL`)).groupBy(mindHistory.session).orderBy(sql2`MIN(${mindHistory.created_at}) DESC`);
5542
5455
  return c.json(rows);
5543
5456
  }).get("/:name/history/channels", requireSelf(), async (c) => {
5544
5457
  const name = c.req.param("name");
5545
5458
  const db = await getDb();
5546
- const rows = await db.selectDistinct({ channel: mindHistory.channel }).from(mindHistory).where(eq5(mindHistory.mind, name));
5459
+ const rows = await db.selectDistinct({ channel: mindHistory.channel }).from(mindHistory).where(eq4(mindHistory.mind, name));
5547
5460
  return c.json(rows.map((r) => r.channel));
5548
5461
  }).get("/:name/history/export", requireSelf(), async (c) => {
5549
5462
  const name = c.req.param("name");
5550
5463
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
5551
5464
  const db = await getDb();
5552
- const rows = await db.select().from(mindHistory).where(eq5(mindHistory.mind, name));
5465
+ const rows = await db.select().from(mindHistory).where(eq4(mindHistory.mind, name));
5553
5466
  return c.json(rows);
5554
5467
  }).get("/:name/history/turn", requireSelf(), async (c) => {
5555
5468
  const name = c.req.param("name");
@@ -5559,7 +5472,7 @@ ${user.trimEnd()}
5559
5472
  const typeFilter = detail ? void 0 : sql2`${mindHistory.type} IN ('inbound','outbound','tool_use','tool_result','text','thinking','activity')`;
5560
5473
  let rows;
5561
5474
  if (turnId) {
5562
- rows = await db.select().from(mindHistory).where(and4(eq5(mindHistory.mind, name), eq5(mindHistory.turn_id, turnId), typeFilter)).orderBy(mindHistory.id);
5475
+ rows = await db.select().from(mindHistory).where(and4(eq4(mindHistory.mind, name), eq4(mindHistory.turn_id, turnId), typeFilter)).orderBy(mindHistory.id);
5563
5476
  } else {
5564
5477
  const session = c.req.query("session");
5565
5478
  const fromId = parseInt(c.req.query("from_id") ?? "", 10);
@@ -5569,8 +5482,8 @@ ${user.trimEnd()}
5569
5482
  }
5570
5483
  rows = await db.select().from(mindHistory).where(
5571
5484
  and4(
5572
- eq5(mindHistory.mind, name),
5573
- eq5(mindHistory.session, session),
5485
+ eq4(mindHistory.mind, name),
5486
+ eq4(mindHistory.session, session),
5574
5487
  sql2`${mindHistory.id} >= ${fromId}`,
5575
5488
  sql2`${mindHistory.id} <= ${toId}`,
5576
5489
  typeFilter
@@ -5586,13 +5499,13 @@ ${user.trimEnd()}
5586
5499
  if (currentSession) {
5587
5500
  const lastTurn = await db.select({ turn_id: mindHistory.turn_id }).from(mindHistory).where(
5588
5501
  and4(
5589
- eq5(mindHistory.mind, name),
5590
- eq5(mindHistory.session, currentSession),
5502
+ eq4(mindHistory.mind, name),
5503
+ eq4(mindHistory.session, currentSession),
5591
5504
  sql2`${mindHistory.turn_id} IS NOT NULL`
5592
5505
  )
5593
5506
  ).orderBy(desc3(mindHistory.created_at)).limit(1);
5594
5507
  if (lastTurn.length > 0 && lastTurn[0].turn_id) {
5595
- const firstEvent = await db.select({ created_at: mindHistory.created_at }).from(mindHistory).where(eq5(mindHistory.turn_id, lastTurn[0].turn_id)).orderBy(mindHistory.created_at).limit(1);
5508
+ const firstEvent = await db.select({ created_at: mindHistory.created_at }).from(mindHistory).where(eq4(mindHistory.turn_id, lastTurn[0].turn_id)).orderBy(mindHistory.created_at).limit(1);
5596
5509
  if (firstEvent.length > 0) {
5597
5510
  sinceTimestamp = firstEvent[0].created_at;
5598
5511
  }
@@ -5602,8 +5515,8 @@ ${user.trimEnd()}
5602
5515
  sinceTimestamp = new Date(Date.now() - 36e5).toISOString().replace("T", " ").slice(0, 19);
5603
5516
  }
5604
5517
  const conditions = [
5605
- eq5(summaries.mind, name),
5606
- eq5(summaries.period, "turn"),
5518
+ eq4(summaries.mind, name),
5519
+ eq4(summaries.period, "turn"),
5607
5520
  sql2`${summaries.created_at} > ${sinceTimestamp}`
5608
5521
  ];
5609
5522
  if (currentSession) {
@@ -5613,7 +5526,7 @@ ${user.trimEnd()}
5613
5526
  session: turns.session,
5614
5527
  content: summaries.content,
5615
5528
  created_at: summaries.created_at
5616
- }).from(summaries).innerJoin(turns, eq5(turns.id, summaries.period_key)).where(and4(...conditions)).orderBy(desc3(summaries.created_at)).limit(50);
5529
+ }).from(summaries).innerJoin(turns, eq4(turns.id, summaries.period_key)).where(and4(...conditions)).orderBy(desc3(summaries.created_at)).limit(50);
5617
5530
  if (rows.length === 0) {
5618
5531
  return c.json({ context: null });
5619
5532
  }
@@ -5643,18 +5556,18 @@ ${lines.join("\n")}` });
5643
5556
  const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 200);
5644
5557
  const offset = Math.max(parseInt(c.req.query("offset") ?? "0", 10) || 0, 0);
5645
5558
  const db = await getDb();
5646
- const conditions = [eq5(mindHistory.mind, name)];
5559
+ const conditions = [eq4(mindHistory.mind, name)];
5647
5560
  if (channel) {
5648
- conditions.push(eq5(mindHistory.channel, channel));
5561
+ conditions.push(eq4(mindHistory.channel, channel));
5649
5562
  }
5650
5563
  if (session) {
5651
- conditions.push(eq5(mindHistory.session, session));
5564
+ conditions.push(eq4(mindHistory.session, session));
5652
5565
  }
5653
5566
  const effectivePreset = full ? "all" : preset;
5654
5567
  if (!effectivePreset || effectivePreset === "summary") {
5655
- const sumConditions = [eq5(summaries.mind, name), eq5(summaries.period, "turn")];
5568
+ const sumConditions = [eq4(summaries.mind, name), eq4(summaries.period, "turn")];
5656
5569
  if (session) {
5657
- sumConditions.push(eq5(turns.session, session));
5570
+ sumConditions.push(eq4(turns.session, session));
5658
5571
  const sumRows2 = await db.select({
5659
5572
  id: summaries.id,
5660
5573
  mind: summaries.mind,
@@ -5664,7 +5577,7 @@ ${lines.join("\n")}` });
5664
5577
  metadata: summaries.metadata,
5665
5578
  created_at: summaries.created_at,
5666
5579
  session: turns.session
5667
- }).from(summaries).innerJoin(turns, eq5(turns.id, summaries.period_key)).where(and4(...sumConditions)).orderBy(desc3(summaries.created_at)).limit(limit).offset(offset);
5580
+ }).from(summaries).innerJoin(turns, eq4(turns.id, summaries.period_key)).where(and4(...sumConditions)).orderBy(desc3(summaries.created_at)).limit(limit).offset(offset);
5668
5581
  return c.json(
5669
5582
  sumRows2.map((r) => ({
5670
5583
  id: r.id,
@@ -5717,7 +5630,7 @@ var minds_default = app13;
5717
5630
 
5718
5631
  // packages/daemon/src/web/api/prompts.ts
5719
5632
  import { zValidator as zValidator6 } from "@hono/zod-validator";
5720
- import { eq as eq6, sql as sql3 } from "drizzle-orm";
5633
+ import { eq as eq5, sql as sql3 } from "drizzle-orm";
5721
5634
  import { Hono as Hono16 } from "hono";
5722
5635
  import { z as z6 } from "zod";
5723
5636
  var app14 = new Hono16().get("/", async (c) => {
@@ -5761,7 +5674,7 @@ var app14 = new Hono16().get("/", async (c) => {
5761
5674
  return c.json({ error: "Unknown prompt key" }, 404);
5762
5675
  }
5763
5676
  const db = await getDb();
5764
- await db.delete(systemPrompts).where(eq6(systemPrompts.key, key));
5677
+ await db.delete(systemPrompts).where(eq5(systemPrompts.key, key));
5765
5678
  return c.json({ ok: true });
5766
5679
  });
5767
5680
  var prompts_default = app14;
@@ -6009,7 +5922,7 @@ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) =>
6009
5922
  const body = await c.req.text();
6010
5923
  const message = `[webhook: ${event}] ${body}`;
6011
5924
  try {
6012
- const { sendSystemMessage } = await import("./system-chat-7CA2PP6A.js");
5925
+ const { sendSystemMessage } = await import("./system-chat-HZUKBIKJ.js");
6013
5926
  await sendSystemMessage(name, message);
6014
5927
  return c.json({ ok: true });
6015
5928
  } catch (err) {
@@ -6063,7 +5976,7 @@ setup.get("/status", async (c) => {
6063
5976
  let hasAccount = false;
6064
5977
  if (hasSystem) {
6065
5978
  try {
6066
- const { listUsersByType: listUsersByType2 } = await import("./auth-X6ZITZ7D.js");
5979
+ const { listUsersByType: listUsersByType2 } = await import("./auth-EAASQPTN.js");
6067
5980
  const brains = await listUsersByType2("brain");
6068
5981
  hasAccount = brains.length > 0;
6069
5982
  } catch (err) {
@@ -6274,7 +6187,7 @@ setup.post("/account", async (c) => {
6274
6187
  }
6275
6188
  }
6276
6189
  try {
6277
- const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-X6ZITZ7D.js");
6190
+ const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-EAASQPTN.js");
6278
6191
  const user = await createUser2(body.username.trim(), body.password);
6279
6192
  if (body.displayName?.trim()) {
6280
6193
  await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
@@ -6320,7 +6233,7 @@ setup.post("/models", async (c) => {
6320
6233
  return c.json({ error: "Spirit model is required" }, 400);
6321
6234
  }
6322
6235
  try {
6323
- const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-EVLKMAJD.js");
6236
+ const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-XCLE3MQP.js");
6324
6237
  setEnabledModels3(body.models);
6325
6238
  const config2 = readGlobalConfig();
6326
6239
  config2.spiritModel = body.spiritModel.trim();
@@ -6338,15 +6251,15 @@ setup.post("/complete", async (c) => {
6338
6251
  return c.json({ error: "Setup already complete" }, 400);
6339
6252
  }
6340
6253
  try {
6341
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-T6GK5GEP.js");
6342
- const { startSpiritFull } = await import("./mind-service-X7FH3NA4.js");
6254
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-ONLRFATY.js");
6255
+ const { startSpiritFull } = await import("./mind-service-XGXSMQP6.js");
6343
6256
  await ensureSpiritProject();
6344
6257
  await syncSpiritTemplate();
6345
6258
  const warnings = [];
6346
6259
  const config2 = readGlobalConfig();
6347
6260
  if (config2.setup?.service && config2.setup?.type === "local") {
6348
6261
  try {
6349
- const { installUserService } = await import("./service-install-W3FQXJKB.js");
6262
+ const { installUserService } = await import("./service-install-GTDUHP6R.js");
6350
6263
  const installed = await installUserService(config2.port, config2.hostname);
6351
6264
  if (!installed) {
6352
6265
  warnings.push("Service installation is not supported on this platform.");
@@ -6374,8 +6287,8 @@ setup.post("/complete", async (c) => {
6374
6287
  }
6375
6288
  let spiritConversationId;
6376
6289
  try {
6377
- const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-X6ZITZ7D.js");
6378
- const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-AYLXPOGC.js");
6290
+ const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-EAASQPTN.js");
6291
+ const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-FSZCUUYO.js");
6379
6292
  const spiritUser = await getOrCreateMindUser2("volute");
6380
6293
  const brains = await listUsersByType2("brain");
6381
6294
  const admin2 = brains.find((u) => u.role === "admin");
@@ -6397,8 +6310,8 @@ setup.post("/complete", async (c) => {
6397
6310
  logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
6398
6311
  if (spiritConversationId && spiritStarted) {
6399
6312
  try {
6400
- const { deliverMessage: deliverMessage2 } = await import("./message-delivery-Q7TU24IA.js");
6401
- const { listUsersByType: listUsers2 } = await import("./auth-X6ZITZ7D.js");
6313
+ const { deliverMessage: deliverMessage2 } = await import("./message-delivery-HPMELC4Q.js");
6314
+ const { listUsersByType: listUsers2 } = await import("./auth-EAASQPTN.js");
6402
6315
  const admins = await listUsers2("brain");
6403
6316
  const admin2 = admins.find((u) => u.role === "admin");
6404
6317
  const adminName = admin2?.display_name || admin2?.username || "the admin";
@@ -6757,11 +6670,20 @@ function bufferEvent(data) {
6757
6670
  }
6758
6671
  return id;
6759
6672
  }
6760
- function getEventsSince(sinceId) {
6673
+ function nextEventId() {
6674
+ return nextId++;
6675
+ }
6676
+ function getEventsSince(sinceId, allowedConversationIds) {
6761
6677
  const now = Date.now();
6762
6678
  const startIdx = buffer.findIndex((e) => e.id > sinceId);
6763
6679
  if (startIdx === -1) return [];
6764
- return buffer.slice(startIdx).filter((e) => now - e.timestamp < MAX_AGE_MS);
6680
+ return buffer.slice(startIdx).filter((e) => {
6681
+ if (now - e.timestamp >= MAX_AGE_MS) return false;
6682
+ const data = e.data;
6683
+ if (data.event === "snapshot") return false;
6684
+ if (data.event === "conversation") return allowedConversationIds.has(data.conversationId);
6685
+ return true;
6686
+ });
6765
6687
  }
6766
6688
 
6767
6689
  // packages/daemon/src/web/api/v1/events.ts
@@ -6776,8 +6698,22 @@ var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
6776
6698
  cleanups.push(() => removeConnection(user.username));
6777
6699
  }
6778
6700
  try {
6701
+ let conversations2 = [];
6702
+ try {
6703
+ conversations2 = await listConversationsWithParticipants(user.id);
6704
+ if (conversations2.length > 0) {
6705
+ const convIds = conversations2.map((c2) => c2.id);
6706
+ const unreads = await getUnreadCounts(user.id, convIds);
6707
+ for (const conv of conversations2) {
6708
+ conv.unreadCount = unreads[conv.id] ?? 0;
6709
+ }
6710
+ }
6711
+ } catch (err) {
6712
+ logger_default.error("[v1-events] failed to fetch conversations", logger_default.errorData(err));
6713
+ }
6714
+ const allowedConversationIds = new Set(conversations2.map((c2) => c2.id));
6779
6715
  if (sinceId > 0) {
6780
- const missed = getEventsSince(sinceId);
6716
+ const missed = getEventsSince(sinceId, allowedConversationIds);
6781
6717
  for (const event of missed) {
6782
6718
  await stream.writeSSE({
6783
6719
  id: String(event.id),
@@ -6796,19 +6732,6 @@ var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
6796
6732
  } catch (err) {
6797
6733
  logger_default.error("[v1-events] failed to fetch recent activity", logger_default.errorData(err));
6798
6734
  }
6799
- let conversations2 = [];
6800
- try {
6801
- conversations2 = await listConversationsWithParticipants(user.id);
6802
- if (conversations2.length > 0) {
6803
- const convIds = conversations2.map((c2) => c2.id);
6804
- const unreads = await getUnreadCounts(user.id, convIds);
6805
- for (const conv of conversations2) {
6806
- conv.unreadCount = unreads[conv.id] ?? 0;
6807
- }
6808
- }
6809
- } catch (err) {
6810
- logger_default.error("[v1-events] failed to fetch conversations", logger_default.errorData(err));
6811
- }
6812
6735
  const snapshotData = {
6813
6736
  event: "snapshot",
6814
6737
  activity: recentActivity,
@@ -6816,7 +6739,7 @@ var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
6816
6739
  activeMinds: getActiveMinds(),
6817
6740
  onlineBrains: getOnlineBrains()
6818
6741
  };
6819
- const snapshotId = bufferEvent(snapshotData);
6742
+ const snapshotId = nextEventId();
6820
6743
  await stream.writeSSE({
6821
6744
  id: String(snapshotId),
6822
6745
  data: JSON.stringify(snapshotData)
@@ -6882,14 +6805,23 @@ import { resolve as resolve14 } from "path";
6882
6805
  function tsxBin(cwd) {
6883
6806
  return resolve14(cwd, "node_modules", ".bin", "tsx");
6884
6807
  }
6885
- function spawnServer(cwd, port, options) {
6808
+ async function spawnServer(cwd, port, options) {
6809
+ let cmd = tsxBin(cwd);
6810
+ let args = ["src/server.ts", "--port", String(port)];
6811
+ if (options?.mindName) {
6812
+ if (isIsolationEnabled()) {
6813
+ [cmd, args] = await wrapForIsolation(cmd, args, options.mindName);
6814
+ } else if (isSandboxEnabled() && options.template !== "codex") {
6815
+ [cmd, args] = await wrapForSandbox(cmd, args, cwd, options.mindName, [cwd, mindTmpDir(cwd)]);
6816
+ }
6817
+ }
6886
6818
  if (options?.detached) {
6887
- return spawnDetached(cwd, port, options.logDir);
6819
+ return spawnDetached(cmd, args, cwd, options.logDir);
6888
6820
  }
6889
- return spawnAttached(cwd, port);
6821
+ return spawnAttached(cmd, args, cwd);
6890
6822
  }
6891
- function spawnAttached(cwd, port) {
6892
- const child = spawn4(tsxBin(cwd), ["src/server.ts", "--port", String(port)], {
6823
+ function spawnAttached(cmd, args, cwd) {
6824
+ const child = spawn4(cmd, args, {
6893
6825
  cwd,
6894
6826
  stdio: ["ignore", "pipe", "pipe"]
6895
6827
  });
@@ -6914,12 +6846,12 @@ function spawnAttached(cwd, port) {
6914
6846
  });
6915
6847
  });
6916
6848
  }
6917
- function spawnDetached(cwd, port, logDir) {
6849
+ function spawnDetached(cmd, args, cwd, logDir) {
6918
6850
  const logsDir = logDir ?? resolve14(cwd, ".mind", "logs");
6919
6851
  mkdirSync8(logsDir, { recursive: true });
6920
6852
  const logPath = resolve14(logsDir, "mind.log");
6921
6853
  const logFd = openSync(logPath, "a");
6922
- const child = spawn4(tsxBin(cwd), ["src/server.ts", "--port", String(port)], {
6854
+ const child = spawn4(cmd, args, {
6923
6855
  cwd,
6924
6856
  stdio: ["ignore", logFd, logFd],
6925
6857
  detached: true
@@ -7114,7 +7046,11 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7114
7046
  }
7115
7047
  }
7116
7048
  if (!body.skipVerify) {
7117
- const result = await spawnServer(variantEntry.dir, 0, { detached: true });
7049
+ const result = await spawnServer(variantEntry.dir, 0, {
7050
+ detached: true,
7051
+ mindName: variantName,
7052
+ template: variantEntry.template
7053
+ });
7118
7054
  if (!result) {
7119
7055
  return c.json(
7120
7056
  { error: "Failed to start server for verification. Use skipVerify to skip." },
@@ -7155,8 +7091,8 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7155
7091
  await cleanupVariant(variantName, projectRoot, variantEntry.dir);
7156
7092
  if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
7157
7093
  try {
7158
- const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-DMHSLRDX.js");
7159
- const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-GV35XFT7.js");
7094
+ const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-446HHH5V.js");
7095
+ const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-MDLNPTTI.js");
7160
7096
  const tmpl = parentEntry.template ?? "claude";
7161
7097
  await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
7162
7098
  } catch (err) {
@@ -7270,9 +7206,13 @@ var app22 = new Hono25().get("/", async (c) => {
7270
7206
  });
7271
7207
  }).patch("/:name", zValidator9("json", channelSettingsSchema), async (c) => {
7272
7208
  const name = c.req.param("name");
7209
+ const user = c.get("user");
7273
7210
  const body = c.req.valid("json");
7274
7211
  const ch = await getChannelByName(name);
7275
7212
  if (!ch) return c.json({ error: "Channel not found" }, 404);
7213
+ if (user.role !== "admin" && user.role !== "system" && !await isParticipant(ch.id, user.id)) {
7214
+ return c.json({ error: "Forbidden" }, 403);
7215
+ }
7276
7216
  await updateChannelSettings(name, body);
7277
7217
  const settings = await getChannelSettings(name);
7278
7218
  return c.json({ ...ch, channel_name: name, settings: formatChannelSettings(settings) });
@@ -7302,6 +7242,9 @@ var app22 = new Hono25().get("/", async (c) => {
7302
7242
  const { username } = c.req.valid("json");
7303
7243
  const ch = await getChannelByName(name);
7304
7244
  if (!ch) return c.json({ error: "Channel not found" }, 404);
7245
+ if (inviter.role !== "admin" && inviter.role !== "system" && !await isParticipant(ch.id, inviter.id)) {
7246
+ return c.json({ error: "Forbidden" }, 403);
7247
+ }
7305
7248
  let user = await getUserByUsername(username);
7306
7249
  if (!user && await findMind(username)) {
7307
7250
  user = await getOrCreateMindUser(username);
@@ -7908,6 +7851,11 @@ if (!process.env.VOLUTE_HOME) {
7908
7851
  if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
7909
7852
  process.env.TZ = process.env.VOLUTE_TIMEZONE;
7910
7853
  }
7854
+ function writeDaemonConfig(path, config2) {
7855
+ writeFileSync9(path, `${JSON.stringify(config2, null, 2)}
7856
+ `, { mode: 384 });
7857
+ chmodSync(path, 384);
7858
+ }
7911
7859
  async function startDaemon(opts) {
7912
7860
  const { port, hostname } = opts;
7913
7861
  const myPid = String(process.pid);
@@ -7928,18 +7876,18 @@ async function startDaemon(opts) {
7928
7876
  const DAEMON_JSON_PATH = resolve17(systemDir, "daemon.json");
7929
7877
  mkdirSync10(home, { recursive: true });
7930
7878
  ensureSystemDir();
7931
- const { migrateSetupCompleted } = await import("./setup-OTEC3ZPM.js");
7879
+ const { migrateSetupCompleted } = await import("./setup-FPFWDMXD.js");
7932
7880
  migrateSetupCompleted();
7933
- await (await import("./db-ZEPKEJJD.js")).getDb();
7881
+ await (await import("./db-ZJJJYJBU.js")).getDb();
7934
7882
  try {
7935
- const { eq: eq7, and: and5 } = await import("drizzle-orm");
7936
- const { users: users2 } = await import("./schema-LYQUDL7G.js");
7937
- const db = await (await import("./db-ZEPKEJJD.js")).getDb();
7938
- await db.update(users2).set({ role: "system" }).where(and5(eq7(users2.user_type, "system"), eq7(users2.role, "user")));
7883
+ const { eq: eq6, and: and5 } = await import("drizzle-orm");
7884
+ const { users: users2 } = await import("./schema-HHYJDG7B.js");
7885
+ const db = await (await import("./db-ZJJJYJBU.js")).getDb();
7886
+ await db.update(users2).set({ role: "system" }).where(and5(eq6(users2.user_type, "system"), eq6(users2.role, "user")));
7939
7887
  } catch (err) {
7940
7888
  logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
7941
7889
  }
7942
- const { initSandbox } = await import("./sandbox-5R32QKWQ.js");
7890
+ const { initSandbox } = await import("./sandbox-ND53WZVU.js");
7943
7891
  await initSandbox();
7944
7892
  try {
7945
7893
  await syncBuiltinSkills();
@@ -7966,7 +7914,7 @@ async function startDaemon(opts) {
7966
7914
  logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
7967
7915
  }
7968
7916
  try {
7969
- const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-X6ZITZ7D.js");
7917
+ const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-EAASQPTN.js");
7970
7918
  await getOrCreateSystemUser2();
7971
7919
  } catch (err) {
7972
7920
  logger_default.warn(
@@ -7975,12 +7923,12 @@ async function startDaemon(opts) {
7975
7923
  );
7976
7924
  }
7977
7925
  const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes(32).toString("hex");
7978
- const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-OTEC3ZPM.js");
7926
+ const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-FPFWDMXD.js");
7979
7927
  const globalCfg = readGlobalConfig2();
7980
7928
  let tls;
7981
7929
  if (opts.tailscale || globalCfg.tailscale) {
7982
7930
  try {
7983
- const { getTailscaleTls } = await import("./tailscale-X4HRKRTW.js");
7931
+ const { getTailscaleTls } = await import("./tailscale-TIRTGM6E.js");
7984
7932
  const tlsConfig = await getTailscaleTls();
7985
7933
  tls = { key: tlsConfig.key, cert: tlsConfig.cert };
7986
7934
  logger_default.info("Tailscale HTTPS enabled", { hostname: tlsConfig.hostname });
@@ -8011,8 +7959,7 @@ async function startDaemon(opts) {
8011
7959
  const daemonConfig = { port, hostname, token };
8012
7960
  if (internalPort) daemonConfig.internalPort = internalPort;
8013
7961
  if (tls) daemonConfig.tls = true;
8014
- writeFileSync9(DAEMON_JSON_PATH, `${JSON.stringify(daemonConfig, null, 2)}
8015
- `, { mode: 420 });
7962
+ writeDaemonConfig(DAEMON_JSON_PATH, daemonConfig);
8016
7963
  const delivery = initDeliveryManager();
8017
7964
  const manager = initMindManager();
8018
7965
  manager.loadCrashAttempts();
@@ -8059,10 +8006,10 @@ async function startDaemon(opts) {
8059
8006
  await Promise.all(workers);
8060
8007
  }
8061
8008
  try {
8062
- const { isSetupComplete: isSetupComplete2 } = await import("./setup-OTEC3ZPM.js");
8009
+ const { isSetupComplete: isSetupComplete2 } = await import("./setup-FPFWDMXD.js");
8063
8010
  if (isSetupComplete2()) {
8064
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-T6GK5GEP.js");
8065
- const { startSpiritFull } = await import("./mind-service-X7FH3NA4.js");
8011
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-ONLRFATY.js");
8012
+ const { startSpiritFull } = await import("./mind-service-XGXSMQP6.js");
8066
8013
  await ensureSpiritProject();
8067
8014
  await syncSpiritTemplate();
8068
8015
  const spiritEntry = await findMind("volute");
@@ -8079,7 +8026,7 @@ async function startDaemon(opts) {
8079
8026
  bridgeManager.startBridges(daemonPort).catch((err) => {
8080
8027
  logger_default.warn("failed to start bridges", logger_default.errorData(err));
8081
8028
  });
8082
- import("./cloud-sync-GOSJZIHH.js").then(
8029
+ import("./cloud-sync-2XVXEOSU.js").then(
8083
8030
  ({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
8084
8031
  logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
8085
8032
  })
@@ -8087,7 +8034,7 @@ async function startDaemon(opts) {
8087
8034
  logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
8088
8035
  });
8089
8036
  try {
8090
- const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-DK6AHWX7.js");
8037
+ const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-UFFDUPCX.js");
8091
8038
  backfillTemplateHashes();
8092
8039
  notifyVersionUpdate().catch((err) => {
8093
8040
  logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
@@ -8192,8 +8139,12 @@ if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith
8192
8139
  if (noSandbox) {
8193
8140
  process.env.VOLUTE_SANDBOX = "0";
8194
8141
  }
8195
- startDaemon({ port, hostname, foreground, tailscale });
8142
+ startDaemon({ port, hostname, foreground, tailscale }).catch((err) => {
8143
+ logger_default.error("daemon failed to start", logger_default.errorData(err));
8144
+ process.exit(1);
8145
+ });
8196
8146
  }
8197
8147
  export {
8198
- startDaemon
8148
+ startDaemon,
8149
+ writeDaemonConfig
8199
8150
  };