volute 0.50.0 → 0.51.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 (140) hide show
  1. package/dist/{activity-events-H7YI3BTF.js → activity-events-LQII6PZS.js} +3 -3
  2. package/dist/{ai-service-V4CTNGI3.js → ai-service-YW5SWCSB.js} +7 -3
  3. package/dist/{archive-ORM3ENHI.js → archive-FOHGXHPT.js} +3 -3
  4. package/dist/{auth-DT7GY7EZ.js → auth-X6EMNEGB.js} +4 -4
  5. package/dist/{avatar-image-QEPAP3A5.js → avatar-image-52WGXLHV.js} +3 -3
  6. package/dist/{backup-IE6PMXJO.js → backup-YVGV2ZNM.js} +7 -7
  7. package/dist/{chat-W5K6HCBE.js → chat-VAZ25KVT.js} +4 -4
  8. package/dist/{chunk-5IIVOWSP.js → chunk-2RNMBXD2.js} +16 -0
  9. package/dist/{chunk-U3EJJ7JN.js → chunk-5N32EN4O.js} +2 -2
  10. package/dist/{chunk-ZUG76D3P.js → chunk-5Y54AE3L.js} +1 -1
  11. package/dist/{chunk-5FVANDON.js → chunk-6NLW72HP.js} +2 -2
  12. package/dist/{chunk-JI67D7O2.js → chunk-7HN63Q7J.js} +120 -25
  13. package/dist/{chunk-PW65BXY5.js → chunk-7YJY3F2R.js} +11 -1
  14. package/dist/{chunk-HW6Q7AMB.js → chunk-AI47FDGL.js} +6 -7
  15. package/dist/{chunk-636GFQNE.js → chunk-BSHZ23MS.js} +8 -7
  16. package/dist/{chunk-7DXLIYPY.js → chunk-CDKQJWGK.js} +6 -6
  17. package/dist/{chunk-SSNZ6ZNN.js → chunk-CV6BNGFK.js} +3 -3
  18. package/dist/{chunk-QFVGPKJI.js → chunk-DMK5ASKV.js} +1 -1
  19. package/dist/{chunk-MLZBBLMT.js → chunk-DN3LKLYR.js} +4 -4
  20. package/dist/{chunk-WBBKYUGF.js → chunk-EDR47UE2.js} +2 -2
  21. package/dist/{chunk-632FJ23O.js → chunk-EGV6R6UF.js} +26 -7
  22. package/dist/{chunk-KAEZOVP6.js → chunk-FLIEXG2T.js} +1 -1
  23. package/dist/{chunk-5TPC4KCV.js → chunk-FXWBFDQR.js} +2 -2
  24. package/dist/{chunk-74T3CEXK.js → chunk-G7A5LEVI.js} +2 -2
  25. package/dist/{chunk-7UWXAJMK.js → chunk-GLM7TVWP.js} +1 -1
  26. package/dist/{chunk-CAIYV33P.js → chunk-H6X6CKDN.js} +2 -1
  27. package/dist/{chunk-UC6BNMGT.js → chunk-HKP6OAJP.js} +3 -3
  28. package/dist/{chunk-C3KLHJDB.js → chunk-HTRSSOHY.js} +1 -1
  29. package/dist/{chunk-77IZUVBB.js → chunk-I7U5EEZC.js} +2 -2
  30. package/dist/{chunk-7OZWKHA3.js → chunk-ICL6T4SN.js} +18 -4
  31. package/dist/{chunk-X67VT4QO.js → chunk-ICXY54ZC.js} +1 -1
  32. package/dist/{chunk-YQOYZ6G7.js → chunk-IWAVIJO2.js} +2 -2
  33. package/dist/{chunk-5PKFJHCR.js → chunk-JHKBALS2.js} +2 -2
  34. package/dist/{chunk-7XDOTN4R.js → chunk-L7BKTZ5U.js} +1 -1
  35. package/dist/{chunk-AFSLNUTT.js → chunk-LAUCO2HC.js} +1 -1
  36. package/dist/{chunk-AJWFDIEY.js → chunk-M77B73VV.js} +1 -1
  37. package/dist/{chunk-4CN7OCJE.js → chunk-OXWUEU5V.js} +2 -2
  38. package/dist/{chunk-7FDWPQCU.js → chunk-Q7XQLKZB.js} +6 -6
  39. package/dist/{chunk-TGJHGVBZ.js → chunk-QT4D5XCI.js} +4 -4
  40. package/dist/{chunk-574M6I7F.js → chunk-TPX6E6PL.js} +3 -3
  41. package/dist/{chunk-3BAFMGCJ.js → chunk-U54PJPTB.js} +2 -2
  42. package/dist/{chunk-6BM2I736.js → chunk-UDZLPR34.js} +1 -1
  43. package/dist/{chunk-E5S3ILVA.js → chunk-UFTDRTCP.js} +1 -1
  44. package/dist/{chunk-ALIVXDM4.js → chunk-VAEZCIJC.js} +95 -51
  45. package/dist/{chunk-EQKSRVDE.js → chunk-VP5PFNZO.js} +89 -41
  46. package/dist/{chunk-SFRYRW37.js → chunk-VSBMLB2W.js} +9 -9
  47. package/dist/{chunk-RRZ4RQQU.js → chunk-X67BDDZR.js} +5 -7
  48. package/dist/cli.js +19 -19
  49. package/dist/{clock-LH7UFNLJ.js → clock-ZT5YT6HA.js} +2 -2
  50. package/dist/{cloud-sync-IDJFVDEP.js → cloud-sync-GPXYPTIC.js} +22 -22
  51. package/dist/{conversations-S2232Y5I.js → conversations-ZL6PHROD.js} +4 -4
  52. package/dist/{create-2M7DAHQX.js → create-G2RIKQYK.js} +1 -1
  53. package/dist/{daemon-restart-2AAGYFHE.js → daemon-restart-2EWBRTN5.js} +6 -6
  54. package/dist/daemon.js +478 -331
  55. package/dist/{db-QAY45Z56.js → db-BONH4SUG.js} +2 -2
  56. package/dist/delivery-manager-HGVZSEES.js +35 -0
  57. package/dist/{delivery-router-JE7SHYNU.js → delivery-router-RHANNTAC.js} +3 -3
  58. package/dist/{down-D4IRNEMJ.js → down-QSNEMTTX.js} +5 -5
  59. package/dist/echo-text-6ANI5HHN.js +39 -0
  60. package/dist/{env-ABM5IMA7.js → env-IBW2QI6K.js} +1 -1
  61. package/dist/{env-AZK5X4W7.js → env-SQFCWW52.js} +3 -3
  62. package/dist/{exec-2H65LMTA.js → exec-ABD3DYA2.js} +3 -3
  63. package/dist/{export-3E3EL6W3.js → export-VBNWM7I4.js} +3 -3
  64. package/dist/{extensions-7KP3X6G7.js → extensions-NY6WST33.js} +22 -22
  65. package/dist/{files-6BMKVG5G.js → files-BRY5RRIM.js} +3 -3
  66. package/dist/{import-UPNTEBBT.js → import-DB2KULRO.js} +6 -6
  67. package/dist/{isolation-OKDFM6WA.js → isolation-GVV2IBAU.js} +3 -3
  68. package/dist/{list-4BVGH7AN.js → list-UQGIW7OF.js} +1 -1
  69. package/dist/{login-MOXVLULE.js → login-SB5OENMV.js} +2 -2
  70. package/dist/{logout-DWD3OQVT.js → logout-YFZAJRPY.js} +2 -2
  71. package/dist/message-delivery-JHMAJ2GU.js +43 -0
  72. package/dist/{migrate-thread-config-4A5LW36Z.js → migrate-thread-config-EQSEP2XG.js} +2 -2
  73. package/dist/{mind-NYRALSV2.js → mind-WF6QIXWV.js} +7 -7
  74. package/dist/{mind-activity-tracker-L7GCYXQR.js → mind-activity-tracker-QF6DCX2X.js} +4 -4
  75. package/dist/{mind-history-NXXOOTX6.js → mind-history-OGNR4L7W.js} +1 -1
  76. package/dist/mind-service-DZCUUC7J.js +47 -0
  77. package/dist/{mind-sleep-TH6BRQ5X.js → mind-sleep-LZAFBDZD.js} +2 -2
  78. package/dist/{package-XYSV7NUT.js → package-B6O5APCZ.js} +1 -1
  79. package/dist/{prompts-QKFPX6DQ.js → prompts-NBO3HRK3.js} +3 -3
  80. package/dist/{read-ZXGUT4QC.js → read-RJ5NAW5J.js} +3 -14
  81. package/dist/{registry-4UF6OCOE.js → registry-TRC2HJXR.js} +2 -2
  82. package/dist/{sandbox-EGEU5GGE.js → sandbox-NNWCTHRI.js} +3 -3
  83. package/dist/scheduler-TNBN54ZK.js +25 -0
  84. package/dist/{schema-C2GIPD4V.js → schema-ZZQVM4GR.js} +3 -1
  85. package/dist/{seed-3IMBOAGK.js → seed-K2LYODIH.js} +1 -1
  86. package/dist/{seed-cmd-U73XVQMI.js → seed-cmd-2EWBTR6P.js} +2 -2
  87. package/dist/{seed-create-FBLNVSUP.js → seed-create-VGTLU5FD.js} +3 -3
  88. package/dist/{seed-readiness-QRA46ZJQ.js → seed-readiness-DYOVCYHN.js} +4 -4
  89. package/dist/{seed-sprout-3B4SZX7J.js → seed-sprout-PILHJ3YS.js} +7 -7
  90. package/dist/{send-NBRZJXKX.js → send-2YKOZJJ5.js} +81 -49
  91. package/dist/{service-XMXAXGJD.js → service-XQPMZAGI.js} +4 -4
  92. package/dist/{service-install-MOKTEG7B.js → service-install-2EWD7KXD.js} +5 -5
  93. package/dist/{setup-JGYAXXW7.js → setup-MDPSK2XG.js} +6 -6
  94. package/dist/{setup-CAJFOR2N.js → setup-WZSXHHRJ.js} +2 -2
  95. package/dist/{skill-NXIHDQCG.js → skill-B5OJEQUA.js} +1 -1
  96. package/dist/{skills-5MSMT7PT.js → skills-NH2GQKAF.js} +4 -4
  97. package/dist/sleep-manager-7JXEQQ2P.js +41 -0
  98. package/dist/{spirit-IL5EMWYZ.js → spirit-25JVAL3M.js} +7 -7
  99. package/dist/spirit-availability-PJDWZJ3J.js +42 -0
  100. package/dist/{sprout-UPXGJ5HX.js → sprout-EXUZMIOR.js} +1 -1
  101. package/dist/{status-IL67CYM4.js → status-MWLE3RVC.js} +5 -5
  102. package/dist/{system-events-A6IGCEC3.js → system-events-ZPSH63QX.js} +3 -3
  103. package/dist/{tailscale-SJUW2ETR.js → tailscale-KHNZFC7L.js} +2 -2
  104. package/dist/{template-hash-GSOUARW4.js → template-hash-YKWMVYMM.js} +2 -2
  105. package/dist/{template-staleness-T27VCGYA.js → template-staleness-PY2CULH6.js} +5 -5
  106. package/dist/{turn-tracker-6EI2EL7G.js → turn-tracker-TAT2HGK6.js} +5 -5
  107. package/dist/{up-CLL4665A.js → up-J7XCAH7P.js} +5 -5
  108. package/dist/{update-HVAUCQPN.js → update-CIWI2JYA.js} +5 -5
  109. package/dist/{update-check-2MGBBAFF.js → update-check-SZ7B5IFI.js} +3 -3
  110. package/dist/variant-cleanup-YXN25ZVW.js +22 -0
  111. package/dist/{version-notify-7BUHWZNT.js → version-notify-EN3KJ7HH.js} +8 -8
  112. package/dist/web-assets/assets/index-BOyJ4Gqs.css +1 -0
  113. package/dist/web-assets/assets/{index-ClsUcXiW.js → index-CrxBwnzp.js} +19 -19
  114. package/dist/web-assets/index.html +2 -2
  115. package/drizzle/0018_api_tokens.sql +20 -0
  116. package/drizzle/meta/_journal.json +7 -0
  117. package/package.json +1 -1
  118. package/templates/_base/{biome.json.tmpl → biome.json} +2 -1
  119. package/templates/_base/gitignore +44 -0
  120. package/templates/_base/home/public/.gitkeep +0 -0
  121. package/templates/_base/src/lib/format-prefix.ts +15 -8
  122. package/templates/_base/src/lib/router.ts +13 -8
  123. package/templates/claude/volute-template.json +1 -3
  124. package/templates/codex/volute-template.json +1 -3
  125. package/templates/pi/{package.json.tmpl → package.json} +2 -2
  126. package/templates/pi/volute-template.json +1 -3
  127. package/dist/delivery-manager-B4OKWD2P.js +0 -33
  128. package/dist/echo-text-WYAAODBV.js +0 -39
  129. package/dist/message-delivery-3456PXB7.js +0 -43
  130. package/dist/mind-service-5TA7UJAT.js +0 -47
  131. package/dist/scheduler-UV6RUJ7P.js +0 -25
  132. package/dist/sleep-manager-LIEPO6WG.js +0 -41
  133. package/dist/spirit-availability-YFEGJNJ2.js +0 -42
  134. package/dist/variant-cleanup-HJ7Z75R6.js +0 -22
  135. package/dist/web-assets/assets/index-Dz3wTbtR.css +0 -1
  136. /package/templates/_base/home/.config/{config.json.tmpl → config.json} +0 -0
  137. /package/templates/claude/{package.json.tmpl → package.json} +0 -0
  138. /package/templates/codex/home/.config/{config.json.tmpl → config.json} +0 -0
  139. /package/templates/codex/{package.json.tmpl → package.json} +0 -0
  140. /package/templates/pi/home/.config/{config.json.tmpl → config.json} +0 -0
package/dist/daemon.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  readBackupState,
7
7
  resticVersion,
8
8
  runBackup
9
- } from "./chunk-WBBKYUGF.js";
9
+ } from "./chunk-EDR47UE2.js";
10
10
  import {
11
11
  acceptPending,
12
12
  formatFileSize,
@@ -14,44 +14,44 @@ import {
14
14
  rejectPending,
15
15
  stageFile,
16
16
  validateFilePath
17
- } from "./chunk-QFVGPKJI.js";
17
+ } from "./chunk-DMK5ASKV.js";
18
18
  import {
19
19
  findOpenClawSession,
20
20
  importOpenClawConnectors,
21
21
  importPiSession,
22
22
  parseNameFromIdentity
23
- } from "./chunk-77IZUVBB.js";
23
+ } from "./chunk-I7U5EEZC.js";
24
24
  import {
25
25
  SPIRIT_NOTICE_PREFIX,
26
26
  ensureSpiritAvailable
27
- } from "./chunk-MLZBBLMT.js";
27
+ } from "./chunk-DN3LKLYR.js";
28
28
  import {
29
29
  isHomeOnlyArchive
30
- } from "./chunk-KAEZOVP6.js";
30
+ } from "./chunk-FLIEXG2T.js";
31
31
  import {
32
32
  evaluateSeedChecklist
33
- } from "./chunk-5PKFJHCR.js";
33
+ } from "./chunk-JHKBALS2.js";
34
34
  import {
35
35
  isTemplateStale
36
- } from "./chunk-SSNZ6ZNN.js";
36
+ } from "./chunk-CV6BNGFK.js";
37
37
  import {
38
38
  computeTemplateHash
39
- } from "./chunk-C3KLHJDB.js";
39
+ } from "./chunk-HTRSSOHY.js";
40
40
  import {
41
41
  cleanupVariant
42
- } from "./chunk-HW6Q7AMB.js";
42
+ } from "./chunk-AI47FDGL.js";
43
43
  import {
44
44
  checkForUpdate,
45
45
  checkForUpdateCached,
46
46
  getCurrentVersion
47
- } from "./chunk-AFSLNUTT.js";
47
+ } from "./chunk-LAUCO2HC.js";
48
48
  import {
49
49
  PLATFORMS,
50
50
  echoTextToChannel,
51
51
  fixModelEscapes,
52
52
  getPlatformDriver,
53
53
  routeOutboundBridge
54
- } from "./chunk-636GFQNE.js";
54
+ } from "./chunk-BSHZ23MS.js";
55
55
  import {
56
56
  getBridgeConfig,
57
57
  readBridgesConfig,
@@ -60,7 +60,7 @@ import {
60
60
  resolveChannelMapping,
61
61
  setBridgeConfig,
62
62
  setChannelMapping
63
- } from "./chunk-7XDOTN4R.js";
63
+ } from "./chunk-L7BKTZ5U.js";
64
64
  import {
65
65
  SESSION_MAX_AGE,
66
66
  announceSprout,
@@ -86,9 +86,11 @@ import {
86
86
  installNpmExtension,
87
87
  invalidateMindUserCache,
88
88
  invalidateSessionCache,
89
+ issueApiToken,
89
90
  joinSystemChannel,
90
91
  joinSystemChannelForMind,
91
92
  linkToolResultToTurn,
93
+ listApiTokens,
92
94
  loadAllExtensions,
93
95
  notifyExtensionsDaemonStart,
94
96
  notifyExtensionsDaemonStop,
@@ -97,13 +99,14 @@ import {
97
99
  requireAdmin,
98
100
  requireAdminOrSystem,
99
101
  requireSelf,
102
+ revokeApiToken,
100
103
  setExtensionEnabled,
101
104
  startMindFull,
102
105
  stopMindFull,
103
106
  uninstallNpmExtension,
104
107
  writeSystemsConfig
105
- } from "./chunk-EQKSRVDE.js";
106
- import "./chunk-SFRYRW37.js";
108
+ } from "./chunk-VP5PFNZO.js";
109
+ import "./chunk-VSBMLB2W.js";
107
110
  import {
108
111
  applyInitFiles,
109
112
  applyTemplateHomeFiles,
@@ -112,11 +115,11 @@ import {
112
115
  findTemplatesRoot,
113
116
  isKnownTemplate,
114
117
  listFiles
115
- } from "./chunk-RRZ4RQQU.js";
118
+ } from "./chunk-X67BDDZR.js";
116
119
  import {
117
120
  getScheduler,
118
121
  initScheduler
119
- } from "./chunk-7FDWPQCU.js";
122
+ } from "./chunk-Q7XQLKZB.js";
120
123
  import {
121
124
  checkStaleSend,
122
125
  formatHoldNotice,
@@ -125,7 +128,7 @@ import {
125
128
  initDeliveryManager,
126
129
  isConversationId,
127
130
  publishTypingForChannels
128
- } from "./chunk-JI67D7O2.js";
131
+ } from "./chunk-7HN63Q7J.js";
129
132
  import {
130
133
  MindStartupError,
131
134
  RestartTracker,
@@ -135,10 +138,10 @@ import {
135
138
  initMindManager,
136
139
  syncProviderToMinds,
137
140
  tryGetMindManager
138
- } from "./chunk-ALIVXDM4.js";
141
+ } from "./chunk-VAEZCIJC.js";
139
142
  import {
140
143
  extractTextContent
141
- } from "./chunk-6BM2I736.js";
144
+ } from "./chunk-UDZLPR34.js";
142
145
  import {
143
146
  SYSTEM_MIND,
144
147
  assignSession,
@@ -158,7 +161,7 @@ import {
158
161
  takeErrored,
159
162
  trackToolUse,
160
163
  utcDateTimeStr
161
- } from "./chunk-7DXLIYPY.js";
164
+ } from "./chunk-CDKQJWGK.js";
162
165
  import {
163
166
  SEED_SKILLS,
164
167
  STANDARD_SKILLS,
@@ -180,7 +183,7 @@ import {
180
183
  syncBuiltinSkills,
181
184
  uninstallSkill,
182
185
  updateSkill
183
- } from "./chunk-TGJHGVBZ.js";
186
+ } from "./chunk-QT4D5XCI.js";
184
187
  import {
185
188
  approveUser,
186
189
  changePassword,
@@ -201,7 +204,7 @@ import {
201
204
  updateUserProfile,
202
205
  verifyUser,
203
206
  withSenderDisplayNames
204
- } from "./chunk-UC6BNMGT.js";
207
+ } from "./chunk-HKP6OAJP.js";
205
208
  import {
206
209
  captureReflection,
207
210
  clearDeliveredEvents,
@@ -214,7 +217,7 @@ import {
214
217
  listEvents,
215
218
  parseMeta,
216
219
  recordNotice
217
- } from "./chunk-7OZWKHA3.js";
220
+ } from "./chunk-ICL6T4SN.js";
218
221
  import {
219
222
  publish as publish2,
220
223
  subscribe as subscribe2,
@@ -227,11 +230,11 @@ import {
227
230
  getPrompt,
228
231
  getPromptIfCustom,
229
232
  substitute
230
- } from "./chunk-5TPC4KCV.js";
233
+ } from "./chunk-FXWBFDQR.js";
231
234
  import {
232
235
  isSandboxEnabled,
233
236
  wrapForSandbox
234
- } from "./chunk-ZUG76D3P.js";
237
+ } from "./chunk-5Y54AE3L.js";
235
238
  import {
236
239
  addMessage,
237
240
  createChannel,
@@ -267,22 +270,22 @@ import {
267
270
  subscribe as subscribe3,
268
271
  subscribeParticipantAdded,
269
272
  updateChannelSettings
270
- } from "./chunk-574M6I7F.js";
273
+ } from "./chunk-TPX6E6PL.js";
271
274
  import {
272
275
  getActiveMinds,
273
276
  onMindEvent,
274
277
  stopAll
275
- } from "./chunk-E5S3ILVA.js";
278
+ } from "./chunk-UFTDRTCP.js";
276
279
  import {
277
280
  broadcast,
278
281
  getEventsSince,
279
282
  nextEventId,
280
283
  publish,
281
284
  subscribe
282
- } from "./chunk-3BAFMGCJ.js";
285
+ } from "./chunk-U54PJPTB.js";
283
286
  import {
284
287
  normalizeAvatar
285
- } from "./chunk-X67VT4QO.js";
288
+ } from "./chunk-ICXY54ZC.js";
286
289
  import {
287
290
  safeResolveWithinBase
288
291
  } from "./chunk-DW4TRDOZ.js";
@@ -290,7 +293,7 @@ import {
290
293
  readVoluteConfig,
291
294
  writeVoluteConfig
292
295
  } from "./chunk-WCFSBH33.js";
293
- import "./chunk-5FVANDON.js";
296
+ import "./chunk-6NLW72HP.js";
294
297
  import {
295
298
  chownMindDir,
296
299
  chownMindFile,
@@ -302,15 +305,16 @@ import {
302
305
  isIsolationEnabled,
303
306
  resolveVoluteBin,
304
307
  wrapForIsolation
305
- } from "./chunk-AJWFDIEY.js";
308
+ } from "./chunk-M77B73VV.js";
306
309
  import {
307
310
  loadMergedEnv,
308
311
  mindEnvPath,
309
312
  readEnv,
310
313
  sharedEnvPath,
311
314
  writeEnv
312
- } from "./chunk-7UWXAJMK.js";
315
+ } from "./chunk-GLM7TVWP.js";
313
316
  import {
317
+ OAuthRefreshError,
314
318
  addCustomModel,
315
319
  aiCompleteUtility,
316
320
  buildCustomModel,
@@ -334,7 +338,7 @@ import {
334
338
  setProviderRefreshHook,
335
339
  setUtilityModel,
336
340
  unqualifyModelId
337
- } from "./chunk-632FJ23O.js";
341
+ } from "./chunk-EGV6R6UF.js";
338
342
  import {
339
343
  logBuffer,
340
344
  logger_default
@@ -374,7 +378,7 @@ import {
374
378
  voluteHome,
375
379
  voluteSystemDir,
376
380
  writeGlobalConfig
377
- } from "./chunk-CAIYV33P.js";
381
+ } from "./chunk-H6X6CKDN.js";
378
382
  import {
379
383
  activity,
380
384
  channels,
@@ -386,14 +390,14 @@ import {
386
390
  systemPrompts,
387
391
  turns,
388
392
  users
389
- } from "./chunk-5IIVOWSP.js";
393
+ } from "./chunk-2RNMBXD2.js";
390
394
  import "./chunk-K3NQKI34.js";
391
395
 
392
396
  // packages/daemon/src/daemon.ts
393
397
  import { randomBytes as randomBytes3 } from "crypto";
394
398
  import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync12, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
395
399
  import { homedir as homedir3 } from "os";
396
- import { resolve as resolve18 } from "path";
400
+ import { resolve as resolve19 } from "path";
397
401
  import { format } from "util";
398
402
 
399
403
  // packages/daemon/src/lib/daemon/backup-manager.ts
@@ -504,7 +508,7 @@ var BackupManager = class {
504
508
  } catch (pubErr) {
505
509
  blog.error("failed to publish backup-failure activity", logger_default.errorData(pubErr));
506
510
  }
507
- const { deliverEvent: deliverEvent2 } = await import("./system-events-A6IGCEC3.js");
511
+ const { deliverEvent: deliverEvent2 } = await import("./system-events-ZPSH63QX.js");
508
512
  await deliverEvent2(getSpiritName(), {
509
513
  type: "notice",
510
514
  meta: { subtype: "backup" },
@@ -728,8 +732,8 @@ var BridgeManager = class {
728
732
  if (!tracked) return;
729
733
  this.stopping.add(platform);
730
734
  this.bridges.delete(platform);
731
- await new Promise((resolve19) => {
732
- tracked.child.on("exit", () => resolve19());
735
+ await new Promise((resolve20) => {
736
+ tracked.child.on("exit", () => resolve20());
733
737
  try {
734
738
  if (tracked.child.pid) {
735
739
  process.kill(-tracked.child.pid, "SIGTERM");
@@ -740,7 +744,7 @@ var BridgeManager = class {
740
744
  if (err instanceof Error && err.code !== "ESRCH") {
741
745
  blog2.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
742
746
  }
743
- resolve19();
747
+ resolve20();
744
748
  }
745
749
  setTimeout(() => {
746
750
  try {
@@ -751,7 +755,7 @@ var BridgeManager = class {
751
755
  }
752
756
  } catch {
753
757
  }
754
- resolve19();
758
+ resolve20();
755
759
  }, 5e3);
756
760
  });
757
761
  this.stopping.delete(platform);
@@ -1112,6 +1116,7 @@ async function xaiSearch(_query, _cred) {
1112
1116
  }
1113
1117
 
1114
1118
  // packages/daemon/src/lib/services/imagegen.ts
1119
+ var igLog = logger_default.child("imagegen");
1115
1120
  var PROVIDERS = {
1116
1121
  replicate: {
1117
1122
  envVar: "REPLICATE_API_TOKEN",
@@ -1275,12 +1280,19 @@ async function resolveCredential(providerId) {
1275
1280
  const config2 = readGlobalConfig();
1276
1281
  const configKey = config2.imagegen?.providers?.[providerId]?.apiKey;
1277
1282
  if (configKey) return { kind: "api_key", token: configKey };
1278
- const oauth = await resolveOAuthCredentials(aiProviderId);
1279
- if (oauth) return { kind: "oauth", token: oauth.access };
1283
+ let oauthError;
1284
+ try {
1285
+ const oauth = await resolveOAuthCredentials(aiProviderId);
1286
+ if (oauth) return { kind: "oauth", token: oauth.access };
1287
+ } catch (err) {
1288
+ if (!(err instanceof OAuthRefreshError)) throw err;
1289
+ oauthError = err;
1290
+ }
1280
1291
  const aiKey = config2.ai?.providers?.[aiProviderId]?.apiKey;
1281
1292
  if (aiKey) return { kind: "api_key", token: aiKey };
1282
1293
  const envKey = provider.envVar ? process.env[provider.envVar] : void 0;
1283
1294
  if (envKey) return { kind: "api_key", token: envKey };
1295
+ if (oauthError) throw oauthError;
1284
1296
  return void 0;
1285
1297
  }
1286
1298
  function getEnabledModels2() {
@@ -1315,12 +1327,27 @@ async function searchModels(query, provider) {
1315
1327
  return providerDef.search(query || "text to image", cred);
1316
1328
  }
1317
1329
  const searches = [];
1330
+ let transientError;
1318
1331
  for (const [id, def] of Object.entries(PROVIDERS)) {
1319
- const cred = await resolveCredential(id);
1332
+ let cred;
1333
+ try {
1334
+ cred = await resolveCredential(id);
1335
+ } catch (err) {
1336
+ if (!(err instanceof OAuthRefreshError)) throw err;
1337
+ igLog.warn(`skipping ${id} in model search: OAuth temporarily unavailable`);
1338
+ transientError = err;
1339
+ continue;
1340
+ }
1320
1341
  if (!cred) continue;
1321
- searches.push(def.search(query || "text to image", cred).catch(() => []));
1342
+ searches.push(
1343
+ def.search(query || "text to image", cred).catch((err) => {
1344
+ igLog.warn(`model search failed for ${id}`, logger_default.errorData(err));
1345
+ return [];
1346
+ })
1347
+ );
1322
1348
  }
1323
1349
  if (searches.length === 0) {
1350
+ if (transientError) throw transientError;
1324
1351
  throw new Error("No imagegen providers configured");
1325
1352
  }
1326
1353
  return (await Promise.all(searches)).flat();
@@ -1382,7 +1409,7 @@ async function generateImage(model, prompt, signal) {
1382
1409
 
1383
1410
  // packages/daemon/src/web/api/system.ts
1384
1411
  var DEFAULT_API_URL = "https://volute.systems";
1385
- var igLog = logger_default.child("imagegen");
1412
+ var igLog2 = logger_default.child("imagegen");
1386
1413
  var app = new Hono().post("/restart", requireAdmin, (c) => {
1387
1414
  setTimeout(() => process.exit(1), 200);
1388
1415
  return c.json({ ok: true });
@@ -1400,10 +1427,10 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1400
1427
  stream.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
1401
1428
  });
1402
1429
  });
1403
- await new Promise((resolve19) => {
1430
+ await new Promise((resolve20) => {
1404
1431
  stream.onAbort(() => {
1405
1432
  unsubscribe();
1406
- resolve19();
1433
+ resolve20();
1407
1434
  });
1408
1435
  });
1409
1436
  });
@@ -1428,7 +1455,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1428
1455
  config2.name = name.trim() || void 0;
1429
1456
  writeGlobalConfig(config2);
1430
1457
  if (config2.name !== previousName) {
1431
- const { notifySpiritSystemChange } = await import("./spirit-IL5EMWYZ.js");
1458
+ const { notifySpiritSystemChange } = await import("./spirit-25JVAL3M.js");
1432
1459
  await notifySpiritSystemChange();
1433
1460
  }
1434
1461
  return c.json({ name: config2.name ?? null });
@@ -1621,7 +1648,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1621
1648
  const results = await searchModels(q || void 0, provider || void 0);
1622
1649
  return c.json(results);
1623
1650
  } catch (err) {
1624
- igLog.error("model search failed", logger_default.errorData(err));
1651
+ igLog2.error("model search failed", logger_default.errorData(err));
1625
1652
  return c.json({ error: err instanceof Error ? err.message : "Search failed" }, 500);
1626
1653
  }
1627
1654
  }).post(
@@ -1638,7 +1665,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1638
1665
  }
1639
1666
  });
1640
1667
  } catch (err) {
1641
- igLog.error("image generation failed", logger_default.errorData(err));
1668
+ igLog2.error("image generation failed", logger_default.errorData(err));
1642
1669
  return c.json({ error: err instanceof Error ? err.message : "Generation failed" }, 500);
1643
1670
  }
1644
1671
  }
@@ -1787,8 +1814,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1787
1814
  createdAt: Date.now()
1788
1815
  };
1789
1816
  oauthFlows.set(flowId, flow);
1790
- const promptPromise = needsManualCode ? new Promise((resolve19) => {
1791
- flow.resolveCode = resolve19;
1817
+ const promptPromise = needsManualCode ? new Promise((resolve20) => {
1818
+ flow.resolveCode = resolve20;
1792
1819
  }) : void 0;
1793
1820
  oauthProvider.login({
1794
1821
  onAuth: (info) => {
@@ -1827,7 +1854,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1827
1854
  existing.error = err instanceof Error ? err.message : String(err);
1828
1855
  }
1829
1856
  });
1830
- await new Promise((resolve19) => setTimeout(resolve19, 2e3));
1857
+ await new Promise((resolve20) => setTimeout(resolve20, 2e3));
1831
1858
  const state = oauthFlows.get(flowId);
1832
1859
  return c.json({
1833
1860
  flowId,
@@ -2088,8 +2115,8 @@ var app2 = new Hono2().get("/events", async (c) => {
2088
2115
  });
2089
2116
  }, 15e3);
2090
2117
  cleanups.push(() => clearInterval(keepAlive));
2091
- await new Promise((resolve19) => {
2092
- stream.onAbort(() => resolve19());
2118
+ await new Promise((resolve20) => {
2119
+ stream.onAbort(() => resolve20());
2093
2120
  });
2094
2121
  } finally {
2095
2122
  for (const cleanup of cleanups) {
@@ -2145,6 +2172,12 @@ var profileSchema = z2.object({
2145
2172
  display_name: z2.string().max(100).nullable().optional(),
2146
2173
  description: z2.string().max(500).nullable().optional()
2147
2174
  });
2175
+ var registerMindSchema = z2.object({
2176
+ name: z2.string().min(1),
2177
+ displayName: z2.string().max(100).optional(),
2178
+ description: z2.string().max(500).optional(),
2179
+ tokenLabel: z2.string().max(100).optional()
2180
+ });
2148
2181
  var AVATAR_MIME = {
2149
2182
  ".png": "image/png",
2150
2183
  ".jpg": "image/jpeg",
@@ -2156,7 +2189,39 @@ var MAX_AVATAR_SIZE = 2 * 1024 * 1024;
2156
2189
  function avatarsDir() {
2157
2190
  return resolve3(voluteHome(), "avatars");
2158
2191
  }
2159
- var authenticated = new Hono3().use(authMiddleware).post("/change-password", zValidator2("json", changePasswordSchema), async (c) => {
2192
+ var authenticated = new Hono3().use(authMiddleware).post("/minds", requireAdmin, zValidator2("json", registerMindSchema), async (c) => {
2193
+ const { name, displayName, description, tokenLabel } = c.req.valid("json");
2194
+ const invalid = validateMindName(name);
2195
+ if (invalid) return c.json({ error: invalid }, 400);
2196
+ if (await getUserByUsername(name)) {
2197
+ return c.json({ error: `"${name}" is already taken` }, 409);
2198
+ }
2199
+ const db = await getDb();
2200
+ let user;
2201
+ try {
2202
+ [user] = await db.insert(users).values({
2203
+ username: name,
2204
+ password_hash: "!mind",
2205
+ role: "user",
2206
+ user_type: "mind",
2207
+ display_name: displayName ?? null,
2208
+ description: description ?? null
2209
+ }).returning({
2210
+ id: users.id,
2211
+ username: users.username,
2212
+ user_type: users.user_type,
2213
+ role: users.role,
2214
+ display_name: users.display_name
2215
+ });
2216
+ } catch (err) {
2217
+ if (await getUserByUsername(name)) {
2218
+ return c.json({ error: `"${name}" is already taken` }, 409);
2219
+ }
2220
+ throw err;
2221
+ }
2222
+ const { id: tokenId, token } = await issueApiToken(user.id, tokenLabel);
2223
+ return c.json({ name, user, token, tokenId }, 201);
2224
+ }).post("/change-password", zValidator2("json", changePasswordSchema), async (c) => {
2160
2225
  const user = c.get("user");
2161
2226
  const { currentPassword, newPassword } = c.req.valid("json");
2162
2227
  const ok = await changePassword(user.id, currentPassword, newPassword);
@@ -2272,7 +2337,42 @@ var admin = new Hono3().use(authMiddleware).get("/users", async (c) => {
2272
2337
  await setUserRole(id, role);
2273
2338
  return c.json({ ok: true });
2274
2339
  }
2275
- ).put("/users/:id/profile", zValidator2("json", profileSchema), async (c) => {
2340
+ ).post(
2341
+ "/users/:id/tokens",
2342
+ requireAdmin,
2343
+ zValidator2("json", z2.object({ label: z2.string().max(200).optional() })),
2344
+ async (c) => {
2345
+ const id = parseInt(c.req.param("id"), 10);
2346
+ if (Number.isNaN(id)) return c.json({ error: "Invalid user ID" }, 400);
2347
+ const target = await getUser(id);
2348
+ if (!target) return c.json({ error: "User not found" }, 404);
2349
+ const { label } = c.req.valid("json");
2350
+ const issued = await issueApiToken(id, label);
2351
+ return c.json(
2352
+ {
2353
+ id: issued.id,
2354
+ token: issued.token,
2355
+ label: issued.label,
2356
+ createdAt: issued.created_at
2357
+ },
2358
+ 201
2359
+ );
2360
+ }
2361
+ ).get("/users/:id/tokens", requireAdmin, async (c) => {
2362
+ const id = parseInt(c.req.param("id"), 10);
2363
+ if (Number.isNaN(id)) return c.json({ error: "Invalid user ID" }, 400);
2364
+ const target = await getUser(id);
2365
+ if (!target) return c.json({ error: "User not found" }, 404);
2366
+ const tokens = await listApiTokens(id);
2367
+ return c.json(tokens.map((t) => ({ id: t.id, label: t.label, createdAt: t.created_at })));
2368
+ }).delete("/users/:id/tokens/:tokenId", requireAdmin, async (c) => {
2369
+ const id = parseInt(c.req.param("id"), 10);
2370
+ const tokenId = parseInt(c.req.param("tokenId"), 10);
2371
+ if (Number.isNaN(id) || Number.isNaN(tokenId)) return c.json({ error: "Invalid ID" }, 400);
2372
+ const revoked = await revokeApiToken(id, tokenId);
2373
+ if (!revoked) return c.json({ error: "Token not found" }, 404);
2374
+ return c.json({ ok: true });
2375
+ }).put("/users/:id/profile", zValidator2("json", profileSchema), async (c) => {
2276
2376
  const user = c.get("user");
2277
2377
  if (user.role !== "admin") return c.json({ error: "Forbidden" }, 403);
2278
2378
  const id = parseInt(c.req.param("id"), 10);
@@ -2557,15 +2657,18 @@ async function fanOutToMinds(opts) {
2557
2657
  const isDM = opts.isDM ?? participants.length === 2;
2558
2658
  const manager = getMindManager();
2559
2659
  const sm = getSleepManagerIfReady();
2660
+ const registeredMinds = new Set((await readAllMinds()).map((m) => m.name));
2560
2661
  const targetMinds = mindParticipants.map((ap) => {
2561
2662
  const key = opts.targetName ? opts.targetName(ap.username) : ap.username;
2562
2663
  if (manager.isRunning(key) || sm?.isSleeping(ap.username)) return ap.username;
2563
2664
  if (ap.username !== opts.senderName) {
2564
- logger_default.warn(
2565
- `fan-out: skipping ${ap.username} (not running) for conversation ${opts.conversationId}`
2566
- );
2665
+ if (registeredMinds.has(ap.username)) {
2666
+ logger_default.warn(
2667
+ `fan-out: skipping ${ap.username} (not running) for conversation ${opts.conversationId}`
2668
+ );
2669
+ }
2567
2670
  if (ap.userType === "system") {
2568
- import("./spirit-availability-YFEGJNJ2.js").then(({ ensureSpiritAvailable: ensureSpiritAvailable2 }) => ensureSpiritAvailable2()).catch((err) => logger_default.warn("fan-out: on-demand spirit start failed", logger_default.errorData(err)));
2671
+ import("./spirit-availability-PJDWZJ3J.js").then(({ ensureSpiritAvailable: ensureSpiritAvailable2 }) => ensureSpiritAvailable2()).catch((err) => logger_default.warn("fan-out: on-demand spirit start failed", logger_default.errorData(err)));
2569
2672
  }
2570
2673
  }
2571
2674
  return null;
@@ -2668,7 +2771,7 @@ var app4 = new Hono5().post("/:platform/inbound", zValidator4("json", inboundSch
2668
2771
  }
2669
2772
  const participants = await getParticipants(channel.id);
2670
2773
  if (!participants.some((p) => p.userId === puppet.id)) {
2671
- const { addParticipant } = await import("./conversations-S2232Y5I.js");
2774
+ const { addParticipant } = await import("./conversations-ZL6PHROD.js");
2672
2775
  await addParticipant(channel.id, puppet.id);
2673
2776
  }
2674
2777
  const contentBlocks = body.content;
@@ -2952,7 +3055,7 @@ async function notifyMind(mindName, message) {
2952
3055
  const entry = await findMind(mindName);
2953
3056
  if (!entry) return;
2954
3057
  try {
2955
- const { deliverEvent: deliverEvent2 } = await import("./system-events-A6IGCEC3.js");
3058
+ const { deliverEvent: deliverEvent2 } = await import("./system-events-ZPSH63QX.js");
2956
3059
  await deliverEvent2(mindName, { type: "file-share", body: message });
2957
3060
  } catch (err) {
2958
3061
  logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
@@ -3923,9 +4026,9 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
3923
4026
  stream.onAbort(() => {
3924
4027
  tail.kill();
3925
4028
  });
3926
- await new Promise((resolve19) => {
3927
- tail.on("exit", resolve19);
3928
- stream.onAbort(resolve19);
4029
+ await new Promise((resolve20) => {
4030
+ tail.on("exit", resolve20);
4031
+ stream.onAbort(resolve20);
3929
4032
  });
3930
4033
  });
3931
4034
  }).get("/:name/logs/tail", requireSelf(), async (c) => {
@@ -3943,8 +4046,8 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
3943
4046
  tail.stdout.on("data", (data) => {
3944
4047
  output += data.toString();
3945
4048
  });
3946
- await new Promise((resolve19) => {
3947
- tail.on("exit", resolve19);
4049
+ await new Promise((resolve20) => {
4050
+ tail.on("exit", resolve20);
3948
4051
  });
3949
4052
  return c.text(output);
3950
4053
  });
@@ -4037,14 +4140,14 @@ var mind_skills_default = app12;
4037
4140
  // packages/daemon/src/web/api/minds.ts
4038
4141
  import {
4039
4142
  cpSync,
4040
- existsSync as existsSync7,
4143
+ existsSync as existsSync8,
4041
4144
  mkdirSync as mkdirSync6,
4042
4145
  readdirSync as readdirSync2,
4043
4146
  readFileSync as readFileSync9,
4044
4147
  rmSync as rmSync3,
4045
4148
  writeFileSync as writeFileSync8
4046
4149
  } from "fs";
4047
- import { relative, resolve as resolve11 } from "path";
4150
+ import { relative, resolve as resolve12 } from "path";
4048
4151
  import { zValidator as zValidator6 } from "@hono/zod-validator";
4049
4152
  import { and as and5, desc as desc3, eq as eq5, sql as sql3 } from "drizzle-orm";
4050
4153
  import { Hono as Hono16 } from "hono";
@@ -4487,6 +4590,49 @@ async function commitSrcChanges(dir, mindName) {
4487
4590
  glog.info(`committed known-good src changes (${dir})`);
4488
4591
  }
4489
4592
 
4593
+ // packages/daemon/src/lib/mind/npm-install.ts
4594
+ import { existsSync as existsSync7 } from "fs";
4595
+ import { resolve as resolve10 } from "path";
4596
+ var NPM_INSTALL_ARGS = [
4597
+ "install",
4598
+ "--no-audit",
4599
+ "--no-fund",
4600
+ "--prefer-offline",
4601
+ "--loglevel=error"
4602
+ ];
4603
+ function lowPriorityArgv(cmd, args, ionice) {
4604
+ return ionice ? ["ionice", ["-c2", "-n7", "nice", "-n19", cmd, ...args]] : ["nice", ["-n19", cmd, ...args]];
4605
+ }
4606
+ function hasIonice() {
4607
+ return process.platform === "linux" && (existsSync7("/usr/bin/ionice") || existsSync7("/bin/ionice"));
4608
+ }
4609
+ async function npmInstallAsMind(cwd, mindName) {
4610
+ const [cmd, args] = lowPriorityArgv("npm", NPM_INSTALL_ARGS, hasIonice());
4611
+ if (isIsolationEnabled()) {
4612
+ const [wrappedCmd, wrappedArgs] = await wrapForIsolation(cmd, args, mindName);
4613
+ await exec(wrappedCmd, wrappedArgs, {
4614
+ cwd,
4615
+ env: { ...process.env, HOME: resolve10(cwd, "home") }
4616
+ });
4617
+ } else {
4618
+ await exec(cmd, args, { cwd });
4619
+ }
4620
+ }
4621
+ async function depsChangedSince(dir, fromRef) {
4622
+ try {
4623
+ await gitExec(["diff", "--quiet", fromRef, "HEAD", "--", "package.json", "package-lock.json"], {
4624
+ cwd: dir
4625
+ });
4626
+ return false;
4627
+ } catch {
4628
+ return true;
4629
+ }
4630
+ }
4631
+ async function npmInstallNeeded(dir, preMergeRef) {
4632
+ if (!existsSync7(resolve10(dir, "node_modules"))) return true;
4633
+ return depsChangedSince(dir, preMergeRef);
4634
+ }
4635
+
4490
4636
  // packages/daemon/src/lib/mind/thinking-config.ts
4491
4637
  var CLAUDE_EFFORT = {
4492
4638
  minimal: "low",
@@ -4743,7 +4889,7 @@ async function waitForImagegenJob(mind, id, timeoutMs) {
4743
4889
  import { randomUUID } from "crypto";
4744
4890
  import { mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
4745
4891
  import { homedir } from "os";
4746
- import { resolve as resolve10 } from "path";
4892
+ import { resolve as resolve11 } from "path";
4747
4893
  function convertSession(opts) {
4748
4894
  const lines = readFileSync8(opts.sessionPath, "utf-8").trim().split("\n");
4749
4895
  const sessionId = randomUUID();
@@ -4859,9 +5005,9 @@ function convertSession(opts) {
4859
5005
  }
4860
5006
  }
4861
5007
  const projectId = opts.projectDir.replace(/\//g, "-");
4862
- const sdkDir = resolve10(homedir(), ".claude", "projects", projectId);
5008
+ const sdkDir = resolve11(homedir(), ".claude", "projects", projectId);
4863
5009
  mkdirSync5(sdkDir, { recursive: true });
4864
- const sdkPath = resolve10(sdkDir, `${sessionId}.jsonl`);
5010
+ const sdkPath = resolve11(sdkDir, `${sessionId}.jsonl`);
4865
5011
  writeFileSync7(sdkPath, `${sdkEvents.join("\n")}
4866
5012
  `);
4867
5013
  console.log(`Converted ${sdkEvents.length} messages \u2192 ${sdkPath}`);
@@ -4928,7 +5074,7 @@ async function getMindStatus(name, port, registryRunning, seed) {
4928
5074
  let status = "stopped";
4929
5075
  let wakeAt = null;
4930
5076
  try {
4931
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-LIEPO6WG.js");
5077
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
4932
5078
  const sleepManager = getSleepManagerIfReady2();
4933
5079
  if (sleepManager?.isSleeping(name)) {
4934
5080
  status = "sleeping";
@@ -5007,7 +5153,7 @@ async function initTemplateBranch(projectRoot, composedDir, manifest, mindName,
5007
5153
  await gitExec(["commit", "-m", "initial commit"], opts);
5008
5154
  }
5009
5155
  async function updateTemplateBranch(projectRoot, template, mindName) {
5010
- const tempWorktree = resolve11(projectRoot, ".variants", "_template_update");
5156
+ const tempWorktree = resolve12(projectRoot, ".variants", "_template_update");
5011
5157
  let branchExists = false;
5012
5158
  try {
5013
5159
  await gitExec(["rev-parse", "--verify", TEMPLATE_BRANCH], { cwd: projectRoot });
@@ -5018,7 +5164,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
5018
5164
  await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
5019
5165
  } catch {
5020
5166
  }
5021
- if (existsSync7(tempWorktree)) {
5167
+ if (existsSync8(tempWorktree)) {
5022
5168
  rmSync3(tempWorktree, { recursive: true, force: true });
5023
5169
  }
5024
5170
  const templatesRoot = findTemplatesRoot();
@@ -5039,15 +5185,15 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
5039
5185
  });
5040
5186
  }
5041
5187
  copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
5042
- const initDir = resolve11(tempWorktree, ".init");
5043
- if (existsSync7(initDir)) {
5188
+ const initDir = resolve12(tempWorktree, ".init");
5189
+ if (existsSync8(initDir)) {
5044
5190
  rmSync3(initDir, { recursive: true, force: true });
5045
5191
  }
5046
- const homeDir = resolve11(tempWorktree, "home");
5047
- if (existsSync7(homeDir)) {
5192
+ const homeDir = resolve12(tempWorktree, "home");
5193
+ if (existsSync8(homeDir)) {
5048
5194
  for (const entry of readdirSync2(homeDir)) {
5049
5195
  if (entry !== "VOLUTE.md") {
5050
- rmSync3(resolve11(homeDir, entry), { recursive: true, force: true });
5196
+ rmSync3(resolve12(homeDir, entry), { recursive: true, force: true });
5051
5197
  }
5052
5198
  }
5053
5199
  }
@@ -5062,7 +5208,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
5062
5208
  await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
5063
5209
  } catch {
5064
5210
  }
5065
- if (existsSync7(tempWorktree)) {
5211
+ if (existsSync8(tempWorktree)) {
5066
5212
  rmSync3(tempWorktree, { recursive: true, force: true });
5067
5213
  }
5068
5214
  rmSync3(composedDir, { recursive: true, force: true });
@@ -5085,14 +5231,6 @@ async function mergeTemplateBranch(worktreeDir) {
5085
5231
  throw e;
5086
5232
  }
5087
5233
  }
5088
- async function npmInstallAsMind(cwd, mindName) {
5089
- if (isIsolationEnabled()) {
5090
- const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
5091
- await exec(cmd, args, { cwd, env: { ...process.env, HOME: resolve11(cwd, "home") } });
5092
- } else {
5093
- await exec("npm", ["install"], { cwd });
5094
- }
5095
- }
5096
5234
  async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariantName, upgradeBranch, template, oldTemplate) {
5097
5235
  const templateChanged = template !== oldTemplate;
5098
5236
  const mainStatus = (await gitExec(["status", "--porcelain"], { cwd: dir })).trim();
@@ -5100,9 +5238,10 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
5100
5238
  await gitExec(["add", "-A"], { cwd: dir });
5101
5239
  await gitExec(["commit", "-m", "Auto-commit before upgrade merge"], { cwd: dir });
5102
5240
  }
5241
+ const preMergeHead = (await gitExec(["rev-parse", "HEAD"], { cwd: dir })).trim();
5103
5242
  await gitExec(["merge", upgradeBranch], { cwd: dir });
5104
5243
  try {
5105
- await cleanupVariant(upgradeVariantName, dir, worktreeDir);
5244
+ await cleanupVariant(upgradeVariantName, mindName, dir, worktreeDir);
5106
5245
  } catch (err) {
5107
5246
  logger_default.warn(`failed to clean up upgrade worktree for ${mindName}`, logger_default.errorData(err));
5108
5247
  }
@@ -5113,7 +5252,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
5113
5252
  let switchWarning;
5114
5253
  if (templateChanged) {
5115
5254
  try {
5116
- applyTemplateHomeFiles(resolve11(dir, "home"), template);
5255
+ applyTemplateHomeFiles(resolve12(dir, "home"), template);
5117
5256
  const migratedSkills = migrateSkillsToTemplate(dir, oldTemplate, template);
5118
5257
  await gitExec(["add", "home/"], { cwd: dir });
5119
5258
  try {
@@ -5140,14 +5279,18 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
5140
5279
  } catch (err) {
5141
5280
  logger_default.warn(`failed to update template for ${mindName}`, logger_default.errorData(err));
5142
5281
  }
5143
- try {
5144
- await npmInstallAsMind(dir, mindName);
5145
- } catch (err) {
5146
- logger_default.warn(`npm install failed after upgrade merge for ${mindName}`, logger_default.errorData(err));
5147
- return {
5148
- ok: true,
5149
- warning: `Upgrade merged but npm install failed: ${err instanceof Error ? err.message : String(err)}. You may need to run npm install manually.`
5150
- };
5282
+ if (await npmInstallNeeded(dir, preMergeHead)) {
5283
+ try {
5284
+ await npmInstallAsMind(dir, mindName);
5285
+ } catch (err) {
5286
+ logger_default.warn(`npm install failed after upgrade merge for ${mindName}`, logger_default.errorData(err));
5287
+ return {
5288
+ ok: true,
5289
+ warning: `Upgrade merged but npm install failed: ${err instanceof Error ? err.message : String(err)}. You may need to run npm install manually.`
5290
+ };
5291
+ }
5292
+ } else {
5293
+ logger_default.info(`skipping npm install for ${mindName} \u2014 dependencies unchanged by upgrade`);
5151
5294
  }
5152
5295
  const manager = getMindManager();
5153
5296
  try {
@@ -5155,7 +5298,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
5155
5298
  await manager.stopMind(mindName);
5156
5299
  }
5157
5300
  manager.setPendingContext(mindName, { type: "upgraded" });
5158
- await manager.startMind(mindName);
5301
+ await manager.startMind(mindName, { healthTimeoutMs: 12e4 });
5159
5302
  } catch (e) {
5160
5303
  return {
5161
5304
  ok: true,
@@ -5165,8 +5308,8 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
5165
5308
  return { ok: true, warning: switchWarning };
5166
5309
  }
5167
5310
  async function importFromArchive(c, tempDir, nameOverride, manifest) {
5168
- const extractedMindDir = resolve11(tempDir, "mind");
5169
- if (!existsSync7(extractedMindDir)) {
5311
+ const extractedMindDir = resolve12(tempDir, "mind");
5312
+ if (!existsSync8(extractedMindDir)) {
5170
5313
  return c.json({ error: "Invalid archive: missing mind/ directory" }, 400);
5171
5314
  }
5172
5315
  if (!manifest?.includes || !manifest.name || !manifest.template) {
@@ -5184,7 +5327,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
5184
5327
  if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
5185
5328
  ensureVoluteHome();
5186
5329
  const dest = mindDir(name);
5187
- if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
5330
+ if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
5188
5331
  try {
5189
5332
  cpSync(extractedMindDir, dest, { recursive: true });
5190
5333
  if (!manifest.includes.identity) {
@@ -5192,9 +5335,9 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
5192
5335
  }
5193
5336
  const state = stateDir(name);
5194
5337
  mkdirSync6(state, { recursive: true });
5195
- const envJson = resolve11(tempDir, "state/env.json");
5196
- if (existsSync7(envJson)) {
5197
- cpSync(envJson, resolve11(state, "env.json"));
5338
+ const envJson = resolve12(tempDir, "state/env.json");
5339
+ if (existsSync8(envJson)) {
5340
+ cpSync(envJson, resolve12(state, "env.json"));
5198
5341
  }
5199
5342
  const port = await nextPort();
5200
5343
  await addMind(name, port, manifest.stage, manifest.template);
@@ -5203,30 +5346,30 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
5203
5346
  } catch (err) {
5204
5347
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
5205
5348
  }
5206
- const homeDir = resolve11(dest, "home");
5349
+ const homeDir = resolve12(dest, "home");
5207
5350
  ensureVoluteGroup();
5208
5351
  createMindUser(name, homeDir);
5209
5352
  await chownMindDir(dest, name);
5210
5353
  await npmInstallAsMind(dest, name);
5211
5354
  await importHistoryFromArchive(name, tempDir);
5212
5355
  importSessionsFromArchive(dest, tempDir);
5213
- if (!existsSync7(resolve11(dest, ".git"))) {
5356
+ if (!existsSync8(resolve12(dest, ".git"))) {
5214
5357
  try {
5215
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
5358
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve12(dest, "home") } : void 0;
5216
5359
  await gitExec(["init"], { cwd: dest, mindName: name, env });
5217
5360
  await configureGitIdentity(name, { cwd: dest, mindName: name, env });
5218
5361
  await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
5219
5362
  await gitExec(["commit", "-m", "import from archive"], { cwd: dest, mindName: name, env });
5220
5363
  } catch (err) {
5221
5364
  logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
5222
- rmSync3(resolve11(dest, ".git"), { recursive: true, force: true });
5365
+ rmSync3(resolve12(dest, ".git"), { recursive: true, force: true });
5223
5366
  }
5224
5367
  }
5225
5368
  await chownMindDir(dest, name);
5226
5369
  rmSync3(tempDir, { recursive: true, force: true });
5227
5370
  return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
5228
5371
  } catch (err) {
5229
- if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
5372
+ if (existsSync8(dest)) rmSync3(dest, { recursive: true, force: true });
5230
5373
  try {
5231
5374
  await removeMind(name);
5232
5375
  } catch (cleanupErr) {
@@ -5243,7 +5386,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
5243
5386
  if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
5244
5387
  ensureVoluteHome();
5245
5388
  const dest = mindDir(name);
5246
- if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
5389
+ if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
5247
5390
  const templatesRoot = findTemplatesRoot();
5248
5391
  const { composedDir, manifest: templateManifest } = composeTemplate(
5249
5392
  templatesRoot,
@@ -5252,36 +5395,36 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
5252
5395
  try {
5253
5396
  copyTemplateToDir(composedDir, dest, name, templateManifest);
5254
5397
  applyInitFiles(dest);
5255
- const extractedHome = resolve11(extractedMindDir, "home");
5256
- if (existsSync7(extractedHome)) {
5257
- cpSync(extractedHome, resolve11(dest, "home"), { recursive: true });
5398
+ const extractedHome = resolve12(extractedMindDir, "home");
5399
+ if (existsSync8(extractedHome)) {
5400
+ cpSync(extractedHome, resolve12(dest, "home"), { recursive: true });
5258
5401
  }
5259
- const extractedMindInternal = resolve11(extractedMindDir, ".mind");
5260
- if (existsSync7(extractedMindInternal)) {
5261
- cpSync(extractedMindInternal, resolve11(dest, ".mind"), { recursive: true });
5402
+ const extractedMindInternal = resolve12(extractedMindDir, ".mind");
5403
+ if (existsSync8(extractedMindInternal)) {
5404
+ cpSync(extractedMindInternal, resolve12(dest, ".mind"), { recursive: true });
5262
5405
  }
5263
- const identityDir = resolve11(dest, ".mind/identity");
5406
+ const identityDir = resolve12(dest, ".mind/identity");
5264
5407
  let publicKeyPem;
5265
- if (!manifest.includes.identity || !existsSync7(resolve11(identityDir, "private.pem"))) {
5408
+ if (!manifest.includes.identity || !existsSync8(resolve12(identityDir, "private.pem"))) {
5266
5409
  ({ publicKeyPem } = generateIdentity(dest));
5267
5410
  } else {
5268
- publicKeyPem = readFileSync9(resolve11(identityDir, "public.pem"), "utf-8");
5411
+ publicKeyPem = readFileSync9(resolve12(identityDir, "public.pem"), "utf-8");
5269
5412
  }
5270
- const promptsPath = resolve11(dest, "home/.config/prompts.json");
5271
- if (!existsSync7(promptsPath)) {
5413
+ const promptsPath = resolve12(dest, "home/.config/prompts.json");
5414
+ if (!existsSync8(promptsPath)) {
5272
5415
  const mindPrompts = await getMindPromptDefaults();
5273
5416
  writeFileSync8(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
5274
5417
  `);
5275
5418
  }
5276
5419
  const state = stateDir(name);
5277
5420
  mkdirSync6(state, { recursive: true });
5278
- const envJson = resolve11(tempDir, "state/env.json");
5279
- if (existsSync7(envJson)) {
5280
- cpSync(envJson, resolve11(state, "env.json"));
5421
+ const envJson = resolve12(tempDir, "state/env.json");
5422
+ if (existsSync8(envJson)) {
5423
+ cpSync(envJson, resolve12(state, "env.json"));
5281
5424
  }
5282
5425
  const port = await nextPort();
5283
5426
  await addMind(name, port, manifest.stage, manifest.template);
5284
- const homeDir = resolve11(dest, "home");
5427
+ const homeDir = resolve12(dest, "home");
5285
5428
  ensureVoluteGroup();
5286
5429
  createMindUser(name, homeDir);
5287
5430
  await chownMindDir(dest, name);
@@ -5294,7 +5437,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
5294
5437
  await initTemplateBranch(dest, composedDir, templateManifest, name, env);
5295
5438
  } catch (err) {
5296
5439
  logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
5297
- rmSync3(resolve11(dest, ".git"), { recursive: true, force: true });
5440
+ rmSync3(resolve12(dest, ".git"), { recursive: true, force: true });
5298
5441
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
5299
5442
  }
5300
5443
  const skillSet = manifest.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions();
@@ -5324,7 +5467,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
5324
5467
  ...skillWarnings.length > 0 && { skillWarnings }
5325
5468
  });
5326
5469
  } catch (err) {
5327
- if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
5470
+ if (existsSync8(dest)) rmSync3(dest, { recursive: true, force: true });
5328
5471
  try {
5329
5472
  await removeMind(name);
5330
5473
  } catch (cleanupErr) {
@@ -5337,8 +5480,8 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
5337
5480
  }
5338
5481
  }
5339
5482
  async function importHistoryFromArchive(name, tempDir) {
5340
- const historyJsonl = resolve11(tempDir, "history.jsonl");
5341
- if (!existsSync7(historyJsonl)) return;
5483
+ const historyJsonl = resolve12(tempDir, "history.jsonl");
5484
+ if (!existsSync8(historyJsonl)) return;
5342
5485
  try {
5343
5486
  const db = await getDb();
5344
5487
  const lines = readFileSync9(historyJsonl, "utf-8").trim().split("\n");
@@ -5378,13 +5521,13 @@ async function importHistoryFromArchive(name, tempDir) {
5378
5521
  }
5379
5522
  }
5380
5523
  function importSessionsFromArchive(dest, tempDir) {
5381
- const sessionsDir = resolve11(tempDir, "sessions");
5382
- if (!existsSync7(sessionsDir)) return;
5524
+ const sessionsDir = resolve12(tempDir, "sessions");
5525
+ if (!existsSync8(sessionsDir)) return;
5383
5526
  try {
5384
- const destSessions = resolve11(dest, ".mind/sessions");
5527
+ const destSessions = resolve12(dest, ".mind/sessions");
5385
5528
  mkdirSync6(destSessions, { recursive: true });
5386
5529
  for (const file of readdirSync2(sessionsDir)) {
5387
- cpSync(resolve11(sessionsDir, file), resolve11(destSessions, file));
5530
+ cpSync(resolve12(sessionsDir, file), resolve12(destSessions, file));
5388
5531
  }
5389
5532
  } catch (err) {
5390
5533
  logger_default.error("Failed to import sessions from archive", logger_default.errorData(err));
@@ -5458,13 +5601,13 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
5458
5601
  );
5459
5602
  }
5460
5603
  {
5461
- const { mindLimitError, readGlobalConfig: readGlobalConfig2 } = await import("./setup-CAJFOR2N.js");
5604
+ const { mindLimitError, readGlobalConfig: readGlobalConfig2 } = await import("./setup-WZSXHHRJ.js");
5462
5605
  const limitError = mindLimitError(await countCappedMinds(), readGlobalConfig2().maxMinds);
5463
5606
  if (limitError) return c.json({ error: limitError }, 409);
5464
5607
  }
5465
5608
  ensureVoluteHome();
5466
5609
  const dest = mindDir(name);
5467
- if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
5610
+ if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
5468
5611
  const templatesRoot = findTemplatesRoot();
5469
5612
  const { composedDir, manifest } = composeTemplate(templatesRoot, template);
5470
5613
  try {
@@ -5473,7 +5616,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
5473
5616
  const { publicKeyPem } = generateIdentity(dest);
5474
5617
  let effectiveModel = body.model;
5475
5618
  {
5476
- const { readGlobalConfig: readGlobal } = await import("./setup-CAJFOR2N.js");
5619
+ const { readGlobalConfig: readGlobal } = await import("./setup-WZSXHHRJ.js");
5477
5620
  const mindDefaults = readGlobal().mindDefaults;
5478
5621
  const config2 = readVoluteConfig(dest);
5479
5622
  if (!config2) throw new Error("Failed to read volute.json after identity generation");
@@ -5501,9 +5644,9 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
5501
5644
  writeVoluteConfig(dest, config2);
5502
5645
  const modelId = body.model ?? cog?.model;
5503
5646
  effectiveModel = modelId ? qualifyModelId(modelId) : void 0;
5504
- const sdkConfigPath = resolve11(dest, "home/.config/config.json");
5647
+ const sdkConfigPath = resolve12(dest, "home/.config/config.json");
5505
5648
  if (modelId || cog?.compaction) {
5506
- const existing = existsSync7(sdkConfigPath) ? JSON.parse(readFileSync9(sdkConfigPath, "utf-8")) : {};
5649
+ const existing = existsSync8(sdkConfigPath) ? JSON.parse(readFileSync9(sdkConfigPath, "utf-8")) : {};
5507
5650
  if (modelId) {
5508
5651
  existing.model = template === "pi" ? qualifyModelId(modelId) : unqualifyModelId(modelId);
5509
5652
  }
@@ -5516,7 +5659,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
5516
5659
  }
5517
5660
  const mindPrompts = await getMindPromptDefaults();
5518
5661
  writeFileSync8(
5519
- resolve11(dest, "home/.config/prompts.json"),
5662
+ resolve12(dest, "home/.config/prompts.json"),
5520
5663
  `${JSON.stringify(mindPrompts, null, 2)}
5521
5664
  `
5522
5665
  );
@@ -5528,7 +5671,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
5528
5671
  } catch (err) {
5529
5672
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
5530
5673
  }
5531
- const homeDir = resolve11(dest, "home");
5674
+ const homeDir = resolve12(dest, "home");
5532
5675
  ensureVoluteGroup();
5533
5676
  createMindUser(name, homeDir);
5534
5677
  await chownMindDir(dest, name);
@@ -5541,7 +5684,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
5541
5684
  await initTemplateBranch(dest, composedDir, manifest, name, env);
5542
5685
  } catch (err) {
5543
5686
  logger_default.error(`git setup failed for ${name}`, logger_default.errorData(err));
5544
- rmSync3(resolve11(dest, ".git"), { recursive: true, force: true });
5687
+ rmSync3(resolve12(dest, ".git"), { recursive: true, force: true });
5545
5688
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
5546
5689
  }
5547
5690
  if (body.stage === "seed") {
@@ -5550,11 +5693,11 @@ Your creator described you as: "${body.description}"
5550
5693
  ` : "";
5551
5694
  const seedSoulRaw = body.seedSoul ?? await getPrompt("seed_soul", { name, description: descLine });
5552
5695
  const seedSoul = body.seedSoul ? substitute(seedSoulRaw, { name, description: descLine }) : seedSoulRaw;
5553
- writeFileSync8(resolve11(dest, "home/SOUL.md"), seedSoul);
5696
+ writeFileSync8(resolve12(dest, "home/SOUL.md"), seedSoul);
5554
5697
  }
5555
5698
  let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
5556
5699
  if (body.stage === "seed" && !body.skills) {
5557
- const { isImagegenEnabled } = await import("./setup-CAJFOR2N.js");
5700
+ const { isImagegenEnabled } = await import("./setup-WZSXHHRJ.js");
5558
5701
  if (isImagegenEnabled()) {
5559
5702
  skillSet = [...skillSet, "imagegen"];
5560
5703
  }
@@ -5576,7 +5719,7 @@ Your creator described you as: "${body.description}"
5576
5719
  const spiritName = getSpiritName();
5577
5720
  const spiritEntry = await findMind(spiritName);
5578
5721
  if (spiritEntry) {
5579
- const { spiritDir } = await import("./spirit-IL5EMWYZ.js");
5722
+ const { spiritDir } = await import("./spirit-25JVAL3M.js");
5580
5723
  const sDir = spiritEntry.dir ?? spiritDir();
5581
5724
  const spiritConfig = readVoluteConfig(sDir) ?? {};
5582
5725
  const schedules = spiritConfig.schedules ?? [];
@@ -5591,7 +5734,7 @@ Your creator described you as: "${body.description}"
5591
5734
  });
5592
5735
  spiritConfig.schedules = schedules;
5593
5736
  writeVoluteConfig(sDir, spiritConfig);
5594
- const { getScheduler: getScheduler2 } = await import("./scheduler-UV6RUJ7P.js");
5737
+ const { getScheduler: getScheduler2 } = await import("./scheduler-TNBN54ZK.js");
5595
5738
  getScheduler2().loadSchedules(spiritName, sDir);
5596
5739
  }
5597
5740
  }
@@ -5602,11 +5745,11 @@ Your creator described you as: "${body.description}"
5602
5745
  if (body.stage !== "seed") {
5603
5746
  const customSoul = await getPromptIfCustom("default_soul");
5604
5747
  if (customSoul) {
5605
- writeFileSync8(resolve11(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
5748
+ writeFileSync8(resolve12(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
5606
5749
  }
5607
5750
  const customMemory = await getPromptIfCustom("default_memory");
5608
5751
  if (customMemory) {
5609
- writeFileSync8(resolve11(dest, "home/MEMORY.md"), customMemory);
5752
+ writeFileSync8(resolve12(dest, "home/MEMORY.md"), customMemory);
5610
5753
  }
5611
5754
  }
5612
5755
  await chownMindDir(dest, name);
@@ -5624,8 +5767,9 @@ Your creator described you as: "${body.description}"
5624
5767
  description: body.description
5625
5768
  }
5626
5769
  });
5627
- announceToSystem(`${name} has joined`).catch(() => {
5628
- });
5770
+ announceToSystem(`${name} has joined`).catch(
5771
+ (err) => logger_default.warn(`failed to announce ${name} joining #system`, logger_default.errorData(err))
5772
+ );
5629
5773
  const credentialWarning = await missingCredentialWarning(
5630
5774
  template,
5631
5775
  effectiveModel,
@@ -5645,10 +5789,11 @@ Your creator described you as: "${body.description}"
5645
5789
  ...skillWarnings.length > 0 && { skillWarnings }
5646
5790
  });
5647
5791
  } catch (err) {
5648
- if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
5792
+ if (existsSync8(dest)) rmSync3(dest, { recursive: true, force: true });
5649
5793
  try {
5650
5794
  await removeMind(name);
5651
- } catch {
5795
+ } catch (cleanupErr) {
5796
+ logger_default.warn(`failed to clean up registry for ${name}`, logger_default.errorData(cleanupErr));
5652
5797
  }
5653
5798
  return c.json({ error: err instanceof Error ? err.message : "Failed to create mind" }, 500);
5654
5799
  } finally {
@@ -5665,13 +5810,13 @@ Your creator described you as: "${body.description}"
5665
5810
  return importFromArchive(c, body.archivePath, body.name, body.manifest);
5666
5811
  }
5667
5812
  const wsDir = body.workspacePath;
5668
- if (!wsDir || !existsSync7(resolve11(wsDir, "SOUL.md")) || !existsSync7(resolve11(wsDir, "IDENTITY.md"))) {
5813
+ if (!wsDir || !existsSync8(resolve12(wsDir, "SOUL.md")) || !existsSync8(resolve12(wsDir, "IDENTITY.md"))) {
5669
5814
  return c.json({ error: "Invalid workspace: missing SOUL.md or IDENTITY.md" }, 400);
5670
5815
  }
5671
- const soul = readFileSync9(resolve11(wsDir, "SOUL.md"), "utf-8");
5672
- const identity = readFileSync9(resolve11(wsDir, "IDENTITY.md"), "utf-8");
5673
- const userPath = resolve11(wsDir, "USER.md");
5674
- const user = existsSync7(userPath) ? readFileSync9(userPath, "utf-8") : "";
5816
+ const soul = readFileSync9(resolve12(wsDir, "SOUL.md"), "utf-8");
5817
+ const identity = readFileSync9(resolve12(wsDir, "IDENTITY.md"), "utf-8");
5818
+ const userPath = resolve12(wsDir, "USER.md");
5819
+ const user = existsSync8(userPath) ? readFileSync9(userPath, "utf-8") : "";
5675
5820
  const name = body.name ?? parseNameFromIdentity(identity) ?? "imported-mind";
5676
5821
  const template = body.template ?? "claude";
5677
5822
  const nameErr = validateMindName(name);
@@ -5691,33 +5836,33 @@ ${user.trimEnd()}
5691
5836
  ` : "";
5692
5837
  ensureVoluteHome();
5693
5838
  const dest = mindDir(name);
5694
- if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
5839
+ if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
5695
5840
  const templatesRoot = findTemplatesRoot();
5696
5841
  const { composedDir, manifest } = composeTemplate(templatesRoot, template);
5697
5842
  try {
5698
5843
  copyTemplateToDir(composedDir, dest, name, manifest);
5699
5844
  applyInitFiles(dest);
5700
5845
  const { publicKeyPem: importPublicKey } = generateIdentity(dest);
5701
- writeFileSync8(resolve11(dest, "home/SOUL.md"), mergedSoul);
5702
- const wsMemoryPath = resolve11(wsDir, "MEMORY.md");
5703
- const hasMemory = existsSync7(wsMemoryPath);
5846
+ writeFileSync8(resolve12(dest, "home/SOUL.md"), mergedSoul);
5847
+ const wsMemoryPath = resolve12(wsDir, "MEMORY.md");
5848
+ const hasMemory = existsSync8(wsMemoryPath);
5704
5849
  if (hasMemory) {
5705
5850
  const existingMemory = readFileSync9(wsMemoryPath, "utf-8");
5706
5851
  writeFileSync8(
5707
- resolve11(dest, "home/MEMORY.md"),
5852
+ resolve12(dest, "home/MEMORY.md"),
5708
5853
  `${existingMemory.trimEnd()}${mergedMemoryExtra}`
5709
5854
  );
5710
5855
  } else if (user) {
5711
- writeFileSync8(resolve11(dest, "home/MEMORY.md"), `${user.trimEnd()}
5856
+ writeFileSync8(resolve12(dest, "home/MEMORY.md"), `${user.trimEnd()}
5712
5857
  `);
5713
5858
  }
5714
- const wsMemoryDir = resolve11(wsDir, "memory");
5859
+ const wsMemoryDir = resolve12(wsDir, "memory");
5715
5860
  let dailyLogCount = 0;
5716
- if (existsSync7(wsMemoryDir)) {
5717
- const destMemoryDir = resolve11(dest, "home/memory");
5861
+ if (existsSync8(wsMemoryDir)) {
5862
+ const destMemoryDir = resolve12(dest, "home/memory");
5718
5863
  const files = readdirSync2(wsMemoryDir).filter((f) => f.endsWith(".md"));
5719
5864
  for (const file of files) {
5720
- cpSync(resolve11(wsMemoryDir, file), resolve11(destMemoryDir, file));
5865
+ cpSync(resolve12(wsMemoryDir, file), resolve12(destMemoryDir, file));
5721
5866
  }
5722
5867
  dailyLogCount = files.length;
5723
5868
  }
@@ -5728,7 +5873,7 @@ ${user.trimEnd()}
5728
5873
  } catch (err) {
5729
5874
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
5730
5875
  }
5731
- const homeDir = resolve11(dest, "home");
5876
+ const homeDir = resolve12(dest, "home");
5732
5877
  ensureVoluteGroup();
5733
5878
  createMindUser(name, homeDir);
5734
5879
  await chownMindDir(dest, name);
@@ -5736,20 +5881,20 @@ ${user.trimEnd()}
5736
5881
  if (!hasMemory && dailyLogCount > 0) {
5737
5882
  await consolidateMemory(dest);
5738
5883
  }
5739
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
5884
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve12(dest, "home") } : void 0;
5740
5885
  await gitExec(["init"], { cwd: dest, mindName: name, env });
5741
5886
  await configureGitIdentity(name, { cwd: dest, mindName: name, env });
5742
5887
  await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
5743
5888
  await gitExec(["commit", "-m", "import from OpenClaw"], { cwd: dest, mindName: name, env });
5744
- const sessionFile = body.sessionPath ? resolve11(body.sessionPath) : findOpenClawSession(wsDir);
5745
- if (sessionFile && existsSync7(sessionFile)) {
5889
+ const sessionFile = body.sessionPath ? resolve12(body.sessionPath) : findOpenClawSession(wsDir);
5890
+ if (sessionFile && existsSync8(sessionFile)) {
5746
5891
  if (template === "pi") {
5747
5892
  importPiSession(sessionFile, dest);
5748
5893
  } else if (template === "claude") {
5749
5894
  const sessionId = convertSession({ sessionPath: sessionFile, projectDir: dest });
5750
- const mindRuntimeDir = resolve11(dest, ".mind");
5895
+ const mindRuntimeDir = resolve12(dest, ".mind");
5751
5896
  mkdirSync6(mindRuntimeDir, { recursive: true });
5752
- writeFileSync8(resolve11(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
5897
+ writeFileSync8(resolve12(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
5753
5898
  }
5754
5899
  }
5755
5900
  importOpenClawConnectors(name, dest);
@@ -5759,10 +5904,11 @@ ${user.trimEnd()}
5759
5904
  );
5760
5905
  return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
5761
5906
  } catch (err) {
5762
- if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
5907
+ if (existsSync8(dest)) rmSync3(dest, { recursive: true, force: true });
5763
5908
  try {
5764
5909
  await removeMind(name);
5765
- } catch {
5910
+ } catch (cleanupErr) {
5911
+ logger_default.warn(`failed to clean up registry for ${name}`, logger_default.errorData(cleanupErr));
5766
5912
  }
5767
5913
  return c.json({ error: err instanceof Error ? err.message : "Failed to import mind" }, 500);
5768
5914
  } finally {
@@ -5794,7 +5940,7 @@ ${user.trimEnd()}
5794
5940
  stage: entry.stage,
5795
5941
  dir: entry.dir
5796
5942
  });
5797
- const hasPages = existsSync7(resolve11(mindDir(entry.name), "home", "pages"));
5943
+ const hasPages = existsSync8(resolve12(mindDir(entry.name), "home", "pages"));
5798
5944
  const lastActiveAt = lastActiveMap.get(entry.name) ?? null;
5799
5945
  if (!privileged) return toPublicMind(entry, mindStatus, { hasPages, lastActiveAt });
5800
5946
  return {
@@ -5812,12 +5958,12 @@ ${user.trimEnd()}
5812
5958
  const entry = await findMind(name);
5813
5959
  if (!entry) return c.json({ error: "Mind not found" }, 404);
5814
5960
  const dir = entry.dir ?? mindDir(entry.parent ?? name);
5815
- if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
5961
+ if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
5816
5962
  const mindStatus = await getMindStatus(name, entry.port, void 0, {
5817
5963
  stage: entry.stage,
5818
5964
  dir: entry.dir
5819
5965
  });
5820
- const hasPages = existsSync7(resolve11(mindDir(name), "home", "pages"));
5966
+ const hasPages = existsSync8(resolve12(mindDir(name), "home", "pages"));
5821
5967
  if (!isPrivileged(c)) {
5822
5968
  return c.json(toPublicMind(entry, mindStatus, { hasPages }));
5823
5969
  }
@@ -5857,7 +6003,7 @@ ${user.trimEnd()}
5857
6003
  const projectDir = entry.dir ?? mindDir(name);
5858
6004
  if (entry.parent) {
5859
6005
  if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
5860
- } else if (!existsSync7(projectDir)) {
6006
+ } else if (!existsSync8(projectDir)) {
5861
6007
  return c.json({ error: "Mind directory missing" }, 404);
5862
6008
  }
5863
6009
  if (getMindManager().isRunning(name)) {
@@ -5878,7 +6024,7 @@ ${user.trimEnd()}
5878
6024
  const projectDir = entry.dir ?? mindDir(name);
5879
6025
  if (entry.parent) {
5880
6026
  if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
5881
- } else if (!existsSync7(projectDir)) {
6027
+ } else if (!existsSync8(projectDir)) {
5882
6028
  return c.json({ error: "Mind directory missing" }, 404);
5883
6029
  }
5884
6030
  let context;
@@ -5894,7 +6040,7 @@ ${user.trimEnd()}
5894
6040
  const manager = getMindManager();
5895
6041
  try {
5896
6042
  if (context?.type === "reload") {
5897
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-LIEPO6WG.js");
6043
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
5898
6044
  const sleepState = getSleepManagerIfReady2()?.getState(name);
5899
6045
  if (sleepState?.sleeping) {
5900
6046
  logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
@@ -5914,7 +6060,7 @@ ${user.trimEnd()}
5914
6060
  const variantEntry = await findMind(mergeVariantName);
5915
6061
  if (variantEntry && variantEntry.parent === baseName && variantEntry.dir && variantEntry.branch) {
5916
6062
  const projectRoot = mindDir(baseName);
5917
- if (existsSync7(variantEntry.dir)) {
6063
+ if (existsSync8(variantEntry.dir)) {
5918
6064
  const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
5919
6065
  if (status) {
5920
6066
  try {
@@ -5941,13 +6087,16 @@ ${user.trimEnd()}
5941
6087
  logger_default.error(`failed to auto-commit main worktree for ${baseName}`, logger_default.errorData(e));
5942
6088
  }
5943
6089
  }
6090
+ const preMergeHead = (await gitExec(["rev-parse", "HEAD"], { cwd: projectRoot })).trim();
5944
6091
  const memoryDelta = await mergeVariantExcludingMemory(projectRoot, variantEntry.branch);
5945
6092
  if (memoryDelta && context) context.memoryDelta = memoryDelta;
5946
- await cleanupVariant(mergeVariantName, projectRoot, variantEntry.dir);
5947
- try {
5948
- await npmInstallAsMind(projectRoot, baseName);
5949
- } catch (e) {
5950
- logger_default.error(`npm install failed after merge for ${baseName}`, logger_default.errorData(e));
6093
+ await cleanupVariant(mergeVariantName, baseName, projectRoot, variantEntry.dir);
6094
+ if (await npmInstallNeeded(projectRoot, preMergeHead)) {
6095
+ try {
6096
+ await npmInstallAsMind(projectRoot, baseName);
6097
+ } catch (e) {
6098
+ logger_default.error(`npm install failed after merge for ${baseName}`, logger_default.errorData(e));
6099
+ }
5951
6100
  }
5952
6101
  }
5953
6102
  }
@@ -6009,7 +6158,7 @@ ${user.trimEnd()}
6009
6158
  const name = c.req.param("name");
6010
6159
  const entry = await findMind(name);
6011
6160
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6012
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-LIEPO6WG.js");
6161
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6013
6162
  const sm = getSleepManagerIfReady2();
6014
6163
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6015
6164
  return c.json(sm.getState(name));
@@ -6017,7 +6166,7 @@ ${user.trimEnd()}
6017
6166
  const name = c.req.param("name");
6018
6167
  const entry = await findMind(name);
6019
6168
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6020
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-LIEPO6WG.js");
6169
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6021
6170
  const sm = getSleepManagerIfReady2();
6022
6171
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6023
6172
  if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
@@ -6037,7 +6186,7 @@ ${user.trimEnd()}
6037
6186
  const name = c.req.param("name");
6038
6187
  const entry = await findMind(name);
6039
6188
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6040
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-LIEPO6WG.js");
6189
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6041
6190
  const sm = getSleepManagerIfReady2();
6042
6191
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6043
6192
  const sleepState = sm.getState(name);
@@ -6052,7 +6201,7 @@ ${user.trimEnd()}
6052
6201
  const name = c.req.param("name");
6053
6202
  const entry = await findMind(name);
6054
6203
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6055
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-LIEPO6WG.js");
6204
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6056
6205
  const sm = getSleepManagerIfReady2();
6057
6206
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6058
6207
  const flushed = await sm.flushQueuedMessages(name);
@@ -6068,19 +6217,19 @@ ${user.trimEnd()}
6068
6217
  if (body.displayName !== void 0) profile.displayName = body.displayName;
6069
6218
  if (body.description !== void 0) profile.description = body.description;
6070
6219
  if (body.avatar !== void 0) {
6071
- const homeDir = resolve11(dir, "home");
6220
+ const homeDir = resolve12(dir, "home");
6072
6221
  const avatarPath = safeResolveWithinBase(homeDir, body.avatar);
6073
6222
  if (!avatarPath) {
6074
6223
  return c.json({ error: "Avatar path must be inside the mind's home directory" }, 400);
6075
6224
  }
6076
- if (!existsSync7(avatarPath)) {
6225
+ if (!existsSync8(avatarPath)) {
6077
6226
  return c.json({ error: `Avatar file not found: ${relative(homeDir, avatarPath)}` }, 400);
6078
6227
  }
6079
6228
  profile.avatar = relative(homeDir, avatarPath);
6080
6229
  }
6081
6230
  config2.profile = profile;
6082
6231
  writeVoluteConfig(dir, config2);
6083
- const { syncMindProfile: syncMindProfile2 } = await import("./auth-DT7GY7EZ.js");
6232
+ const { syncMindProfile: syncMindProfile2 } = await import("./auth-X6EMNEGB.js");
6084
6233
  await syncMindProfile2(name, profile);
6085
6234
  broadcast({ type: "profile_updated", mind: name, summary: `${name} profile updated` });
6086
6235
  return c.json({ ok: true });
@@ -6124,7 +6273,7 @@ ${user.trimEnd()}
6124
6273
  });
6125
6274
  }
6126
6275
  if (!force) {
6127
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-LIEPO6WG.js");
6276
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-7JXEQQ2P.js");
6128
6277
  if (getSleepManagerIfReady2()?.isSleeping(name)) {
6129
6278
  return c.json({ output: "" });
6130
6279
  }
@@ -6179,7 +6328,7 @@ ${user.trimEnd()}
6179
6328
  }
6180
6329
  }
6181
6330
  const dir = entry.dir ?? mindDir(name);
6182
- const { evaluateSeedChecklist: evaluateSeedChecklist2 } = await import("./seed-readiness-QRA46ZJQ.js");
6331
+ const { evaluateSeedChecklist: evaluateSeedChecklist2 } = await import("./seed-readiness-DYOVCYHN.js");
6183
6332
  const checklist = evaluateSeedChecklist2(dir);
6184
6333
  const done = [];
6185
6334
  const remaining = [];
@@ -6221,7 +6370,7 @@ ${user.trimEnd()}
6221
6370
  try {
6222
6371
  const sproutedDir = entry.dir ?? mindDir(name);
6223
6372
  if (setupDefaultDreaming(sproutedDir).schedulesChanged) {
6224
- const { getScheduler: getScheduler2 } = await import("./scheduler-UV6RUJ7P.js");
6373
+ const { getScheduler: getScheduler2 } = await import("./scheduler-TNBN54ZK.js");
6225
6374
  getScheduler2().loadSchedules(name, sproutedDir);
6226
6375
  }
6227
6376
  } catch (err) {
@@ -6231,7 +6380,7 @@ ${user.trimEnd()}
6231
6380
  const spiritName = getSpiritName();
6232
6381
  const spiritEntry = await findMind(spiritName);
6233
6382
  if (spiritEntry) {
6234
- const { firstWeekSchedules, spiritDir } = await import("./spirit-IL5EMWYZ.js");
6383
+ const { firstWeekSchedules, spiritDir } = await import("./spirit-25JVAL3M.js");
6235
6384
  const sDir = spiritEntry.dir ?? spiritDir();
6236
6385
  const spiritConfig = readVoluteConfig(sDir);
6237
6386
  if (spiritConfig) {
@@ -6245,7 +6394,7 @@ ${user.trimEnd()}
6245
6394
  spiritConfig.schedules = schedules;
6246
6395
  writeVoluteConfig(sDir, spiritConfig);
6247
6396
  try {
6248
- const { getScheduler: getScheduler2 } = await import("./scheduler-UV6RUJ7P.js");
6397
+ const { getScheduler: getScheduler2 } = await import("./scheduler-TNBN54ZK.js");
6249
6398
  getScheduler2().loadSchedules(spiritName, sDir);
6250
6399
  } catch (err) {
6251
6400
  logger_default.warn(
@@ -6276,17 +6425,17 @@ ${user.trimEnd()}
6276
6425
  const variants = await findVariants(name);
6277
6426
  for (const s of variants) {
6278
6427
  if (s.dir) {
6279
- await cleanupVariant(s.name, dir, s.dir, { stop: true });
6428
+ await cleanupVariant(s.name, name, dir, s.dir, { stop: true });
6280
6429
  }
6281
6430
  }
6282
6431
  await removeMind(name);
6283
6432
  await deleteMindUser2(name);
6284
6433
  invalidateMindUserCache(name);
6285
6434
  const state = stateDir(name);
6286
- if (existsSync7(state)) {
6435
+ if (existsSync8(state)) {
6287
6436
  rmSync3(state, { recursive: true, force: true });
6288
6437
  }
6289
- if (force && existsSync7(dir)) {
6438
+ if (force && existsSync8(dir)) {
6290
6439
  rmSync3(dir, { recursive: true, force: true });
6291
6440
  deleteMindUser(name);
6292
6441
  }
@@ -6301,7 +6450,7 @@ ${user.trimEnd()}
6301
6450
  const entry = await findMind(mindName);
6302
6451
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6303
6452
  const dir = mindDir(mindName);
6304
- if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
6453
+ if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
6305
6454
  let body = {};
6306
6455
  try {
6307
6456
  body = await c.req.json();
@@ -6314,21 +6463,21 @@ ${user.trimEnd()}
6314
6463
  }
6315
6464
  const UPGRADE_BRANCH = "upgrade";
6316
6465
  const upgradeVariantName = `${mindName}-upgrade`;
6317
- const worktreeDir = resolve11(dir, ".variants", UPGRADE_BRANCH);
6466
+ const worktreeDir = resolve12(dir, ".variants", UPGRADE_BRANCH);
6318
6467
  if (body.abort) {
6319
- if (!existsSync7(worktreeDir)) {
6468
+ if (!existsSync8(worktreeDir)) {
6320
6469
  return c.json({ error: "No upgrade in progress" }, 400);
6321
6470
  }
6322
6471
  try {
6323
6472
  try {
6324
- const gitDirContent = readFileSync9(resolve11(worktreeDir, ".git"), "utf-8").trim();
6473
+ const gitDirContent = readFileSync9(resolve12(worktreeDir, ".git"), "utf-8").trim();
6325
6474
  const gitDir = gitDirContent.replace("gitdir: ", "");
6326
- if (existsSync7(resolve11(gitDir, "MERGE_HEAD"))) {
6475
+ if (existsSync8(resolve12(gitDir, "MERGE_HEAD"))) {
6327
6476
  await gitExec(["merge", "--abort"], { cwd: worktreeDir });
6328
6477
  }
6329
6478
  } catch {
6330
6479
  }
6331
- await cleanupVariant(upgradeVariantName, dir, worktreeDir, { stop: true });
6480
+ await cleanupVariant(upgradeVariantName, mindName, dir, worktreeDir, { stop: true });
6332
6481
  try {
6333
6482
  await gitExec(["branch", "-D", UPGRADE_BRANCH], { cwd: dir });
6334
6483
  } catch {
@@ -6342,7 +6491,7 @@ ${user.trimEnd()}
6342
6491
  }
6343
6492
  }
6344
6493
  if (body.continue) {
6345
- if (!existsSync7(worktreeDir)) {
6494
+ if (!existsSync8(worktreeDir)) {
6346
6495
  return c.json({ error: "No upgrade in progress" }, 400);
6347
6496
  }
6348
6497
  const status = await gitExec(["status", "--porcelain"], { cwd: worktreeDir });
@@ -6392,9 +6541,9 @@ ${user.trimEnd()}
6392
6541
  }
6393
6542
  }
6394
6543
  if (body.accept) {
6395
- if (existsSync7(worktreeDir)) {
6544
+ if (existsSync8(worktreeDir)) {
6396
6545
  try {
6397
- await cleanupVariant(upgradeVariantName, dir, worktreeDir, { stop: true });
6546
+ await cleanupVariant(upgradeVariantName, mindName, dir, worktreeDir, { stop: true });
6398
6547
  } catch (err) {
6399
6548
  logger_default.warn(`failed to clean up legacy upgrade variant for ${mindName}`, logger_default.errorData(err));
6400
6549
  }
@@ -6407,7 +6556,7 @@ ${user.trimEnd()}
6407
6556
  }
6408
6557
  if (body.diff) {
6409
6558
  try {
6410
- if (!existsSync7(resolve11(dir, ".git"))) {
6559
+ if (!existsSync8(resolve12(dir, ".git"))) {
6411
6560
  return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
6412
6561
  }
6413
6562
  await updateTemplateBranch(dir, template, mindName);
@@ -6425,22 +6574,22 @@ ${user.trimEnd()}
6425
6574
  );
6426
6575
  }
6427
6576
  }
6428
- if (existsSync7(worktreeDir)) {
6577
+ if (existsSync8(worktreeDir)) {
6429
6578
  return c.json(
6430
6579
  { error: "Upgrade variant already exists. Use continue or delete it first." },
6431
6580
  409
6432
6581
  );
6433
6582
  }
6434
- if (!existsSync7(resolve11(dir, ".git"))) {
6583
+ if (!existsSync8(resolve12(dir, ".git"))) {
6435
6584
  try {
6436
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dir, "home") } : void 0;
6585
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve12(dir, "home") } : void 0;
6437
6586
  await gitExec(["init"], { cwd: dir, mindName, env });
6438
6587
  await configureGitIdentity(mindName, { cwd: dir, mindName, env });
6439
6588
  await gitExec(["add", "-A"], { cwd: dir, mindName, env });
6440
6589
  await gitExec(["commit", "-m", "initial commit"], { cwd: dir, mindName, env });
6441
6590
  await chownMindDir(dir, mindName);
6442
6591
  } catch (err) {
6443
- rmSync3(resolve11(dir, ".git"), { recursive: true, force: true });
6592
+ rmSync3(resolve12(dir, ".git"), { recursive: true, force: true });
6444
6593
  return c.json(
6445
6594
  {
6446
6595
  error: `Git initialization failed: ${err instanceof Error ? err.message : String(err)}`
@@ -6455,8 +6604,8 @@ ${user.trimEnd()}
6455
6604
  } catch {
6456
6605
  }
6457
6606
  await updateTemplateBranch(dir, template, mindName);
6458
- const parentDir = resolve11(dir, ".variants");
6459
- if (!existsSync7(parentDir)) {
6607
+ const parentDir = resolve12(dir, ".variants");
6608
+ if (!existsSync8(parentDir)) {
6460
6609
  mkdirSync6(parentDir, { recursive: true });
6461
6610
  }
6462
6611
  await gitExec(["worktree", "add", "-b", UPGRADE_BRANCH, worktreeDir], { cwd: dir });
@@ -6519,7 +6668,7 @@ ${user.trimEnd()}
6519
6668
  return c.json(result);
6520
6669
  } catch (err) {
6521
6670
  try {
6522
- await cleanupVariant(upgradeVariantName, dir, worktreeDir);
6671
+ await cleanupVariant(upgradeVariantName, mindName, dir, worktreeDir);
6523
6672
  } catch (cleanupErr) {
6524
6673
  logger_default.warn(`cleanup failed after upgrade error for ${mindName}`, logger_default.errorData(cleanupErr));
6525
6674
  }
@@ -6589,11 +6738,11 @@ ${user.trimEnd()}
6589
6738
  const entry = await findMind(name);
6590
6739
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6591
6740
  const dir = entry.dir ?? mindDir(name);
6592
- if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
6741
+ if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
6593
6742
  let config2 = readVoluteConfig(dir);
6594
6743
  if (!config2 && entry.template === "pi") {
6595
- const piConfigPath = resolve11(dir, "home/.config/config.json");
6596
- if (existsSync7(piConfigPath)) {
6744
+ const piConfigPath = resolve12(dir, "home/.config/config.json");
6745
+ if (existsSync8(piConfigPath)) {
6597
6746
  try {
6598
6747
  config2 = JSON.parse(readFileSync9(piConfigPath, "utf-8"));
6599
6748
  } catch {
@@ -6601,8 +6750,8 @@ ${user.trimEnd()}
6601
6750
  }
6602
6751
  }
6603
6752
  let templateConfig = {};
6604
- const configJsonPath = resolve11(dir, "home/.config/config.json");
6605
- if (existsSync7(configJsonPath)) {
6753
+ const configJsonPath = resolve12(dir, "home/.config/config.json");
6754
+ if (existsSync8(configJsonPath)) {
6606
6755
  try {
6607
6756
  templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
6608
6757
  } catch {
@@ -6644,7 +6793,7 @@ ${user.trimEnd()}
6644
6793
  const entry = await findMind(name);
6645
6794
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6646
6795
  const dir = entry.dir ?? mindDir(name);
6647
- if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
6796
+ if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
6648
6797
  const body = c.req.valid("json");
6649
6798
  const existing = readVoluteConfig(dir) ?? {};
6650
6799
  if (body.model !== void 0) existing.model = body.model;
@@ -6670,14 +6819,14 @@ ${user.trimEnd()}
6670
6819
  }
6671
6820
  writeVoluteConfig(dir, existing);
6672
6821
  if (body.unescapeNewlines !== void 0) {
6673
- const { clearEchoTextCache } = await import("./echo-text-WYAAODBV.js");
6822
+ const { clearEchoTextCache } = await import("./echo-text-6ANI5HHN.js");
6674
6823
  clearEchoTextCache(name);
6675
6824
  }
6676
6825
  const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.compaction !== void 0;
6677
6826
  if (needsConfigJson) {
6678
- const configJsonPath = resolve11(dir, "home/.config/config.json");
6827
+ const configJsonPath = resolve12(dir, "home/.config/config.json");
6679
6828
  let templateConfig = {};
6680
- if (existsSync7(configJsonPath)) {
6829
+ if (existsSync8(configJsonPath)) {
6681
6830
  try {
6682
6831
  templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
6683
6832
  } catch {
@@ -6707,7 +6856,7 @@ ${user.trimEnd()}
6707
6856
  }
6708
6857
  if (entry.mindType === "spirit" && body.model !== void 0) {
6709
6858
  try {
6710
- const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-CAJFOR2N.js");
6859
+ const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-WZSXHHRJ.js");
6711
6860
  const globalConfig = readGlobalConfig2();
6712
6861
  globalConfig.spiritModel = body.model;
6713
6862
  writeGlobalConfig2(globalConfig);
@@ -6750,7 +6899,7 @@ ${user.trimEnd()}
6750
6899
  if (!body.systemPrompt || !body.message) {
6751
6900
  return c.json({ error: "systemPrompt and message required" }, 400);
6752
6901
  }
6753
- const { aiComplete: aiCompleteFn, isAiConfigured: isAiConfigured2 } = await import("./ai-service-V4CTNGI3.js");
6902
+ const { aiComplete: aiCompleteFn, isAiConfigured: isAiConfigured2 } = await import("./ai-service-YW5SWCSB.js");
6754
6903
  if (!isAiConfigured2()) {
6755
6904
  return c.json({ error: "AI service not configured" }, 503);
6756
6905
  }
@@ -7444,7 +7593,7 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
7444
7593
  const entry = await findMind(name);
7445
7594
  if (!entry) return c.json({ error: "Mind not found" }, 404);
7446
7595
  const body = await c.req.text();
7447
- const { deliverEvent: deliverEvent2 } = await import("./system-events-A6IGCEC3.js");
7596
+ const { deliverEvent: deliverEvent2 } = await import("./system-events-ZPSH63QX.js");
7448
7597
  const { id, delivered } = await deliverEvent2(name, {
7449
7598
  type: "webhook",
7450
7599
  body,
@@ -7462,14 +7611,14 @@ var schedules_default = app15;
7462
7611
  // packages/daemon/src/web/api/setup.ts
7463
7612
  import { mkdirSync as mkdirSync7 } from "fs";
7464
7613
  import { homedir as homedir2 } from "os";
7465
- import { resolve as resolve12 } from "path";
7614
+ import { resolve as resolve13 } from "path";
7466
7615
  import { Hono as Hono19 } from "hono";
7467
7616
  import { setCookie as setCookie2 } from "hono/cookie";
7468
7617
  var DEFAULT_API_URL2 = "https://volute.systems";
7469
7618
  var setup = new Hono19();
7470
7619
  function writeSetupConfig(systemName, description) {
7471
- const configHome = process.env.VOLUTE_HOME ?? resolve12(homedir2(), ".volute");
7472
- const mindsDir = resolve12(configHome, "minds");
7620
+ const configHome = process.env.VOLUTE_HOME ?? resolve13(homedir2(), ".volute");
7621
+ const mindsDir = resolve13(configHome, "minds");
7473
7622
  mkdirSync7(configHome, { recursive: true });
7474
7623
  mkdirSync7(mindsDir, { recursive: true });
7475
7624
  const existingConfig = readGlobalConfig();
@@ -7503,11 +7652,11 @@ setup.get("/status", async (c) => {
7503
7652
  let hasAccount = false;
7504
7653
  if (hasSystem) {
7505
7654
  try {
7506
- const { listUsersByType: listUsersByType2 } = await import("./auth-DT7GY7EZ.js");
7655
+ const { listUsersByType: listUsersByType2 } = await import("./auth-X6EMNEGB.js");
7507
7656
  const brains = await listUsersByType2("human");
7508
7657
  hasAccount = brains.length > 0;
7509
7658
  } catch (err) {
7510
- logger_default.debug("could not check for existing accounts during setup status", logger_default.errorData(err));
7659
+ logger_default.error("could not check for existing accounts during setup status", logger_default.errorData(err));
7511
7660
  }
7512
7661
  }
7513
7662
  return c.json({
@@ -7715,7 +7864,7 @@ setup.post("/account", async (c) => {
7715
7864
  }
7716
7865
  }
7717
7866
  try {
7718
- const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-DT7GY7EZ.js");
7867
+ const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-X6EMNEGB.js");
7719
7868
  const user = await createUser2(body.username.trim(), body.password);
7720
7869
  if (body.displayName?.trim()) {
7721
7870
  await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
@@ -7761,7 +7910,7 @@ setup.post("/models", async (c) => {
7761
7910
  return c.json({ error: "Spirit model is required" }, 400);
7762
7911
  }
7763
7912
  try {
7764
- const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-V4CTNGI3.js");
7913
+ const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-YW5SWCSB.js");
7765
7914
  setEnabledModels3(body.models);
7766
7915
  const config2 = readGlobalConfig();
7767
7916
  config2.spiritModel = body.spiritModel.trim();
@@ -7808,15 +7957,15 @@ setup.post("/complete", async (c) => {
7808
7957
  return c.json({ error: "Setup already complete" }, 400);
7809
7958
  }
7810
7959
  try {
7811
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-IL5EMWYZ.js");
7812
- const { startSpiritFull } = await import("./mind-service-5TA7UJAT.js");
7960
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-25JVAL3M.js");
7961
+ const { startSpiritFull } = await import("./mind-service-DZCUUC7J.js");
7813
7962
  await ensureSpiritProject();
7814
7963
  await syncSpiritTemplate();
7815
7964
  const warnings = [];
7816
7965
  const config2 = readGlobalConfig();
7817
7966
  if (config2.setup?.service && config2.setup?.type === "local") {
7818
7967
  try {
7819
- const { installUserService } = await import("./service-install-MOKTEG7B.js");
7968
+ const { installUserService } = await import("./service-install-2EWD7KXD.js");
7820
7969
  const installed = await installUserService(config2.port, config2.hostname);
7821
7970
  if (!installed) {
7822
7971
  warnings.push("Service installation is not supported on this platform.");
@@ -7846,8 +7995,8 @@ setup.post("/complete", async (c) => {
7846
7995
  }
7847
7996
  let spiritConversationId;
7848
7997
  try {
7849
- const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-DT7GY7EZ.js");
7850
- const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-S2232Y5I.js");
7998
+ const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-X6EMNEGB.js");
7999
+ const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-ZL6PHROD.js");
7851
8000
  const spiritUser = await getOrCreateMindUser2(spiritName);
7852
8001
  const brains = await listUsersByType2("human");
7853
8002
  const admin2 = brains.find((u) => u.role === "admin");
@@ -7869,8 +8018,8 @@ setup.post("/complete", async (c) => {
7869
8018
  logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
7870
8019
  if (spiritConversationId && spiritStarted) {
7871
8020
  try {
7872
- const { deliverMessage: deliverMessage2 } = await import("./message-delivery-3456PXB7.js");
7873
- const { listUsersByType: listUsers2 } = await import("./auth-DT7GY7EZ.js");
8021
+ const { deliverMessage: deliverMessage2 } = await import("./message-delivery-JHMAJ2GU.js");
8022
+ const { listUsersByType: listUsers2 } = await import("./auth-X6EMNEGB.js");
7874
8023
  const admins = await listUsers2("human");
7875
8024
  const admin2 = admins.find((u) => u.role === "admin");
7876
8025
  if (admin2) {
@@ -7911,9 +8060,9 @@ setup.post("/complete", async (c) => {
7911
8060
  var setup_default = setup;
7912
8061
 
7913
8062
  // packages/daemon/src/web/api/skills.ts
7914
- import { existsSync as existsSync8, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync4 } from "fs";
8063
+ import { existsSync as existsSync9, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync4 } from "fs";
7915
8064
  import { tmpdir } from "os";
7916
- import { join, resolve as resolve13 } from "path";
8065
+ import { join, resolve as resolve14 } from "path";
7917
8066
  import AdmZip from "adm-zip";
7918
8067
  import { Hono as Hono20 } from "hono";
7919
8068
  var app16 = new Hono20().get("/", async (c) => {
@@ -7989,19 +8138,19 @@ var app16 = new Hono20().get("/", async (c) => {
7989
8138
  try {
7990
8139
  const zip = new AdmZip(buffer);
7991
8140
  for (const entry of zip.getEntries()) {
7992
- const target = resolve13(tmpDir, entry.entryName);
8141
+ const target = resolve14(tmpDir, entry.entryName);
7993
8142
  if (!target.startsWith(tmpDir)) {
7994
8143
  return c.json({ error: "Invalid zip: paths must not escape archive" }, 400);
7995
8144
  }
7996
8145
  }
7997
8146
  zip.extractAllTo(tmpDir, true);
7998
8147
  let skillDir = null;
7999
- if (existsSync8(join(tmpDir, "SKILL.md"))) {
8148
+ if (existsSync9(join(tmpDir, "SKILL.md"))) {
8000
8149
  skillDir = tmpDir;
8001
8150
  } else {
8002
8151
  const entries = readdirSync3(tmpDir, { withFileTypes: true }).filter((e) => e.isDirectory());
8003
8152
  for (const entry of entries) {
8004
- if (existsSync8(join(tmpDir, entry.name, "SKILL.md"))) {
8153
+ if (existsSync9(join(tmpDir, entry.name, "SKILL.md"))) {
8005
8154
  skillDir = join(tmpDir, entry.name);
8006
8155
  break;
8007
8156
  }
@@ -8363,8 +8512,8 @@ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
8363
8512
  });
8364
8513
  }, 15e3);
8365
8514
  cleanups.push(() => clearInterval(keepAlive));
8366
- await new Promise((resolve19) => {
8367
- stream.onAbort(() => resolve19());
8515
+ await new Promise((resolve20) => {
8516
+ stream.onAbort(() => resolve20());
8368
8517
  });
8369
8518
  } finally {
8370
8519
  for (const cleanup of cleanups) {
@@ -8382,7 +8531,7 @@ var events_default = app20;
8382
8531
  import { Hono as Hono25 } from "hono";
8383
8532
 
8384
8533
  // packages/daemon/src/lib/events/feed.ts
8385
- import { and as and6, desc as desc5, eq as eq8, gte as gte3, inArray as inArray3, sql as sql5 } from "drizzle-orm";
8534
+ import { and as and6, desc as desc5, eq as eq8, gte as gte3, inArray as inArray3, ne, sql as sql5 } from "drizzle-orm";
8386
8535
  var BURST_GAP_MS = 45 * 6e4;
8387
8536
  var FEED_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
8388
8537
  var LIFECYCLE_TYPES = [
@@ -8459,7 +8608,13 @@ async function getChatFeedEvents(opts) {
8459
8608
  content: messages.content,
8460
8609
  created_at: messages.created_at,
8461
8610
  conversation_type: conversations.type
8462
- }).from(messages).innerJoin(conversations, eq8(conversations.id, messages.conversation_id)).where(and6(gte3(messages.created_at, cutoff), eq8(conversations.private, 0))).orderBy(desc5(messages.id)).limit(5e3);
8611
+ }).from(messages).innerJoin(conversations, eq8(conversations.id, messages.conversation_id)).where(
8612
+ and6(
8613
+ gte3(messages.created_at, cutoff),
8614
+ eq8(conversations.private, 0),
8615
+ ne(messages.role, "event")
8616
+ )
8617
+ ).orderBy(desc5(messages.id)).limit(5e3);
8463
8618
  const ascending = rows.reverse();
8464
8619
  const bursts = splitIntoBursts(ascending);
8465
8620
  bursts.sort((a, b) => {
@@ -8639,23 +8794,23 @@ var app21 = new Hono25().use("*", authMiddleware).get("/", async (c) => {
8639
8794
  var feed_default = app21;
8640
8795
 
8641
8796
  // packages/daemon/src/web/api/variants.ts
8642
- import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
8643
- import { resolve as resolve16 } from "path";
8797
+ import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
8798
+ import { resolve as resolve17 } from "path";
8644
8799
  import { Hono as Hono26 } from "hono";
8645
8800
 
8646
8801
  // packages/daemon/src/lib/mind/farewell.ts
8647
- import { existsSync as existsSync9, readFileSync as readFileSync10, rmSync as rmSync5 } from "fs";
8648
- import { resolve as resolve14 } from "path";
8802
+ import { existsSync as existsSync10, readFileSync as readFileSync10, rmSync as rmSync5 } from "fs";
8803
+ import { resolve as resolve15 } from "path";
8649
8804
  var flog = logger_default.child("farewell");
8650
8805
  var FAREWELL_RELPATH = ".mind/farewell.md";
8651
8806
  var FAREWELL_MIND_PATH = "../.mind/farewell.md";
8652
8807
  var FAREWELL_TIMEOUT_MS = 12e4;
8653
8808
  function farewellPath(variantDir) {
8654
- return resolve14(variantDir, FAREWELL_RELPATH);
8809
+ return resolve15(variantDir, FAREWELL_RELPATH);
8655
8810
  }
8656
8811
  function readFarewell(variantDir) {
8657
8812
  const path = farewellPath(variantDir);
8658
- if (!existsSync9(path)) return void 0;
8813
+ if (!existsSync10(path)) return void 0;
8659
8814
  try {
8660
8815
  const text = readFileSync10(path, "utf-8").trim();
8661
8816
  return text || void 0;
@@ -8678,7 +8833,7 @@ function waitForFarewell(name, variantDir, timeoutMs) {
8678
8833
  const unsub = subscribe((event) => {
8679
8834
  if (event.mind !== name) return;
8680
8835
  if (event.type !== "mind_done" && event.type !== "mind_idle") return;
8681
- if (existsSync9(farewellPath(variantDir))) cleanup();
8836
+ if (existsSync10(farewellPath(variantDir))) cleanup();
8682
8837
  });
8683
8838
  return { done, cancel: cleanup };
8684
8839
  }
@@ -8712,7 +8867,7 @@ async function runFarewellTurn(opts) {
8712
8867
  // packages/daemon/src/lib/mind/spawn-server.ts
8713
8868
  import { spawn as spawn4 } from "child_process";
8714
8869
  import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync11, statSync as statSync3 } from "fs";
8715
- import { resolve as resolve15 } from "path";
8870
+ import { resolve as resolve16 } from "path";
8716
8871
  async function spawnServer(cwd, port, options) {
8717
8872
  let cmd = process.env.VOLUTE_NODE_PATH ?? process.execPath;
8718
8873
  let args = ["--import", "tsx", "src/server.ts", "--port", String(port)];
@@ -8733,31 +8888,31 @@ function spawnAttached(cmd, args, cwd) {
8733
8888
  cwd,
8734
8889
  stdio: ["ignore", "pipe", "pipe"]
8735
8890
  });
8736
- return new Promise((resolve19) => {
8737
- const timeout = setTimeout(() => resolve19(null), 3e4);
8891
+ return new Promise((resolve20) => {
8892
+ const timeout = setTimeout(() => resolve20(null), 3e4);
8738
8893
  function checkOutput(data) {
8739
8894
  const match = data.toString().match(/listening on :(\d+)/);
8740
8895
  if (match) {
8741
8896
  clearTimeout(timeout);
8742
- resolve19({ child, actualPort: parseInt(match[1], 10) });
8897
+ resolve20({ child, actualPort: parseInt(match[1], 10) });
8743
8898
  }
8744
8899
  }
8745
8900
  child.stdout?.on("data", checkOutput);
8746
8901
  child.stderr?.on("data", checkOutput);
8747
8902
  child.on("error", () => {
8748
8903
  clearTimeout(timeout);
8749
- resolve19(null);
8904
+ resolve20(null);
8750
8905
  });
8751
8906
  child.on("exit", () => {
8752
8907
  clearTimeout(timeout);
8753
- resolve19(null);
8908
+ resolve20(null);
8754
8909
  });
8755
8910
  });
8756
8911
  }
8757
8912
  function spawnDetached(cmd, args, cwd, logDir) {
8758
- const logsDir = logDir ?? resolve15(cwd, ".mind", "logs");
8913
+ const logsDir = logDir ?? resolve16(cwd, ".mind", "logs");
8759
8914
  mkdirSync8(logsDir, { recursive: true });
8760
- const logPath = resolve15(logsDir, "mind.log");
8915
+ const logPath = resolve16(logsDir, "mind.log");
8761
8916
  let startOffset = 0;
8762
8917
  try {
8763
8918
  startOffset = statSync3(logPath).size;
@@ -8898,11 +9053,11 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
8898
9053
  return c.json({ error: `Name already in use: ${variantName}` }, 409);
8899
9054
  }
8900
9055
  const projectRoot = entry.dir ?? mindDir(mindName);
8901
- const variantDir = resolve16(projectRoot, ".variants", variantName);
8902
- if (existsSync10(variantDir)) {
9056
+ const variantDir = resolve17(projectRoot, ".variants", variantName);
9057
+ if (existsSync11(variantDir)) {
8903
9058
  return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
8904
9059
  }
8905
- mkdirSync9(resolve16(projectRoot, ".variants"), { recursive: true });
9060
+ mkdirSync9(resolve17(projectRoot, ".variants"), { recursive: true });
8906
9061
  try {
8907
9062
  await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
8908
9063
  } catch (e) {
@@ -8921,18 +9076,10 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
8921
9076
  }
8922
9077
  const rollbackSplit = async () => {
8923
9078
  try {
8924
- await cleanupVariant(variantName, projectRoot, variantDir, { stop: true });
9079
+ await cleanupVariant(variantName, mindName, projectRoot, variantDir, { stop: true });
8925
9080
  } catch (err2) {
8926
9081
  logger_default.warn(`failed to roll back split of ${variantName}`, logger_default.errorData(err2));
8927
9082
  }
8928
- try {
8929
- await chownMindDir(projectRoot, mindName);
8930
- } catch (err2) {
8931
- logger_default.warn(
8932
- `failed to restore ${mindName} ownership after split rollback`,
8933
- logger_default.errorData(err2)
8934
- );
8935
- }
8936
9083
  };
8937
9084
  try {
8938
9085
  await chownMindDir(projectRoot, mindName);
@@ -8946,7 +9093,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
8946
9093
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
8947
9094
  await exec(cmd, args, {
8948
9095
  cwd: variantDir,
8949
- env: { ...process.env, HOME: resolve16(variantDir, "home") }
9096
+ env: { ...process.env, HOME: resolve17(variantDir, "home") }
8950
9097
  });
8951
9098
  } else {
8952
9099
  await exec("npm", ["install"], { cwd: variantDir });
@@ -8957,7 +9104,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
8957
9104
  return c.json({ error: `npm install failed: ${msg}` }, 500);
8958
9105
  }
8959
9106
  if (body.soul) {
8960
- writeFileSync9(resolve16(variantDir, "home/SOUL.md"), body.soul);
9107
+ writeFileSync9(resolve17(variantDir, "home/SOUL.md"), body.soul);
8961
9108
  }
8962
9109
  const variantPort = body.port ?? await nextPort();
8963
9110
  try {
@@ -9040,7 +9187,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9040
9187
  logger_default.warn(`farewell turn failed for ${variantName}`, logger_default.errorData(err));
9041
9188
  }
9042
9189
  try {
9043
- if (existsSync10(variantEntry.dir)) {
9190
+ if (existsSync11(variantEntry.dir)) {
9044
9191
  const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
9045
9192
  if (status) {
9046
9193
  try {
@@ -9098,12 +9245,12 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9098
9245
  { conflicts: err.conflicts }
9099
9246
  );
9100
9247
  }
9101
- await cleanupVariant(variantName, projectRoot, variantEntry.dir, { stop: true });
9248
+ await cleanupVariant(variantName, mindName, projectRoot, variantEntry.dir, { stop: true });
9102
9249
  await chownMindDir(projectRoot, mindName);
9103
9250
  if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
9104
9251
  try {
9105
- const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-GSOUARW4.js");
9106
- const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-4UF6OCOE.js");
9252
+ const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-YKWMVYMM.js");
9253
+ const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-TRC2HJXR.js");
9107
9254
  const tmpl = parentEntry.template ?? "claude";
9108
9255
  await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
9109
9256
  } catch (err) {
@@ -9116,7 +9263,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9116
9263
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
9117
9264
  await exec(cmd, args, {
9118
9265
  cwd: projectRoot,
9119
- env: { ...process.env, HOME: resolve16(projectRoot, "home") }
9266
+ env: { ...process.env, HOME: resolve17(projectRoot, "home") }
9120
9267
  });
9121
9268
  } else {
9122
9269
  await exec("npm", ["install"], { cwd: projectRoot });
@@ -9164,7 +9311,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9164
9311
  }
9165
9312
  if (!variantEntry.dir) return c.json({ error: `Variant ${variantName} has no directory` }, 500);
9166
9313
  const projectRoot = parentEntry.dir ?? mindDir(mindName);
9167
- await cleanupVariant(variantName, projectRoot, variantEntry.dir, { stop: true });
9314
+ await cleanupVariant(variantName, mindName, projectRoot, variantEntry.dir, { stop: true });
9168
9315
  return c.json({ ok: true });
9169
9316
  });
9170
9317
  var variants_default = app22;
@@ -9603,11 +9750,11 @@ var app24 = new Hono28().get("/:name/conversations/:id/events", async (c) => {
9603
9750
  if (!stream.aborted) console.error("[chat] SSE ping error:", err);
9604
9751
  });
9605
9752
  }, 15e3);
9606
- await new Promise((resolve19) => {
9753
+ await new Promise((resolve20) => {
9607
9754
  stream.onAbort(() => {
9608
9755
  unsubscribe();
9609
9756
  clearInterval(keepAlive);
9610
- resolve19();
9757
+ resolve20();
9611
9758
  });
9612
9759
  });
9613
9760
  });
@@ -9824,10 +9971,10 @@ app26.route("/api/conversations", conversations_default);
9824
9971
  var app_default = app26;
9825
9972
 
9826
9973
  // packages/daemon/src/web/server.ts
9827
- import { existsSync as existsSync11 } from "fs";
9974
+ import { existsSync as existsSync12 } from "fs";
9828
9975
  import { readFile as readFile2, stat as stat2 } from "fs/promises";
9829
9976
  import { createServer as createHttpsServer } from "https";
9830
- import { dirname as dirname3, extname as extname3, resolve as resolve17 } from "path";
9977
+ import { dirname as dirname3, extname as extname3, resolve as resolve18 } from "path";
9831
9978
  import { serve } from "@hono/node-server";
9832
9979
  var MIME_TYPES2 = {
9833
9980
  ".html": "text/html",
@@ -9846,8 +9993,8 @@ async function startServer({
9846
9993
  let assetsDir = "";
9847
9994
  let searchDir = dirname3(new URL(import.meta.url).pathname);
9848
9995
  for (let i = 0; i < 5; i++) {
9849
- const candidate = resolve17(searchDir, "dist", "web-assets");
9850
- if (existsSync11(candidate)) {
9996
+ const candidate = resolve18(searchDir, "dist", "web-assets");
9997
+ if (existsSync12(candidate)) {
9851
9998
  assetsDir = candidate;
9852
9999
  break;
9853
10000
  }
@@ -9857,7 +10004,7 @@ async function startServer({
9857
10004
  app_default.get("*", async (c) => {
9858
10005
  const urlPath = new URL(c.req.url).pathname;
9859
10006
  if (urlPath.startsWith("/api/") || urlPath.startsWith("/ext/")) return c.notFound();
9860
- const filePath = resolve17(assetsDir, urlPath.slice(1));
10007
+ const filePath = resolve18(assetsDir, urlPath.slice(1));
9861
10008
  if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
9862
10009
  const s = await stat2(filePath).catch(() => null);
9863
10010
  if (s?.isFile()) {
@@ -9870,7 +10017,7 @@ async function startServer({
9870
10017
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
9871
10018
  return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
9872
10019
  }
9873
- const indexPath = resolve17(assetsDir, "index.html");
10020
+ const indexPath = resolve18(assetsDir, "index.html");
9874
10021
  const indexStat = await stat2(indexPath).catch(() => null);
9875
10022
  if (indexStat?.isFile()) {
9876
10023
  const body = await readFile2(indexPath, "utf-8");
@@ -9887,10 +10034,10 @@ async function startServer({
9887
10034
  createServer: createHttpsServer,
9888
10035
  serverOptions: { key: tls.key, cert: tls.cert }
9889
10036
  });
9890
- await new Promise((resolve19, reject) => {
10037
+ await new Promise((resolve20, reject) => {
9891
10038
  server2.on("listening", () => {
9892
10039
  logger_default.info("Volute UI running (https)", { hostname, port });
9893
- resolve19();
10040
+ resolve20();
9894
10041
  });
9895
10042
  server2.on("error", (err) => {
9896
10043
  reject(err);
@@ -9898,13 +10045,13 @@ async function startServer({
9898
10045
  });
9899
10046
  const internalPort = port + 1;
9900
10047
  const internalServer = serve({ fetch: app_default.fetch, port: internalPort, hostname: "127.0.0.1" });
9901
- await new Promise((resolve19, reject) => {
10048
+ await new Promise((resolve20, reject) => {
9902
10049
  internalServer.on("listening", () => {
9903
10050
  logger_default.info("Volute API running (http, internal)", {
9904
10051
  hostname: "127.0.0.1",
9905
10052
  port: internalPort
9906
10053
  });
9907
- resolve19();
10054
+ resolve20();
9908
10055
  });
9909
10056
  internalServer.on("error", (err) => {
9910
10057
  reject(err);
@@ -9913,10 +10060,10 @@ async function startServer({
9913
10060
  return { server: server2, internalPort };
9914
10061
  }
9915
10062
  const server = serve({ fetch: app_default.fetch, port, hostname });
9916
- await new Promise((resolve19, reject) => {
10063
+ await new Promise((resolve20, reject) => {
9917
10064
  server.on("listening", () => {
9918
10065
  logger_default.info("Volute API running (http)", { hostname, port });
9919
- resolve19();
10066
+ resolve20();
9920
10067
  });
9921
10068
  server.on("error", (err) => {
9922
10069
  reject(err);
@@ -9927,17 +10074,17 @@ async function startServer({
9927
10074
 
9928
10075
  // packages/daemon/src/daemon.ts
9929
10076
  if (!process.env.VOLUTE_HOME) {
9930
- process.env.VOLUTE_HOME = resolve18(homedir3(), ".volute");
10077
+ process.env.VOLUTE_HOME = resolve19(homedir3(), ".volute");
9931
10078
  }
9932
10079
  if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
9933
10080
  process.env.TZ = process.env.VOLUTE_TIMEZONE;
9934
10081
  }
9935
10082
  function writeDaemonConfig(systemDir, config2, token) {
9936
- const configPath = resolve18(systemDir, "daemon.json");
10083
+ const configPath = resolve19(systemDir, "daemon.json");
9937
10084
  writeFileSync10(configPath, `${JSON.stringify(config2, null, 2)}
9938
10085
  `, { mode: 420 });
9939
10086
  chmodSync(configPath, 420);
9940
- const tokenPath = resolve18(systemDir, "daemon-token");
10087
+ const tokenPath = resolve19(systemDir, "daemon-token");
9941
10088
  writeFileSync10(tokenPath, `${token}
9942
10089
  `, { mode: 384 });
9943
10090
  chmodSync(tokenPath, 384);
@@ -9948,7 +10095,7 @@ async function startDaemon(opts) {
9948
10095
  const home = voluteHome();
9949
10096
  const systemDir = voluteSystemDir();
9950
10097
  if (!opts.foreground) {
9951
- const rotatingLog = new RotatingLog(resolve18(systemDir, "daemon.log"));
10098
+ const rotatingLog = new RotatingLog(resolve19(systemDir, "daemon.log"));
9952
10099
  logger_default.setOutput((line) => rotatingLog.write(`${line}
9953
10100
  `));
9954
10101
  const write = (...args) => rotatingLog.write(`${format(...args)}
@@ -9958,38 +10105,38 @@ async function startDaemon(opts) {
9958
10105
  console.warn = write;
9959
10106
  console.info = write;
9960
10107
  }
9961
- const DAEMON_PID_PATH = resolve18(systemDir, "daemon.pid");
9962
- const DAEMON_JSON_PATH = resolve18(systemDir, "daemon.json");
9963
- const DAEMON_TOKEN_PATH = resolve18(systemDir, "daemon-token");
10108
+ const DAEMON_PID_PATH = resolve19(systemDir, "daemon.pid");
10109
+ const DAEMON_JSON_PATH = resolve19(systemDir, "daemon.json");
10110
+ const DAEMON_TOKEN_PATH = resolve19(systemDir, "daemon-token");
9964
10111
  mkdirSync10(home, { recursive: true });
9965
10112
  ensureSystemDir();
9966
- const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-CAJFOR2N.js");
10113
+ const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-WZSXHHRJ.js");
9967
10114
  migrateConfigSecrets();
9968
10115
  migrateSetupCompleted();
9969
- const { migrateAiModelQualification } = await import("./ai-service-V4CTNGI3.js");
10116
+ const { migrateAiModelQualification } = await import("./ai-service-YW5SWCSB.js");
9970
10117
  migrateAiModelQualification();
9971
- await (await import("./db-QAY45Z56.js")).getDb();
10118
+ await (await import("./db-BONH4SUG.js")).getDb();
9972
10119
  try {
9973
10120
  const { eq: eq9, and: and7 } = await import("drizzle-orm");
9974
- const { users: users2 } = await import("./schema-C2GIPD4V.js");
9975
- const db = await (await import("./db-QAY45Z56.js")).getDb();
10121
+ const { users: users2 } = await import("./schema-ZZQVM4GR.js");
10122
+ const db = await (await import("./db-BONH4SUG.js")).getDb();
9976
10123
  await db.update(users2).set({ role: "system" }).where(and7(eq9(users2.user_type, "system"), eq9(users2.role, "user")));
9977
10124
  } catch (err) {
9978
10125
  logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
9979
10126
  }
9980
10127
  try {
9981
- const { migrateAvatarSizes } = await import("./avatar-image-QEPAP3A5.js");
10128
+ const { migrateAvatarSizes } = await import("./avatar-image-52WGXLHV.js");
9982
10129
  await migrateAvatarSizes();
9983
10130
  } catch (err) {
9984
10131
  logger_default.warn("avatar size migration failed", logger_default.errorData(err));
9985
10132
  }
9986
10133
  try {
9987
- const { migrateThreadConfigs } = await import("./migrate-thread-config-4A5LW36Z.js");
10134
+ const { migrateThreadConfigs } = await import("./migrate-thread-config-EQSEP2XG.js");
9988
10135
  await migrateThreadConfigs();
9989
10136
  } catch (err) {
9990
10137
  logger_default.warn("session\u2192thread config migration failed", logger_default.errorData(err));
9991
10138
  }
9992
- const { initSandbox } = await import("./sandbox-EGEU5GGE.js");
10139
+ const { initSandbox } = await import("./sandbox-NNWCTHRI.js");
9993
10140
  await initSandbox();
9994
10141
  try {
9995
10142
  await syncBuiltinSkills();
@@ -10021,7 +10168,7 @@ async function startDaemon(opts) {
10021
10168
  logger_default.warn("failed to backfill minds into #system", logger_default.errorData(err));
10022
10169
  }
10023
10170
  try {
10024
- const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-DT7GY7EZ.js");
10171
+ const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-X6EMNEGB.js");
10025
10172
  await getOrCreateSystemUser2();
10026
10173
  } catch (err) {
10027
10174
  logger_default.warn(
@@ -10030,12 +10177,12 @@ async function startDaemon(opts) {
10030
10177
  );
10031
10178
  }
10032
10179
  const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes3(32).toString("hex");
10033
- const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-CAJFOR2N.js");
10180
+ const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-WZSXHHRJ.js");
10034
10181
  const globalCfg = readGlobalConfig2();
10035
10182
  let tls;
10036
10183
  if (opts.tailscale || globalCfg.tailscale) {
10037
10184
  try {
10038
- const { getTailscaleTls } = await import("./tailscale-SJUW2ETR.js");
10185
+ const { getTailscaleTls } = await import("./tailscale-KHNZFC7L.js");
10039
10186
  const tlsConfig = await getTailscaleTls();
10040
10187
  tls = { key: tlsConfig.key, cert: tlsConfig.cert };
10041
10188
  logger_default.info("Tailscale HTTPS enabled", { hostname: tlsConfig.hostname });
@@ -10089,7 +10236,7 @@ async function startDaemon(opts) {
10089
10236
  const orphanedTurns = await completeOrphanedTurns();
10090
10237
  summarizeOrphanedTurns(orphanedTurns);
10091
10238
  try {
10092
- const { reconcileVariants } = await import("./variant-cleanup-HJ7Z75R6.js");
10239
+ const { reconcileVariants } = await import("./variant-cleanup-YXN25ZVW.js");
10093
10240
  await reconcileVariants();
10094
10241
  } catch (err) {
10095
10242
  logger_default.error("failed to reconcile variants", logger_default.errorData(err));
@@ -10123,15 +10270,15 @@ async function startDaemon(opts) {
10123
10270
  await Promise.all(workers);
10124
10271
  }
10125
10272
  try {
10126
- const { isSetupComplete: isSetupComplete2, getSpiritName: getSpiritName2 } = await import("./setup-CAJFOR2N.js");
10273
+ const { isSetupComplete: isSetupComplete2, getSpiritName: getSpiritName2 } = await import("./setup-WZSXHHRJ.js");
10127
10274
  if (isSetupComplete2()) {
10128
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-IL5EMWYZ.js");
10129
- const { startSpiritFull } = await import("./mind-service-5TA7UJAT.js");
10275
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-25JVAL3M.js");
10276
+ const { startSpiritFull } = await import("./mind-service-DZCUUC7J.js");
10130
10277
  await ensureSpiritProject();
10131
10278
  const spiritName = getSpiritName2();
10132
10279
  const spiritEntry = await findMind(spiritName);
10133
10280
  if (spiritEntry?.dir) {
10134
- const { registerMindDir } = await import("./delivery-router-JE7SHYNU.js");
10281
+ const { registerMindDir } = await import("./delivery-router-RHANNTAC.js");
10135
10282
  registerMindDir(spiritName, spiritEntry.dir);
10136
10283
  }
10137
10284
  await syncSpiritTemplate();
@@ -10145,7 +10292,7 @@ async function startDaemon(opts) {
10145
10292
  bridgeManager.startBridges(daemonPort).catch((err) => {
10146
10293
  logger_default.warn("failed to start bridges", logger_default.errorData(err));
10147
10294
  });
10148
- import("./cloud-sync-IDJFVDEP.js").then(
10295
+ import("./cloud-sync-GPXYPTIC.js").then(
10149
10296
  ({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
10150
10297
  logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
10151
10298
  })
@@ -10153,7 +10300,7 @@ async function startDaemon(opts) {
10153
10300
  logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
10154
10301
  });
10155
10302
  try {
10156
- const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-7BUHWZNT.js");
10303
+ const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-EN3KJ7HH.js");
10157
10304
  backfillTemplateHashes().then(() => warnStaleTemplates()).catch((err) => {
10158
10305
  logger_default.warn("failed to check template staleness", logger_default.errorData(err));
10159
10306
  });