volute 0.49.0 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/README.md +2 -2
  2. package/dist/{accept-KYNC5X3U.js → accept-5NK5XJB5.js} +2 -1
  3. package/dist/{activity-events-GJJAI2WT.js → activity-events-LQII6PZS.js} +3 -3
  4. package/dist/{ai-service-A7FS7EC3.js → ai-service-YW5SWCSB.js} +9 -4
  5. package/dist/{archive-7E3YE6VF.js → archive-FOHGXHPT.js} +3 -3
  6. package/dist/{auth-ABYLOEZ7.js → auth-X6EMNEGB.js} +10 -6
  7. package/dist/{avatar-image-6ATV2IOZ.js → avatar-image-52WGXLHV.js} +3 -3
  8. package/dist/{backup-XYAMT4CU.js → backup-YVGV2ZNM.js} +11 -12
  9. package/dist/{bridge-3FNSWLNQ.js → bridge-YK7NTRU5.js} +2 -1
  10. package/dist/{channels-SGQZHNQJ.js → channels-FSAHOQWI.js} +2 -1
  11. package/dist/{chat-OGXAEXMV.js → chat-VAZ25KVT.js} +9 -9
  12. package/dist/{chunk-P4LHVRNE.js → chunk-2RNMBXD2.js} +43 -19
  13. package/dist/{chunk-6HGEZJDH.js → chunk-5N32EN4O.js} +2 -2
  14. package/dist/{chunk-JCWB2ITW.js → chunk-5Y54AE3L.js} +35 -5
  15. package/dist/{chunk-HCYQRME2.js → chunk-6NLW72HP.js} +2 -2
  16. package/dist/chunk-7HN63Q7J.js +1317 -0
  17. package/dist/chunk-7YJY3F2R.js +38 -0
  18. package/dist/{chunk-EADX54RG.js → chunk-AI47FDGL.js} +6 -7
  19. package/dist/{chunk-IH5TKXX6.js → chunk-BSHZ23MS.js} +12 -11
  20. package/dist/{chunk-K3JOLGWF.js → chunk-CDKQJWGK.js} +76 -63
  21. package/dist/{chunk-L27YYONJ.js → chunk-CV6BNGFK.js} +3 -3
  22. package/dist/{chunk-NOIAHMJB.js → chunk-DMK5ASKV.js} +1 -1
  23. package/dist/chunk-DN3LKLYR.js +109 -0
  24. package/dist/{chunk-JBIFXB6I.js → chunk-EDR47UE2.js} +3 -5
  25. package/dist/{chunk-SHKM5RGD.js → chunk-EEOMA4DX.js} +1 -1
  26. package/dist/{chunk-YIJGKHIS.js → chunk-EGV6R6UF.js} +43 -20
  27. package/dist/{chunk-KHCKZ36O.js → chunk-FLIEXG2T.js} +1 -1
  28. package/dist/chunk-FNJCBRD3.js +31 -0
  29. package/dist/{chunk-JPGHSXSV.js → chunk-FXWBFDQR.js} +23 -9
  30. package/dist/{chunk-JCBPU57A.js → chunk-G7A5LEVI.js} +6 -6
  31. package/dist/{chunk-PY24ZL62.js → chunk-GLM7TVWP.js} +1 -1
  32. package/dist/{chunk-RSBL3FAD.js → chunk-H6X6CKDN.js} +235 -24
  33. package/dist/{chunk-4DSGN4FL.js → chunk-HKP6OAJP.js} +43 -13
  34. package/dist/{chunk-C3KLHJDB.js → chunk-HTRSSOHY.js} +1 -1
  35. package/dist/{chunk-EG5LSKHU.js → chunk-I7U5EEZC.js} +2 -2
  36. package/dist/chunk-ICL6T4SN.js +562 -0
  37. package/dist/{chunk-FBBS4BVR.js → chunk-ICXY54ZC.js} +1 -1
  38. package/dist/{chunk-DAIIMBLB.js → chunk-IWAVIJO2.js} +3 -5
  39. package/dist/{chunk-TXJL36ZQ.js → chunk-JHKBALS2.js} +2 -2
  40. package/dist/{chunk-MG3Z34YE.js → chunk-L7BKTZ5U.js} +1 -1
  41. package/dist/{chunk-SX72DOO3.js → chunk-LAUCO2HC.js} +1 -1
  42. package/dist/chunk-LNNI3MS4.js +54 -0
  43. package/dist/{chunk-BCG45AQB.js → chunk-M74I3HHF.js} +15 -5
  44. package/dist/{chunk-DVN6DNMI.js → chunk-M77B73VV.js} +17 -2
  45. package/dist/{chunk-4B62E4CG.js → chunk-OXWUEU5V.js} +2 -2
  46. package/dist/chunk-Q7XQLKZB.js +289 -0
  47. package/dist/{chunk-GWVFDUNB.js → chunk-QT4D5XCI.js} +8 -10
  48. package/dist/{chunk-VNRSXEBF.js → chunk-TPX6E6PL.js} +38 -5
  49. package/dist/{chunk-3B427GUK.js → chunk-U54PJPTB.js} +2 -2
  50. package/dist/{chunk-EFT2OALG.js → chunk-UDZLPR34.js} +20 -5
  51. package/dist/{chunk-ZX46PGCC.js → chunk-UFTDRTCP.js} +1 -1
  52. package/dist/chunk-VAEZCIJC.js +1058 -0
  53. package/dist/chunk-VP5PFNZO.js +2905 -0
  54. package/dist/{chunk-VIUH5CHQ.js → chunk-VSBMLB2W.js} +51 -34
  55. package/dist/{chunk-RRZ4RQQU.js → chunk-X67BDDZR.js} +5 -7
  56. package/dist/cli.js +34 -27
  57. package/dist/{clock-6JZL2FS6.js → clock-ZT5YT6HA.js} +4 -3
  58. package/dist/{cloud-sync-VFDTNNCA.js → cloud-sync-GPXYPTIC.js} +23 -20
  59. package/dist/{config-RPSLA2HX.js → config-UGJS57VT.js} +3 -3
  60. package/dist/{conversations-TUM5PJJ4.js → conversations-ZL6PHROD.js} +8 -4
  61. package/dist/{create-Z5FSDNVZ.js → create-G2RIKQYK.js} +2 -2
  62. package/dist/{create-VIQVP3QB.js → create-M727VUDF.js} +2 -1
  63. package/dist/{daemon-client-ZFY5MOAL.js → daemon-client-VVYFZI2D.js} +2 -1
  64. package/dist/{daemon-restart-54L4B6AQ.js → daemon-restart-2EWBRTN5.js} +6 -7
  65. package/dist/daemon.js +2005 -762
  66. package/dist/{db-F6UMFRYD.js → db-BONH4SUG.js} +2 -2
  67. package/dist/{delete-ESEP7NGQ.js → delete-O7PEFQDF.js} +1 -1
  68. package/dist/delivery-manager-HGVZSEES.js +35 -0
  69. package/dist/{delivery-router-VUOL5YSA.js → delivery-router-RHANNTAC.js} +7 -5
  70. package/dist/{down-6X7KX7BZ.js → down-QSNEMTTX.js} +5 -5
  71. package/dist/echo-text-6ANI5HHN.js +39 -0
  72. package/dist/{env-ZYMSCB7B.js → env-IBW2QI6K.js} +3 -2
  73. package/dist/{env-KUL4XKN2.js → env-SQFCWW52.js} +3 -3
  74. package/dist/{exec-FBXA3CM4.js → exec-ABD3DYA2.js} +3 -3
  75. package/dist/{export-TNBPDH77.js → export-VBNWM7I4.js} +4 -4
  76. package/dist/{extension-J4ZQ2GHV.js → extension-MRYJWSMV.js} +2 -1
  77. package/dist/{extensions-AWNO3SZF.js → extensions-NY6WST33.js} +23 -20
  78. package/dist/{files-BVBRJJ2P.js → files-BRY5RRIM.js} +5 -4
  79. package/dist/{import-ZUNKMCKC.js → import-DB2KULRO.js} +8 -8
  80. package/dist/{isolation-OPCZQRTH.js → isolation-GVV2IBAU.js} +5 -3
  81. package/dist/{join-34TR2GXQ.js → join-PYA36HEC.js} +1 -1
  82. package/dist/{list-PMUXZNAM.js → list-UQGIW7OF.js} +8 -3
  83. package/dist/{login-LKNLCJPA.js → login-RJJTCVR3.js} +2 -1
  84. package/dist/{login-KAKNFCW5.js → login-SB5OENMV.js} +4 -3
  85. package/dist/{logout-YZRMZ3O2.js → logout-BYV433X6.js} +2 -1
  86. package/dist/{logout-RLT62RQP.js → logout-YFZAJRPY.js} +4 -3
  87. package/dist/message-delivery-JHMAJ2GU.js +43 -0
  88. package/dist/migrate-thread-config-EQSEP2XG.js +90 -0
  89. package/dist/{mind-IF6CGMFW.js → mind-WF6QIXWV.js} +19 -19
  90. package/dist/{mind-activity-tracker-YMMERB6B.js → mind-activity-tracker-QF6DCX2X.js} +4 -4
  91. package/dist/{mind-contacts-BKUFPUCU.js → mind-contacts-QYU4TPEA.js} +3 -2
  92. package/dist/{mind-history-WI5OI3BW.js → mind-history-OGNR4L7W.js} +30 -7
  93. package/dist/{mind-list-OTHV4ZO4.js → mind-list-SYRA7CH5.js} +3 -2
  94. package/dist/{mind-profile-LUG353ZT.js → mind-profile-MRCVZPYT.js} +1 -1
  95. package/dist/mind-service-DZCUUC7J.js +47 -0
  96. package/dist/{mind-sleep-VBV7YRSU.js → mind-sleep-LZAFBDZD.js} +4 -3
  97. package/dist/{mind-status-BJNPGXKC.js → mind-status-Z2LQFA6F.js} +3 -2
  98. package/dist/{mind-wake-LVTZ55EZ.js → mind-wake-LDGPRA42.js} +2 -1
  99. package/dist/{package-PD67VPHB.js → package-B6O5APCZ.js} +23 -23
  100. package/dist/{prompts-MDHDLWEX.js → prompts-NBO3HRK3.js} +3 -3
  101. package/dist/{read-YSWUXYL7.js → read-RJ5NAW5J.js} +5 -14
  102. package/dist/{register-TWQDKQRT.js → register-OX4HRSGC.js} +2 -1
  103. package/dist/{registry-3ELJPUGJ.js → registry-TRC2HJXR.js} +6 -4
  104. package/dist/{reject-SXGCYN4A.js → reject-TWB4QJHG.js} +2 -1
  105. package/dist/{restart-5F5QDBOG.js → restart-AGEGNSYQ.js} +2 -1
  106. package/dist/{sandbox-XPYA7UIF.js → sandbox-NNWCTHRI.js} +7 -4
  107. package/dist/scheduler-TNBN54ZK.js +25 -0
  108. package/dist/{schema-6YONVTKZ.js → schema-ZZQVM4GR.js} +5 -3
  109. package/dist/{seed-NQED7PSX.js → seed-K2LYODIH.js} +1 -1
  110. package/dist/{seed-check-TYD7RRZY.js → seed-check-NRJEQZST.js} +14 -5
  111. package/dist/{seed-cmd-QF3F2G4S.js → seed-cmd-2EWBTR6P.js} +3 -3
  112. package/dist/{seed-create-XOO4N2OE.js → seed-create-VGTLU5FD.js} +4 -4
  113. package/dist/{seed-readiness-3LRYASA4.js → seed-readiness-DYOVCYHN.js} +4 -5
  114. package/dist/{seed-sprout-HSBBGSS2.js → seed-sprout-PILHJ3YS.js} +9 -9
  115. package/dist/{send-IHRJYNXA.js → send-2YKOZJJ5.js} +108 -54
  116. package/dist/{service-YCOPCTSZ.js → service-XQPMZAGI.js} +4 -4
  117. package/dist/{service-install-Y46OTF55.js → service-install-2EWD7KXD.js} +5 -5
  118. package/dist/{setup-F4TE64YI.js → setup-MDPSK2XG.js} +6 -7
  119. package/dist/{setup-TCN7VH5U.js → setup-WZSXHHRJ.js} +10 -3
  120. package/dist/{skill-4CYJLYVY.js → skill-B5OJEQUA.js} +3 -2
  121. package/dist/skills/dreaming/references/INSTALL.md +2 -2
  122. package/dist/skills/imagegen/SKILL.md +21 -4
  123. package/dist/skills/imagegen/scripts/imagegen.ts +124 -21
  124. package/dist/skills/tending/SKILL.md +7 -7
  125. package/dist/skills/volute-mind/SKILL.md +3 -3
  126. package/dist/skills/volute-mind/references/integrations.md +2 -2
  127. package/dist/skills/volute-mind/references/routing.md +15 -15
  128. package/dist/{skills-NN5UZCUU.js → skills-NH2GQKAF.js} +4 -5
  129. package/dist/sleep-manager-7JXEQQ2P.js +41 -0
  130. package/dist/{spirit-SSJMYC6A.js → spirit-25JVAL3M.js} +11 -8
  131. package/dist/spirit-availability-PJDWZJ3J.js +42 -0
  132. package/dist/{split-JF2VWTXA.js → split-BU5VWX6P.js} +1 -1
  133. package/dist/{sprout-AXA2SECQ.js → sprout-EXUZMIOR.js} +1 -1
  134. package/dist/{src-YH6PQ7LJ.js → src-HGNE2XG4.js} +7 -1
  135. package/dist/{src-ZN4LXMPI.js → src-LCSOQY6Z.js} +57 -51
  136. package/dist/{src-JAOVXO5W.js → src-UDMJZ6MH.js} +8 -8
  137. package/dist/{start-BTVMTP3K.js → start-MUMNFR52.js} +2 -1
  138. package/dist/{status-VJGXMQ4L.js → status-MWLE3RVC.js} +7 -6
  139. package/dist/{stop-YORESK4U.js → stop-EKERNYTX.js} +2 -1
  140. package/dist/system-events-ZPSH63QX.js +46 -0
  141. package/dist/system-install-YZSWCPDK.js +8 -0
  142. package/dist/{systems-5MH2ELQE.js → systems-VDRUZXNF.js} +5 -4
  143. package/dist/{tailscale-AMMVKDXB.js → tailscale-KHNZFC7L.js} +2 -2
  144. package/dist/{template-hash-GSOUARW4.js → template-hash-YKWMVYMM.js} +2 -2
  145. package/dist/{template-staleness-HKGCTS3H.js → template-staleness-PY2CULH6.js} +5 -5
  146. package/dist/{turn-tracker-JQ2YUUY2.js → turn-tracker-TAT2HGK6.js} +6 -6
  147. package/dist/{up-SDLTLPAO.js → up-J7XCAH7P.js} +5 -6
  148. package/dist/{update-WEA4N2TR.js → update-CIWI2JYA.js} +5 -5
  149. package/dist/{update-check-DZOTONII.js → update-check-SZ7B5IFI.js} +3 -3
  150. package/dist/{upgrade-K5FIQPQD.js → upgrade-LIE46UBB.js} +1 -1
  151. package/dist/variant-cleanup-YXN25ZVW.js +22 -0
  152. package/dist/{version-notify-WFA5XB5A.js → version-notify-EN3KJ7HH.js} +11 -28
  153. package/dist/web-assets/assets/index-BOyJ4Gqs.css +1 -0
  154. package/dist/web-assets/assets/index-CrxBwnzp.js +95 -0
  155. package/dist/web-assets/index.html +2 -2
  156. package/dist/xai-P42CRCZA.js +129 -0
  157. package/drizzle/0014_system_events.sql +26 -0
  158. package/drizzle/0015_rename_session_to_thread.sql +12 -0
  159. package/drizzle/0016_brain_to_human.sql +4 -0
  160. package/drizzle/0017_event_history_rows.sql +9 -0
  161. package/drizzle/0018_api_tokens.sql +20 -0
  162. package/drizzle/meta/_journal.json +35 -0
  163. package/package.json +23 -23
  164. package/packages/extensions/notes/dist/ui/assets/index-BBs8pyel.js +67 -0
  165. package/packages/extensions/notes/dist/ui/index.html +1 -1
  166. package/packages/extensions/pages/dist/ui/assets/index-B589e8Xe.js +2 -0
  167. package/packages/extensions/pages/dist/ui/index.html +1 -1
  168. package/packages/extensions/plan/dist/ui/assets/index-B8s8wxyt.js +67 -0
  169. package/packages/extensions/plan/dist/ui/index.html +1 -1
  170. package/templates/_base/.init/.config/prompts.json +1 -0
  171. package/templates/_base/.init/.local/hooks/startup-context.ts +24 -9
  172. package/templates/_base/{biome.json.tmpl → biome.json} +2 -1
  173. package/templates/_base/gitignore +44 -0
  174. package/templates/_base/home/.config/routes.json +2 -2
  175. package/templates/_base/home/VOLUTE.md +18 -5
  176. package/templates/_base/home/public/.gitkeep +0 -0
  177. package/templates/_base/src/lib/daemon-client.ts +1 -1
  178. package/templates/_base/src/lib/event-turn.ts +39 -0
  179. package/templates/_base/src/lib/format-prefix.ts +36 -10
  180. package/templates/_base/src/lib/router.ts +19 -10
  181. package/templates/_base/src/lib/routing.ts +8 -8
  182. package/templates/_base/src/lib/startup.ts +9 -1
  183. package/templates/_base/src/lib/types.ts +7 -1
  184. package/templates/_base/src/lib/volute-server.ts +30 -1
  185. package/templates/claude/.init/.config/routes.json +3 -3
  186. package/templates/claude/.init/CLAUDE.md +1 -1
  187. package/templates/claude/{package.json.tmpl → package.json} +4 -4
  188. package/templates/claude/src/agent.ts +4 -1
  189. package/templates/claude/src/lib/hooks/reply-instructions.ts +26 -1
  190. package/templates/claude/volute-template.json +1 -3
  191. package/templates/codex/.init/.config/routes.json +3 -3
  192. package/templates/codex/.init/AGENTS.md +1 -1
  193. package/templates/codex/{package.json.tmpl → package.json} +4 -4
  194. package/templates/codex/src/agent.ts +11 -11
  195. package/templates/codex/src/lib/turn-context.ts +51 -0
  196. package/templates/codex/volute-template.json +1 -3
  197. package/templates/pi/.init/.config/routes.json +3 -3
  198. package/templates/pi/.init/MINDS.md +1 -1
  199. package/templates/pi/{package.json.tmpl → package.json} +6 -6
  200. package/templates/pi/src/agent.ts +9 -1
  201. package/templates/pi/src/lib/event-handler.ts +1 -1
  202. package/templates/pi/src/lib/reply-instructions-extension.ts +28 -1
  203. package/templates/pi/volute-template.json +1 -3
  204. package/dist/chunk-5T5YMX6S.js +0 -23
  205. package/dist/chunk-NJHN6IRB.js +0 -177
  206. package/dist/chunk-QQBOI3QA.js +0 -5345
  207. package/dist/chunk-XTEKINWG.js +0 -158
  208. package/dist/delivery-manager-RBXBPVWM.js +0 -36
  209. package/dist/echo-text-B6NZ5FGE.js +0 -36
  210. package/dist/message-delivery-ABPV76EA.js +0 -42
  211. package/dist/mind-service-42GDO4KH.js +0 -44
  212. package/dist/notices-N6BCGHFV.js +0 -25
  213. package/dist/scheduler-K7Y7Z7FQ.js +0 -34
  214. package/dist/sleep-manager-DSPXFHGX.js +0 -38
  215. package/dist/system-chat-M2XOBKEM.js +0 -40
  216. package/dist/variant-cleanup-P4MBNLJD.js +0 -33
  217. package/dist/web-assets/assets/index-BostMFoR.css +0 -1
  218. package/dist/web-assets/assets/index-CKlqUkyG.js +0 -92
  219. package/packages/extensions/notes/dist/ui/assets/index-D0-DgYyj.js +0 -67
  220. package/packages/extensions/pages/dist/ui/assets/index-DtzftuPA.js +0 -2
  221. package/packages/extensions/plan/dist/ui/assets/index-Cfzs-0G9.js +0 -67
  222. /package/templates/_base/home/.config/{config.json.tmpl → config.json} +0 -0
  223. /package/templates/codex/home/.config/{config.json.tmpl → config.json} +0 -0
  224. /package/templates/pi/home/.config/{config.json.tmpl → config.json} +0 -0
@@ -0,0 +1,562 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ publish
4
+ } from "./chunk-LNNI3MS4.js";
5
+ import {
6
+ logger_default
7
+ } from "./chunk-QUSMYGNQ.js";
8
+ import {
9
+ findMind,
10
+ getBaseName,
11
+ getDb
12
+ } from "./chunk-H6X6CKDN.js";
13
+ import {
14
+ mindHistory,
15
+ systemEvents,
16
+ turns
17
+ } from "./chunk-2RNMBXD2.js";
18
+
19
+ // packages/daemon/src/lib/chat/system-events.ts
20
+ import { and, asc, desc, eq, gt, isNull, lte, or, sql } from "drizzle-orm";
21
+
22
+ // packages/daemon/src/lib/util/session-name.ts
23
+ function newEphemeralSession() {
24
+ return `new-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
25
+ }
26
+
27
+ // packages/daemon/src/lib/chat/system-events.ts
28
+ var elog = logger_default.child("system-events");
29
+ var MIND_LEVEL_THREAD = "";
30
+ var MAX_NEXT_TURN_EVENTS = 100;
31
+ var FLUSH_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
32
+ function parseMeta(meta, context) {
33
+ if (!meta) return {};
34
+ try {
35
+ return JSON.parse(meta);
36
+ } catch (err) {
37
+ elog.error(`corrupt event meta${context ? ` (${context})` : ""}: ${meta}`, logger_default.errorData(err));
38
+ return {};
39
+ }
40
+ }
41
+ function eventLabel(type, meta) {
42
+ const m = meta ?? {};
43
+ const s = (k) => typeof m[k] === "string" ? m[k] : void 0;
44
+ switch (type) {
45
+ case "schedule":
46
+ return s("scheduleId") ? `Schedule: ${s("scheduleId")}` : "Schedule";
47
+ case "sleep":
48
+ return "Time to rest";
49
+ case "wake":
50
+ return "Woke from sleep";
51
+ case "lifecycle":
52
+ switch (s("subtype")) {
53
+ case "merge":
54
+ return "Variant merged in";
55
+ case "split":
56
+ return "Split into a variant";
57
+ case "variant-created":
58
+ return "Variant split off";
59
+ case "sprout":
60
+ return "Sprouted";
61
+ case "upgrade":
62
+ return "Framework upgraded";
63
+ case "restart":
64
+ return "Server restarted";
65
+ case "farewell":
66
+ return "Farewell before merge";
67
+ case "sprout-welcome":
68
+ return "A mind sprouted";
69
+ default:
70
+ return "Lifecycle";
71
+ }
72
+ case "orientation":
73
+ return "Orientation";
74
+ case "budget":
75
+ return "Token budget";
76
+ case "version":
77
+ return "New version available";
78
+ case "channel":
79
+ return "Channel invite";
80
+ case "file-share":
81
+ return "File offered";
82
+ case "webhook":
83
+ return s("source") ? `Webhook: ${s("source")}` : "Webhook";
84
+ case "notice":
85
+ switch (s("subtype")) {
86
+ case "crash":
87
+ return "Crash notice";
88
+ case "turn_error":
89
+ return "Turn error";
90
+ case "startup":
91
+ return "Startup notice";
92
+ case "extension":
93
+ return s("reason") ? `Notice: ${s("reason")}` : "Notice";
94
+ case "delivery_failed":
95
+ return "Delivery failed";
96
+ default:
97
+ return "Notice";
98
+ }
99
+ default:
100
+ return type.charAt(0).toUpperCase() + type.slice(1);
101
+ }
102
+ }
103
+ async function recordNotice(input) {
104
+ const type = input.kind === "budget" ? "budget" : "notice";
105
+ await deliverEvent(input.mind, {
106
+ type,
107
+ body: input.detail,
108
+ thread: input.thread,
109
+ delivery: "next-turn",
110
+ meta: {
111
+ subtype: input.kind,
112
+ reason: input.reason,
113
+ ...input.raw ? { raw: input.raw } : {}
114
+ }
115
+ });
116
+ }
117
+ function eventChannel(type, id) {
118
+ return `event:${type}:${id}`;
119
+ }
120
+ async function recordEventRow(mind, event) {
121
+ const channel = eventChannel(event.type, event.id);
122
+ const label = eventLabel(event.type, parseMeta(event.meta, `event ${event.id}`));
123
+ const metadata = { systemEventId: event.id, label };
124
+ try {
125
+ const db = await getDb();
126
+ const baseName = await getBaseName(mind);
127
+ await db.insert(mindHistory).values({
128
+ mind: baseName,
129
+ type: "event",
130
+ channel,
131
+ sender: null,
132
+ content: event.body,
133
+ metadata: JSON.stringify(metadata)
134
+ });
135
+ publish(baseName, {
136
+ mind: baseName,
137
+ type: "event",
138
+ channel,
139
+ content: event.body,
140
+ metadata
141
+ });
142
+ } catch (err) {
143
+ elog.warn(`failed to persist event row for ${mind}`, logger_default.errorData(err));
144
+ }
145
+ }
146
+ var staleTemplateWarned = /* @__PURE__ */ new Set();
147
+ async function postEventEnvelope(mind, event) {
148
+ const entry = await findMind(mind);
149
+ if (!entry) {
150
+ elog.warn(`cannot deliver event ${event.id} to ${mind}: mind not found`);
151
+ return false;
152
+ }
153
+ const meta = parseMeta(event.meta, `event ${event.id}`);
154
+ try {
155
+ const res = await fetch(`http://127.0.0.1:${entry.port}/message`, {
156
+ method: "POST",
157
+ headers: { "Content-Type": "application/json" },
158
+ body: JSON.stringify({
159
+ kind: "event",
160
+ event: {
161
+ id: event.id,
162
+ type: event.type,
163
+ label: eventLabel(event.type, meta),
164
+ body: event.body,
165
+ at: event.created_at
166
+ },
167
+ session: event.thread
168
+ }),
169
+ signal: AbortSignal.timeout(1e4)
170
+ });
171
+ if (!res.ok) {
172
+ elog.warn(`mind ${mind} rejected event ${event.id}: HTTP ${res.status}`);
173
+ return false;
174
+ }
175
+ try {
176
+ const ack = await res.json();
177
+ if (ack.event !== true && !staleTemplateWarned.has(mind)) {
178
+ staleTemplateWarned.add(mind);
179
+ elog.warn(
180
+ `mind ${mind} ack'd an event without event support \u2014 its template predates system events; run \`volute mind upgrade ${mind}\``
181
+ );
182
+ }
183
+ } catch {
184
+ if (!staleTemplateWarned.has(mind)) {
185
+ staleTemplateWarned.add(mind);
186
+ elog.warn(
187
+ `mind ${mind} ack'd an event without event support \u2014 its template predates system events; run \`volute mind upgrade ${mind}\``
188
+ );
189
+ }
190
+ }
191
+ return true;
192
+ } catch (err) {
193
+ elog.warn(`failed to POST event ${event.id} to ${mind}`, logger_default.errorData(err));
194
+ return false;
195
+ }
196
+ }
197
+ async function markDelivered(id, extraMeta) {
198
+ try {
199
+ const db = await getDb();
200
+ if (extraMeta) {
201
+ const row = await db.select({ meta: systemEvents.meta }).from(systemEvents).where(eq(systemEvents.id, id)).get();
202
+ const merged = { ...parseMeta(row?.meta, `event ${id}`), ...extraMeta };
203
+ await db.update(systemEvents).set({ delivered_at: sql`(datetime('now'))`, meta: JSON.stringify(merged) }).where(eq(systemEvents.id, id));
204
+ } else {
205
+ await db.update(systemEvents).set({ delivered_at: sql`(datetime('now'))` }).where(eq(systemEvents.id, id));
206
+ }
207
+ } catch (err) {
208
+ elog.error(
209
+ `failed to stamp event ${id} delivered \u2014 it will be redelivered on the next wake/start`,
210
+ logger_default.errorData(err)
211
+ );
212
+ }
213
+ }
214
+ function resolveEventThread(thread, delivery) {
215
+ if (thread !== "$new") return thread;
216
+ return delivery === "immediate" ? newEphemeralSession() : MIND_LEVEL_THREAD;
217
+ }
218
+ async function deliverEvent(mind, input) {
219
+ const delivery = input.delivery ?? "immediate";
220
+ const thread = resolveEventThread(input.thread ?? "main", delivery);
221
+ let eventId;
222
+ try {
223
+ const db = await getDb();
224
+ const rows = await db.insert(systemEvents).values({
225
+ mind,
226
+ type: input.type,
227
+ body: input.body,
228
+ meta: input.meta ? JSON.stringify(input.meta) : null,
229
+ delivery,
230
+ thread
231
+ }).returning({ id: systemEvents.id });
232
+ eventId = rows[0]?.id;
233
+ if (eventId == null) {
234
+ elog.error(`event insert for ${mind} (${input.type}) returned no id \u2014 event dropped`);
235
+ return { delivered: false };
236
+ }
237
+ if (delivery === "next-turn") {
238
+ await db.run(
239
+ sql`UPDATE system_events SET delivered_at = datetime('now'), meta = json_set(COALESCE(meta, '{}'), '$.dropped', 1) WHERE mind = ${mind} AND thread = ${thread} AND delivery = 'next-turn' AND delivered_at IS NULL AND id NOT IN (SELECT id FROM system_events WHERE mind = ${mind} AND thread = ${thread} AND delivery = 'next-turn' AND delivered_at IS NULL ORDER BY id DESC LIMIT ${MAX_NEXT_TURN_EVENTS})`
240
+ );
241
+ return { id: eventId, delivered: false };
242
+ }
243
+ const baseName = await getBaseName(mind);
244
+ const { getSleepManagerIfReady } = await import("./sleep-manager-7JXEQQ2P.js");
245
+ const sleepManager = getSleepManagerIfReady();
246
+ const sleeping = !input.force && sleepManager?.isSleeping(baseName);
247
+ const behavior = input.whileSleeping ?? "queue";
248
+ if (sleeping && behavior === "skip") {
249
+ await markDelivered(eventId, { skipped: true });
250
+ return { id: eventId, delivered: false };
251
+ }
252
+ if (!sleeping) {
253
+ const event = await db.select().from(systemEvents).where(eq(systemEvents.id, eventId)).get();
254
+ if (event && await postEventEnvelope(mind, event)) {
255
+ await markDelivered(eventId);
256
+ await recordEventRow(mind, event);
257
+ return { id: eventId, delivered: true };
258
+ }
259
+ elog.warn(
260
+ `event ${eventId} (${input.type}) for ${mind} was not delivered; left pending for the next wake or mind start`
261
+ );
262
+ return { id: eventId, delivered: false };
263
+ }
264
+ if (behavior === "trigger-wake") {
265
+ sleepManager?.initiateWake(baseName, { trigger: { channel: `event:${input.type}` } }).catch(
266
+ (err) => elog.warn(`failed to trigger-wake ${baseName} for event`, logger_default.errorData(err))
267
+ );
268
+ }
269
+ return { id: eventId, delivered: false };
270
+ } catch (err) {
271
+ elog.error(`failed to deliver event to ${mind}`, logger_default.errorData(err));
272
+ return { id: eventId, delivered: false };
273
+ }
274
+ }
275
+ var NO_REPLAY_TYPES = /* @__PURE__ */ new Set(["sleep"]);
276
+ async function flushQueuedEvents(mind) {
277
+ try {
278
+ const db = await getDb();
279
+ const rows = await db.select().from(systemEvents).where(
280
+ and(
281
+ eq(systemEvents.mind, mind),
282
+ eq(systemEvents.delivery, "immediate"),
283
+ isNull(systemEvents.delivered_at)
284
+ )
285
+ ).orderBy(asc(systemEvents.id)).all();
286
+ let delivered = 0;
287
+ for (const event of rows) {
288
+ if (NO_REPLAY_TYPES.has(event.type) || eventAgeMs(event.created_at) > FLUSH_MAX_AGE_MS) {
289
+ elog.info(`expiring stale pending event ${event.id} (${event.type}) for ${mind}`);
290
+ await markDelivered(event.id, { expired: true });
291
+ continue;
292
+ }
293
+ if (await postEventEnvelope(mind, event)) {
294
+ await markDelivered(event.id);
295
+ await recordEventRow(mind, event);
296
+ delivered++;
297
+ } else {
298
+ elog.warn(`flush could not deliver event ${event.id} (${event.type}) to ${mind}`);
299
+ }
300
+ }
301
+ return delivered;
302
+ } catch (err) {
303
+ elog.warn(`failed to flush queued events for ${mind}`, logger_default.errorData(err));
304
+ return 0;
305
+ }
306
+ }
307
+ function eventAgeMs(createdAt) {
308
+ const iso = createdAt.endsWith("Z") ? createdAt : `${createdAt.replace(" ", "T")}Z`;
309
+ const t = new Date(iso).getTime();
310
+ return Number.isNaN(t) ? 0 : Date.now() - t;
311
+ }
312
+ async function pendingEventCount(mind) {
313
+ try {
314
+ const db = await getDb();
315
+ const row = await db.select({ n: sql`count(*)` }).from(systemEvents).where(
316
+ and(
317
+ eq(systemEvents.mind, mind),
318
+ eq(systemEvents.delivery, "immediate"),
319
+ isNull(systemEvents.delivered_at)
320
+ )
321
+ ).get();
322
+ return row?.n ?? 0;
323
+ } catch (err) {
324
+ elog.warn(`failed to count pending events for ${mind}`, logger_default.errorData(err));
325
+ return 0;
326
+ }
327
+ }
328
+ function pendingEventsLine(count) {
329
+ if (count <= 0) return "";
330
+ return `${count} system event${count === 1 ? "" : "s"} arrived while you slept and will follow shortly.`;
331
+ }
332
+ async function drainEvents(mind, thread, limit = MAX_NEXT_TURN_EVENTS) {
333
+ const db = await getDb();
334
+ return db.select().from(systemEvents).where(
335
+ and(
336
+ eq(systemEvents.mind, mind),
337
+ eq(systemEvents.delivery, "next-turn"),
338
+ isNull(systemEvents.delivered_at),
339
+ or(eq(systemEvents.thread, thread), eq(systemEvents.thread, MIND_LEVEL_THREAD))
340
+ )
341
+ ).orderBy(asc(systemEvents.id)).limit(limit);
342
+ }
343
+ function metaOf(e) {
344
+ return parseMeta(e.meta, `event ${e.id}`);
345
+ }
346
+ var FAILURE_SUBTYPES = /* @__PURE__ */ new Set(["turn_error", "crash", "startup"]);
347
+ var NOTICE_HEADER = "[Notices] While you were unavailable, one or more turns failed. You're back now:";
348
+ function formatEvents(events) {
349
+ if (events.length === 0) return null;
350
+ const failures = [];
351
+ const budgets = [];
352
+ const versions = [];
353
+ const extensions = [];
354
+ const others = [];
355
+ for (const e of events) {
356
+ if (e.type === "budget") budgets.push(e);
357
+ else if (e.type === "version") versions.push(e);
358
+ else if (e.type === "notice") {
359
+ const subtype = String(metaOf(e).subtype);
360
+ if (FAILURE_SUBTYPES.has(subtype)) failures.push(e);
361
+ else if (subtype === "extension") extensions.push(e);
362
+ else others.push(e);
363
+ } else others.push(e);
364
+ }
365
+ const blocks = [];
366
+ if (failures.length > 0) {
367
+ const groups = /* @__PURE__ */ new Map();
368
+ for (const e of failures) {
369
+ const reason = String(metaOf(e).reason ?? "unknown");
370
+ const time = localHM(e.created_at);
371
+ const g = groups.get(reason);
372
+ if (g) {
373
+ g.count += 1;
374
+ g.detail = e.body;
375
+ g.last = time;
376
+ } else {
377
+ groups.set(reason, { count: 1, detail: e.body, first: time, last: time });
378
+ }
379
+ }
380
+ const lines = [...groups.values()].map((g) => {
381
+ const span = g.first === g.last ? g.first : `${g.first}\u2013${g.last}`;
382
+ const plural = g.count === 1 ? "turn" : "turns";
383
+ return `- ${g.count} ${plural} failed (${span}): ${g.detail}`;
384
+ });
385
+ blocks.push(`${NOTICE_HEADER}
386
+ ${lines.join("\n")}`);
387
+ }
388
+ if (budgets.length > 0) {
389
+ const lines = budgets.map((e) => `- ${localHM(e.created_at)} ${e.body}`);
390
+ blocks.push(`[Budget]
391
+ ${lines.join("\n")}`);
392
+ }
393
+ if (versions.length > 0) {
394
+ const lines = versions.map((e) => `- ${localHM(e.created_at)} ${e.body}`);
395
+ blocks.push(`[Update]
396
+ ${lines.join("\n")}`);
397
+ }
398
+ if (extensions.length > 0) {
399
+ const byExt = /* @__PURE__ */ new Map();
400
+ for (const e of extensions) {
401
+ const ext = String(metaOf(e).reason ?? "extension");
402
+ const arr = byExt.get(ext);
403
+ if (arr) arr.push(e);
404
+ else byExt.set(ext, [e]);
405
+ }
406
+ for (const [ext, items] of byExt) {
407
+ const header = `[${ext.charAt(0).toUpperCase()}${ext.slice(1)}]`;
408
+ const lines = items.map((e) => `- ${localHM(e.created_at)} ${e.body}`);
409
+ blocks.push(`${header}
410
+ ${lines.join("\n")}`);
411
+ }
412
+ }
413
+ if (others.length > 0) {
414
+ const lines = others.map(
415
+ (e) => `- ${localHM(e.created_at)} (${eventLabel(e.type, metaOf(e))}) ${e.body}`
416
+ );
417
+ blocks.push(`[Events]
418
+ ${lines.join("\n")}`);
419
+ }
420
+ return blocks.join("\n\n");
421
+ }
422
+ function localHM(createdAt) {
423
+ const iso = createdAt.endsWith("Z") ? createdAt : `${createdAt.replace(" ", "T")}Z`;
424
+ return new Date(iso).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
425
+ }
426
+ async function clearDeliveredEvents(mind, thread, uptoId) {
427
+ try {
428
+ const db = await getDb();
429
+ await db.update(systemEvents).set({ delivered_at: sql`(datetime('now'))` }).where(
430
+ and(
431
+ eq(systemEvents.mind, mind),
432
+ eq(systemEvents.delivery, "next-turn"),
433
+ isNull(systemEvents.delivered_at),
434
+ or(eq(systemEvents.thread, thread), eq(systemEvents.thread, MIND_LEVEL_THREAD)),
435
+ lte(systemEvents.id, uptoId)
436
+ )
437
+ );
438
+ } catch (err) {
439
+ elog.warn(`failed to clear delivered events for ${mind}:${thread}`, logger_default.errorData(err));
440
+ }
441
+ }
442
+ var failureReadErrorLogged = false;
443
+ async function latestFailureEvent(mind) {
444
+ try {
445
+ const db = await getDb();
446
+ const e = await db.select().from(systemEvents).where(
447
+ and(
448
+ eq(systemEvents.mind, mind),
449
+ eq(systemEvents.type, "notice"),
450
+ isNull(systemEvents.delivered_at),
451
+ // Closed set of literal subtypes (not user input).
452
+ sql`json_extract(${systemEvents.meta}, '$.subtype') IN ('turn_error', 'crash', 'startup')`
453
+ )
454
+ ).orderBy(desc(systemEvents.id)).limit(1).get();
455
+ if (!e) return null;
456
+ const recovered = await db.select({ id: turns.id }).from(turns).where(
457
+ and(eq(turns.mind, mind), eq(turns.status, "complete"), gt(turns.created_at, e.created_at))
458
+ ).limit(1);
459
+ if (recovered.length > 0) return null;
460
+ const m = metaOf(e);
461
+ return {
462
+ kind: String(m.subtype ?? "notice"),
463
+ reason: String(m.reason ?? "unknown"),
464
+ detail: e.body,
465
+ at: e.created_at
466
+ };
467
+ } catch (err) {
468
+ if (!failureReadErrorLogged) {
469
+ failureReadErrorLogged = true;
470
+ elog.error(`failed to read latest failure event for ${mind}`, logger_default.errorData(err));
471
+ }
472
+ return null;
473
+ }
474
+ }
475
+ async function latestEvent(mind) {
476
+ const db = await getDb();
477
+ const row = await db.select().from(systemEvents).where(
478
+ and(
479
+ eq(systemEvents.mind, mind),
480
+ eq(systemEvents.delivery, "next-turn"),
481
+ isNull(systemEvents.delivered_at)
482
+ )
483
+ ).orderBy(desc(systemEvents.id)).limit(1).get();
484
+ if (!row) return null;
485
+ const m = metaOf(row);
486
+ return {
487
+ kind: String(m.subtype ?? row.type),
488
+ reason: String(m.reason ?? row.type),
489
+ detail: row.body,
490
+ created_at: row.created_at
491
+ };
492
+ }
493
+ async function hasUndeliveredEvent(mind, reason) {
494
+ const db = await getDb();
495
+ const row = await db.select({ id: systemEvents.id }).from(systemEvents).where(
496
+ and(
497
+ eq(systemEvents.mind, mind),
498
+ eq(systemEvents.delivery, "next-turn"),
499
+ isNull(systemEvents.delivered_at),
500
+ sql`json_extract(${systemEvents.meta}, '$.reason') = ${reason}`
501
+ )
502
+ ).limit(1).get();
503
+ return row != null;
504
+ }
505
+ async function listEvents(mind, limit = 100, before) {
506
+ const db = await getDb();
507
+ const conditions = [eq(systemEvents.mind, mind)];
508
+ if (before != null) conditions.push(sql`${systemEvents.id} < ${before}`);
509
+ return db.select().from(systemEvents).where(and(...conditions)).orderBy(desc(systemEvents.id)).limit(limit);
510
+ }
511
+ async function recordReflection(mind, eventId, text) {
512
+ try {
513
+ const db = await getDb();
514
+ await db.update(systemEvents).set({ reflection: text }).where(and(eq(systemEvents.id, eventId), eq(systemEvents.mind, mind)));
515
+ } catch (err) {
516
+ elog.warn(`failed to record reflection for event ${eventId}`, logger_default.errorData(err));
517
+ }
518
+ }
519
+ async function captureReflection(mind, turnId) {
520
+ if (!turnId) return;
521
+ try {
522
+ const db = await getDb();
523
+ const turn = await db.select({ trigger: turns.trigger_event_id }).from(turns).where(eq(turns.id, turnId)).get();
524
+ if (turn?.trigger == null) return;
525
+ const trigger = await db.select({ metadata: mindHistory.metadata }).from(mindHistory).where(eq(mindHistory.id, turn.trigger)).get();
526
+ const eventId = trigger?.metadata ? parseMeta(trigger.metadata, `event row ${turn.trigger}`).systemEventId : void 0;
527
+ if (typeof eventId !== "number") return;
528
+ const row = await db.select({ content: mindHistory.content }).from(mindHistory).where(
529
+ and(
530
+ eq(mindHistory.mind, mind),
531
+ eq(mindHistory.turn_id, turnId),
532
+ eq(mindHistory.type, "text")
533
+ )
534
+ ).orderBy(desc(mindHistory.id)).limit(1).get();
535
+ const text = row?.content?.trim();
536
+ if (text) await recordReflection(mind, eventId, text);
537
+ } catch (err) {
538
+ elog.warn(`failed to capture reflection for turn ${turnId}`, logger_default.errorData(err));
539
+ }
540
+ }
541
+
542
+ export {
543
+ newEphemeralSession,
544
+ MIND_LEVEL_THREAD,
545
+ parseMeta,
546
+ eventLabel,
547
+ recordNotice,
548
+ eventChannel,
549
+ deliverEvent,
550
+ flushQueuedEvents,
551
+ pendingEventCount,
552
+ pendingEventsLine,
553
+ drainEvents,
554
+ formatEvents,
555
+ clearDeliveredEvents,
556
+ latestFailureEvent,
557
+ latestEvent,
558
+ hasUndeliveredEvent,
559
+ listEvents,
560
+ recordReflection,
561
+ captureReflection
562
+ };
@@ -12,7 +12,7 @@ import {
12
12
  mindDir,
13
13
  readAllMinds,
14
14
  voluteHome
15
- } from "./chunk-RSBL3FAD.js";
15
+ } from "./chunk-H6X6CKDN.js";
16
16
 
17
17
  // packages/daemon/src/lib/util/avatar-image.ts
18
18
  import { readdir, readFile, writeFile } from "fs/promises";
@@ -8,14 +8,12 @@ import {
8
8
  modeLabel,
9
9
  pollHealth,
10
10
  startService
11
- } from "./chunk-HCYQRME2.js";
12
- import {
13
- readGlobalConfig
14
- } from "./chunk-NJHN6IRB.js";
11
+ } from "./chunk-6NLW72HP.js";
15
12
  import {
13
+ readGlobalConfig,
16
14
  voluteHome,
17
15
  voluteSystemDir
18
- } from "./chunk-RSBL3FAD.js";
16
+ } from "./chunk-H6X6CKDN.js";
19
17
 
20
18
  // src/commands/up.ts
21
19
  import { spawn } from "child_process";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  MEMORY_PLACEHOLDER_MARKER,
4
4
  ORIENTATION_MARKER
5
- } from "./chunk-JPGHSXSV.js";
5
+ } from "./chunk-FXWBFDQR.js";
6
6
  import {
7
7
  safeResolveWithinBase
8
8
  } from "./chunk-DW4TRDOZ.js";
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-WCFSBH33.js";
12
12
  import {
13
13
  isImagegenEnabled
14
- } from "./chunk-NJHN6IRB.js";
14
+ } from "./chunk-H6X6CKDN.js";
15
15
 
16
16
  // packages/daemon/src/lib/mind/seed-readiness.ts
17
17
  import { existsSync, readFileSync } from "fs";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-QUSMYGNQ.js";
5
5
  import {
6
6
  voluteSystemDir
7
- } from "./chunk-RSBL3FAD.js";
7
+ } from "./chunk-H6X6CKDN.js";
8
8
 
9
9
  // packages/daemon/src/lib/bridges/bridges.ts
10
10
  import { existsSync, readFileSync, writeFileSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteSystemDir
4
- } from "./chunk-RSBL3FAD.js";
4
+ } from "./chunk-H6X6CKDN.js";
5
5
 
6
6
  // packages/daemon/src/lib/update-check.ts
7
7
  import { execFile as execFileCb, execFileSync } from "child_process";
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ logger_default
4
+ } from "./chunk-QUSMYGNQ.js";
5
+
6
+ // packages/daemon/src/lib/events/mind-events.ts
7
+ var subscribers = /* @__PURE__ */ new Map();
8
+ var globalSubscribers = /* @__PURE__ */ new Set();
9
+ function subscribe(mind, callback) {
10
+ let set = subscribers.get(mind);
11
+ if (!set) {
12
+ set = /* @__PURE__ */ new Set();
13
+ subscribers.set(mind, set);
14
+ }
15
+ set.add(callback);
16
+ return () => {
17
+ set.delete(callback);
18
+ if (set.size === 0) subscribers.delete(mind);
19
+ };
20
+ }
21
+ function subscribeAll(callback) {
22
+ globalSubscribers.add(callback);
23
+ return () => {
24
+ globalSubscribers.delete(callback);
25
+ };
26
+ }
27
+ function publish(mind, event) {
28
+ const set = subscribers.get(mind);
29
+ if (set) {
30
+ for (const cb of set) {
31
+ try {
32
+ cb(event);
33
+ } catch (err) {
34
+ logger_default.error(`[mind-events] subscriber threw for ${mind}`, logger_default.errorData(err));
35
+ set.delete(cb);
36
+ if (set.size === 0) subscribers.delete(mind);
37
+ }
38
+ }
39
+ }
40
+ for (const cb of globalSubscribers) {
41
+ try {
42
+ cb(event);
43
+ } catch (err) {
44
+ logger_default.error("[mind-events] global subscriber threw", logger_default.errorData(err));
45
+ globalSubscribers.delete(cb);
46
+ }
47
+ }
48
+ }
49
+
50
+ export {
51
+ subscribe,
52
+ subscribeAll,
53
+ publish
54
+ };