volute 0.48.0 → 0.50.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 (215) hide show
  1. package/README.md +79 -328
  2. package/dist/{accept-KYNC5X3U.js → accept-5NK5XJB5.js} +2 -1
  3. package/dist/{activity-events-MIOK3IOU.js → activity-events-H7YI3BTF.js} +4 -4
  4. package/dist/{ai-service-643TNFPH.js → ai-service-V4CTNGI3.js} +6 -5
  5. package/dist/{archive-6Z4GFQPH.js → archive-ORM3ENHI.js} +3 -3
  6. package/dist/{auth-A4VGHADI.js → auth-DT7GY7EZ.js} +11 -7
  7. package/dist/{avatar-image-Y45R7LW5.js → avatar-image-QEPAP3A5.js} +4 -4
  8. package/dist/{backup-UDH4GMSW.js → backup-IE6PMXJO.js} +17 -18
  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-X43VYHH2.js → chat-W5K6HCBE.js} +9 -9
  12. package/dist/{chunk-LTLFOSA4.js → chunk-3BAFMGCJ.js} +3 -3
  13. package/dist/{chunk-XVBSFLM7.js → chunk-4CN7OCJE.js} +2 -2
  14. package/dist/{chunk-HPGN6XRT.js → chunk-574M6I7F.js} +39 -6
  15. package/dist/{chunk-FJ2MZ5PH.js → chunk-5FVANDON.js} +2 -2
  16. package/dist/{chunk-2MJ7EOMT.js → chunk-5IIVOWSP.js} +28 -19
  17. package/dist/{chunk-4FCL4DVZ.js → chunk-5PKFJHCR.js} +2 -2
  18. package/dist/{chunk-MOERAQXH.js → chunk-5TPC4KCV.js} +38 -31
  19. package/dist/{chunk-YNBXEQAP.js → chunk-632FJ23O.js} +24 -20
  20. package/dist/{chunk-T4VS7UDW.js → chunk-636GFQNE.js} +12 -12
  21. package/dist/{chunk-EIQDZC43.js → chunk-6BM2I736.js} +25 -6
  22. package/dist/{chunk-WARH6GIV.js → chunk-74T3CEXK.js} +17 -15
  23. package/dist/{chunk-OQJMTHEH.js → chunk-77IZUVBB.js} +2 -2
  24. package/dist/{chunk-USD45JKR.js → chunk-7DXLIYPY.js} +77 -64
  25. package/dist/chunk-7FDWPQCU.js +289 -0
  26. package/dist/chunk-7OZWKHA3.js +548 -0
  27. package/dist/{chunk-IJPMIEVE.js → chunk-7UWXAJMK.js} +1 -1
  28. package/dist/{chunk-SZJCJVXV.js → chunk-7XDOTN4R.js} +2 -2
  29. package/dist/{chunk-YKA7DCVW.js → chunk-AFSLNUTT.js} +1 -1
  30. package/dist/{chunk-DGGZVZTM.js → chunk-AJWFDIEY.js} +17 -2
  31. package/dist/chunk-ALIVXDM4.js +1014 -0
  32. package/dist/chunk-CAIYV33P.js +523 -0
  33. package/dist/{chunk-MTRMQFCQ.js → chunk-E5S3ILVA.js} +2 -2
  34. package/dist/{chunk-SHKM5RGD.js → chunk-EEOMA4DX.js} +1 -1
  35. package/dist/chunk-EQKSRVDE.js +2857 -0
  36. package/dist/chunk-FNJCBRD3.js +31 -0
  37. package/dist/chunk-HW6Q7AMB.js +113 -0
  38. package/dist/chunk-JI67D7O2.js +1222 -0
  39. package/dist/{chunk-3YUBFTDN.js → chunk-KAEZOVP6.js} +1 -1
  40. package/dist/chunk-LNNI3MS4.js +54 -0
  41. package/dist/{chunk-BCG45AQB.js → chunk-M74I3HHF.js} +15 -5
  42. package/dist/chunk-MLZBBLMT.js +109 -0
  43. package/dist/{chunk-5T5YMX6S.js → chunk-PW65BXY5.js} +5 -0
  44. package/dist/{chunk-2OIYNHWO.js → chunk-QFVGPKJI.js} +1 -1
  45. package/dist/{chunk-T2TP6ZC6.js → chunk-QUSMYGNQ.js} +6 -0
  46. package/dist/{chunk-HNGFKPNS.js → chunk-SFRYRW37.js} +85 -36
  47. package/dist/{chunk-7KRIHYLR.js → chunk-SSNZ6ZNN.js} +2 -2
  48. package/dist/{chunk-HUNDXZBZ.js → chunk-TGJHGVBZ.js} +48 -19
  49. package/dist/{chunk-PJVPDY2Z.js → chunk-U3EJJ7JN.js} +2 -2
  50. package/dist/{chunk-ODDGGLM6.js → chunk-UC6BNMGT.js} +43 -13
  51. package/dist/{chunk-Q7HOAVFR.js → chunk-WBBKYUGF.js} +4 -6
  52. package/dist/{chunk-WQ46E33M.js → chunk-X67VT4QO.js} +2 -2
  53. package/dist/{chunk-MJRXFUMS.js → chunk-YQOYZ6G7.js} +3 -5
  54. package/dist/{chunk-VZRA5TYO.js → chunk-ZUG76D3P.js} +36 -6
  55. package/dist/cli.js +34 -27
  56. package/dist/{clock-CNRF6F7T.js → clock-LH7UFNLJ.js} +5 -4
  57. package/dist/{cloud-sync-WHKCB4CD.js → cloud-sync-IDJFVDEP.js} +23 -20
  58. package/dist/{config-RPSLA2HX.js → config-UGJS57VT.js} +3 -3
  59. package/dist/{conversations-C7IKYSHD.js → conversations-S2232Y5I.js} +9 -5
  60. package/dist/{create-GJKHABJB.js → create-2M7DAHQX.js} +2 -2
  61. package/dist/{create-VIQVP3QB.js → create-M727VUDF.js} +2 -1
  62. package/dist/{daemon-client-ZFY5MOAL.js → daemon-client-VVYFZI2D.js} +2 -1
  63. package/dist/{daemon-restart-7KUHVZIN.js → daemon-restart-2AAGYFHE.js} +6 -7
  64. package/dist/daemon.js +2166 -833
  65. package/dist/{db-FO6LXYCW.js → db-QAY45Z56.js} +2 -2
  66. package/dist/{delete-ESEP7NGQ.js → delete-O7PEFQDF.js} +1 -1
  67. package/dist/delivery-manager-B4OKWD2P.js +33 -0
  68. package/dist/{delivery-router-3QFG2ZEX.js → delivery-router-JE7SHYNU.js} +10 -6
  69. package/dist/{down-G6IADJXV.js → down-D4IRNEMJ.js} +5 -5
  70. package/dist/echo-text-WYAAODBV.js +39 -0
  71. package/dist/{env-C7Z55QCJ.js → env-ABM5IMA7.js} +8 -7
  72. package/dist/{env-6TGPO5WG.js → env-AZK5X4W7.js} +3 -3
  73. package/dist/{exec-QIFYZG4C.js → exec-2H65LMTA.js} +3 -3
  74. package/dist/{export-C2K3NIRD.js → export-3E3EL6W3.js} +4 -4
  75. package/dist/{extension-J4ZQ2GHV.js → extension-MRYJWSMV.js} +2 -1
  76. package/dist/{extensions-GEKF47A4.js → extensions-7KP3X6G7.js} +23 -20
  77. package/dist/{files-LXQSQOFG.js → files-6BMKVG5G.js} +5 -4
  78. package/dist/{import-SX3ZXHB4.js → import-UPNTEBBT.js} +9 -9
  79. package/dist/{isolation-MCT4ZYLT.js → isolation-OKDFM6WA.js} +5 -3
  80. package/dist/{join-34TR2GXQ.js → join-PYA36HEC.js} +1 -1
  81. package/dist/{list-PMUXZNAM.js → list-4BVGH7AN.js} +8 -3
  82. package/dist/{login-CL4IT2ED.js → login-MOXVLULE.js} +7 -6
  83. package/dist/{login-ARRZ4ORJ.js → login-RJJTCVR3.js} +4 -3
  84. package/dist/{logout-YZRMZ3O2.js → logout-BYV433X6.js} +2 -1
  85. package/dist/{logout-HZYJCYCA.js → logout-DWD3OQVT.js} +4 -3
  86. package/dist/message-delivery-3456PXB7.js +43 -0
  87. package/dist/migrate-thread-config-4A5LW36Z.js +90 -0
  88. package/dist/{mind-46AOK373.js → mind-NYRALSV2.js} +19 -19
  89. package/dist/{mind-activity-tracker-YVZPC4A5.js → mind-activity-tracker-L7GCYXQR.js} +5 -5
  90. package/dist/{mind-contacts-GV7XYL5D.js → mind-contacts-QYU4TPEA.js} +8 -7
  91. package/dist/{mind-history-TTGA5BHZ.js → mind-history-NXXOOTX6.js} +34 -11
  92. package/dist/{mind-list-OTHV4ZO4.js → mind-list-SYRA7CH5.js} +3 -2
  93. package/dist/{mind-profile-LUG353ZT.js → mind-profile-MRCVZPYT.js} +1 -1
  94. package/dist/mind-service-5TA7UJAT.js +47 -0
  95. package/dist/{mind-sleep-DV7KP255.js → mind-sleep-TH6BRQ5X.js} +5 -4
  96. package/dist/{mind-status-BJNPGXKC.js → mind-status-Z2LQFA6F.js} +3 -2
  97. package/dist/{mind-wake-LVTZ55EZ.js → mind-wake-LDGPRA42.js} +2 -1
  98. package/dist/{package-RTN2PS7O.js → package-XYSV7NUT.js} +27 -26
  99. package/dist/prompts-QKFPX6DQ.js +24 -0
  100. package/dist/{read-YSWUXYL7.js → read-ZXGUT4QC.js} +5 -3
  101. package/dist/{register-42VBJKTP.js → register-OX4HRSGC.js} +4 -3
  102. package/dist/{registry-UMMDRPRM.js → registry-4UF6OCOE.js} +10 -4
  103. package/dist/{reject-SXGCYN4A.js → reject-TWB4QJHG.js} +2 -1
  104. package/dist/{restart-YYEGZJDD.js → restart-AGEGNSYQ.js} +6 -5
  105. package/dist/{sandbox-5VQ454XP.js → sandbox-EGEU5GGE.js} +8 -5
  106. package/dist/scheduler-UV6RUJ7P.js +25 -0
  107. package/dist/{schema-VEVO7HG6.js → schema-C2GIPD4V.js} +3 -3
  108. package/dist/{seed-F2HXZQU4.js → seed-3IMBOAGK.js} +1 -1
  109. package/dist/{seed-check-TYD7RRZY.js → seed-check-NRJEQZST.js} +14 -5
  110. package/dist/{seed-cmd-MLCTGSX5.js → seed-cmd-U73XVQMI.js} +3 -3
  111. package/dist/{seed-create-KQ7OILWB.js → seed-create-FBLNVSUP.js} +4 -4
  112. package/dist/{seed-readiness-RBPGOLSZ.js → seed-readiness-QRA46ZJQ.js} +4 -5
  113. package/dist/{seed-sprout-HVYCFJLA.js → seed-sprout-3B4SZX7J.js} +12 -12
  114. package/dist/{send-TD2X5U3K.js → send-NBRZJXKX.js} +34 -12
  115. package/dist/{service-CVZMQYK6.js → service-XMXAXGJD.js} +4 -4
  116. package/dist/{service-install-VCRMFWX5.js → service-install-MOKTEG7B.js} +5 -5
  117. package/dist/{setup-5ECWTYKG.js → setup-CAJFOR2N.js} +12 -3
  118. package/dist/{setup-AE4CVUC4.js → setup-JGYAXXW7.js} +6 -7
  119. package/dist/{skill-UUM4JZRF.js → skill-NXIHDQCG.js} +7 -6
  120. package/dist/skills/dreaming/references/INSTALL.md +2 -2
  121. package/dist/skills/imagegen/SKILL.md +21 -4
  122. package/dist/skills/imagegen/scripts/imagegen.ts +124 -21
  123. package/dist/skills/tending/SKILL.md +7 -7
  124. package/dist/skills/volute-mind/SKILL.md +6 -6
  125. package/dist/skills/volute-mind/references/integrations.md +2 -2
  126. package/dist/skills/volute-mind/references/routing.md +19 -18
  127. package/dist/skills/volute-mind/references/variants.md +48 -14
  128. package/dist/{skills-B3SVDCEB.js → skills-5MSMT7PT.js} +7 -6
  129. package/dist/sleep-manager-LIEPO6WG.js +41 -0
  130. package/dist/spirit-IL5EMWYZ.js +34 -0
  131. package/dist/spirit-availability-YFEGJNJ2.js +42 -0
  132. package/dist/{split-SKZ4Y2D6.js → split-BU5VWX6P.js} +5 -2
  133. package/dist/{sprout-KQ43BWZJ.js → sprout-UPXGJ5HX.js} +1 -1
  134. package/dist/{src-YH6PQ7LJ.js → src-HGNE2XG4.js} +7 -1
  135. package/dist/{src-WLJE73NP.js → src-LCSOQY6Z.js} +60 -54
  136. package/dist/{src-JAOVXO5W.js → src-UDMJZ6MH.js} +8 -8
  137. package/dist/{start-O6UKK7BG.js → start-MUMNFR52.js} +4 -3
  138. package/dist/{status-F4PGREUU.js → status-IL67CYM4.js} +7 -6
  139. package/dist/{stop-UBX6X5RA.js → stop-EKERNYTX.js} +6 -5
  140. package/dist/system-events-A6IGCEC3.js +46 -0
  141. package/dist/system-install-YZSWCPDK.js +8 -0
  142. package/dist/{systems-JJNGQHAO.js → systems-VDRUZXNF.js} +5 -4
  143. package/dist/{tailscale-MCLY5GYE.js → tailscale-SJUW2ETR.js} +3 -3
  144. package/dist/{template-staleness-EMQORSGG.js → template-staleness-T27VCGYA.js} +4 -4
  145. package/dist/{turn-tracker-KLPV3PAU.js → turn-tracker-6EI2EL7G.js} +7 -7
  146. package/dist/{up-RVGDE6CQ.js → up-CLL4665A.js} +5 -6
  147. package/dist/{update-OXQEGGXD.js → update-HVAUCQPN.js} +5 -5
  148. package/dist/{update-check-266R4ZSY.js → update-check-2MGBBAFF.js} +3 -3
  149. package/dist/{upgrade-K5FIQPQD.js → upgrade-LIE46UBB.js} +1 -1
  150. package/dist/variant-cleanup-HJ7Z75R6.js +22 -0
  151. package/dist/{version-notify-73YURTFR.js → version-notify-7BUHWZNT.js} +11 -28
  152. package/dist/web-assets/assets/index-ClsUcXiW.js +95 -0
  153. package/dist/web-assets/assets/index-Dz3wTbtR.css +1 -0
  154. package/dist/web-assets/index.html +2 -2
  155. package/dist/xai-P42CRCZA.js +129 -0
  156. package/drizzle/0013_variant_purpose.sql +3 -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/meta/_journal.json +35 -0
  162. package/package.json +27 -26
  163. package/packages/extensions/notes/dist/ui/assets/index-BBs8pyel.js +67 -0
  164. package/packages/extensions/notes/dist/ui/index.html +1 -1
  165. package/packages/extensions/pages/dist/ui/assets/index-B589e8Xe.js +2 -0
  166. package/packages/extensions/pages/dist/ui/index.html +1 -1
  167. package/packages/extensions/plan/dist/ui/assets/index-B8s8wxyt.js +67 -0
  168. package/packages/extensions/plan/dist/ui/index.html +1 -1
  169. package/templates/_base/.init/.config/prompts.json +1 -0
  170. package/templates/_base/.init/.local/hooks/startup-context.ts +34 -2
  171. package/templates/_base/home/.config/routes.json +2 -2
  172. package/templates/_base/home/VOLUTE.md +30 -5
  173. package/templates/_base/src/lib/daemon-client.ts +28 -8
  174. package/templates/_base/src/lib/event-turn.ts +39 -0
  175. package/templates/_base/src/lib/format-prefix.ts +21 -2
  176. package/templates/_base/src/lib/router.ts +6 -2
  177. package/templates/_base/src/lib/routing.ts +8 -8
  178. package/templates/_base/src/lib/startup.ts +9 -1
  179. package/templates/_base/src/lib/types.ts +7 -1
  180. package/templates/_base/src/lib/volute-server.ts +30 -1
  181. package/templates/claude/.init/.config/routes.json +3 -3
  182. package/templates/claude/.init/CLAUDE.md +1 -1
  183. package/templates/claude/package.json.tmpl +4 -4
  184. package/templates/claude/src/agent.ts +5 -2
  185. package/templates/claude/src/lib/hooks/identity-reload.ts +12 -3
  186. package/templates/claude/src/lib/hooks/reply-instructions.ts +26 -1
  187. package/templates/codex/.init/.config/routes.json +3 -3
  188. package/templates/codex/.init/AGENTS.md +1 -1
  189. package/templates/codex/package.json.tmpl +4 -4
  190. package/templates/codex/src/agent.ts +11 -11
  191. package/templates/codex/src/lib/turn-context.ts +51 -0
  192. package/templates/pi/.init/.config/routes.json +3 -3
  193. package/templates/pi/.init/MINDS.md +1 -1
  194. package/templates/pi/package.json.tmpl +6 -6
  195. package/templates/pi/src/agent.ts +9 -1
  196. package/templates/pi/src/lib/event-handler.ts +47 -6
  197. package/templates/pi/src/lib/reply-instructions-extension.ts +28 -1
  198. package/dist/chunk-5KXCM5AW.js +0 -169
  199. package/dist/chunk-IYCV34IU.js +0 -158
  200. package/dist/chunk-VB2QXUJQ.js +0 -5260
  201. package/dist/chunk-WW6C3PLV.js +0 -280
  202. package/dist/delivery-manager-HZTT5SJR.js +0 -36
  203. package/dist/echo-text-H3SH337Q.js +0 -36
  204. package/dist/message-delivery-GPQ5SE5N.js +0 -40
  205. package/dist/mind-service-2ARGJNKP.js +0 -44
  206. package/dist/notices-2KU5NTRY.js +0 -25
  207. package/dist/scheduler-I7JZCT47.js +0 -34
  208. package/dist/sleep-manager-Z27R3WTW.js +0 -38
  209. package/dist/spirit-WXS3HCLN.js +0 -25
  210. package/dist/system-chat-63ABFF6V.js +0 -40
  211. package/dist/web-assets/assets/index-WdZ60R6c.css +0 -1
  212. package/dist/web-assets/assets/index-taX6Ezfa.js +0 -92
  213. package/packages/extensions/notes/dist/ui/assets/index-D0-DgYyj.js +0 -67
  214. package/packages/extensions/pages/dist/ui/assets/index-DtzftuPA.js +0 -2
  215. package/packages/extensions/plan/dist/ui/assets/index-Cfzs-0G9.js +0 -67
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ logger_default
4
+ } from "./chunk-QUSMYGNQ.js";
2
5
  import {
3
6
  readGlobalConfig,
4
7
  writeGlobalConfig
5
- } from "./chunk-5KXCM5AW.js";
6
- import {
7
- logger_default
8
- } from "./chunk-T2TP6ZC6.js";
8
+ } from "./chunk-CAIYV33P.js";
9
9
 
10
10
  // packages/daemon/src/lib/ai-service.ts
11
11
  import { defaultProviderAuthContext } from "@earendil-works/pi-ai";
@@ -133,7 +133,7 @@ async function missingCredentialWarning(template, model, mindName) {
133
133
  const envVar = PROVIDER_ENV_VAR[provider] ?? `${provider.toUpperCase().replace(/-/g, "_")}_API_KEY`;
134
134
  if (await resolveApiKey(provider)) return null;
135
135
  if (provider === "openai-codex" && process.env.OPENAI_API_KEY) return null;
136
- const { loadMergedEnv } = await import("./env-6TGPO5WG.js");
136
+ const { loadMergedEnv } = await import("./env-AZK5X4W7.js");
137
137
  if (loadMergedEnv(mindName)[envVar]) return null;
138
138
  return `No ${provider} credentials are configured, so ${mindName} will start but stay silent until a key is available. Set one with \`volute env set ${envVar} <key> --mind ${mindName}\`, or configure the ${provider} provider in the web dashboard (Settings \u2192 Providers).`;
139
139
  }
@@ -299,25 +299,28 @@ async function getAvailableModels() {
299
299
  }
300
300
  return result;
301
301
  }
302
- async function resolveApiKey(providerId) {
302
+ async function resolveOAuthCredentials(providerId) {
303
303
  const ai = getAiConfig();
304
304
  const providerConfig = ai?.providers[providerId];
305
- if (providerConfig?.oauth) {
306
- try {
307
- const result = await getOAuthApiKey(providerId, {
308
- [providerId]: providerConfig.oauth
309
- });
310
- if (result) {
311
- if (result.newCredentials.access !== providerConfig.oauth.access) {
312
- saveProviderConfig(providerId, { ...providerConfig, oauth: result.newCredentials });
313
- fireProviderRefreshHook(providerId);
314
- }
315
- return result.apiKey;
316
- }
317
- } catch (err) {
318
- aiLog.warn(`OAuth key resolution failed for ${providerId}`, logger_default.errorData(err));
305
+ if (!providerConfig?.oauth) return void 0;
306
+ try {
307
+ const result = await getOAuthApiKey(providerId, { [providerId]: providerConfig.oauth });
308
+ if (!result) return void 0;
309
+ if (result.newCredentials.access !== providerConfig.oauth.access) {
310
+ saveProviderConfig(providerId, { ...providerConfig, oauth: result.newCredentials });
311
+ fireProviderRefreshHook(providerId);
319
312
  }
313
+ return result.newCredentials;
314
+ } catch (err) {
315
+ aiLog.warn(`OAuth credential resolution failed for ${providerId}`, logger_default.errorData(err));
316
+ return void 0;
320
317
  }
318
+ }
319
+ async function resolveApiKey(providerId) {
320
+ const ai = getAiConfig();
321
+ const providerConfig = ai?.providers[providerId];
322
+ const oauthCreds = await resolveOAuthCredentials(providerId);
323
+ if (oauthCreds) return oauthCreds.access;
321
324
  return resolveProviderKey(providerId, providerConfig?.apiKey);
322
325
  }
323
326
  function qualifyModelId(modelId) {
@@ -418,6 +421,7 @@ export {
418
421
  removeCustomModel,
419
422
  buildCustomModel,
420
423
  getAvailableModels,
424
+ resolveOAuthCredentials,
421
425
  resolveApiKey,
422
426
  qualifyModelId,
423
427
  unqualifyModelId,
@@ -2,17 +2,17 @@
2
2
  import {
3
3
  findBridgeForChannel,
4
4
  getBridgeConfig
5
- } from "./chunk-SZJCJVXV.js";
5
+ } from "./chunk-7XDOTN4R.js";
6
6
  import {
7
7
  recordOutbound
8
- } from "./chunk-VB2QXUJQ.js";
9
- import {
10
- publish
11
- } from "./chunk-USD45JKR.js";
8
+ } from "./chunk-EQKSRVDE.js";
12
9
  import {
13
10
  getOrCreateMindUser,
14
11
  getUserByUsername
15
- } from "./chunk-ODDGGLM6.js";
12
+ } from "./chunk-UC6BNMGT.js";
13
+ import {
14
+ publish
15
+ } from "./chunk-LNNI3MS4.js";
16
16
  import {
17
17
  addMessage,
18
18
  findDMConversation,
@@ -20,27 +20,27 @@ import {
20
20
  getChannelName,
21
21
  getConversation,
22
22
  getParticipants
23
- } from "./chunk-HPGN6XRT.js";
23
+ } from "./chunk-574M6I7F.js";
24
24
  import {
25
25
  readVoluteConfig
26
26
  } from "./chunk-WCFSBH33.js";
27
27
  import {
28
28
  daemonConfigPath,
29
29
  readDaemonToken
30
- } from "./chunk-FJ2MZ5PH.js";
30
+ } from "./chunk-5FVANDON.js";
31
31
  import {
32
32
  readEnv,
33
33
  sharedEnvPath
34
- } from "./chunk-IJPMIEVE.js";
34
+ } from "./chunk-7UWXAJMK.js";
35
35
  import {
36
36
  logger_default
37
- } from "./chunk-T2TP6ZC6.js";
37
+ } from "./chunk-QUSMYGNQ.js";
38
38
  import {
39
39
  buildVoluteSlug
40
40
  } from "./chunk-LGNUFVMR.js";
41
41
  import {
42
42
  mindDir
43
- } from "./chunk-WW6C3PLV.js";
43
+ } from "./chunk-CAIYV33P.js";
44
44
  import {
45
45
  __export
46
46
  } from "./chunk-K3NQKI34.js";
@@ -595,7 +595,7 @@ async function send4(env, channelSlug, message, images) {
595
595
  };
596
596
  if (token) headers.Authorization = `Bearer ${token}`;
597
597
  const voluteSession = env.VOLUTE_SESSION || (env.VOLUTE_MIND_DIR ? readSessionFile(env.VOLUTE_MIND_DIR) : void 0);
598
- if (voluteSession) headers["X-Volute-Session"] = voluteSession;
598
+ if (voluteSession) headers["X-Volute-Thread"] = voluteSession;
599
599
  const res = await fetch(`${url}/api/v1/chat`, {
600
600
  method: "POST",
601
601
  headers,
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  logger_default
4
- } from "./chunk-T2TP6ZC6.js";
4
+ } from "./chunk-QUSMYGNQ.js";
5
5
  import {
6
6
  mindDir
7
- } from "./chunk-WW6C3PLV.js";
7
+ } from "./chunk-CAIYV33P.js";
8
8
 
9
9
  // packages/daemon/src/lib/delivery/delivery-router.ts
10
10
  import { readFileSync, statSync } from "fs";
@@ -63,6 +63,7 @@ function getRoutingConfig(mindName) {
63
63
  try {
64
64
  const config = JSON.parse(readFileSync(path, "utf-8"));
65
65
  const changed = cached != null && cached.mtime !== mtime;
66
+ warnUnknownRuleKeys(mindName, config);
66
67
  configCache.set(mindName, { config, mtime });
67
68
  if (changed) notifyRoutesChanged(mindName);
68
69
  return config;
@@ -94,7 +95,20 @@ function globMatch(pattern, value) {
94
95
  return regex.test(value);
95
96
  }
96
97
  var GLOB_MATCH_KEYS = /* @__PURE__ */ new Set(["channel", "sender"]);
97
- var NON_MATCH_KEYS = /* @__PURE__ */ new Set(["session", "destination", "path", "mode", "batch"]);
98
+ var NON_MATCH_KEYS = /* @__PURE__ */ new Set(["thread", "destination", "path", "mode", "batch"]);
99
+ var KNOWN_RULE_KEYS = /* @__PURE__ */ new Set([...GLOB_MATCH_KEYS, ...NON_MATCH_KEYS, "isDM", "participants"]);
100
+ function warnUnknownRuleKeys(mindName, config) {
101
+ if (!Array.isArray(config.rules)) return;
102
+ for (const rule of config.rules) {
103
+ if (rule == null || typeof rule !== "object") continue;
104
+ const unknown = Object.keys(rule).filter((k) => !KNOWN_RULE_KEYS.has(k));
105
+ if (unknown.length > 0) {
106
+ dlog.warn(
107
+ `routes.json for ${mindName} has a rule with unrecognized key(s) ${unknown.map((k) => `"${k}"`).join(", ")} \u2014 the rule will never match (known keys: ${[...KNOWN_RULE_KEYS].join(", ")})`
108
+ );
109
+ }
110
+ }
111
+ }
98
112
  function ruleMatches(rule, meta) {
99
113
  for (const [key, pattern] of Object.entries(rule)) {
100
114
  if (NON_MATCH_KEYS.has(key)) continue;
@@ -137,7 +151,7 @@ function resolveRoute(config, meta) {
137
151
  }
138
152
  return {
139
153
  destination: "mind",
140
- session: sanitizeSessionName(expandTemplate(rule.session ?? fallback, meta)),
154
+ session: sanitizeSessionName(expandTemplate(rule.thread ?? fallback, meta)),
141
155
  matched: true,
142
156
  mode: rule.mode,
143
157
  rule
@@ -146,6 +160,9 @@ function resolveRoute(config, meta) {
146
160
  }
147
161
  return { destination: "mind", session: fallback, matched: false };
148
162
  }
163
+ function shouldGate(config, route) {
164
+ return route.destination === "mind" && !route.matched && config.gateUnmatched !== false;
165
+ }
149
166
  var DEFAULT_BATCH_DEBOUNCE = 5;
150
167
  var DEFAULT_BATCH_MAX_WAIT = 120;
151
168
  function normalizeBatchConfig(batch) {
@@ -157,7 +174,7 @@ function resolveDeliveryMode(config, sessionName, rule) {
157
174
  const defaults = {
158
175
  delivery: { mode: "immediate" }
159
176
  };
160
- if (!config.sessions) {
177
+ if (!config.threads) {
161
178
  if (ruleBatch != null) {
162
179
  const batch = normalizeBatchConfig(ruleBatch);
163
180
  return {
@@ -171,7 +188,7 @@ function resolveDeliveryMode(config, sessionName, rule) {
171
188
  }
172
189
  return defaults;
173
190
  }
174
- for (const [pattern, sessionConfig] of Object.entries(config.sessions)) {
191
+ for (const [pattern, sessionConfig] of Object.entries(config.threads)) {
175
192
  if (globMatch(pattern, sessionName)) {
176
193
  let delivery;
177
194
  if (sessionConfig.delivery == null || sessionConfig.delivery === "immediate") {
@@ -216,6 +233,8 @@ export {
216
233
  registerMindDir,
217
234
  getRoutingConfig,
218
235
  clearConfigCache,
236
+ warnUnknownRuleKeys,
219
237
  resolveRoute,
238
+ shouldGate,
220
239
  resolveDeliveryMode
221
240
  };
@@ -2,17 +2,17 @@
2
2
  import {
3
3
  compactDateTime,
4
4
  isCompact
5
- } from "./chunk-5T5YMX6S.js";
6
- import {
7
- getClient,
8
- urlOf
9
- } from "./chunk-LOPXTW6H.js";
5
+ } from "./chunk-PW65BXY5.js";
10
6
  import {
11
7
  resolveMindName
12
8
  } from "./chunk-BTY4WNFE.js";
13
9
  import {
14
10
  daemonFetch
15
- } from "./chunk-BCG45AQB.js";
11
+ } from "./chunk-M74I3HHF.js";
12
+ import {
13
+ getClient,
14
+ urlOf
15
+ } from "./chunk-LOPXTW6H.js";
16
16
  import {
17
17
  command,
18
18
  subcommands
@@ -114,18 +114,20 @@ var listSchedulesCmd = command({
114
114
  console.log("No schedules configured.");
115
115
  return;
116
116
  }
117
+ const compact = isCompact();
118
+ const fmtTime = (s) => compact ? compactDateTime(s) : new Date(s).toLocaleString();
119
+ const scheduleOf = (s) => s.cron ?? (s.fireAt ? `at ${fmtTime(s.fireAt)}` : "");
117
120
  const actionLabel = (s) => s.script ? `[script] ${s.script}` : s.messages?.length ? `[rotating x${s.messages.length}] ${s.messages[0]}` : s.message ?? "";
118
- if (isCompact()) {
121
+ if (compact) {
119
122
  for (const s of schedules) {
120
- const sched = s.cron ?? (s.fireAt ? `at ${s.fireAt}` : "");
121
- console.log(`${s.id} ${sched} ${actionLabel(s)}`);
123
+ console.log(`${s.id} ${scheduleOf(s)} ${actionLabel(s)}`);
122
124
  }
123
125
  } else {
124
126
  const idW = Math.max(2, ...schedules.map((s) => s.id.length));
125
- const schedW = Math.max(8, ...schedules.map((s) => (s.cron ?? s.fireAt ?? "").length));
127
+ const schedW = Math.max(8, ...schedules.map((s) => scheduleOf(s).length));
126
128
  console.log(`${"ID".padEnd(idW)} ${"SCHEDULE".padEnd(schedW)} ENABLED ACTION`);
127
129
  for (const s of schedules) {
128
- const sched = s.cron ?? (s.fireAt ? `at ${s.fireAt}` : "");
130
+ const sched = scheduleOf(s);
129
131
  console.log(
130
132
  `${s.id.padEnd(idW)} ${sched.padEnd(schedW)} ${String(s.enabled).padEnd(7)} ${actionLabel(s)}`
131
133
  );
@@ -143,7 +145,7 @@ var addScheduleCmd = command({
143
145
  message: { type: "string", description: "Message to send" },
144
146
  script: { type: "string", description: "Script to run" },
145
147
  id: { type: "string", description: "Unique name for this schedule (required)" },
146
- session: { type: "string", description: "Session name" },
148
+ thread: { type: "string", description: "Thread name" },
147
149
  "while-sleeping": {
148
150
  type: "string",
149
151
  description: "Behavior during sleep (skip, queue, trigger-wake)"
@@ -192,7 +194,7 @@ var addScheduleCmd = command({
192
194
  if (flags.message) body.message = flags.message;
193
195
  if (flags.script) body.script = flags.script;
194
196
  if (flags.id) body.id = flags.id;
195
- if (flags.session) body.session = flags.session;
197
+ if (flags.thread) body.thread = flags.thread;
196
198
  if (flags["while-sleeping"]) {
197
199
  const ws = flags["while-sleeping"];
198
200
  if (!["skip", "queue", "trigger-wake"].includes(ws)) {
@@ -277,11 +279,11 @@ var cmd = subcommands({
277
279
  },
278
280
  sleep: {
279
281
  description: "Put a mind to sleep",
280
- run: (args) => import("./mind-sleep-DV7KP255.js").then((m) => m.run(args))
282
+ run: (args) => import("./mind-sleep-TH6BRQ5X.js").then((m) => m.run(args))
281
283
  },
282
284
  wake: {
283
285
  description: "Wake a sleeping mind",
284
- run: (args) => import("./mind-wake-LVTZ55EZ.js").then((m) => m.run(args))
286
+ run: (args) => import("./mind-wake-LDGPRA42.js").then((m) => m.run(args))
285
287
  }
286
288
  },
287
289
  footer: "Use --mind <name> or VOLUTE_MIND to identify the mind."
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  setBridgeConfig
4
- } from "./chunk-SZJCJVXV.js";
4
+ } from "./chunk-7XDOTN4R.js";
5
5
  import {
6
6
  readEnv,
7
7
  sharedEnvPath,
8
8
  writeEnv
9
- } from "./chunk-IJPMIEVE.js";
9
+ } from "./chunk-7UWXAJMK.js";
10
10
 
11
11
  // packages/daemon/src/lib/template/import-utils.ts
12
12
  import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
@@ -1,74 +1,33 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ publish
4
+ } from "./chunk-LNNI3MS4.js";
2
5
  import {
3
6
  getPrompt
4
- } from "./chunk-MOERAQXH.js";
7
+ } from "./chunk-5TPC4KCV.js";
5
8
  import {
6
9
  aiCompleteUtility
7
- } from "./chunk-YNBXEQAP.js";
10
+ } from "./chunk-632FJ23O.js";
8
11
  import {
9
12
  logger_default
10
- } from "./chunk-T2TP6ZC6.js";
13
+ } from "./chunk-QUSMYGNQ.js";
11
14
  import {
12
15
  getDb
13
- } from "./chunk-WW6C3PLV.js";
16
+ } from "./chunk-CAIYV33P.js";
14
17
  import {
15
18
  messages,
16
19
  mindHistory,
17
20
  summaries,
18
21
  turns
19
- } from "./chunk-2MJ7EOMT.js";
22
+ } from "./chunk-5IIVOWSP.js";
20
23
 
21
24
  // packages/daemon/src/lib/daemon/turn-tracker.ts
22
25
  import { randomUUID } from "crypto";
23
- import { and as and2, eq as eq2, sql as sql2 } from "drizzle-orm";
26
+ import { and as and2, eq as eq2, inArray as inArray2, sql as sql2 } from "drizzle-orm";
24
27
 
25
28
  // packages/daemon/src/lib/daemon/summarizer.ts
26
29
  import { and, desc, eq, gte, inArray, like, lt, sql } from "drizzle-orm";
27
30
 
28
- // packages/daemon/src/lib/events/mind-events.ts
29
- var subscribers = /* @__PURE__ */ new Map();
30
- var globalSubscribers = /* @__PURE__ */ new Set();
31
- function subscribe(mind, callback) {
32
- let set = subscribers.get(mind);
33
- if (!set) {
34
- set = /* @__PURE__ */ new Set();
35
- subscribers.set(mind, set);
36
- }
37
- set.add(callback);
38
- return () => {
39
- set.delete(callback);
40
- if (set.size === 0) subscribers.delete(mind);
41
- };
42
- }
43
- function subscribeAll(callback) {
44
- globalSubscribers.add(callback);
45
- return () => {
46
- globalSubscribers.delete(callback);
47
- };
48
- }
49
- function publish(mind, event) {
50
- const set = subscribers.get(mind);
51
- if (set) {
52
- for (const cb of set) {
53
- try {
54
- cb(event);
55
- } catch (err) {
56
- logger_default.error(`[mind-events] subscriber threw for ${mind}`, logger_default.errorData(err));
57
- set.delete(cb);
58
- if (set.size === 0) subscribers.delete(mind);
59
- }
60
- }
61
- }
62
- for (const cb of globalSubscribers) {
63
- try {
64
- cb(event);
65
- } catch (err) {
66
- logger_default.error("[mind-events] global subscriber threw", logger_default.errorData(err));
67
- globalSubscribers.delete(cb);
68
- }
69
- }
70
- }
71
-
72
31
  // packages/daemon/src/lib/util/format-tool.ts
73
32
  function summarizeTool(name, input) {
74
33
  if (input && typeof input === "object") {
@@ -166,6 +125,33 @@ function utcDateTimeStr(d) {
166
125
  function parseUtcDateTime(s) {
167
126
  return /* @__PURE__ */ new Date(`${s.replace(" ", "T")}Z`);
168
127
  }
128
+ function getUtcTimeRange(periodKey, period) {
129
+ switch (period) {
130
+ case "hour": {
131
+ const d = /* @__PURE__ */ new Date(`${periodKey.slice(0, 10)}T${periodKey.slice(11)}:00:00`);
132
+ return { start: utcDateTimeStr(d), end: utcDateTimeStr(new Date(d.getTime() + 36e5)) };
133
+ }
134
+ case "day": {
135
+ const d = /* @__PURE__ */ new Date(`${periodKey}T00:00:00`);
136
+ const dEnd = new Date(d);
137
+ dEnd.setDate(d.getDate() + 1);
138
+ return { start: utcDateTimeStr(d), end: utcDateTimeStr(dEnd) };
139
+ }
140
+ case "week": {
141
+ const monday = isoWeekToDate(periodKey);
142
+ const nextMonday = new Date(monday);
143
+ nextMonday.setDate(monday.getDate() + 7);
144
+ return { start: utcDateTimeStr(monday), end: utcDateTimeStr(nextMonday) };
145
+ }
146
+ case "month": {
147
+ const [y, m] = periodKey.split("-").map(Number);
148
+ return {
149
+ start: utcDateTimeStr(new Date(y, m - 1, 1)),
150
+ end: utcDateTimeStr(new Date(y, m, 1))
151
+ };
152
+ }
153
+ }
154
+ }
169
155
  function getTimeRange(periodKey, period) {
170
156
  switch (period) {
171
157
  case "hour": {
@@ -206,19 +192,19 @@ async function gatherTurnEvents(mind, session, doneId) {
206
192
  eq(mindHistory.type, "done"),
207
193
  lt(mindHistory.id, doneId)
208
194
  ];
209
- if (session) subConditions.push(eq(mindHistory.session, session));
195
+ if (session) subConditions.push(eq(mindHistory.thread, session));
210
196
  const prevDoneSubquery = db.select({ id: mindHistory.id }).from(mindHistory).where(and(...subConditions)).orderBy(desc(mindHistory.id)).limit(1);
211
197
  const turnConditions = [
212
198
  eq(mindHistory.mind, mind),
213
199
  sql`${mindHistory.id} > COALESCE((${prevDoneSubquery}), 0)`,
214
200
  sql`${mindHistory.id} <= ${doneId}`
215
201
  ];
216
- if (session) turnConditions.push(eq(mindHistory.session, session));
202
+ if (session) turnConditions.push(eq(mindHistory.thread, session));
217
203
  const events = await db.select({
218
204
  id: mindHistory.id,
219
205
  type: mindHistory.type,
220
206
  channel: mindHistory.channel,
221
- session: mindHistory.session,
207
+ session: mindHistory.thread,
222
208
  content: mindHistory.content,
223
209
  metadata: mindHistory.metadata,
224
210
  turn_id: mindHistory.turn_id,
@@ -236,7 +222,7 @@ async function gatherTurnEventsByTurnId(turnId) {
236
222
  id: mindHistory.id,
237
223
  type: mindHistory.type,
238
224
  channel: mindHistory.channel,
239
- session: mindHistory.session,
225
+ session: mindHistory.thread,
240
226
  content: mindHistory.content,
241
227
  metadata: mindHistory.metadata,
242
228
  turn_id: mindHistory.turn_id,
@@ -266,11 +252,16 @@ function buildTurnDeterministicSummary(events, parsedMeta) {
266
252
  const tools = [];
267
253
  let hasInbound = false;
268
254
  let hasOutbound = false;
255
+ let eventLabel;
269
256
  for (const ev of events) {
270
257
  if (ev.type === "inbound") {
271
258
  hasInbound = true;
272
259
  if (ev.channel) channels.add(ev.channel);
273
260
  }
261
+ if (ev.type === "event") {
262
+ const label = parsedMeta.get(ev.id)?.label;
263
+ eventLabel = typeof label === "string" && label ? label : "System event";
264
+ }
274
265
  if (ev.type === "outbound" || ev.type === "text") {
275
266
  hasOutbound = true;
276
267
  }
@@ -280,6 +271,9 @@ function buildTurnDeterministicSummary(events, parsedMeta) {
280
271
  }
281
272
  }
282
273
  const parts = [];
274
+ if (eventLabel) {
275
+ parts.push(`System event: ${eventLabel}`);
276
+ }
283
277
  if (hasInbound) {
284
278
  const channelList = [...channels];
285
279
  parts.push(
@@ -302,6 +296,16 @@ function buildTranscript(events, parsedMeta) {
302
296
  case "inbound":
303
297
  lines.push(`[inbound${ev.channel ? ` ${ev.channel}` : ""}] ${ev.content ?? ""}`);
304
298
  break;
299
+ // A system event is what triggered the turn — the summarizer needs to see it, or a
300
+ // schedule/orientation/wake turn gets summarized from its tool calls alone, with no
301
+ // idea what prompted them. Framed as an event, not an inbound message: it has no
302
+ // sender, and the summary shouldn't imply someone spoke to the mind.
303
+ case "event": {
304
+ const label = parsedMeta.get(ev.id)?.label;
305
+ const named = typeof label === "string" && label ? `: ${label}` : "";
306
+ lines.push(`[system event${named}] ${ev.content ?? ""}`);
307
+ break;
308
+ }
305
309
  case "outbound":
306
310
  case "text":
307
311
  lines.push(`[response] ${(ev.content ?? "").slice(0, 500)}`);
@@ -345,7 +349,14 @@ async function summarizeTurn(mind, session, channel, doneId, turnId) {
345
349
  if (effectiveTurnId) {
346
350
  try {
347
351
  const db2 = await getDb();
348
- await db2.update(mindHistory).set({ turn_id: null }).where(and(eq(mindHistory.turn_id, effectiveTurnId), eq(mindHistory.type, "inbound")));
352
+ await db2.update(mindHistory).set({ turn_id: null }).where(
353
+ and(
354
+ eq(mindHistory.turn_id, effectiveTurnId),
355
+ // Release system-event rows too, so an interrupted event turn's row can be
356
+ // re-linked to the turn that actually processes it.
357
+ inArray(mindHistory.type, ["inbound", "event"])
358
+ )
359
+ );
349
360
  await db2.update(messages).set({ turn_id: null }).where(eq(messages.turn_id, effectiveTurnId));
350
361
  await db2.delete(turns).where(eq(turns.id, effectiveTurnId));
351
362
  } catch (err) {
@@ -1049,11 +1060,11 @@ var Summarizer = class {
1049
1060
  }
1050
1061
  };
1051
1062
  async function reconcileWedgedTurns(idleMs) {
1052
- const { sweepWedgedTurns: sweepWedgedTurns2, summarizeOrphanedTurns: summarizeOrphanedTurns2 } = await import("./turn-tracker-KLPV3PAU.js");
1063
+ const { sweepWedgedTurns: sweepWedgedTurns2, summarizeOrphanedTurns: summarizeOrphanedTurns2 } = await import("./turn-tracker-6EI2EL7G.js");
1053
1064
  const wedged = await sweepWedgedTurns2(idleMs);
1054
1065
  if (wedged.length === 0) return;
1055
1066
  summarizeOrphanedTurns2(wedged);
1056
- const { tryGetDeliveryManager } = await import("./delivery-manager-HZTT5SJR.js");
1067
+ const { tryGetDeliveryManager } = await import("./delivery-manager-B4OKWD2P.js");
1057
1068
  const dm = tryGetDeliveryManager();
1058
1069
  if (!dm) return;
1059
1070
  for (const t of wedged) {
@@ -1112,7 +1123,8 @@ async function linkInboundToActiveTurn(mind, session, channel) {
1112
1123
  await db.update(mindHistory).set({ turn_id: turnId }).where(
1113
1124
  and2(
1114
1125
  eq2(mindHistory.mind, mind),
1115
- eq2(mindHistory.type, "inbound"),
1126
+ // System events ("event") arrive mid-turn too and need the same attribution.
1127
+ inArray2(mindHistory.type, ["inbound", "event"]),
1116
1128
  sql2`${mindHistory.turn_id} IS NULL`,
1117
1129
  eq2(mindHistory.channel, channel)
1118
1130
  )
@@ -1145,7 +1157,7 @@ async function assignSession(mind, turnId, session) {
1145
1157
  }
1146
1158
  try {
1147
1159
  const db = await getDb();
1148
- await db.update(turns).set({ session }).where(eq2(turns.id, turnId));
1160
+ await db.update(turns).set({ thread: session }).where(eq2(turns.id, turnId));
1149
1161
  } catch (err) {
1150
1162
  tlog.error(`failed to assign session to turn ${turnId}`, logger_default.errorData(err));
1151
1163
  return;
@@ -1171,7 +1183,7 @@ async function completeTurn(mind, session) {
1171
1183
  }
1172
1184
  async function completeOrphanedTurns() {
1173
1185
  const db = await getDb();
1174
- const active = await db.select({ id: turns.id, mind: turns.mind, session: turns.session }).from(turns).where(eq2(turns.status, "active"));
1186
+ const active = await db.select({ id: turns.id, mind: turns.mind, session: turns.thread }).from(turns).where(eq2(turns.status, "active"));
1175
1187
  if (active.length === 0) return [];
1176
1188
  try {
1177
1189
  await db.update(turns).set({ status: "complete" }).where(eq2(turns.status, "active"));
@@ -1220,7 +1232,7 @@ async function sweepWedgedTurns(idleMs) {
1220
1232
  const cutoff = new Date(Date.now() - idleMs).toISOString().slice(0, 19).replace("T", " ");
1221
1233
  let rows;
1222
1234
  try {
1223
- rows = await db.select({ id: turns.id, mind: turns.mind, session: turns.session }).from(turns).innerJoin(mindHistory, eq2(mindHistory.turn_id, turns.id)).where(eq2(turns.status, "active")).groupBy(turns.id).having(
1235
+ rows = await db.select({ id: turns.id, mind: turns.mind, session: turns.thread }).from(turns).innerJoin(mindHistory, eq2(mindHistory.turn_id, turns.id)).where(eq2(turns.status, "active")).groupBy(turns.id).having(
1224
1236
  sql2`max(${mindHistory.created_at}) < ${cutoff} and sum(case when ${mindHistory.type} = 'done' then 1 else 0 end) > 0`
1225
1237
  );
1226
1238
  } catch (err) {
@@ -1251,11 +1263,12 @@ function summarizeOrphanedTurns(orphanedTurns) {
1251
1263
  }
1252
1264
 
1253
1265
  export {
1254
- subscribe,
1255
- subscribeAll,
1256
- publish,
1266
+ getPeriodKey,
1257
1267
  isoWeekKeyForDateStr,
1258
1268
  utcDateTimeStr,
1269
+ parseUtcDateTime,
1270
+ getUtcTimeRange,
1271
+ SYSTEM_MIND,
1259
1272
  summarizeTurn,
1260
1273
  initSummarizer,
1261
1274
  markErrored,