volute 0.39.0 → 0.40.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/dist/{accept-AHAOUFBK.js → accept-IVHOHXQS.js} +1 -1
  2. package/dist/{activity-events-CR4RIHJT.js → activity-events-DS4QRWBY.js} +4 -4
  3. package/dist/{ai-service-PL7GKFQC.js → ai-service-AUWIPWLP.js} +9 -5
  4. package/dist/{api-client-LC5YRA32.js → api-client-NFM6GX2N.js} +1 -1
  5. package/dist/{archive-UEWIFRAR.js → archive-UDHFZN4G.js} +4 -4
  6. package/dist/{auth-OJ2YW3NR.js → auth-X6ZITZ7D.js} +5 -5
  7. package/dist/{bridge-F3ZJEKDN.js → bridge-MSZC4HUT.js} +1 -1
  8. package/dist/{chat-RQ5NV5EA.js → chat-JD3TJINV.js} +9 -9
  9. package/dist/{chunk-CJ26DXZL.js → chunk-2HZRJ35V.js} +17 -1
  10. package/dist/{chunk-QDWPM73D.js → chunk-3Y7UDHO7.js} +3 -3
  11. package/dist/{chunk-6V2U3GFQ.js → chunk-4UMXOMZ6.js} +2 -2
  12. package/dist/{chunk-7OS7QFDF.js → chunk-5EVW4KOD.js} +3 -3
  13. package/dist/{chunk-6FSSMAXU.js → chunk-6SYHHEQ7.js} +1 -1
  14. package/dist/{chunk-OEXOFBW5.js → chunk-AEAZRTEV.js} +1 -1
  15. package/dist/{chunk-DZ4LYU6J.js → chunk-ANSTTB55.js} +1 -1
  16. package/dist/{chunk-QDWP435B.js → chunk-B4WPXYPI.js} +1 -1
  17. package/dist/{chunk-CHCISTH7.js → chunk-BLAXARBZ.js} +511 -335
  18. package/dist/{chunk-TCNCRDB5.js → chunk-DNU6XLE2.js} +1 -1
  19. package/dist/{chunk-7W3UWCQD.js → chunk-E25SO3QW.js} +3 -3
  20. package/dist/{chunk-IA2SZSLB.js → chunk-I57LLNAQ.js} +1 -1
  21. package/dist/{chunk-WUH54G5S.js → chunk-ITH5ZLZJ.js} +1 -1
  22. package/dist/{chunk-QJ4GU5XT.js → chunk-JYQQDI3M.js} +2 -2
  23. package/dist/{chunk-EVKGKQ2P.js → chunk-KMHC36CA.js} +1 -7
  24. package/dist/chunk-LMMQX4CK.js +49 -0
  25. package/dist/{chunk-4BO4I7UF.js → chunk-LZ6CQYRO.js} +7 -7
  26. package/dist/{chunk-RAVQXKAG.js → chunk-MNUXL4XN.js} +67 -3
  27. package/dist/{chunk-OS5MRIEP.js → chunk-NERYUSER.js} +1 -1
  28. package/dist/{chunk-XOSAY7PY.js → chunk-PKGA23XM.js} +1 -1
  29. package/dist/{chunk-IBOU6Q3Y.js → chunk-QV7P3TYO.js} +5 -5
  30. package/dist/{chunk-7GZB3ZJP.js → chunk-QYI65HCL.js} +2 -2
  31. package/dist/{chunk-B7MWXFAH.js → chunk-S4SXBQ7F.js} +15 -1
  32. package/dist/{chunk-X7GM2OPM.js → chunk-SVXOBKQY.js} +2 -2
  33. package/dist/{chunk-Y5UC6G3O.js → chunk-TOANT6FD.js} +2 -2
  34. package/dist/{chunk-TT4WT6Y7.js → chunk-YHWGN4FX.js} +1 -1
  35. package/dist/{chunk-Y4W3OS7Q.js → chunk-YTNBO7S6.js} +8 -8
  36. package/dist/cli.js +24 -24
  37. package/dist/{clock-BMLJ2TR6.js → clock-YLDJUKBW.js} +3 -3
  38. package/dist/{cloud-sync-NQCWJLYI.js → cloud-sync-MAQCJEFJ.js} +17 -17
  39. package/dist/{config-QB7W3Z7P.js → config-PO4EZLIK.js} +4 -4
  40. package/dist/connectors/discord-bridge.js +1 -1
  41. package/dist/connectors/slack-bridge.js +1 -1
  42. package/dist/connectors/telegram-bridge.js +1 -1
  43. package/dist/{conversations-EUXHBWJD.js → conversations-AYLXPOGC.js} +5 -5
  44. package/dist/{create-3QH7DVLC.js → create-T4UJ64WB.js} +4 -4
  45. package/dist/{create-C3BBFYV7.js → create-ZMTGINV3.js} +1 -1
  46. package/dist/{daemon-client-2MIPKY3E.js → daemon-client-H6MEKK2W.js} +1 -1
  47. package/dist/{daemon-restart-UEB3PLKB.js → daemon-restart-LP2DR24J.js} +9 -9
  48. package/dist/daemon.js +424 -294
  49. package/dist/{db-IJL6B26S.js → db-FSYOTHSN.js} +1 -1
  50. package/dist/db-ZEPKEJJD.js +9 -0
  51. package/dist/{delete-NLXES2C7.js → delete-TXVOH2OC.js} +3 -3
  52. package/dist/delivery-manager-VNHLQTTO.js +30 -0
  53. package/dist/{delivery-router-EUW4RIWG.js → delivery-router-T6CYTS3M.js} +4 -4
  54. package/dist/down-6DYO2QV7.js +17 -0
  55. package/dist/echo-text-QFCH3H6G.js +31 -0
  56. package/dist/{env-IQ6Q2333.js → env-77IOWG4U.js} +1 -1
  57. package/dist/exec-5DGKQ5V3.js +17 -0
  58. package/dist/{export-JDAK3THX.js → export-TZKOCSCE.js} +6 -6
  59. package/dist/{extension-LZYHBNLV.js → extension-35NB6GHW.js} +1 -1
  60. package/dist/{extensions-V7TXKAKM.js → extensions-LQX2N7TI.js} +17 -17
  61. package/dist/{files-K5XV23H6.js → files-WNNVJWJB.js} +4 -4
  62. package/dist/{import-GZ5IYVV7.js → import-BNNFCQ7U.js} +11 -11
  63. package/dist/{isolation-FPF4UTH2.js → isolation-4Q4P7HRV.js} +4 -4
  64. package/dist/{join-6SZCA5FX.js → join-E2EJEXZO.js} +3 -3
  65. package/dist/{list-KHJZJPEJ.js → list-BYCEDASJ.js} +1 -1
  66. package/dist/{login-GYTH67ES.js → login-JNSIYFVH.js} +1 -1
  67. package/dist/{login-BGF5JY3I.js → login-Y6UAYQVO.js} +3 -3
  68. package/dist/{logout-YHQLOFLR.js → logout-M6FI62BL.js} +1 -1
  69. package/dist/{logout-GQHI6KH6.js → logout-VHGWVH63.js} +3 -3
  70. package/dist/message-delivery-7BCYJLH2.js +40 -0
  71. package/dist/{mind-QMJIWWWW.js → mind-ELPD6VBP.js} +19 -19
  72. package/dist/{mind-activity-tracker-Z3KBQTVU.js → mind-activity-tracker-XFRVGXFS.js} +5 -5
  73. package/dist/{mind-history-WHCNZ6I5.js → mind-history-W4JPTPTV.js} +1 -1
  74. package/dist/{mind-list-H3HC2ZRG.js → mind-list-QROHCLGT.js} +1 -1
  75. package/dist/mind-manager-EDCLALBF.js +30 -0
  76. package/dist/{mind-profile-7VYRJGFZ.js → mind-profile-3LNKXNPA.js} +2 -2
  77. package/dist/mind-service-WTOFVNLW.js +36 -0
  78. package/dist/{mind-sleep-ZL5ZXFTM.js → mind-sleep-PVCMLTAH.js} +1 -1
  79. package/dist/{mind-status-ZWULKOUO.js → mind-status-RAJFLRCN.js} +1 -1
  80. package/dist/{mind-wake-HK5ORGUK.js → mind-wake-HZUOVE7J.js} +1 -1
  81. package/dist/{package-IR4ZEQA2.js → package-GO3PHHUF.js} +28 -27
  82. package/dist/{read-CP7MYMJQ.js → read-OOINVR2H.js} +1 -1
  83. package/dist/{read-stdin-4B5UYPPM.js → read-stdin-P6HCZUAA.js} +1 -1
  84. package/dist/{register-XOBFEMI4.js → register-ISOH34RF.js} +1 -1
  85. package/dist/{registry-LWEOAO53.js → registry-GV35XFT7.js} +3 -3
  86. package/dist/{reject-43AGXB6B.js → reject-ZBWP62X5.js} +1 -1
  87. package/dist/{restart-O5QIYQJT.js → restart-QBJV5455.js} +1 -1
  88. package/dist/{sandbox-KUAVC37A.js → sandbox-5R32QKWQ.js} +5 -5
  89. package/dist/scheduler-GQBDCGLU.js +30 -0
  90. package/dist/{schema-K575EBPE.js → schema-LYQUDL7G.js} +4 -2
  91. package/dist/{seed-GPBERPXJ.js → seed-MO2C7CWC.js} +2 -2
  92. package/dist/{seed-check-HZPVFJKZ.js → seed-check-3WXXRHTC.js} +2 -2
  93. package/dist/{seed-cmd-PWF4FYFG.js → seed-cmd-ETIF4WD6.js} +4 -4
  94. package/dist/{seed-create-NTIICZVB.js → seed-create-BPQC2IOR.js} +6 -6
  95. package/dist/{seed-sprout-PRPFKGJF.js → seed-sprout-TX72K33T.js} +11 -11
  96. package/dist/{send-IMHDYJHW.js → send-WO3CVG73.js} +4 -4
  97. package/dist/{service-DWBRRFXS.js → service-WMV6R6VJ.js} +6 -6
  98. package/dist/service-install-W3FQXJKB.js +17 -0
  99. package/dist/{setup-IFYS3TLS.js → setup-OTEC3ZPM.js} +4 -4
  100. package/dist/{setup-4CWQ53VV.js → setup-ZTW4FVMQ.js} +9 -9
  101. package/dist/{skill-ICN6Y2ZF.js → skill-QHACP7EU.js} +1 -1
  102. package/dist/{skills-FJ5W73AV.js → skills-JEWMHIIE.js} +7 -7
  103. package/dist/sleep-manager-5277OBHI.js +34 -0
  104. package/dist/{spirit-U6MDQLYT.js → spirit-NVXWSVKM.js} +9 -9
  105. package/dist/{split-5YBEQTBF.js → split-7AO4IO42.js} +3 -3
  106. package/dist/{sprout-ABX2G76C.js → sprout-NFJZKYEW.js} +2 -2
  107. package/dist/{src-OYWRPLC6.js → src-2IMB3V27.js} +1 -1
  108. package/dist/src-OS75U2O7.js +241910 -0
  109. package/dist/{src-O4PRLMKM.js → src-XNUXP2FP.js} +1 -1
  110. package/dist/{start-LMXXRR3X.js → start-2U57BBK7.js} +1 -1
  111. package/dist/{status-C6BBWNU3.js → status-BRYYYO7C.js} +7 -7
  112. package/dist/{stop-TWDKVEUX.js → stop-QILBDUAR.js} +1 -1
  113. package/dist/system-chat-LQSJVY55.js +34 -0
  114. package/dist/{systems-Y2WZV2K4.js → systems-3XTAHA35.js} +4 -4
  115. package/dist/{tailscale-2KKXDMNK.js → tailscale-X4HRKRTW.js} +3 -3
  116. package/dist/{template-hash-SSIBEEYK.js → template-hash-DMHSLRDX.js} +1 -1
  117. package/dist/up-4H7TL6WB.js +19 -0
  118. package/dist/{update-V26PT4VN.js → update-OY2JYXYK.js} +61 -14
  119. package/dist/update-check-IUB7QHAF.js +24 -0
  120. package/dist/{upgrade-RXFZR5FI.js → upgrade-25J6AE47.js} +3 -3
  121. package/dist/{variant-HHDTW74J.js → variant-5LQOPCQA.js} +1 -1
  122. package/dist/{version-notify-ZBMY2TEX.js → version-notify-N37N2C4G.js} +18 -18
  123. package/dist/{volute-config-TS62GS6A.js → volute-config-7FO6QKWU.js} +1 -1
  124. package/dist/web-assets/assets/index-DaUp9iE2.js +79 -0
  125. package/dist/web-assets/assets/index-DqHSW9Fr.css +1 -0
  126. package/dist/web-assets/index.html +2 -2
  127. package/drizzle/0009_mind_notices.sql +14 -0
  128. package/drizzle/meta/_journal.json +7 -0
  129. package/package.json +27 -26
  130. package/packages/extensions/notes/dist/ui/assets/index-BbgANhFm.js +67 -0
  131. package/packages/extensions/notes/dist/ui/index.html +1 -1
  132. package/packages/extensions/pages/dist/ui/assets/index-Dxk-DYrf.js +2 -0
  133. package/packages/extensions/pages/dist/ui/index.html +1 -1
  134. package/packages/extensions/plan/dist/ui/assets/index-Cfzs-0G9.js +67 -0
  135. package/packages/extensions/plan/dist/ui/index.html +1 -1
  136. package/templates/_base/.init/.local/hooks/pre-prompt/notices.ts +46 -0
  137. package/templates/_base/src/lib/context-breakdown.ts +281 -126
  138. package/templates/_base/src/lib/daemon-client.ts +5 -2
  139. package/templates/_base/src/lib/transparency.ts +5 -3
  140. package/templates/_base/src/lib/volute-server.ts +23 -0
  141. package/templates/claude/package.json.tmpl +5 -5
  142. package/templates/claude/src/agent.ts +54 -16
  143. package/templates/claude/src/server.ts +1 -0
  144. package/templates/codex/package.json.tmpl +5 -5
  145. package/templates/codex/src/agent.ts +45 -12
  146. package/templates/codex/src/server.ts +1 -0
  147. package/templates/pi/package.json.tmpl +6 -6
  148. package/templates/pi/src/agent.ts +74 -13
  149. package/templates/pi/src/lib/subagents.ts +19 -17
  150. package/templates/pi/src/server.ts +1 -0
  151. package/dist/chunk-K3NQKI34.js +0 -10
  152. package/dist/db-32YFKMFL.js +0 -9
  153. package/dist/delivery-manager-N34XKUGL.js +0 -30
  154. package/dist/down-TCEBGTMY.js +0 -17
  155. package/dist/echo-text-N3BC3WNX.js +0 -31
  156. package/dist/exec-2MFHTGOS.js +0 -17
  157. package/dist/message-delivery-X7MKA3TA.js +0 -40
  158. package/dist/mind-manager-7GWTTKWD.js +0 -30
  159. package/dist/mind-service-MO2XJKJN.js +0 -36
  160. package/dist/scheduler-CGUPAEBA.js +0 -30
  161. package/dist/service-install-KEBDNZVE.js +0 -17
  162. package/dist/sleep-manager-6QRMUNHK.js +0 -34
  163. package/dist/src-6Z4XYDH5.js +0 -2164
  164. package/dist/system-chat-D343HYGR.js +0 -34
  165. package/dist/up-ZU6ILVMA.js +0 -19
  166. package/dist/update-check-XRERV36Y.js +0 -18
  167. package/dist/web-assets/assets/index-B1zwqwt8.css +0 -1
  168. package/dist/web-assets/assets/index-D1guJF1i.js +0 -73
  169. package/packages/extensions/notes/dist/ui/assets/index-Dsua7alJ.js +0 -61
  170. package/packages/extensions/pages/dist/ui/assets/index-BM7gRdg7.js +0 -2
  171. package/packages/extensions/plan/dist/ui/assets/index-DWiqtzBv.js +0 -61
package/dist/daemon.js CHANGED
@@ -6,21 +6,21 @@ import {
6
6
  rejectPending,
7
7
  stageFile,
8
8
  validateFilePath
9
- } from "./chunk-TT4WT6Y7.js";
9
+ } from "./chunk-YHWGN4FX.js";
10
10
  import {
11
11
  findOpenClawSession,
12
12
  importOpenClawConnectors,
13
13
  importPiSession,
14
14
  parseNameFromIdentity
15
- } from "./chunk-X7GM2OPM.js";
15
+ } from "./chunk-SVXOBKQY.js";
16
16
  import {
17
17
  checkForUpdate,
18
18
  checkForUpdateCached,
19
19
  getCurrentVersion
20
- } from "./chunk-RAVQXKAG.js";
20
+ } from "./chunk-MNUXL4XN.js";
21
21
  import {
22
22
  isHomeOnlyArchive
23
- } from "./chunk-IA2SZSLB.js";
23
+ } from "./chunk-I57LLNAQ.js";
24
24
  import {
25
25
  computeTemplateHash
26
26
  } from "./chunk-KAB6UGOL.js";
@@ -30,7 +30,7 @@ import {
30
30
  fixModelEscapes,
31
31
  getPlatformDriver,
32
32
  routeOutboundBridge
33
- } from "./chunk-4BO4I7UF.js";
33
+ } from "./chunk-LZ6CQYRO.js";
34
34
  import {
35
35
  getBridgeConfig,
36
36
  readBridgesConfig,
@@ -39,7 +39,7 @@ import {
39
39
  resolveChannelMapping,
40
40
  setBridgeConfig,
41
41
  setChannelMapping
42
- } from "./chunk-XOSAY7PY.js";
42
+ } from "./chunk-PKGA23XM.js";
43
43
  import {
44
44
  PROMPT_DEFAULTS,
45
45
  PROMPT_KEYS,
@@ -47,12 +47,15 @@ import {
47
47
  RotatingLog,
48
48
  announceToSystem,
49
49
  assignSession,
50
+ clearDeliveredNotices,
50
51
  completeOrphanedTurns,
51
52
  completeTurn,
52
53
  createTurn,
53
54
  deleteSystemsConfig,
54
55
  deliverMessage,
56
+ drainNotices,
55
57
  ensureSystemChannel,
58
+ formatNotices,
56
59
  generateSystemReply,
57
60
  getActiveTurnId,
58
61
  getAllDiscoveredExtensions,
@@ -81,12 +84,14 @@ import {
81
84
  joinSystemChannel,
82
85
  linkToolResultToTurn,
83
86
  loadAllExtensions,
87
+ markErrored,
84
88
  notifyExtensionsDaemonStart,
85
89
  notifyExtensionsDaemonStop,
86
90
  publish as publish2,
87
91
  publishTypingForChannels,
88
92
  readSystemsConfig,
89
93
  recordInbound,
94
+ recordNotice,
90
95
  recordOutbound,
91
96
  resolveMindToken,
92
97
  setExtensionEnabled,
@@ -97,20 +102,22 @@ import {
97
102
  substitute,
98
103
  summarizeOrphanedTurns,
99
104
  summarizeTurn,
105
+ syncProviderToMinds,
100
106
  tagUntaggedInbound,
101
107
  tagUntaggedOutbound,
108
+ takeErrored,
102
109
  trackToolUse,
103
110
  uninstallNpmExtension,
104
111
  writeSystemsConfig
105
- } from "./chunk-CHCISTH7.js";
112
+ } from "./chunk-BLAXARBZ.js";
106
113
  import {
107
114
  loadMergedEnv,
108
115
  mindEnvPath,
109
116
  readEnv,
110
117
  sharedEnvPath,
111
118
  writeEnv
112
- } from "./chunk-WUH54G5S.js";
113
- import "./chunk-Y4W3OS7Q.js";
119
+ } from "./chunk-ITH5ZLZJ.js";
120
+ import "./chunk-YTNBO7S6.js";
114
121
  import {
115
122
  applyInitFiles,
116
123
  composeTemplate,
@@ -137,7 +144,7 @@ import {
137
144
  syncBuiltinSkills,
138
145
  uninstallSkill,
139
146
  updateSkill
140
- } from "./chunk-IBOU6Q3Y.js";
147
+ } from "./chunk-QV7P3TYO.js";
141
148
  import {
142
149
  addMessage,
143
150
  createChannel,
@@ -169,25 +176,25 @@ import {
169
176
  setConversationPrivate,
170
177
  subscribe as subscribe2,
171
178
  updateChannelSettings
172
- } from "./chunk-QDWPM73D.js";
179
+ } from "./chunk-3Y7UDHO7.js";
173
180
  import {
174
181
  readVoluteConfig,
175
182
  writeVoluteConfig
176
183
  } from "./chunk-CU6OFXMM.js";
177
- import "./chunk-EVKGKQ2P.js";
184
+ import "./chunk-KMHC36CA.js";
178
185
  import {
179
186
  getActiveMinds,
180
187
  onMindEvent,
181
188
  stopAll
182
- } from "./chunk-DZ4LYU6J.js";
189
+ } from "./chunk-ANSTTB55.js";
183
190
  import {
184
191
  extractTextContent
185
- } from "./chunk-OS5MRIEP.js";
192
+ } from "./chunk-NERYUSER.js";
186
193
  import {
187
194
  exec,
188
195
  gitExec,
189
196
  resolveVoluteBin
190
- } from "./chunk-OEXOFBW5.js";
197
+ } from "./chunk-AEAZRTEV.js";
191
198
  import {
192
199
  chownMindDir,
193
200
  createMindUser,
@@ -195,7 +202,29 @@ import {
195
202
  ensureVoluteGroup,
196
203
  isIsolationEnabled,
197
204
  wrapForIsolation
198
- } from "./chunk-6FSSMAXU.js";
205
+ } from "./chunk-6SYHHEQ7.js";
206
+ import {
207
+ getAiConfig,
208
+ getAvailableModels,
209
+ getConfiguredProviders,
210
+ getEnabledModels,
211
+ getUtilityModel,
212
+ qualifyModelId,
213
+ removeAiConfig,
214
+ removeProviderConfig,
215
+ resolveApiKey,
216
+ resolveTemplate,
217
+ saveProviderConfig,
218
+ setEnabledModels,
219
+ setProviderRefreshHook,
220
+ setUtilityModel,
221
+ unqualifyModelId
222
+ } from "./chunk-S4SXBQ7F.js";
223
+ import {
224
+ isSetupComplete,
225
+ readGlobalConfig,
226
+ writeGlobalConfig
227
+ } from "./chunk-DNU6XLE2.js";
199
228
  import {
200
229
  approveUser,
201
230
  changePassword,
@@ -214,32 +243,11 @@ import {
214
243
  syncMindProfile,
215
244
  updateUserProfile,
216
245
  verifyUser
217
- } from "./chunk-7W3UWCQD.js";
246
+ } from "./chunk-E25SO3QW.js";
218
247
  import {
219
248
  broadcast,
220
249
  subscribe
221
- } from "./chunk-7GZB3ZJP.js";
222
- import {
223
- getAiConfig,
224
- getAvailableModels,
225
- getConfiguredProviders,
226
- getEnabledModels,
227
- getUtilityModel,
228
- qualifyModelId,
229
- removeAiConfig,
230
- removeProviderConfig,
231
- resolveApiKey,
232
- resolveTemplate,
233
- saveProviderConfig,
234
- setEnabledModels,
235
- setUtilityModel,
236
- unqualifyModelId
237
- } from "./chunk-B7MWXFAH.js";
238
- import {
239
- isSetupComplete,
240
- readGlobalConfig,
241
- writeGlobalConfig
242
- } from "./chunk-TCNCRDB5.js";
250
+ } from "./chunk-QYI65HCL.js";
243
251
  import {
244
252
  logBuffer,
245
253
  logger_default
@@ -269,7 +277,7 @@ import {
269
277
  validateMindName,
270
278
  voluteHome,
271
279
  voluteSystemDir
272
- } from "./chunk-QDWP435B.js";
280
+ } from "./chunk-B4WPXYPI.js";
273
281
  import {
274
282
  activity,
275
283
  channels,
@@ -281,14 +289,14 @@ import {
281
289
  systemPrompts,
282
290
  turns,
283
291
  users
284
- } from "./chunk-CJ26DXZL.js";
285
- import "./chunk-K3NQKI34.js";
292
+ } from "./chunk-2HZRJ35V.js";
293
+ import "./chunk-LMMQX4CK.js";
286
294
 
287
295
  // packages/daemon/src/daemon.ts
288
296
  import { randomBytes } from "crypto";
289
297
  import { mkdirSync as mkdirSync10, readFileSync as readFileSync10, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "fs";
290
298
  import { homedir as homedir3 } from "os";
291
- import { resolve as resolve16 } from "path";
299
+ import { resolve as resolve17 } from "path";
292
300
  import { format } from "util";
293
301
 
294
302
  // packages/daemon/src/lib/daemon/bridge-manager.ts
@@ -498,8 +506,8 @@ var BridgeManager = class {
498
506
  if (!tracked) return;
499
507
  this.stopping.add(platform);
500
508
  this.bridges.delete(platform);
501
- await new Promise((resolve17) => {
502
- tracked.child.on("exit", () => resolve17());
509
+ await new Promise((resolve18) => {
510
+ tracked.child.on("exit", () => resolve18());
503
511
  try {
504
512
  if (tracked.child.pid) {
505
513
  process.kill(-tracked.child.pid, "SIGTERM");
@@ -510,7 +518,7 @@ var BridgeManager = class {
510
518
  if (err instanceof Error && err.code !== "ESRCH") {
511
519
  blog.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
512
520
  }
513
- resolve17();
521
+ resolve18();
514
522
  }
515
523
  setTimeout(() => {
516
524
  try {
@@ -521,7 +529,7 @@ var BridgeManager = class {
521
529
  }
522
530
  } catch {
523
531
  }
524
- resolve17();
532
+ resolve18();
525
533
  }, 5e3);
526
534
  });
527
535
  this.stopping.delete(platform);
@@ -985,10 +993,10 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
985
993
  stream.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
986
994
  });
987
995
  });
988
- await new Promise((resolve17) => {
996
+ await new Promise((resolve18) => {
989
997
  stream.onAbort(() => {
990
998
  unsubscribe();
991
- resolve17();
999
+ resolve18();
992
1000
  });
993
1001
  });
994
1002
  });
@@ -1301,8 +1309,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1301
1309
  createdAt: Date.now()
1302
1310
  };
1303
1311
  oauthFlows.set(flowId, flow);
1304
- const promptPromise = needsManualCode ? new Promise((resolve17) => {
1305
- flow.resolveCode = resolve17;
1312
+ const promptPromise = needsManualCode ? new Promise((resolve18) => {
1313
+ flow.resolveCode = resolve18;
1306
1314
  }) : void 0;
1307
1315
  oauthProvider.login({
1308
1316
  onAuth: (info) => {
@@ -1332,7 +1340,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1332
1340
  existing.error = err instanceof Error ? err.message : String(err);
1333
1341
  }
1334
1342
  });
1335
- await new Promise((resolve17) => setTimeout(resolve17, 2e3));
1343
+ await new Promise((resolve18) => setTimeout(resolve18, 2e3));
1336
1344
  const state = oauthFlows.get(flowId);
1337
1345
  return c.json({
1338
1346
  flowId,
@@ -1590,8 +1598,8 @@ var app2 = new Hono2().get("/events", async (c) => {
1590
1598
  });
1591
1599
  }, 15e3);
1592
1600
  cleanups.push(() => clearInterval(keepAlive));
1593
- await new Promise((resolve17) => {
1594
- stream.onAbort(() => resolve17());
1601
+ await new Promise((resolve18) => {
1602
+ stream.onAbort(() => resolve18());
1595
1603
  });
1596
1604
  } finally {
1597
1605
  for (const cleanup of cleanups) {
@@ -1994,7 +2002,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
1994
2002
  }
1995
2003
  const participants = await getParticipants(channel.id);
1996
2004
  if (!participants.some((p) => p.userId === puppet.id)) {
1997
- const { addParticipant } = await import("./conversations-EUXHBWJD.js");
2005
+ const { addParticipant } = await import("./conversations-AYLXPOGC.js");
1998
2006
  await addParticipant(channel.id, puppet.id);
1999
2007
  }
2000
2008
  const contentBlocks = body.content;
@@ -2087,8 +2095,8 @@ async function fanOutToBridgedMinds(opts) {
2087
2095
  const participants = await getParticipants(opts.conversationId);
2088
2096
  const mindParticipants = participants.filter((p) => p.userType === "mind");
2089
2097
  const participantNames = participants.map((p) => p.username);
2090
- const { getMindManager: getMindManager2 } = await import("./mind-manager-7GWTTKWD.js");
2091
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-6QRMUNHK.js");
2098
+ const { getMindManager: getMindManager2 } = await import("./mind-manager-EDCLALBF.js");
2099
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-5277OBHI.js");
2092
2100
  const manager = getMindManager2();
2093
2101
  const sm = getSleepManagerIfReady2();
2094
2102
  const targetMinds = mindParticipants.filter((ap) => {
@@ -2174,13 +2182,13 @@ var config_default = config;
2174
2182
 
2175
2183
  // packages/daemon/src/web/api/env.ts
2176
2184
  import { Hono as Hono7 } from "hono";
2177
- var app6 = new Hono7().get("/:name/env", async (c) => {
2185
+ var app6 = new Hono7().get("/:name/env", requireSelf(), async (c) => {
2178
2186
  const name = c.req.param("name");
2179
2187
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
2180
2188
  const shared = readEnv(sharedEnvPath());
2181
2189
  const mind = readEnv(mindEnvPath(name));
2182
2190
  return c.json({ shared, mind });
2183
- }).get("/:name/env/:key", async (c) => {
2191
+ }).get("/:name/env/:key", requireSelf(), async (c) => {
2184
2192
  const name = c.req.param("name");
2185
2193
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
2186
2194
  const key = c.req.param("key");
@@ -2217,7 +2225,7 @@ var app6 = new Hono7().get("/:name/env", async (c) => {
2217
2225
  writeEnv(path, env);
2218
2226
  return c.json({ ok: true });
2219
2227
  });
2220
- var sharedEnvApp = new Hono7().get("/", (c) => {
2228
+ var sharedEnvApp = new Hono7().get("/", requireAdmin, (c) => {
2221
2229
  return c.json(readEnv(sharedEnvPath()));
2222
2230
  }).put("/:key", requireAdmin, async (c) => {
2223
2231
  const key = c.req.param("key");
@@ -2253,7 +2261,7 @@ var app7 = new Hono8().get("/", (c) => {
2253
2261
  }).get("/all", (c) => {
2254
2262
  const detail = c.req.query("detail") === "true";
2255
2263
  return c.json(detail ? getAllDiscoveredExtensionsDetailed() : getAllDiscoveredExtensions());
2256
- }).put("/:id/enabled", async (c) => {
2264
+ }).put("/:id/enabled", requireAdmin, async (c) => {
2257
2265
  const { id } = c.req.param();
2258
2266
  const body = await c.req.json().catch(() => null);
2259
2267
  if (!body || typeof body.enabled !== "boolean") {
@@ -2265,7 +2273,7 @@ var app7 = new Hono8().get("/", (c) => {
2265
2273
  return c.json({ error: err.message }, 404);
2266
2274
  }
2267
2275
  return c.json({ ok: true, requiresRestart: true });
2268
- }).post("/install", async (c) => {
2276
+ }).post("/install", requireAdmin, async (c) => {
2269
2277
  const body = await c.req.json();
2270
2278
  const pkg = body.package?.trim();
2271
2279
  if (!pkg) {
@@ -2279,7 +2287,7 @@ var app7 = new Hono8().get("/", (c) => {
2279
2287
  const isValidation = message.includes("already installed") || message.includes("Invalid package");
2280
2288
  return c.json({ error: message }, isValidation ? 400 : 500);
2281
2289
  }
2282
- }).delete("/uninstall/:package", async (c) => {
2290
+ }).delete("/uninstall/:package", requireAdmin, async (c) => {
2283
2291
  const pkg = c.req.param("package");
2284
2292
  try {
2285
2293
  await uninstallNpmExtension(pkg);
@@ -2300,7 +2308,7 @@ async function notifyMind(mindName, message) {
2300
2308
  const entry = await findMind(mindName);
2301
2309
  if (!entry) return;
2302
2310
  try {
2303
- const { sendSystemMessage } = await import("./system-chat-D343HYGR.js");
2311
+ const { sendSystemMessage } = await import("./system-chat-LQSJVY55.js");
2304
2312
  await sendSystemMessage(mindName, message);
2305
2313
  } catch (err) {
2306
2314
  logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
@@ -2349,11 +2357,11 @@ var app8 = new Hono9().post("/:name/files/send", requireSelf(), async (c) => {
2349
2357
  `[file] ${senderName} sent ${filename} (${sizeStr}) \u2014 run: volute chat accept ${id}`
2350
2358
  );
2351
2359
  return c.json({ status: "pending", id }, 200);
2352
- }).get("/:name/files/pending", async (c) => {
2360
+ }).get("/:name/files/pending", requireSelf(), async (c) => {
2353
2361
  const name = c.req.param("name");
2354
2362
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
2355
2363
  return c.json(listPending(name));
2356
- }).post("/:name/files/accept", async (c) => {
2364
+ }).post("/:name/files/accept", requireSelf(), async (c) => {
2357
2365
  const name = c.req.param("name");
2358
2366
  const entry = await findMind(name);
2359
2367
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -2375,7 +2383,7 @@ var app8 = new Hono9().post("/:name/files/send", requireSelf(), async (c) => {
2375
2383
  }
2376
2384
  await notifyMind(result.sender, `[file] ${name} accepted ${result.filename}`);
2377
2385
  return c.json({ ok: true, destPath: result.destPath });
2378
- }).post("/:name/files/reject", async (c) => {
2386
+ }).post("/:name/files/reject", requireSelf(), async (c) => {
2379
2387
  const name = c.req.param("name");
2380
2388
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
2381
2389
  const body = await c.req.json();
@@ -2392,7 +2400,7 @@ var app8 = new Hono9().post("/:name/files/send", requireSelf(), async (c) => {
2392
2400
  }
2393
2401
  await notifyMind(result.sender, `[file] ${name} rejected ${result.filename}`);
2394
2402
  return c.json({ ok: true });
2395
- }).post("/:name/files/stage", async (c) => {
2403
+ }).post("/:name/files/stage", requireSelf(), async (c) => {
2396
2404
  const receiverName = c.req.param("name");
2397
2405
  const receiverEntry = await findMind(receiverName);
2398
2406
  if (!receiverEntry) return c.json({ error: "Mind not found" }, 404);
@@ -2425,8 +2433,34 @@ var file_sharing_default = app8;
2425
2433
  // packages/daemon/src/web/api/files.ts
2426
2434
  import { mkdirSync as mkdirSync3, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
2427
2435
  import { readdir, readFile, realpath, stat } from "fs/promises";
2428
- import { extname as extname2, resolve as resolve5 } from "path";
2436
+ import { extname as extname2, resolve as resolve6 } from "path";
2429
2437
  import { Hono as Hono10 } from "hono";
2438
+
2439
+ // packages/daemon/src/lib/util/paths.ts
2440
+ import { resolve as resolve5, sep } from "path";
2441
+ var PathTraversalError = class extends Error {
2442
+ constructor(base, userPath) {
2443
+ super(`Path "${userPath}" escapes base directory "${base}"`);
2444
+ this.name = "PathTraversalError";
2445
+ }
2446
+ };
2447
+ function resolveWithinBase(base, userPath) {
2448
+ const resolvedBase = resolve5(base);
2449
+ const target = resolve5(resolvedBase, userPath);
2450
+ if (target !== resolvedBase && !target.startsWith(resolvedBase + sep)) {
2451
+ throw new PathTraversalError(base, userPath);
2452
+ }
2453
+ return target;
2454
+ }
2455
+ function safeResolveWithinBase(base, userPath) {
2456
+ try {
2457
+ return resolveWithinBase(base, userPath);
2458
+ } catch {
2459
+ return null;
2460
+ }
2461
+ }
2462
+
2463
+ // packages/daemon/src/web/api/files.ts
2430
2464
  var AVATAR_MIME2 = {
2431
2465
  ".png": "image/png",
2432
2466
  ".jpg": "image/jpeg",
@@ -2470,13 +2504,14 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2470
2504
  return c.json({ error: "Invalid file type (png, jpg, gif, webp only)" }, 400);
2471
2505
  }
2472
2506
  const dir = entry.dir ?? mindDir(name);
2473
- const homeDir = resolve5(dir, "home");
2507
+ const homeDir = resolve6(dir, "home");
2474
2508
  const filename = `avatar${ext}`;
2475
- const avatarPath = resolve5(homeDir, filename);
2509
+ const avatarPath = resolve6(homeDir, filename);
2476
2510
  const config2 = readVoluteConfig(dir) ?? {};
2477
2511
  const oldAvatar = config2.profile?.avatar;
2478
2512
  if (oldAvatar && oldAvatar !== filename) {
2479
- rmSync2(resolve5(homeDir, oldAvatar), { force: true });
2513
+ const oldAvatarPath = safeResolveWithinBase(homeDir, oldAvatar);
2514
+ if (oldAvatarPath) rmSync2(oldAvatarPath, { force: true });
2480
2515
  }
2481
2516
  const buffer2 = Buffer.from(await file.arrayBuffer());
2482
2517
  mkdirSync3(homeDir, { recursive: true });
@@ -2498,8 +2533,8 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2498
2533
  const ext = extname2(config2.profile.avatar).toLowerCase();
2499
2534
  const mime = AVATAR_MIME2[ext];
2500
2535
  if (!mime) return c.json({ error: "Invalid avatar extension" }, 400);
2501
- const homeDir = resolve5(dir, "home");
2502
- const avatarPath = resolve5(homeDir, config2.profile.avatar);
2536
+ const homeDir = resolve6(dir, "home");
2537
+ const avatarPath = resolve6(homeDir, config2.profile.avatar);
2503
2538
  if (!avatarPath.startsWith(`${homeDir}/`)) return c.json({ error: "Invalid avatar path" }, 400);
2504
2539
  let realAvatarPath;
2505
2540
  try {
@@ -2527,7 +2562,7 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2527
2562
  const name = c.req.param("name");
2528
2563
  const entry = await findMind(name);
2529
2564
  if (!entry) return c.json({ error: "Mind not found" }, 404);
2530
- const homeDir = resolve5(entry.dir ?? mindDir(name), "home");
2565
+ const homeDir = resolve6(entry.dir ?? mindDir(name), "home");
2531
2566
  let entries;
2532
2567
  try {
2533
2568
  entries = await readdir(homeDir, { withFileTypes: true });
@@ -2542,10 +2577,10 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
2542
2577
  const name = c.req.param("name");
2543
2578
  const entry = await findMind(name);
2544
2579
  if (!entry) return c.json({ error: "Mind not found" }, 404);
2545
- const homeDir = resolve5(entry.dir ?? mindDir(name), "home");
2580
+ const homeDir = resolve6(entry.dir ?? mindDir(name), "home");
2546
2581
  const wildcard = c.req.path.replace(new RegExp(`^.*/minds/${name}/files`), "") || "/";
2547
2582
  const relativePath = wildcard.slice(1);
2548
- const requestedPath = resolve5(homeDir, relativePath);
2583
+ const requestedPath = resolve6(homeDir, relativePath);
2549
2584
  if (requestedPath !== homeDir && !requestedPath.startsWith(`${homeDir}/`))
2550
2585
  return c.text("Forbidden", 403);
2551
2586
  if (relativePath.split("/").some((seg) => seg.startsWith("."))) return c.text("Forbidden", 403);
@@ -2977,16 +3012,16 @@ import { Hono as Hono12 } from "hono";
2977
3012
  // packages/daemon/src/lib/mind/identity.ts
2978
3013
  import { createHash, generateKeyPairSync, sign, verify } from "crypto";
2979
3014
  import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
2980
- import { resolve as resolve6 } from "path";
3015
+ import { resolve as resolve7 } from "path";
2981
3016
  function generateIdentity(mindDir2) {
2982
- const identityDir = resolve6(mindDir2, ".mind/identity");
3017
+ const identityDir = resolve7(mindDir2, ".mind/identity");
2983
3018
  mkdirSync4(identityDir, { recursive: true });
2984
3019
  const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
2985
3020
  publicKeyEncoding: { type: "spki", format: "pem" },
2986
3021
  privateKeyEncoding: { type: "pkcs8", format: "pem" }
2987
3022
  });
2988
- const privatePath = resolve6(identityDir, "private.pem");
2989
- const publicPath = resolve6(identityDir, "public.pem");
3023
+ const privatePath = resolve7(identityDir, "private.pem");
3024
+ const publicPath = resolve7(identityDir, "public.pem");
2990
3025
  writeFileSync4(privatePath, privateKey, { mode: 384 });
2991
3026
  writeFileSync4(publicPath, publicKey, { mode: 420 });
2992
3027
  const config2 = readVoluteConfig(mindDir2) ?? {};
@@ -3001,7 +3036,7 @@ function getPublicKey(mindDir2) {
3001
3036
  const config2 = readVoluteConfig(mindDir2);
3002
3037
  const relPath = config2?.identity?.publicKey;
3003
3038
  if (!relPath) return null;
3004
- const fullPath = resolve6(mindDir2, relPath);
3039
+ const fullPath = resolve7(mindDir2, relPath);
3005
3040
  if (!existsSync4(fullPath)) return null;
3006
3041
  return readFileSync5(fullPath, "utf-8");
3007
3042
  }
@@ -3051,14 +3086,14 @@ var keys_default = app10;
3051
3086
  // packages/daemon/src/web/api/logs.ts
3052
3087
  import { spawn as spawn2 } from "child_process";
3053
3088
  import { existsSync as existsSync5 } from "fs";
3054
- import { resolve as resolve7 } from "path";
3089
+ import { resolve as resolve8 } from "path";
3055
3090
  import { Hono as Hono13 } from "hono";
3056
3091
  import { streamSSE as streamSSE3 } from "hono/streaming";
3057
- var app11 = new Hono13().get("/:name/logs", async (c) => {
3092
+ var app11 = new Hono13().get("/:name/logs", requireSelf(), async (c) => {
3058
3093
  const name = c.req.param("name");
3059
3094
  const entry = await findMind(name);
3060
3095
  if (!entry) return c.json({ error: "Mind not found" }, 404);
3061
- const logFile = resolve7(stateDir(name), "logs", "mind.log");
3096
+ const logFile = resolve8(stateDir(name), "logs", "mind.log");
3062
3097
  if (!existsSync5(logFile)) {
3063
3098
  return c.json({ error: "No log file found" }, 404);
3064
3099
  }
@@ -3077,16 +3112,16 @@ var app11 = new Hono13().get("/:name/logs", async (c) => {
3077
3112
  stream.onAbort(() => {
3078
3113
  tail.kill();
3079
3114
  });
3080
- await new Promise((resolve17) => {
3081
- tail.on("exit", resolve17);
3082
- stream.onAbort(resolve17);
3115
+ await new Promise((resolve18) => {
3116
+ tail.on("exit", resolve18);
3117
+ stream.onAbort(resolve18);
3083
3118
  });
3084
3119
  });
3085
- }).get("/:name/logs/tail", async (c) => {
3120
+ }).get("/:name/logs/tail", requireSelf(), async (c) => {
3086
3121
  const name = c.req.param("name");
3087
3122
  const entry = await findMind(name);
3088
3123
  if (!entry) return c.json({ error: "Mind not found" }, 404);
3089
- const logFile = resolve7(stateDir(name), "logs", "mind.log");
3124
+ const logFile = resolve8(stateDir(name), "logs", "mind.log");
3090
3125
  if (!existsSync5(logFile)) {
3091
3126
  return c.json({ error: "No log file found" }, 404);
3092
3127
  }
@@ -3097,8 +3132,8 @@ var app11 = new Hono13().get("/:name/logs", async (c) => {
3097
3132
  tail.stdout.on("data", (data) => {
3098
3133
  output += data.toString();
3099
3134
  });
3100
- await new Promise((resolve17) => {
3101
- tail.on("exit", resolve17);
3135
+ await new Promise((resolve18) => {
3136
+ tail.on("exit", resolve18);
3102
3137
  });
3103
3138
  return c.text(output);
3104
3139
  });
@@ -3195,26 +3230,63 @@ import {
3195
3230
  rmSync as rmSync4,
3196
3231
  writeFileSync as writeFileSync7
3197
3232
  } from "fs";
3198
- import { resolve as resolve10 } from "path";
3233
+ import { basename, resolve as resolve11 } from "path";
3199
3234
  import { zValidator as zValidator5 } from "@hono/zod-validator";
3200
3235
  import { and as and4, desc as desc3, eq as eq5, sql as sql2 } from "drizzle-orm";
3201
3236
  import { Hono as Hono15 } from "hono";
3202
3237
  import { z as z5 } from "zod";
3203
3238
 
3239
+ // packages/daemon/src/lib/daemon/error-classify.ts
3240
+ function classify(raw) {
3241
+ const s = (raw ?? "").toLowerCase();
3242
+ if (/\b(401|403)\b|authentication_error|invalid authentication|invalid x-api-key|unauthorized|permission_error/.test(
3243
+ s
3244
+ )) {
3245
+ return {
3246
+ reason: "auth_error",
3247
+ detail: "Your last turn failed because your model credentials were rejected (most often an expired token). The daemon refreshes them automatically, so this is normally transient \u2014 you're fine to continue."
3248
+ };
3249
+ }
3250
+ if (/\b429\b|rate.?limit|too many requests/.test(s)) {
3251
+ return {
3252
+ reason: "rate_limit",
3253
+ detail: "Your last turn failed because you hit the model provider's rate limit. This is temporary \u2014 it clears on its own shortly."
3254
+ };
3255
+ }
3256
+ if (/\b529\b|overloaded/.test(s)) {
3257
+ return {
3258
+ reason: "overloaded",
3259
+ detail: "Your last turn failed because the model provider was overloaded (a 529). This is transient and resolves on its own."
3260
+ };
3261
+ }
3262
+ if (/econnreset|etimedout|enotfound|econnrefused|fetch failed|network|socket hang up|timeout/.test(
3263
+ s
3264
+ )) {
3265
+ return {
3266
+ reason: "network",
3267
+ detail: "Your last turn failed due to a network error reaching the model provider. This is transient \u2014 the connection should recover."
3268
+ };
3269
+ }
3270
+ return {
3271
+ reason: "unknown",
3272
+ detail: `Your last turn failed with an error: ${raw}`
3273
+ };
3274
+ }
3275
+
3204
3276
  // packages/daemon/src/lib/mind/consolidate.ts
3205
3277
  import { readdirSync, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
3206
- import { resolve as resolve8 } from "path";
3278
+ import { resolve as resolve9 } from "path";
3207
3279
  async function consolidateMemory(mindDir2) {
3208
- const soulPath = resolve8(mindDir2, "home/SOUL.md");
3209
- const memoryPath = resolve8(mindDir2, "home/MEMORY.md");
3210
- const memoryDir = resolve8(mindDir2, "home/memory");
3280
+ const soulPath = resolve9(mindDir2, "home/SOUL.md");
3281
+ const memoryPath = resolve9(mindDir2, "home/MEMORY.md");
3282
+ const memoryDir = resolve9(mindDir2, "home/memory");
3211
3283
  const soul = readFileSync6(soulPath, "utf-8");
3212
3284
  const logs = [];
3213
3285
  try {
3214
3286
  const files = readdirSync(memoryDir).filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).sort();
3215
3287
  for (const filename of files) {
3216
3288
  const date = filename.replace(".md", "");
3217
- const content2 = readFileSync6(resolve8(memoryDir, filename), "utf-8").trim();
3289
+ const content2 = readFileSync6(resolve9(memoryDir, filename), "utf-8").trim();
3218
3290
  if (content2) {
3219
3291
  logs.push(`### ${date}
3220
3292
 
@@ -3282,7 +3354,7 @@ async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
3282
3354
  logger_default.warn(`failed to stop variant ${variantName}`, logger_default.errorData(err));
3283
3355
  }
3284
3356
  }
3285
- const { findMind: findMind2 } = await import("./registry-LWEOAO53.js");
3357
+ const { findMind: findMind2 } = await import("./registry-GV35XFT7.js");
3286
3358
  const variantEntry = await findMind2(variantName);
3287
3359
  const branchName = variantEntry?.branch ?? variantName;
3288
3360
  if (existsSync6(variantPath)) {
@@ -3334,7 +3406,7 @@ function validateBranchName(branch) {
3334
3406
  import { randomUUID } from "crypto";
3335
3407
  import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
3336
3408
  import { homedir } from "os";
3337
- import { resolve as resolve9 } from "path";
3409
+ import { resolve as resolve10 } from "path";
3338
3410
  function convertSession(opts) {
3339
3411
  const lines = readFileSync7(opts.sessionPath, "utf-8").trim().split("\n");
3340
3412
  const sessionId = randomUUID();
@@ -3450,9 +3522,9 @@ function convertSession(opts) {
3450
3522
  }
3451
3523
  }
3452
3524
  const projectId = opts.projectDir.replace(/\//g, "-");
3453
- const sdkDir = resolve9(homedir(), ".claude", "projects", projectId);
3525
+ const sdkDir = resolve10(homedir(), ".claude", "projects", projectId);
3454
3526
  mkdirSync5(sdkDir, { recursive: true });
3455
- const sdkPath = resolve9(sdkDir, `${sessionId}.jsonl`);
3527
+ const sdkPath = resolve10(sdkDir, `${sessionId}.jsonl`);
3456
3528
  writeFileSync6(sdkPath, `${sdkEvents.join("\n")}
3457
3529
  `);
3458
3530
  console.log(`Converted ${sdkEvents.length} messages \u2192 ${sdkPath}`);
@@ -3520,13 +3592,26 @@ async function checkHealth(port) {
3520
3592
 
3521
3593
  // packages/daemon/src/web/api/minds.ts
3522
3594
  var SUBSTANTIVE_TYPES = /* @__PURE__ */ new Set(["thinking", "text", "tool_use", "tool_result", "outbound"]);
3595
+ var noticeDrainWatermarks = /* @__PURE__ */ new Map();
3596
+ function markDeliveredOnCleanTurn(mind, session) {
3597
+ if (!session) return;
3598
+ const wmKey = `${mind}:${session}`;
3599
+ const watermark = noticeDrainWatermarks.get(wmKey);
3600
+ noticeDrainWatermarks.delete(wmKey);
3601
+ const errored = takeErrored(mind, session);
3602
+ if (!errored && watermark != null) {
3603
+ clearDeliveredNotices(mind, session, watermark).catch(
3604
+ (err) => logger_default.warn(`failed to clear delivered notices for ${mind}:${session}`, logger_default.errorData(err))
3605
+ );
3606
+ }
3607
+ }
3523
3608
  var _lastActiveCache = { map: /* @__PURE__ */ new Map(), ts: 0 };
3524
3609
  var _LAST_ACTIVE_TTL = 6e4;
3525
3610
  async function getMindStatus(name, port, registryRunning) {
3526
3611
  const manager = getMindManager();
3527
3612
  let status = "stopped";
3528
3613
  try {
3529
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-6QRMUNHK.js");
3614
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-5277OBHI.js");
3530
3615
  if (getSleepManagerIfReady2()?.isSleeping(name)) {
3531
3616
  status = "sleeping";
3532
3617
  }
@@ -3572,7 +3657,7 @@ async function initTemplateBranch(projectRoot, composedDir, manifest, mindName,
3572
3657
  await gitExec(["commit", "-m", "initial commit"], opts);
3573
3658
  }
3574
3659
  async function updateTemplateBranch(projectRoot, template, mindName) {
3575
- const tempWorktree = resolve10(projectRoot, ".variants", "_template_update");
3660
+ const tempWorktree = resolve11(projectRoot, ".variants", "_template_update");
3576
3661
  let branchExists = false;
3577
3662
  try {
3578
3663
  await gitExec(["rev-parse", "--verify", TEMPLATE_BRANCH], { cwd: projectRoot });
@@ -3604,15 +3689,15 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
3604
3689
  });
3605
3690
  }
3606
3691
  copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
3607
- const initDir = resolve10(tempWorktree, ".init");
3692
+ const initDir = resolve11(tempWorktree, ".init");
3608
3693
  if (existsSync7(initDir)) {
3609
3694
  rmSync4(initDir, { recursive: true, force: true });
3610
3695
  }
3611
- const homeDir = resolve10(tempWorktree, "home");
3696
+ const homeDir = resolve11(tempWorktree, "home");
3612
3697
  if (existsSync7(homeDir)) {
3613
3698
  for (const entry of readdirSync2(homeDir)) {
3614
3699
  if (entry !== "VOLUTE.md") {
3615
- rmSync4(resolve10(homeDir, entry), { recursive: true, force: true });
3700
+ rmSync4(resolve11(homeDir, entry), { recursive: true, force: true });
3616
3701
  }
3617
3702
  }
3618
3703
  }
@@ -3653,7 +3738,7 @@ async function mergeTemplateBranch(worktreeDir) {
3653
3738
  async function npmInstallAsMind(cwd, mindName) {
3654
3739
  if (isIsolationEnabled()) {
3655
3740
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
3656
- await exec(cmd, args, { cwd, env: { ...process.env, HOME: resolve10(cwd, "home") } });
3741
+ await exec(cmd, args, { cwd, env: { ...process.env, HOME: resolve11(cwd, "home") } });
3657
3742
  } else {
3658
3743
  await exec("npm", ["install"], { cwd });
3659
3744
  }
@@ -3704,7 +3789,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
3704
3789
  return { ok: true };
3705
3790
  }
3706
3791
  async function importFromArchive(c, tempDir, nameOverride, manifest) {
3707
- const extractedMindDir = resolve10(tempDir, "mind");
3792
+ const extractedMindDir = resolve11(tempDir, "mind");
3708
3793
  if (!existsSync7(extractedMindDir)) {
3709
3794
  return c.json({ error: "Invalid archive: missing mind/ directory" }, 400);
3710
3795
  }
@@ -3731,9 +3816,9 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
3731
3816
  }
3732
3817
  const state = stateDir(name);
3733
3818
  mkdirSync6(state, { recursive: true });
3734
- const envJson = resolve10(tempDir, "state/env.json");
3819
+ const envJson = resolve11(tempDir, "state/env.json");
3735
3820
  if (existsSync7(envJson)) {
3736
- cpSync(envJson, resolve10(state, "env.json"));
3821
+ cpSync(envJson, resolve11(state, "env.json"));
3737
3822
  }
3738
3823
  const port = await nextPort();
3739
3824
  await addMind(name, port, manifest.stage, manifest.template);
@@ -3742,23 +3827,23 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
3742
3827
  } catch (err) {
3743
3828
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
3744
3829
  }
3745
- const homeDir = resolve10(dest, "home");
3830
+ const homeDir = resolve11(dest, "home");
3746
3831
  ensureVoluteGroup();
3747
3832
  createMindUser(name, homeDir);
3748
3833
  chownMindDir(dest, name);
3749
3834
  await npmInstallAsMind(dest, name);
3750
3835
  await importHistoryFromArchive(name, tempDir);
3751
3836
  importSessionsFromArchive(dest, tempDir);
3752
- if (!existsSync7(resolve10(dest, ".git"))) {
3837
+ if (!existsSync7(resolve11(dest, ".git"))) {
3753
3838
  try {
3754
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dest, "home") } : void 0;
3839
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
3755
3840
  await gitExec(["init"], { cwd: dest, mindName: name, env });
3756
3841
  await configureGitIdentity(name, { cwd: dest, mindName: name, env });
3757
3842
  await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
3758
3843
  await gitExec(["commit", "-m", "import from archive"], { cwd: dest, mindName: name, env });
3759
3844
  } catch (err) {
3760
3845
  logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
3761
- rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
3846
+ rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
3762
3847
  }
3763
3848
  }
3764
3849
  chownMindDir(dest, name);
@@ -3791,22 +3876,22 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
3791
3876
  try {
3792
3877
  copyTemplateToDir(composedDir, dest, name, templateManifest);
3793
3878
  applyInitFiles(dest);
3794
- const extractedHome = resolve10(extractedMindDir, "home");
3879
+ const extractedHome = resolve11(extractedMindDir, "home");
3795
3880
  if (existsSync7(extractedHome)) {
3796
- cpSync(extractedHome, resolve10(dest, "home"), { recursive: true });
3881
+ cpSync(extractedHome, resolve11(dest, "home"), { recursive: true });
3797
3882
  }
3798
- const extractedMindInternal = resolve10(extractedMindDir, ".mind");
3883
+ const extractedMindInternal = resolve11(extractedMindDir, ".mind");
3799
3884
  if (existsSync7(extractedMindInternal)) {
3800
- cpSync(extractedMindInternal, resolve10(dest, ".mind"), { recursive: true });
3885
+ cpSync(extractedMindInternal, resolve11(dest, ".mind"), { recursive: true });
3801
3886
  }
3802
- const identityDir = resolve10(dest, ".mind/identity");
3887
+ const identityDir = resolve11(dest, ".mind/identity");
3803
3888
  let publicKeyPem;
3804
- if (!manifest.includes.identity || !existsSync7(resolve10(identityDir, "private.pem"))) {
3889
+ if (!manifest.includes.identity || !existsSync7(resolve11(identityDir, "private.pem"))) {
3805
3890
  ({ publicKeyPem } = generateIdentity(dest));
3806
3891
  } else {
3807
- publicKeyPem = readFileSync8(resolve10(identityDir, "public.pem"), "utf-8");
3892
+ publicKeyPem = readFileSync8(resolve11(identityDir, "public.pem"), "utf-8");
3808
3893
  }
3809
- const promptsPath = resolve10(dest, "home/.config/prompts.json");
3894
+ const promptsPath = resolve11(dest, "home/.config/prompts.json");
3810
3895
  if (!existsSync7(promptsPath)) {
3811
3896
  const mindPrompts = await getMindPromptDefaults();
3812
3897
  writeFileSync7(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
@@ -3814,13 +3899,13 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
3814
3899
  }
3815
3900
  const state = stateDir(name);
3816
3901
  mkdirSync6(state, { recursive: true });
3817
- const envJson = resolve10(tempDir, "state/env.json");
3902
+ const envJson = resolve11(tempDir, "state/env.json");
3818
3903
  if (existsSync7(envJson)) {
3819
- cpSync(envJson, resolve10(state, "env.json"));
3904
+ cpSync(envJson, resolve11(state, "env.json"));
3820
3905
  }
3821
3906
  const port = await nextPort();
3822
3907
  await addMind(name, port, manifest.stage, manifest.template);
3823
- const homeDir = resolve10(dest, "home");
3908
+ const homeDir = resolve11(dest, "home");
3824
3909
  ensureVoluteGroup();
3825
3910
  createMindUser(name, homeDir);
3826
3911
  chownMindDir(dest, name);
@@ -3833,7 +3918,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
3833
3918
  await initTemplateBranch(dest, composedDir, templateManifest, name, env);
3834
3919
  } catch (err) {
3835
3920
  logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
3836
- rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
3921
+ rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
3837
3922
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
3838
3923
  }
3839
3924
  const skillSet = manifest.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions();
@@ -3876,7 +3961,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
3876
3961
  }
3877
3962
  }
3878
3963
  async function importHistoryFromArchive(name, tempDir) {
3879
- const historyJsonl = resolve10(tempDir, "history.jsonl");
3964
+ const historyJsonl = resolve11(tempDir, "history.jsonl");
3880
3965
  if (!existsSync7(historyJsonl)) return;
3881
3966
  try {
3882
3967
  const db = await getDb();
@@ -3916,13 +4001,13 @@ async function importHistoryFromArchive(name, tempDir) {
3916
4001
  }
3917
4002
  }
3918
4003
  function importSessionsFromArchive(dest, tempDir) {
3919
- const sessionsDir = resolve10(tempDir, "sessions");
4004
+ const sessionsDir = resolve11(tempDir, "sessions");
3920
4005
  if (!existsSync7(sessionsDir)) return;
3921
4006
  try {
3922
- const destSessions = resolve10(dest, ".mind/sessions");
4007
+ const destSessions = resolve11(dest, ".mind/sessions");
3923
4008
  mkdirSync6(destSessions, { recursive: true });
3924
4009
  for (const file of readdirSync2(sessionsDir)) {
3925
- cpSync(resolve10(sessionsDir, file), resolve10(destSessions, file));
4010
+ cpSync(resolve11(sessionsDir, file), resolve11(destSessions, file));
3926
4011
  }
3927
4012
  } catch (err) {
3928
4013
  logger_default.error("Failed to import sessions from archive", logger_default.errorData(err));
@@ -3948,6 +4033,38 @@ function formatTimeAgo(date) {
3948
4033
  const days = Math.floor(hours / 24);
3949
4034
  return `${days}d ago`;
3950
4035
  }
4036
+ async function proxyToMind(c, path) {
4037
+ const name = c.req.param("name");
4038
+ const entry = await findMind(name);
4039
+ if (!entry) return c.json({ error: "Mind not found" }, 404);
4040
+ if (!getMindManager().isRunning(name)) {
4041
+ return c.json({ error: "Mind is not running" }, 503);
4042
+ }
4043
+ try {
4044
+ const res = await fetch(`http://127.0.0.1:${entry.port}/${path}`, {
4045
+ signal: AbortSignal.timeout(1e4)
4046
+ });
4047
+ if (!res.ok) {
4048
+ const status = res.status >= 500 ? 502 : 404;
4049
+ return c.json(
4050
+ {
4051
+ error: res.status >= 500 ? `Mind ${path} handler errored` : `${path} endpoint not available`
4052
+ },
4053
+ status
4054
+ );
4055
+ }
4056
+ let data;
4057
+ try {
4058
+ data = await res.json();
4059
+ } catch {
4060
+ return c.json({ error: "Mind returned invalid response" }, 502);
4061
+ }
4062
+ return c.json(data);
4063
+ } catch (err) {
4064
+ console.error(`${path} proxy for ${name}:`, err);
4065
+ return c.json({ error: "Failed to reach mind" }, 503);
4066
+ }
4067
+ }
3951
4068
  var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", createMindSchema), async (c) => {
3952
4069
  const body = c.req.valid("json");
3953
4070
  const { name } = body;
@@ -3965,7 +4082,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
3965
4082
  applyInitFiles(dest);
3966
4083
  const { publicKeyPem } = generateIdentity(dest);
3967
4084
  {
3968
- const { readGlobalConfig: readGlobal } = await import("./setup-IFYS3TLS.js");
4085
+ const { readGlobalConfig: readGlobal } = await import("./setup-OTEC3ZPM.js");
3969
4086
  const mindDefaults = readGlobal().mindDefaults;
3970
4087
  const config2 = readVoluteConfig(dest);
3971
4088
  if (!config2) throw new Error("Failed to read volute.json after identity generation");
@@ -4002,7 +4119,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4002
4119
  }
4003
4120
  writeVoluteConfig(dest, config2);
4004
4121
  const modelId = body.model ?? cog?.model;
4005
- const sdkConfigPath = resolve10(dest, "home/.config/config.json");
4122
+ const sdkConfigPath = resolve11(dest, "home/.config/config.json");
4006
4123
  if (modelId || cog?.compaction) {
4007
4124
  const existing = existsSync7(sdkConfigPath) ? JSON.parse(readFileSync8(sdkConfigPath, "utf-8")) : {};
4008
4125
  if (modelId) {
@@ -4017,7 +4134,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4017
4134
  }
4018
4135
  const mindPrompts = await getMindPromptDefaults();
4019
4136
  writeFileSync7(
4020
- resolve10(dest, "home/.config/prompts.json"),
4137
+ resolve11(dest, "home/.config/prompts.json"),
4021
4138
  `${JSON.stringify(mindPrompts, null, 2)}
4022
4139
  `
4023
4140
  );
@@ -4029,7 +4146,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4029
4146
  } catch (err) {
4030
4147
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
4031
4148
  }
4032
- const homeDir = resolve10(dest, "home");
4149
+ const homeDir = resolve11(dest, "home");
4033
4150
  ensureVoluteGroup();
4034
4151
  createMindUser(name, homeDir);
4035
4152
  chownMindDir(dest, name);
@@ -4042,7 +4159,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
4042
4159
  await initTemplateBranch(dest, composedDir, manifest, name, env);
4043
4160
  } catch (err) {
4044
4161
  logger_default.error(`git setup failed for ${name}`, logger_default.errorData(err));
4045
- rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
4162
+ rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
4046
4163
  gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
4047
4164
  }
4048
4165
  chownMindDir(dest, name);
@@ -4052,11 +4169,11 @@ The human who planted you described you as: "${body.description}"
4052
4169
  ` : "";
4053
4170
  const seedSoulRaw = body.seedSoul ?? await getPrompt("seed_soul", { name, description: descLine });
4054
4171
  const seedSoul = body.seedSoul ? substitute(seedSoulRaw, { name, description: descLine }) : seedSoulRaw;
4055
- writeFileSync7(resolve10(dest, "home/SOUL.md"), seedSoul);
4172
+ writeFileSync7(resolve11(dest, "home/SOUL.md"), seedSoul);
4056
4173
  }
4057
4174
  let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
4058
4175
  if (body.stage === "seed" && !body.skills) {
4059
- const { isImagegenEnabled } = await import("./setup-IFYS3TLS.js");
4176
+ const { isImagegenEnabled } = await import("./setup-OTEC3ZPM.js");
4060
4177
  if (isImagegenEnabled()) {
4061
4178
  skillSet = [...skillSet, "imagegen"];
4062
4179
  }
@@ -4074,7 +4191,7 @@ The human who planted you described you as: "${body.description}"
4074
4191
  try {
4075
4192
  const spiritEntry = await findMind("volute");
4076
4193
  if (spiritEntry) {
4077
- const { spiritDir } = await import("./spirit-U6MDQLYT.js");
4194
+ const { spiritDir } = await import("./spirit-NVXWSVKM.js");
4078
4195
  const sDir = spiritEntry.dir ?? spiritDir();
4079
4196
  const spiritConfig = readVoluteConfig(sDir) ?? {};
4080
4197
  const schedules = spiritConfig.schedules ?? [];
@@ -4089,7 +4206,7 @@ The human who planted you described you as: "${body.description}"
4089
4206
  });
4090
4207
  spiritConfig.schedules = schedules;
4091
4208
  writeVoluteConfig(sDir, spiritConfig);
4092
- const { getScheduler: getScheduler2 } = await import("./scheduler-CGUPAEBA.js");
4209
+ const { getScheduler: getScheduler2 } = await import("./scheduler-GQBDCGLU.js");
4093
4210
  getScheduler2().loadSchedules("volute", sDir);
4094
4211
  }
4095
4212
  }
@@ -4100,11 +4217,11 @@ The human who planted you described you as: "${body.description}"
4100
4217
  if (body.stage !== "seed") {
4101
4218
  const customSoul = await getPromptIfCustom("default_soul");
4102
4219
  if (customSoul) {
4103
- writeFileSync7(resolve10(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
4220
+ writeFileSync7(resolve11(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
4104
4221
  }
4105
4222
  const customMemory = await getPromptIfCustom("default_memory");
4106
4223
  if (customMemory) {
4107
- writeFileSync7(resolve10(dest, "home/MEMORY.md"), customMemory);
4224
+ writeFileSync7(resolve11(dest, "home/MEMORY.md"), customMemory);
4108
4225
  }
4109
4226
  }
4110
4227
  publishPublicKey(name, publicKeyPem).catch(
@@ -4153,12 +4270,12 @@ The human who planted you described you as: "${body.description}"
4153
4270
  return importFromArchive(c, body.archivePath, body.name, body.manifest);
4154
4271
  }
4155
4272
  const wsDir = body.workspacePath;
4156
- if (!wsDir || !existsSync7(resolve10(wsDir, "SOUL.md")) || !existsSync7(resolve10(wsDir, "IDENTITY.md"))) {
4273
+ if (!wsDir || !existsSync7(resolve11(wsDir, "SOUL.md")) || !existsSync7(resolve11(wsDir, "IDENTITY.md"))) {
4157
4274
  return c.json({ error: "Invalid workspace: missing SOUL.md or IDENTITY.md" }, 400);
4158
4275
  }
4159
- const soul = readFileSync8(resolve10(wsDir, "SOUL.md"), "utf-8");
4160
- const identity = readFileSync8(resolve10(wsDir, "IDENTITY.md"), "utf-8");
4161
- const userPath = resolve10(wsDir, "USER.md");
4276
+ const soul = readFileSync8(resolve11(wsDir, "SOUL.md"), "utf-8");
4277
+ const identity = readFileSync8(resolve11(wsDir, "IDENTITY.md"), "utf-8");
4278
+ const userPath = resolve11(wsDir, "USER.md");
4162
4279
  const user = existsSync7(userPath) ? readFileSync8(userPath, "utf-8") : "";
4163
4280
  const name = body.name ?? parseNameFromIdentity(identity) ?? "imported-mind";
4164
4281
  const template = body.template ?? "claude";
@@ -4186,26 +4303,26 @@ ${user.trimEnd()}
4186
4303
  copyTemplateToDir(composedDir, dest, name, manifest);
4187
4304
  applyInitFiles(dest);
4188
4305
  const { publicKeyPem: importPublicKey } = generateIdentity(dest);
4189
- writeFileSync7(resolve10(dest, "home/SOUL.md"), mergedSoul);
4190
- const wsMemoryPath = resolve10(wsDir, "MEMORY.md");
4306
+ writeFileSync7(resolve11(dest, "home/SOUL.md"), mergedSoul);
4307
+ const wsMemoryPath = resolve11(wsDir, "MEMORY.md");
4191
4308
  const hasMemory = existsSync7(wsMemoryPath);
4192
4309
  if (hasMemory) {
4193
4310
  const existingMemory = readFileSync8(wsMemoryPath, "utf-8");
4194
4311
  writeFileSync7(
4195
- resolve10(dest, "home/MEMORY.md"),
4312
+ resolve11(dest, "home/MEMORY.md"),
4196
4313
  `${existingMemory.trimEnd()}${mergedMemoryExtra}`
4197
4314
  );
4198
4315
  } else if (user) {
4199
- writeFileSync7(resolve10(dest, "home/MEMORY.md"), `${user.trimEnd()}
4316
+ writeFileSync7(resolve11(dest, "home/MEMORY.md"), `${user.trimEnd()}
4200
4317
  `);
4201
4318
  }
4202
- const wsMemoryDir = resolve10(wsDir, "memory");
4319
+ const wsMemoryDir = resolve11(wsDir, "memory");
4203
4320
  let dailyLogCount = 0;
4204
4321
  if (existsSync7(wsMemoryDir)) {
4205
- const destMemoryDir = resolve10(dest, "home/memory");
4322
+ const destMemoryDir = resolve11(dest, "home/memory");
4206
4323
  const files = readdirSync2(wsMemoryDir).filter((f) => f.endsWith(".md"));
4207
4324
  for (const file of files) {
4208
- cpSync(resolve10(wsMemoryDir, file), resolve10(destMemoryDir, file));
4325
+ cpSync(resolve11(wsMemoryDir, file), resolve11(destMemoryDir, file));
4209
4326
  }
4210
4327
  dailyLogCount = files.length;
4211
4328
  }
@@ -4216,7 +4333,7 @@ ${user.trimEnd()}
4216
4333
  } catch (err) {
4217
4334
  logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
4218
4335
  }
4219
- const homeDir = resolve10(dest, "home");
4336
+ const homeDir = resolve11(dest, "home");
4220
4337
  ensureVoluteGroup();
4221
4338
  createMindUser(name, homeDir);
4222
4339
  chownMindDir(dest, name);
@@ -4224,20 +4341,20 @@ ${user.trimEnd()}
4224
4341
  if (!hasMemory && dailyLogCount > 0) {
4225
4342
  await consolidateMemory(dest);
4226
4343
  }
4227
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dest, "home") } : void 0;
4344
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
4228
4345
  await gitExec(["init"], { cwd: dest, mindName: name, env });
4229
4346
  await configureGitIdentity(name, { cwd: dest, mindName: name, env });
4230
4347
  await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
4231
4348
  await gitExec(["commit", "-m", "import from OpenClaw"], { cwd: dest, mindName: name, env });
4232
- const sessionFile = body.sessionPath ? resolve10(body.sessionPath) : findOpenClawSession(wsDir);
4349
+ const sessionFile = body.sessionPath ? resolve11(body.sessionPath) : findOpenClawSession(wsDir);
4233
4350
  if (sessionFile && existsSync7(sessionFile)) {
4234
4351
  if (template === "pi") {
4235
4352
  importPiSession(sessionFile, dest);
4236
4353
  } else if (template === "claude") {
4237
4354
  const sessionId = convertSession({ sessionPath: sessionFile, projectDir: dest });
4238
- const mindRuntimeDir = resolve10(dest, ".mind");
4355
+ const mindRuntimeDir = resolve11(dest, ".mind");
4239
4356
  mkdirSync6(mindRuntimeDir, { recursive: true });
4240
- writeFileSync7(resolve10(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
4357
+ writeFileSync7(resolve11(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
4241
4358
  }
4242
4359
  }
4243
4360
  importOpenClawConnectors(name, dest);
@@ -4278,7 +4395,7 @@ ${user.trimEnd()}
4278
4395
  const minds = await Promise.all(
4279
4396
  entries.map(async (entry) => {
4280
4397
  const mindStatus = await getMindStatus(entry.name, entry.port, entry.running);
4281
- const hasPages = existsSync7(resolve10(mindDir(entry.name), "home", "pages"));
4398
+ const hasPages = existsSync7(resolve11(mindDir(entry.name), "home", "pages"));
4282
4399
  return {
4283
4400
  ...entry,
4284
4401
  ...mindStatus,
@@ -4307,35 +4424,9 @@ ${user.trimEnd()}
4307
4424
  return { name: s.name, port: s.port, status: variantStatus };
4308
4425
  })
4309
4426
  );
4310
- const hasPages = existsSync7(resolve10(mindDir(name), "home", "pages"));
4427
+ const hasPages = existsSync7(resolve11(mindDir(name), "home", "pages"));
4311
4428
  return c.json({ ...entry, ...mindStatus, variants: variantStatuses, hasPages });
4312
- }).get("/:name/context", async (c) => {
4313
- const name = c.req.param("name");
4314
- const entry = await findMind(name);
4315
- if (!entry) return c.json({ error: "Mind not found" }, 404);
4316
- if (!getMindManager().isRunning(name)) {
4317
- return c.json({ error: "Mind is not running" }, 503);
4318
- }
4319
- try {
4320
- const res = await fetch(`http://127.0.0.1:${entry.port}/context`, {
4321
- signal: AbortSignal.timeout(3e3)
4322
- });
4323
- if (!res.ok) {
4324
- const status = res.status >= 500 ? 502 : 404;
4325
- return c.json(
4326
- {
4327
- error: res.status >= 500 ? "Mind context handler errored" : "Context endpoint not available"
4328
- },
4329
- status
4330
- );
4331
- }
4332
- const data = await res.json();
4333
- return c.json(data);
4334
- } catch (err) {
4335
- console.error(`context proxy for ${name}:`, err);
4336
- return c.json({ error: "Failed to reach mind" }, 503);
4337
- }
4338
- }).post("/:name/start", requireSelf(), async (c) => {
4429
+ }).get("/:name/context", requireSelf(), async (c) => proxyToMind(c, "context")).get("/:name/context/messages", requireSelf(), async (c) => proxyToMind(c, "context/messages")).post("/:name/start", requireSelf(), async (c) => {
4339
4430
  const name = c.req.param("name");
4340
4431
  const entry = await findMind(name);
4341
4432
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -4380,7 +4471,7 @@ ${user.trimEnd()}
4380
4471
  const manager = getMindManager();
4381
4472
  try {
4382
4473
  if (context?.type === "reload") {
4383
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-6QRMUNHK.js");
4474
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-5277OBHI.js");
4384
4475
  const sleepState = getSleepManagerIfReady2()?.getState(name);
4385
4476
  if (sleepState?.sleeping) {
4386
4477
  logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
@@ -4475,7 +4566,7 @@ ${user.trimEnd()}
4475
4566
  const name = c.req.param("name");
4476
4567
  const entry = await findMind(name);
4477
4568
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4478
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-6QRMUNHK.js");
4569
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-5277OBHI.js");
4479
4570
  const sm = getSleepManagerIfReady2();
4480
4571
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4481
4572
  return c.json(sm.getState(name));
@@ -4483,7 +4574,7 @@ ${user.trimEnd()}
4483
4574
  const name = c.req.param("name");
4484
4575
  const entry = await findMind(name);
4485
4576
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4486
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-6QRMUNHK.js");
4577
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-5277OBHI.js");
4487
4578
  const sm = getSleepManagerIfReady2();
4488
4579
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4489
4580
  if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
@@ -4503,7 +4594,7 @@ ${user.trimEnd()}
4503
4594
  const name = c.req.param("name");
4504
4595
  const entry = await findMind(name);
4505
4596
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4506
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-6QRMUNHK.js");
4597
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-5277OBHI.js");
4507
4598
  const sm = getSleepManagerIfReady2();
4508
4599
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4509
4600
  const sleepState = sm.getState(name);
@@ -4518,7 +4609,7 @@ ${user.trimEnd()}
4518
4609
  const name = c.req.param("name");
4519
4610
  const entry = await findMind(name);
4520
4611
  if (!entry) return c.json({ error: "Mind not found" }, 404);
4521
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-6QRMUNHK.js");
4612
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-5277OBHI.js");
4522
4613
  const sm = getSleepManagerIfReady2();
4523
4614
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
4524
4615
  const flushed = await sm.flushQueuedMessages(name);
@@ -4533,10 +4624,10 @@ ${user.trimEnd()}
4533
4624
  const profile = config2.profile ?? {};
4534
4625
  if (body.displayName !== void 0) profile.displayName = body.displayName;
4535
4626
  if (body.description !== void 0) profile.description = body.description;
4536
- if (body.avatar !== void 0) profile.avatar = body.avatar;
4627
+ if (body.avatar !== void 0) profile.avatar = basename(body.avatar);
4537
4628
  config2.profile = profile;
4538
4629
  writeVoluteConfig(dir, config2);
4539
- const { syncMindProfile: syncMindProfile2 } = await import("./auth-OJ2YW3NR.js");
4630
+ const { syncMindProfile: syncMindProfile2 } = await import("./auth-X6ZITZ7D.js");
4540
4631
  await syncMindProfile2(name, profile);
4541
4632
  broadcast({ type: "profile_updated", mind: name, summary: `${name} profile updated` });
4542
4633
  return c.json({ ok: true });
@@ -4576,14 +4667,14 @@ ${user.trimEnd()}
4576
4667
  return c.json({ output: "" });
4577
4668
  }
4578
4669
  const dir = entry.dir ?? mindDir(name);
4579
- const soulPath = resolve10(dir, "home/SOUL.md");
4580
- const memoryPath = resolve10(dir, "home/MEMORY.md");
4670
+ const soulPath = resolve11(dir, "home/SOUL.md");
4671
+ const memoryPath = resolve11(dir, "home/MEMORY.md");
4581
4672
  const soulCustom = existsSync7(soulPath) && !readFileSync8(soulPath, "utf-8").includes(ORIENTATION_MARKER);
4582
4673
  const memoryWritten = existsSync7(memoryPath) && readFileSync8(memoryPath, "utf-8").trim().length > 0;
4583
4674
  const config2 = readVoluteConfig(dir);
4584
4675
  const displayNameSet = !!config2?.profile?.displayName;
4585
4676
  const avatarSet = !!config2?.profile?.avatar;
4586
- const { isImagegenEnabled } = await import("./setup-IFYS3TLS.js");
4677
+ const { isImagegenEnabled } = await import("./setup-OTEC3ZPM.js");
4587
4678
  const imagegenEnabled = isImagegenEnabled();
4588
4679
  const done = [];
4589
4680
  const remaining = [];
@@ -4621,7 +4712,7 @@ ${user.trimEnd()}
4621
4712
  try {
4622
4713
  const spiritEntry = await findMind("volute");
4623
4714
  if (spiritEntry) {
4624
- const { spiritDir } = await import("./spirit-U6MDQLYT.js");
4715
+ const { spiritDir } = await import("./spirit-NVXWSVKM.js");
4625
4716
  const sDir = spiritEntry.dir ?? spiritDir();
4626
4717
  const spiritConfig = readVoluteConfig(sDir);
4627
4718
  if (spiritConfig?.schedules) {
@@ -4629,7 +4720,7 @@ ${user.trimEnd()}
4629
4720
  spiritConfig.schedules = spiritConfig.schedules.filter((s) => s.id !== nurtureId);
4630
4721
  if (spiritConfig.schedules.length === 0) spiritConfig.schedules = void 0;
4631
4722
  writeVoluteConfig(sDir, spiritConfig);
4632
- const { getScheduler: getScheduler2 } = await import("./scheduler-CGUPAEBA.js");
4723
+ const { getScheduler: getScheduler2 } = await import("./scheduler-GQBDCGLU.js");
4633
4724
  getScheduler2().loadSchedules("volute", sDir);
4634
4725
  }
4635
4726
  }
@@ -4684,16 +4775,16 @@ ${user.trimEnd()}
4684
4775
  const template = body.template ?? entry.template ?? "claude";
4685
4776
  const UPGRADE_BRANCH = "upgrade";
4686
4777
  const upgradeVariantName = `${mindName}-upgrade`;
4687
- const worktreeDir = resolve10(dir, ".variants", UPGRADE_BRANCH);
4778
+ const worktreeDir = resolve11(dir, ".variants", UPGRADE_BRANCH);
4688
4779
  if (body.abort) {
4689
4780
  if (!existsSync7(worktreeDir)) {
4690
4781
  return c.json({ error: "No upgrade in progress" }, 400);
4691
4782
  }
4692
4783
  try {
4693
4784
  try {
4694
- const gitDirContent = readFileSync8(resolve10(worktreeDir, ".git"), "utf-8").trim();
4785
+ const gitDirContent = readFileSync8(resolve11(worktreeDir, ".git"), "utf-8").trim();
4695
4786
  const gitDir = gitDirContent.replace("gitdir: ", "");
4696
- if (existsSync7(resolve10(gitDir, "MERGE_HEAD"))) {
4787
+ if (existsSync7(resolve11(gitDir, "MERGE_HEAD"))) {
4697
4788
  await gitExec(["merge", "--abort"], { cwd: worktreeDir });
4698
4789
  }
4699
4790
  } catch {
@@ -4776,7 +4867,7 @@ ${user.trimEnd()}
4776
4867
  }
4777
4868
  if (body.diff) {
4778
4869
  try {
4779
- if (!existsSync7(resolve10(dir, ".git"))) {
4870
+ if (!existsSync7(resolve11(dir, ".git"))) {
4780
4871
  return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
4781
4872
  }
4782
4873
  await updateTemplateBranch(dir, template, mindName);
@@ -4800,16 +4891,16 @@ ${user.trimEnd()}
4800
4891
  409
4801
4892
  );
4802
4893
  }
4803
- if (!existsSync7(resolve10(dir, ".git"))) {
4894
+ if (!existsSync7(resolve11(dir, ".git"))) {
4804
4895
  try {
4805
- const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dir, "home") } : void 0;
4896
+ const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dir, "home") } : void 0;
4806
4897
  await gitExec(["init"], { cwd: dir, mindName, env });
4807
4898
  await configureGitIdentity(mindName, { cwd: dir, mindName, env });
4808
4899
  await gitExec(["add", "-A"], { cwd: dir, mindName, env });
4809
4900
  await gitExec(["commit", "-m", "initial commit"], { cwd: dir, mindName, env });
4810
4901
  chownMindDir(dir, mindName);
4811
4902
  } catch (err) {
4812
- rmSync4(resolve10(dir, ".git"), { recursive: true, force: true });
4903
+ rmSync4(resolve11(dir, ".git"), { recursive: true, force: true });
4813
4904
  return c.json(
4814
4905
  {
4815
4906
  error: `Git initialization failed: ${err instanceof Error ? err.message : String(err)}`
@@ -4824,7 +4915,7 @@ ${user.trimEnd()}
4824
4915
  } catch {
4825
4916
  }
4826
4917
  await updateTemplateBranch(dir, template, mindName);
4827
- const parentDir = resolve10(dir, ".variants");
4918
+ const parentDir = resolve11(dir, ".variants");
4828
4919
  if (!existsSync7(parentDir)) {
4829
4920
  mkdirSync6(parentDir, { recursive: true });
4830
4921
  }
@@ -4943,13 +5034,13 @@ ${user.trimEnd()}
4943
5034
  }
4944
5035
  const result = await getMessagesPaginated(convId, { before, limit });
4945
5036
  return c.json({ items: result.messages, hasMore: result.hasMore });
4946
- }).get("/:name/budget", async (c) => {
5037
+ }).get("/:name/budget", requireSelf(), async (c) => {
4947
5038
  const name = c.req.param("name");
4948
5039
  const baseName = await getBaseName(name);
4949
5040
  const usage = getTokenBudget().getUsage(baseName);
4950
5041
  if (!usage) return c.json({ error: "No budget configured" }, 404);
4951
5042
  return c.json(usage);
4952
- }).get("/:name/config", async (c) => {
5043
+ }).get("/:name/config", requireSelf(), async (c) => {
4953
5044
  const name = c.req.param("name");
4954
5045
  const entry = await findMind(name);
4955
5046
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -4957,7 +5048,7 @@ ${user.trimEnd()}
4957
5048
  if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
4958
5049
  let config2 = readVoluteConfig(dir);
4959
5050
  if (!config2 && entry.template === "pi") {
4960
- const piConfigPath = resolve10(dir, "home/.config/config.json");
5051
+ const piConfigPath = resolve11(dir, "home/.config/config.json");
4961
5052
  if (existsSync7(piConfigPath)) {
4962
5053
  try {
4963
5054
  config2 = JSON.parse(readFileSync8(piConfigPath, "utf-8"));
@@ -4966,7 +5057,7 @@ ${user.trimEnd()}
4966
5057
  }
4967
5058
  }
4968
5059
  let templateConfig = {};
4969
- const configJsonPath = resolve10(dir, "home/.config/config.json");
5060
+ const configJsonPath = resolve11(dir, "home/.config/config.json");
4970
5061
  if (existsSync7(configJsonPath)) {
4971
5062
  try {
4972
5063
  templateConfig = JSON.parse(readFileSync8(configJsonPath, "utf-8"));
@@ -5058,12 +5149,12 @@ ${user.trimEnd()}
5058
5149
  }
5059
5150
  writeVoluteConfig(dir, existing);
5060
5151
  if (body.unescapeNewlines !== void 0) {
5061
- const { clearEchoTextCache } = await import("./echo-text-N3BC3WNX.js");
5152
+ const { clearEchoTextCache } = await import("./echo-text-QFCH3H6G.js");
5062
5153
  clearEchoTextCache(name);
5063
5154
  }
5064
5155
  const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.maxThinkingTokens !== void 0 || body.compaction !== void 0;
5065
5156
  if (needsConfigJson) {
5066
- const configJsonPath = resolve10(dir, "home/.config/config.json");
5157
+ const configJsonPath = resolve11(dir, "home/.config/config.json");
5067
5158
  let templateConfig = {};
5068
5159
  if (existsSync7(configJsonPath)) {
5069
5160
  try {
@@ -5135,7 +5226,7 @@ ${user.trimEnd()}
5135
5226
  }
5136
5227
  if (entry.mindType === "spirit" && body.model !== void 0) {
5137
5228
  try {
5138
- const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-IFYS3TLS.js");
5229
+ const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-OTEC3ZPM.js");
5139
5230
  const globalConfig = readGlobalConfig2();
5140
5231
  globalConfig.spiritModel = body.model;
5141
5232
  writeGlobalConfig2(globalConfig);
@@ -5145,7 +5236,7 @@ ${user.trimEnd()}
5145
5236
  }
5146
5237
  return c.json({ ok: true });
5147
5238
  }
5148
- ).get("/:name/delivery/pending", async (c) => {
5239
+ ).get("/:name/delivery/pending", requireSelf(), async (c) => {
5149
5240
  const name = c.req.param("name");
5150
5241
  const baseName = await getBaseName(name);
5151
5242
  try {
@@ -5163,7 +5254,7 @@ ${user.trimEnd()}
5163
5254
  if (!body.systemPrompt || !body.message) {
5164
5255
  return c.json({ error: "systemPrompt and message required" }, 400);
5165
5256
  }
5166
- const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-PL7GKFQC.js");
5257
+ const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-AUWIPWLP.js");
5167
5258
  if (!isAiConfigured()) {
5168
5259
  return c.json({ error: "AI service not configured" }, 503);
5169
5260
  }
@@ -5270,6 +5361,18 @@ ${user.trimEnd()}
5270
5361
  const affected = map.deleteSender(baseName);
5271
5362
  publishTypingForChannels(affected, map);
5272
5363
  }
5364
+ if (body.type === "error" && body.session) {
5365
+ markErrored(baseName, body.session);
5366
+ const { reason, detail } = classify(body.content ?? "");
5367
+ await recordNotice({
5368
+ mind: baseName,
5369
+ session: body.session,
5370
+ kind: "turn_error",
5371
+ reason,
5372
+ detail,
5373
+ raw: body.content ?? null
5374
+ });
5375
+ }
5273
5376
  if (body.type === "done") {
5274
5377
  const map = getTypingMap();
5275
5378
  const affected = map.deleteSender(baseName);
@@ -5292,6 +5395,7 @@ ${user.trimEnd()}
5292
5395
  (err) => logger_default.warn("failed to tag orphaned outbound records", logger_default.errorData(err))
5293
5396
  );
5294
5397
  }
5398
+ markDeliveredOnCleanTurn(baseName, body.session);
5295
5399
  if (insertedId != null) {
5296
5400
  summarizeTurn(baseName, body.session, body.channel, insertedId, completedTurnId).catch(
5297
5401
  (err) => logger_default.error("turn summarization failed", logger_default.errorData(err))
@@ -5308,6 +5412,7 @@ ${user.trimEnd()}
5308
5412
  (err2) => logger_default.warn("failed to tag orphaned outbound records", logger_default.errorData(err2))
5309
5413
  );
5310
5414
  }
5415
+ markDeliveredOnCleanTurn(baseName, body.session);
5311
5416
  if (insertedId != null) {
5312
5417
  summarizeTurn(baseName, body.session, body.channel, insertedId, completedTurnId).catch(
5313
5418
  (err2) => logger_default.error("turn summarization failed", logger_default.errorData(err2))
@@ -5318,10 +5423,20 @@ ${user.trimEnd()}
5318
5423
  if (body.type === "usage" && body.metadata) {
5319
5424
  const inputTokens = body.metadata.input_tokens ?? 0;
5320
5425
  const outputTokens = body.metadata.output_tokens ?? 0;
5321
- getTokenBudget().recordUsage(baseName, inputTokens, outputTokens);
5426
+ const tb = getTokenBudget();
5427
+ tb.recordUsage(baseName, inputTokens, outputTokens);
5428
+ if (body.session && tb.noteExceeded(baseName)) {
5429
+ void recordNotice({
5430
+ mind: baseName,
5431
+ session: body.session,
5432
+ kind: "budget",
5433
+ reason: "token_budget",
5434
+ detail: "You've reached your token budget for this period. Further activity may be paused until the budget resets \u2014 wrap up or prioritize accordingly."
5435
+ });
5436
+ }
5322
5437
  }
5323
5438
  return c.json({ ok: true });
5324
- }).get("/:name/events", async (c) => {
5439
+ }).get("/:name/events", requireSelf(), async (c) => {
5325
5440
  const name = c.req.param("name");
5326
5441
  const baseName = await getBaseName(name);
5327
5442
  const entry = await findMind(baseName);
@@ -5403,7 +5518,7 @@ ${user.trimEnd()}
5403
5518
  return c.json({ error: "Failed to persist" }, 500);
5404
5519
  }
5405
5520
  return c.json({ ok: true });
5406
- }).get("/:name/history/sessions", async (c) => {
5521
+ }).get("/:name/history/sessions", requireSelf(), async (c) => {
5407
5522
  const name = c.req.param("name");
5408
5523
  const db = await getDb();
5409
5524
  const rows = await db.select({
@@ -5414,18 +5529,18 @@ ${user.trimEnd()}
5414
5529
  tool_count: sql2`SUM(CASE WHEN ${mindHistory.type}='tool_use' THEN 1 ELSE 0 END)`
5415
5530
  }).from(mindHistory).where(and4(eq5(mindHistory.mind, name), sql2`${mindHistory.session} IS NOT NULL`)).groupBy(mindHistory.session).orderBy(sql2`MIN(${mindHistory.created_at}) DESC`);
5416
5531
  return c.json(rows);
5417
- }).get("/:name/history/channels", async (c) => {
5532
+ }).get("/:name/history/channels", requireSelf(), async (c) => {
5418
5533
  const name = c.req.param("name");
5419
5534
  const db = await getDb();
5420
5535
  const rows = await db.selectDistinct({ channel: mindHistory.channel }).from(mindHistory).where(eq5(mindHistory.mind, name));
5421
5536
  return c.json(rows.map((r) => r.channel));
5422
- }).get("/:name/history/export", async (c) => {
5537
+ }).get("/:name/history/export", requireSelf(), async (c) => {
5423
5538
  const name = c.req.param("name");
5424
5539
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
5425
5540
  const db = await getDb();
5426
5541
  const rows = await db.select().from(mindHistory).where(eq5(mindHistory.mind, name));
5427
5542
  return c.json(rows);
5428
- }).get("/:name/history/turn", async (c) => {
5543
+ }).get("/:name/history/turn", requireSelf(), async (c) => {
5429
5544
  const name = c.req.param("name");
5430
5545
  const turnId = c.req.query("turn_id");
5431
5546
  const detail = c.req.query("detail") === "1";
@@ -5452,7 +5567,7 @@ ${user.trimEnd()}
5452
5567
  ).orderBy(mindHistory.id);
5453
5568
  }
5454
5569
  return c.json(rows);
5455
- }).get("/:name/history/cross-session", async (c) => {
5570
+ }).get("/:name/history/cross-session", requireSelf(), async (c) => {
5456
5571
  const name = c.req.param("name");
5457
5572
  const currentSession = c.req.query("session");
5458
5573
  const db = await getDb();
@@ -5498,7 +5613,17 @@ ${user.trimEnd()}
5498
5613
  });
5499
5614
  return c.json({ context: `[Session Activity]
5500
5615
  ${lines.join("\n")}` });
5501
- }).get("/:name/history", async (c) => {
5616
+ }).get("/:name/history/notices", requireSelf(), async (c) => {
5617
+ const name = c.req.param("name");
5618
+ const baseName = await getBaseName(name);
5619
+ const session = c.req.query("session");
5620
+ if (!session) return c.json({ context: null, notices: [] });
5621
+ const notices = await drainNotices(baseName, session);
5622
+ if (notices.length === 0) return c.json({ context: null, notices: [] });
5623
+ const maxId = notices.reduce((m, n) => Math.max(m, n.id), 0);
5624
+ noticeDrainWatermarks.set(`${baseName}:${session}`, maxId);
5625
+ return c.json({ context: formatNotices(notices), notices });
5626
+ }).get("/:name/history", requireSelf(), async (c) => {
5502
5627
  const name = c.req.param("name");
5503
5628
  const channel = c.req.query("channel");
5504
5629
  const session = c.req.query("session");
@@ -5649,7 +5774,7 @@ function writeSchedules(name, dir, schedules) {
5649
5774
  data: { schedules }
5650
5775
  });
5651
5776
  }
5652
- var app15 = new Hono17().get("/:name/clock/status", async (c) => {
5777
+ var app15 = new Hono17().get("/:name/clock/status", requireSelf(), async (c) => {
5653
5778
  const name = c.req.param("name");
5654
5779
  const entry = await findMind(name);
5655
5780
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -5708,7 +5833,7 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
5708
5833
  upcoming.sort((a, b) => a.at.localeCompare(b.at));
5709
5834
  previous.sort((a, b) => b.at.localeCompare(a.at));
5710
5835
  return c.json({ sleep: sleepState, sleepConfig, schedules, upcoming, previous });
5711
- }).get("/:name/sleep/config", async (c) => {
5836
+ }).get("/:name/sleep/config", requireSelf(), async (c) => {
5712
5837
  const name = c.req.param("name");
5713
5838
  const entry = await findMind(name);
5714
5839
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -5740,7 +5865,7 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
5740
5865
  writeVoluteConfig(dir, config2);
5741
5866
  getSleepManagerIfReady()?.invalidateSleepConfig(name);
5742
5867
  return c.json({ ok: true });
5743
- }).get("/:name/schedules", async (c) => {
5868
+ }).get("/:name/schedules", requireSelf(), async (c) => {
5744
5869
  const name = c.req.param("name");
5745
5870
  const entry = await findMind(name);
5746
5871
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -5865,7 +5990,7 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
5865
5990
  }
5866
5991
  writeSchedules(name, dir, filtered);
5867
5992
  return c.json({ ok: true });
5868
- }).post("/:name/webhook/:event", async (c) => {
5993
+ }).post("/:name/webhook/:event", requireSelf(), async (c) => {
5869
5994
  const name = c.req.param("name");
5870
5995
  const event = c.req.param("event");
5871
5996
  const entry = await findMind(name);
@@ -5873,7 +5998,7 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
5873
5998
  const body = await c.req.text();
5874
5999
  const message = `[webhook: ${event}] ${body}`;
5875
6000
  try {
5876
- const { sendSystemMessage } = await import("./system-chat-D343HYGR.js");
6001
+ const { sendSystemMessage } = await import("./system-chat-LQSJVY55.js");
5877
6002
  await sendSystemMessage(name, message);
5878
6003
  return c.json({ ok: true });
5879
6004
  } catch (err) {
@@ -5886,14 +6011,14 @@ var schedules_default = app15;
5886
6011
  // packages/daemon/src/web/api/setup.ts
5887
6012
  import { mkdirSync as mkdirSync7 } from "fs";
5888
6013
  import { homedir as homedir2 } from "os";
5889
- import { resolve as resolve11 } from "path";
6014
+ import { resolve as resolve12 } from "path";
5890
6015
  import { Hono as Hono18 } from "hono";
5891
6016
  import { setCookie as setCookie2 } from "hono/cookie";
5892
6017
  var DEFAULT_API_URL2 = "https://volute.systems";
5893
6018
  var setup = new Hono18();
5894
6019
  function writeSetupConfig(systemName, description) {
5895
- const configHome = process.env.VOLUTE_HOME ?? resolve11(homedir2(), ".volute");
5896
- const mindsDir = resolve11(configHome, "minds");
6020
+ const configHome = process.env.VOLUTE_HOME ?? resolve12(homedir2(), ".volute");
6021
+ const mindsDir = resolve12(configHome, "minds");
5897
6022
  mkdirSync7(configHome, { recursive: true });
5898
6023
  mkdirSync7(mindsDir, { recursive: true });
5899
6024
  const existingConfig = readGlobalConfig();
@@ -5927,7 +6052,7 @@ setup.get("/status", async (c) => {
5927
6052
  let hasAccount = false;
5928
6053
  if (hasSystem) {
5929
6054
  try {
5930
- const { listUsersByType: listUsersByType2 } = await import("./auth-OJ2YW3NR.js");
6055
+ const { listUsersByType: listUsersByType2 } = await import("./auth-X6ZITZ7D.js");
5931
6056
  const brains = await listUsersByType2("brain");
5932
6057
  hasAccount = brains.length > 0;
5933
6058
  } catch (err) {
@@ -6138,7 +6263,7 @@ setup.post("/account", async (c) => {
6138
6263
  }
6139
6264
  }
6140
6265
  try {
6141
- const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-OJ2YW3NR.js");
6266
+ const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-X6ZITZ7D.js");
6142
6267
  const user = await createUser2(body.username.trim(), body.password);
6143
6268
  if (body.displayName?.trim()) {
6144
6269
  await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
@@ -6184,7 +6309,7 @@ setup.post("/models", async (c) => {
6184
6309
  return c.json({ error: "Spirit model is required" }, 400);
6185
6310
  }
6186
6311
  try {
6187
- const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-PL7GKFQC.js");
6312
+ const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-AUWIPWLP.js");
6188
6313
  setEnabledModels3(body.models);
6189
6314
  const config2 = readGlobalConfig();
6190
6315
  config2.spiritModel = body.spiritModel.trim();
@@ -6202,15 +6327,15 @@ setup.post("/complete", async (c) => {
6202
6327
  return c.json({ error: "Setup already complete" }, 400);
6203
6328
  }
6204
6329
  try {
6205
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-U6MDQLYT.js");
6206
- const { startSpiritFull } = await import("./mind-service-MO2XJKJN.js");
6330
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-NVXWSVKM.js");
6331
+ const { startSpiritFull } = await import("./mind-service-WTOFVNLW.js");
6207
6332
  await ensureSpiritProject();
6208
6333
  await syncSpiritTemplate();
6209
6334
  const warnings = [];
6210
6335
  const config2 = readGlobalConfig();
6211
6336
  if (config2.setup?.service && config2.setup?.type === "local") {
6212
6337
  try {
6213
- const { installUserService } = await import("./service-install-KEBDNZVE.js");
6338
+ const { installUserService } = await import("./service-install-W3FQXJKB.js");
6214
6339
  const installed = await installUserService(config2.port, config2.hostname);
6215
6340
  if (!installed) {
6216
6341
  warnings.push("Service installation is not supported on this platform.");
@@ -6238,8 +6363,8 @@ setup.post("/complete", async (c) => {
6238
6363
  }
6239
6364
  let spiritConversationId;
6240
6365
  try {
6241
- const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-OJ2YW3NR.js");
6242
- const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-EUXHBWJD.js");
6366
+ const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-X6ZITZ7D.js");
6367
+ const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-AYLXPOGC.js");
6243
6368
  const spiritUser = await getOrCreateMindUser2("volute");
6244
6369
  const brains = await listUsersByType2("brain");
6245
6370
  const admin2 = brains.find((u) => u.role === "admin");
@@ -6261,8 +6386,8 @@ setup.post("/complete", async (c) => {
6261
6386
  logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
6262
6387
  if (spiritConversationId && spiritStarted) {
6263
6388
  try {
6264
- const { deliverMessage: deliverMessage2 } = await import("./message-delivery-X7MKA3TA.js");
6265
- const { listUsersByType: listUsers2 } = await import("./auth-OJ2YW3NR.js");
6389
+ const { deliverMessage: deliverMessage2 } = await import("./message-delivery-7BCYJLH2.js");
6390
+ const { listUsersByType: listUsers2 } = await import("./auth-X6ZITZ7D.js");
6266
6391
  const admins = await listUsers2("brain");
6267
6392
  const admin2 = admins.find((u) => u.role === "admin");
6268
6393
  const adminName = admin2?.display_name || admin2?.username || "the admin";
@@ -6301,7 +6426,7 @@ var setup_default = setup;
6301
6426
  // packages/daemon/src/web/api/skills.ts
6302
6427
  import { existsSync as existsSync8, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync5 } from "fs";
6303
6428
  import { tmpdir } from "os";
6304
- import { join, resolve as resolve12 } from "path";
6429
+ import { join, resolve as resolve13 } from "path";
6305
6430
  import AdmZip from "adm-zip";
6306
6431
  import { Hono as Hono19 } from "hono";
6307
6432
  var app16 = new Hono19().get("/", async (c) => {
@@ -6377,7 +6502,7 @@ var app16 = new Hono19().get("/", async (c) => {
6377
6502
  try {
6378
6503
  const zip = new AdmZip(buffer2);
6379
6504
  for (const entry of zip.getEntries()) {
6380
- const target = resolve12(tmpDir, entry.entryName);
6505
+ const target = resolve13(tmpDir, entry.entryName);
6381
6506
  if (!target.startsWith(tmpDir)) {
6382
6507
  return c.json({ error: "Invalid zip: paths must not escape archive" }, 400);
6383
6508
  }
@@ -6719,8 +6844,8 @@ var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
6719
6844
  });
6720
6845
  }, 15e3);
6721
6846
  cleanups.push(() => clearInterval(keepAlive));
6722
- await new Promise((resolve17) => {
6723
- stream.onAbort(() => resolve17());
6847
+ await new Promise((resolve18) => {
6848
+ stream.onAbort(() => resolve18());
6724
6849
  });
6725
6850
  } finally {
6726
6851
  for (const cleanup of cleanups) {
@@ -6736,15 +6861,15 @@ var events_default = app20;
6736
6861
 
6737
6862
  // packages/daemon/src/web/api/variants.ts
6738
6863
  import { existsSync as existsSync9, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8 } from "fs";
6739
- import { resolve as resolve14 } from "path";
6864
+ import { resolve as resolve15 } from "path";
6740
6865
  import { Hono as Hono24 } from "hono";
6741
6866
 
6742
6867
  // packages/daemon/src/lib/mind/spawn-server.ts
6743
6868
  import { spawn as spawn4 } from "child_process";
6744
6869
  import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync9 } from "fs";
6745
- import { resolve as resolve13 } from "path";
6870
+ import { resolve as resolve14 } from "path";
6746
6871
  function tsxBin(cwd) {
6747
- return resolve13(cwd, "node_modules", ".bin", "tsx");
6872
+ return resolve14(cwd, "node_modules", ".bin", "tsx");
6748
6873
  }
6749
6874
  function spawnServer(cwd, port, options) {
6750
6875
  if (options?.detached) {
@@ -6757,31 +6882,31 @@ function spawnAttached(cwd, port) {
6757
6882
  cwd,
6758
6883
  stdio: ["ignore", "pipe", "pipe"]
6759
6884
  });
6760
- return new Promise((resolve17) => {
6761
- const timeout = setTimeout(() => resolve17(null), 3e4);
6885
+ return new Promise((resolve18) => {
6886
+ const timeout = setTimeout(() => resolve18(null), 3e4);
6762
6887
  function checkOutput(data) {
6763
6888
  const match = data.toString().match(/listening on :(\d+)/);
6764
6889
  if (match) {
6765
6890
  clearTimeout(timeout);
6766
- resolve17({ child, actualPort: parseInt(match[1], 10) });
6891
+ resolve18({ child, actualPort: parseInt(match[1], 10) });
6767
6892
  }
6768
6893
  }
6769
6894
  child.stdout?.on("data", checkOutput);
6770
6895
  child.stderr?.on("data", checkOutput);
6771
6896
  child.on("error", () => {
6772
6897
  clearTimeout(timeout);
6773
- resolve17(null);
6898
+ resolve18(null);
6774
6899
  });
6775
6900
  child.on("exit", () => {
6776
6901
  clearTimeout(timeout);
6777
- resolve17(null);
6902
+ resolve18(null);
6778
6903
  });
6779
6904
  });
6780
6905
  }
6781
6906
  function spawnDetached(cwd, port, logDir) {
6782
- const logsDir = logDir ?? resolve13(cwd, ".mind", "logs");
6907
+ const logsDir = logDir ?? resolve14(cwd, ".mind", "logs");
6783
6908
  mkdirSync8(logsDir, { recursive: true });
6784
- const logPath = resolve13(logsDir, "mind.log");
6909
+ const logPath = resolve14(logsDir, "mind.log");
6785
6910
  const logFd = openSync(logPath, "a");
6786
6911
  const child = spawn4(tsxBin(cwd), ["src/server.ts", "--port", String(port)], {
6787
6912
  cwd,
@@ -6897,11 +7022,11 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
6897
7022
  return c.json({ error: `Name already in use: ${variantName}` }, 409);
6898
7023
  }
6899
7024
  const projectRoot = mindDir(mindName);
6900
- const variantDir = resolve14(projectRoot, ".variants", variantName);
7025
+ const variantDir = resolve15(projectRoot, ".variants", variantName);
6901
7026
  if (existsSync9(variantDir)) {
6902
7027
  return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
6903
7028
  }
6904
- mkdirSync9(resolve14(projectRoot, ".variants"), { recursive: true });
7029
+ mkdirSync9(resolve15(projectRoot, ".variants"), { recursive: true });
6905
7030
  try {
6906
7031
  await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
6907
7032
  } catch (e) {
@@ -6914,7 +7039,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
6914
7039
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
6915
7040
  await exec(cmd, args, {
6916
7041
  cwd: variantDir,
6917
- env: { ...process.env, HOME: resolve14(variantDir, "home") }
7042
+ env: { ...process.env, HOME: resolve15(variantDir, "home") }
6918
7043
  });
6919
7044
  } else {
6920
7045
  await exec("npm", ["install"], { cwd: variantDir });
@@ -6924,7 +7049,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
6924
7049
  return c.json({ error: `npm install failed: ${msg}` }, 500);
6925
7050
  }
6926
7051
  if (body.soul) {
6927
- writeFileSync8(resolve14(variantDir, "home/SOUL.md"), body.soul);
7052
+ writeFileSync8(resolve15(variantDir, "home/SOUL.md"), body.soul);
6928
7053
  }
6929
7054
  const variantPort = body.port ?? await nextPort();
6930
7055
  await addVariant(variantName, mindName, variantPort, variantDir, variantName);
@@ -7019,8 +7144,8 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7019
7144
  await cleanupVariant(variantName, projectRoot, variantEntry.dir);
7020
7145
  if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
7021
7146
  try {
7022
- const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-SSIBEEYK.js");
7023
- const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-LWEOAO53.js");
7147
+ const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-DMHSLRDX.js");
7148
+ const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-GV35XFT7.js");
7024
7149
  const tmpl = parentEntry.template ?? "claude";
7025
7150
  await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
7026
7151
  } catch (err) {
@@ -7033,7 +7158,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
7033
7158
  const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
7034
7159
  await exec(cmd, args, {
7035
7160
  cwd: projectRoot,
7036
- env: { ...process.env, HOME: resolve14(projectRoot, "home") }
7161
+ env: { ...process.env, HOME: resolve15(projectRoot, "home") }
7037
7162
  });
7038
7163
  } else {
7039
7164
  await exec("npm", ["install"], { cwd: projectRoot });
@@ -7450,11 +7575,11 @@ var app23 = new Hono26().get("/:name/conversations/:id/events", async (c) => {
7450
7575
  if (!stream.aborted) console.error("[chat] SSE ping error:", err);
7451
7576
  });
7452
7577
  }, 15e3);
7453
- await new Promise((resolve17) => {
7578
+ await new Promise((resolve18) => {
7454
7579
  stream.onAbort(() => {
7455
7580
  unsubscribe();
7456
7581
  clearInterval(keepAlive);
7457
- resolve17();
7582
+ resolve18();
7458
7583
  });
7459
7584
  });
7460
7585
  });
@@ -7667,7 +7792,7 @@ var app_default = app25;
7667
7792
  import { existsSync as existsSync10 } from "fs";
7668
7793
  import { readFile as readFile2, stat as stat2 } from "fs/promises";
7669
7794
  import { createServer as createHttpsServer } from "https";
7670
- import { dirname as dirname2, extname as extname3, resolve as resolve15 } from "path";
7795
+ import { dirname as dirname2, extname as extname3, resolve as resolve16 } from "path";
7671
7796
  import { serve } from "@hono/node-server";
7672
7797
  var MIME_TYPES2 = {
7673
7798
  ".html": "text/html",
@@ -7686,7 +7811,7 @@ async function startServer({
7686
7811
  let assetsDir = "";
7687
7812
  let searchDir = dirname2(new URL(import.meta.url).pathname);
7688
7813
  for (let i = 0; i < 5; i++) {
7689
- const candidate = resolve15(searchDir, "dist", "web-assets");
7814
+ const candidate = resolve16(searchDir, "dist", "web-assets");
7690
7815
  if (existsSync10(candidate)) {
7691
7816
  assetsDir = candidate;
7692
7817
  break;
@@ -7697,20 +7822,20 @@ async function startServer({
7697
7822
  app_default.get("*", async (c) => {
7698
7823
  const urlPath = new URL(c.req.url).pathname;
7699
7824
  if (urlPath.startsWith("/api/") || urlPath.startsWith("/ext/")) return c.notFound();
7700
- const filePath = resolve15(assetsDir, urlPath.slice(1));
7825
+ const filePath = resolve16(assetsDir, urlPath.slice(1));
7701
7826
  if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
7702
7827
  const s = await stat2(filePath).catch(() => null);
7703
7828
  if (s?.isFile()) {
7704
7829
  const ext = extname3(filePath);
7705
7830
  const mime = MIME_TYPES2[ext] || "application/octet-stream";
7706
7831
  const body = await readFile2(filePath);
7707
- const basename = filePath.slice(filePath.lastIndexOf("/") + 1);
7708
- const nameWithoutExt = basename.slice(0, basename.lastIndexOf("."));
7832
+ const basename2 = filePath.slice(filePath.lastIndexOf("/") + 1);
7833
+ const nameWithoutExt = basename2.slice(0, basename2.lastIndexOf("."));
7709
7834
  const isHashed = /[-.][\da-f]{8,}$/.test(nameWithoutExt);
7710
7835
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
7711
7836
  return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
7712
7837
  }
7713
- const indexPath = resolve15(assetsDir, "index.html");
7838
+ const indexPath = resolve16(assetsDir, "index.html");
7714
7839
  const indexStat = await stat2(indexPath).catch(() => null);
7715
7840
  if (indexStat?.isFile()) {
7716
7841
  const body = await readFile2(indexPath, "utf-8");
@@ -7727,10 +7852,10 @@ async function startServer({
7727
7852
  createServer: createHttpsServer,
7728
7853
  serverOptions: { key: tls.key, cert: tls.cert }
7729
7854
  });
7730
- await new Promise((resolve17, reject) => {
7855
+ await new Promise((resolve18, reject) => {
7731
7856
  server2.on("listening", () => {
7732
7857
  logger_default.info("Volute UI running (https)", { hostname, port });
7733
- resolve17();
7858
+ resolve18();
7734
7859
  });
7735
7860
  server2.on("error", (err) => {
7736
7861
  reject(err);
@@ -7738,13 +7863,13 @@ async function startServer({
7738
7863
  });
7739
7864
  const internalPort = port + 1;
7740
7865
  const internalServer = serve({ fetch: app_default.fetch, port: internalPort, hostname: "127.0.0.1" });
7741
- await new Promise((resolve17, reject) => {
7866
+ await new Promise((resolve18, reject) => {
7742
7867
  internalServer.on("listening", () => {
7743
7868
  logger_default.info("Volute API running (http, internal)", {
7744
7869
  hostname: "127.0.0.1",
7745
7870
  port: internalPort
7746
7871
  });
7747
- resolve17();
7872
+ resolve18();
7748
7873
  });
7749
7874
  internalServer.on("error", (err) => {
7750
7875
  reject(err);
@@ -7753,10 +7878,10 @@ async function startServer({
7753
7878
  return { server: server2, internalPort };
7754
7879
  }
7755
7880
  const server = serve({ fetch: app_default.fetch, port, hostname });
7756
- await new Promise((resolve17, reject) => {
7881
+ await new Promise((resolve18, reject) => {
7757
7882
  server.on("listening", () => {
7758
7883
  logger_default.info("Volute API running (http)", { hostname, port });
7759
- resolve17();
7884
+ resolve18();
7760
7885
  });
7761
7886
  server.on("error", (err) => {
7762
7887
  reject(err);
@@ -7767,7 +7892,7 @@ async function startServer({
7767
7892
 
7768
7893
  // packages/daemon/src/daemon.ts
7769
7894
  if (!process.env.VOLUTE_HOME) {
7770
- process.env.VOLUTE_HOME = resolve16(homedir3(), ".volute");
7895
+ process.env.VOLUTE_HOME = resolve17(homedir3(), ".volute");
7771
7896
  }
7772
7897
  if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
7773
7898
  process.env.TZ = process.env.VOLUTE_TIMEZONE;
@@ -7778,7 +7903,7 @@ async function startDaemon(opts) {
7778
7903
  const home = voluteHome();
7779
7904
  const systemDir = voluteSystemDir();
7780
7905
  if (!opts.foreground) {
7781
- const rotatingLog = new RotatingLog(resolve16(systemDir, "daemon.log"));
7906
+ const rotatingLog = new RotatingLog(resolve17(systemDir, "daemon.log"));
7782
7907
  logger_default.setOutput((line) => rotatingLog.write(`${line}
7783
7908
  `));
7784
7909
  const write = (...args) => rotatingLog.write(`${format(...args)}
@@ -7788,22 +7913,22 @@ async function startDaemon(opts) {
7788
7913
  console.warn = write;
7789
7914
  console.info = write;
7790
7915
  }
7791
- const DAEMON_PID_PATH = resolve16(systemDir, "daemon.pid");
7792
- const DAEMON_JSON_PATH = resolve16(systemDir, "daemon.json");
7916
+ const DAEMON_PID_PATH = resolve17(systemDir, "daemon.pid");
7917
+ const DAEMON_JSON_PATH = resolve17(systemDir, "daemon.json");
7793
7918
  mkdirSync10(home, { recursive: true });
7794
7919
  ensureSystemDir();
7795
- const { migrateSetupCompleted } = await import("./setup-IFYS3TLS.js");
7920
+ const { migrateSetupCompleted } = await import("./setup-OTEC3ZPM.js");
7796
7921
  migrateSetupCompleted();
7797
- await (await import("./db-32YFKMFL.js")).getDb();
7922
+ await (await import("./db-ZEPKEJJD.js")).getDb();
7798
7923
  try {
7799
7924
  const { eq: eq7, and: and5 } = await import("drizzle-orm");
7800
- const { users: users2 } = await import("./schema-K575EBPE.js");
7801
- const db = await (await import("./db-32YFKMFL.js")).getDb();
7925
+ const { users: users2 } = await import("./schema-LYQUDL7G.js");
7926
+ const db = await (await import("./db-ZEPKEJJD.js")).getDb();
7802
7927
  await db.update(users2).set({ role: "system" }).where(and5(eq7(users2.user_type, "system"), eq7(users2.role, "user")));
7803
7928
  } catch (err) {
7804
7929
  logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
7805
7930
  }
7806
- const { initSandbox } = await import("./sandbox-KUAVC37A.js");
7931
+ const { initSandbox } = await import("./sandbox-5R32QKWQ.js");
7807
7932
  await initSandbox();
7808
7933
  try {
7809
7934
  await syncBuiltinSkills();
@@ -7830,7 +7955,7 @@ async function startDaemon(opts) {
7830
7955
  logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
7831
7956
  }
7832
7957
  try {
7833
- const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-OJ2YW3NR.js");
7958
+ const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-X6ZITZ7D.js");
7834
7959
  await getOrCreateSystemUser2();
7835
7960
  } catch (err) {
7836
7961
  logger_default.warn(
@@ -7839,12 +7964,12 @@ async function startDaemon(opts) {
7839
7964
  );
7840
7965
  }
7841
7966
  const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes(32).toString("hex");
7842
- const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-IFYS3TLS.js");
7967
+ const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-OTEC3ZPM.js");
7843
7968
  const globalCfg = readGlobalConfig2();
7844
7969
  let tls;
7845
7970
  if (opts.tailscale || globalCfg.tailscale) {
7846
7971
  try {
7847
- const { getTailscaleTls } = await import("./tailscale-2KKXDMNK.js");
7972
+ const { getTailscaleTls } = await import("./tailscale-X4HRKRTW.js");
7848
7973
  const tlsConfig = await getTailscaleTls();
7849
7974
  tls = { key: tlsConfig.key, cert: tlsConfig.cert };
7850
7975
  logger_default.info("Tailscale HTTPS enabled", { hostname: tlsConfig.hostname });
@@ -7923,10 +8048,10 @@ async function startDaemon(opts) {
7923
8048
  await Promise.all(workers);
7924
8049
  }
7925
8050
  try {
7926
- const { isSetupComplete: isSetupComplete2 } = await import("./setup-IFYS3TLS.js");
8051
+ const { isSetupComplete: isSetupComplete2 } = await import("./setup-OTEC3ZPM.js");
7927
8052
  if (isSetupComplete2()) {
7928
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-U6MDQLYT.js");
7929
- const { startSpiritFull } = await import("./mind-service-MO2XJKJN.js");
8053
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-NVXWSVKM.js");
8054
+ const { startSpiritFull } = await import("./mind-service-WTOFVNLW.js");
7930
8055
  await ensureSpiritProject();
7931
8056
  await syncSpiritTemplate();
7932
8057
  const spiritEntry = await findMind("volute");
@@ -7943,7 +8068,7 @@ async function startDaemon(opts) {
7943
8068
  bridgeManager.startBridges(daemonPort).catch((err) => {
7944
8069
  logger_default.warn("failed to start bridges", logger_default.errorData(err));
7945
8070
  });
7946
- import("./cloud-sync-NQCWJLYI.js").then(
8071
+ import("./cloud-sync-MAQCJEFJ.js").then(
7947
8072
  ({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
7948
8073
  logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
7949
8074
  })
@@ -7951,7 +8076,7 @@ async function startDaemon(opts) {
7951
8076
  logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
7952
8077
  });
7953
8078
  try {
7954
- const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-ZBMY2TEX.js");
8079
+ const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-N37N2C4G.js");
7955
8080
  backfillTemplateHashes();
7956
8081
  notifyVersionUpdate().catch((err) => {
7957
8082
  logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
@@ -7968,6 +8093,11 @@ async function startDaemon(opts) {
7968
8093
  cleanExpiredLogs().catch((err) => {
7969
8094
  logger_default.warn("failed to clean expired logs", logger_default.errorData(err));
7970
8095
  });
8096
+ setProviderRefreshHook((provider) => {
8097
+ void syncProviderToMinds(provider, {
8098
+ listRunning: () => getMindManager().getRunningMinds()
8099
+ }).catch((err) => logger_default.warn("credential sync to minds failed", logger_default.errorData(err)));
8100
+ });
7971
8101
  startApiKeyRefresh();
7972
8102
  logger_default.info(`running on ${hostname}:${port}, pid ${myPid}`);
7973
8103
  function cleanup() {