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
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  loadMergedEnv
4
- } from "./chunk-WUH54G5S.js";
4
+ } from "./chunk-ITH5ZLZJ.js";
5
5
  import {
6
6
  spiritDir
7
- } from "./chunk-Y4W3OS7Q.js";
7
+ } from "./chunk-YTNBO7S6.js";
8
8
  import {
9
9
  hashSkillDir,
10
10
  importSkillFromDir,
11
11
  removeSharedSkill,
12
12
  sharedSkillsDir
13
- } from "./chunk-IBOU6Q3Y.js";
13
+ } from "./chunk-QV7P3TYO.js";
14
14
  import {
15
15
  addMessage,
16
16
  createChannel,
@@ -20,7 +20,7 @@ import {
20
20
  getParticipants,
21
21
  joinChannel,
22
22
  publish as publish2
23
- } from "./chunk-QDWPM73D.js";
23
+ } from "./chunk-3Y7UDHO7.js";
24
24
  import {
25
25
  readVoluteConfig,
26
26
  writeVoluteConfig
@@ -28,46 +28,46 @@ import {
28
28
  import {
29
29
  isSandboxEnabled,
30
30
  wrapForSandbox
31
- } from "./chunk-EVKGKQ2P.js";
31
+ } from "./chunk-KMHC36CA.js";
32
32
  import {
33
33
  markIdle,
34
34
  onMindEvent
35
- } from "./chunk-DZ4LYU6J.js";
35
+ } from "./chunk-ANSTTB55.js";
36
36
  import {
37
37
  extractTextContent,
38
38
  getRoutingConfig,
39
39
  resolveDeliveryMode,
40
40
  resolveRoute
41
- } from "./chunk-OS5MRIEP.js";
41
+ } from "./chunk-NERYUSER.js";
42
42
  import {
43
43
  exec
44
- } from "./chunk-OEXOFBW5.js";
44
+ } from "./chunk-AEAZRTEV.js";
45
45
  import {
46
46
  chownMindDir,
47
47
  isIsolationEnabled,
48
48
  mindUserName,
49
49
  wrapForIsolation
50
- } from "./chunk-6FSSMAXU.js";
50
+ } from "./chunk-6SYHHEQ7.js";
51
+ import {
52
+ aiCompleteUtility,
53
+ getAiConfig,
54
+ resolveApiKey
55
+ } from "./chunk-S4SXBQ7F.js";
56
+ import {
57
+ readGlobalConfig,
58
+ writeGlobalConfig
59
+ } from "./chunk-DNU6XLE2.js";
51
60
  import {
52
61
  getOrCreateMindUser,
53
62
  getOrCreateSystemUser,
54
63
  getUser,
55
64
  getUserByUsername,
56
65
  syncMindProfile
57
- } from "./chunk-7W3UWCQD.js";
66
+ } from "./chunk-E25SO3QW.js";
58
67
  import {
59
68
  publish,
60
69
  subscribe
61
- } from "./chunk-7GZB3ZJP.js";
62
- import {
63
- aiCompleteUtility,
64
- getAiConfig,
65
- resolveApiKey
66
- } from "./chunk-B7MWXFAH.js";
67
- import {
68
- readGlobalConfig,
69
- writeGlobalConfig
70
- } from "./chunk-TCNCRDB5.js";
70
+ } from "./chunk-QYI65HCL.js";
71
71
  import {
72
72
  logger_default
73
73
  } from "./chunk-T2TP6ZC6.js";
@@ -80,37 +80,38 @@ import {
80
80
  stateDir,
81
81
  voluteHome,
82
82
  voluteSystemDir
83
- } from "./chunk-QDWP435B.js";
83
+ } from "./chunk-B4WPXYPI.js";
84
84
  import {
85
85
  activity,
86
86
  conversationParticipants,
87
87
  deliveryQueue,
88
88
  messages,
89
89
  mindHistory,
90
+ mindNotices,
90
91
  summaries,
91
92
  systemPrompts,
92
93
  turns,
93
94
  users
94
- } from "./chunk-CJ26DXZL.js";
95
+ } from "./chunk-2HZRJ35V.js";
95
96
 
96
97
  // packages/daemon/src/lib/delivery/message-delivery.ts
97
- import { and as and4, desc as desc2, eq as eq6, inArray as inArray3, sql as sql3 } from "drizzle-orm";
98
+ import { and as and5, desc as desc2, eq as eq7, inArray as inArray3, sql as sql4 } from "drizzle-orm";
98
99
 
99
100
  // packages/daemon/src/lib/daemon/sleep-manager.ts
100
101
  import { execFile as execFile2, spawn as spawnChild } from "child_process";
101
102
  import {
102
- existsSync as existsSync7,
103
- mkdirSync as mkdirSync4,
103
+ existsSync as existsSync8,
104
+ mkdirSync as mkdirSync5,
104
105
  readdirSync as readdirSync2,
105
- readFileSync as readFileSync6,
106
+ readFileSync as readFileSync7,
106
107
  readlinkSync,
107
108
  renameSync,
108
- writeFileSync as writeFileSync5
109
+ writeFileSync as writeFileSync6
109
110
  } from "fs";
110
- import { resolve as resolve6 } from "path";
111
+ import { resolve as resolve7 } from "path";
111
112
  import { promisify as promisify2 } from "util";
112
113
  import { CronExpressionParser as CronExpressionParser2 } from "cron-parser";
113
- import { and as and2, eq as eq4, inArray as inArray2 } from "drizzle-orm";
114
+ import { and as and3, eq as eq5, inArray as inArray2 } from "drizzle-orm";
114
115
 
115
116
  // packages/daemon/src/lib/prompts.ts
116
117
  import { eq } from "drizzle-orm";
@@ -326,8 +327,8 @@ async function getMindPromptDefaults() {
326
327
 
327
328
  // packages/daemon/src/lib/daemon/mind-manager.ts
328
329
  import { execFile, spawn } from "child_process";
329
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
330
- import { resolve } from "path";
330
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync3 } from "fs";
331
+ import { resolve as resolve2 } from "path";
331
332
  import { promisify } from "util";
332
333
 
333
334
  // packages/daemon/src/lib/util/json-state.ts
@@ -436,6 +437,78 @@ var RotatingLog = class extends Writable {
436
437
  }
437
438
  };
438
439
 
440
+ // packages/daemon/src/lib/daemon/credential-sync.ts
441
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
442
+ import { resolve } from "path";
443
+ var slog = logger_default.child("cred-sync");
444
+ function writeClaudeCredentials(homeDir, baseName, oauth) {
445
+ const claudeDir = resolve(homeDir, ".claude");
446
+ mkdirSync(claudeDir, { recursive: true });
447
+ writeFileSync2(
448
+ resolve(claudeDir, ".credentials.json"),
449
+ JSON.stringify({
450
+ claudeAiOauth: {
451
+ accessToken: oauth.access,
452
+ refreshToken: oauth.refresh,
453
+ expiresAt: oauth.expires ? new Date(oauth.expires).toISOString() : null,
454
+ scopes: ["user:inference", "user:profile"]
455
+ }
456
+ }),
457
+ { mode: 384 }
458
+ );
459
+ if (isIsolationEnabled()) {
460
+ chownMindDir(claudeDir, baseName);
461
+ }
462
+ return claudeDir;
463
+ }
464
+ function writePiProviderKey(piAgentDir, baseName, provider, key2) {
465
+ mkdirSync(piAgentDir, { recursive: true });
466
+ const authPath = resolve(piAgentDir, "auth.json");
467
+ const authData = existsSync3(authPath) ? JSON.parse(readFileSync2(authPath, "utf-8")) : {};
468
+ authData[provider] = { type: "api_key", key: key2 };
469
+ writeFileSync2(authPath, JSON.stringify(authData, null, 2), { mode: 384 });
470
+ if (isIsolationEnabled()) {
471
+ chownMindDir(piAgentDir, baseName);
472
+ }
473
+ }
474
+ function piUsesProvider(piAgentDir, provider) {
475
+ try {
476
+ const authPath = resolve(piAgentDir, "auth.json");
477
+ if (!existsSync3(authPath)) return false;
478
+ const data = JSON.parse(readFileSync2(authPath, "utf-8"));
479
+ return data[provider] != null;
480
+ } catch {
481
+ return false;
482
+ }
483
+ }
484
+ async function syncProviderToMinds(provider, deps = {}) {
485
+ if (provider !== "anthropic") return;
486
+ const getOauth = deps.getOauth ?? (() => getAiConfig()?.providers.anthropic?.oauth);
487
+ const oauth = getOauth();
488
+ if (!oauth?.access) return;
489
+ const listRunning = deps.listRunning ?? (() => []);
490
+ const lookup = deps.lookup ?? findMind;
491
+ for (const name of listRunning()) {
492
+ try {
493
+ const entry = await lookup(name);
494
+ if (!entry) continue;
495
+ const dir = entry.dir ?? mindDir(name);
496
+ const baseName = entry.parent ?? name;
497
+ const template = entry.template;
498
+ if (template === "claude" || !template) {
499
+ writeClaudeCredentials(resolve(dir, "home"), baseName, oauth);
500
+ } else if (template === "pi") {
501
+ const piAgentDir = resolve(dir, ".mind", "pi-agent");
502
+ if (piUsesProvider(piAgentDir, "anthropic")) {
503
+ writePiProviderKey(piAgentDir, baseName, "anthropic", oauth.access);
504
+ }
505
+ }
506
+ } catch (err) {
507
+ slog.warn(`failed to sync ${provider} credentials to mind ${name}`, logger_default.errorData(err));
508
+ }
509
+ }
510
+ }
511
+
439
512
  // packages/daemon/src/lib/daemon/mind-tokens.ts
440
513
  import { randomUUID } from "crypto";
441
514
  var tokenToMind = /* @__PURE__ */ new Map();
@@ -458,6 +531,74 @@ function resolveMindToken(token) {
458
531
  return tokenToMind.get(token) ?? null;
459
532
  }
460
533
 
534
+ // packages/daemon/src/lib/daemon/notices.ts
535
+ import { and, asc, eq as eq2, lte, sql } from "drizzle-orm";
536
+ var nlog = logger_default.child("notices");
537
+ var MAX_NOTICES_PER_SESSION = 100;
538
+ async function recordNotice(input) {
539
+ try {
540
+ const db = await getDb();
541
+ await db.insert(mindNotices).values({
542
+ mind: input.mind,
543
+ session: input.session,
544
+ kind: input.kind,
545
+ reason: input.reason,
546
+ detail: input.detail,
547
+ raw: input.raw ?? null
548
+ });
549
+ await db.run(
550
+ sql`DELETE FROM mind_notices WHERE mind = ${input.mind} AND session = ${input.session} AND id NOT IN (SELECT id FROM mind_notices WHERE mind = ${input.mind} AND session = ${input.session} ORDER BY id DESC LIMIT ${MAX_NOTICES_PER_SESSION})`
551
+ );
552
+ } catch (err) {
553
+ nlog.error(`failed to record notice for ${input.mind}:${input.session}`, logger_default.errorData(err));
554
+ }
555
+ }
556
+ async function drainNotices(mind, session, limit = MAX_NOTICES_PER_SESSION) {
557
+ const db = await getDb();
558
+ return db.select().from(mindNotices).where(and(eq2(mindNotices.mind, mind), eq2(mindNotices.session, session))).orderBy(asc(mindNotices.id)).limit(limit);
559
+ }
560
+ async function clearDeliveredNotices(mind, session, uptoId) {
561
+ try {
562
+ const db = await getDb();
563
+ await db.delete(mindNotices).where(
564
+ and(
565
+ eq2(mindNotices.mind, mind),
566
+ eq2(mindNotices.session, session),
567
+ lte(mindNotices.id, uptoId)
568
+ )
569
+ );
570
+ } catch (err) {
571
+ nlog.warn(`failed to clear delivered notices for ${mind}:${session}`, logger_default.errorData(err));
572
+ }
573
+ }
574
+ var NOTICE_HEADER = "[Notices] While you were unavailable, one or more turns failed. You're back now:";
575
+ function formatNotices(notices) {
576
+ if (notices.length === 0) return null;
577
+ const groups = /* @__PURE__ */ new Map();
578
+ for (const n of notices) {
579
+ const time = localHM(n.created_at);
580
+ const g = groups.get(n.reason);
581
+ if (g) {
582
+ g.count += 1;
583
+ g.detail = n.detail;
584
+ g.last = time;
585
+ } else {
586
+ groups.set(n.reason, { count: 1, detail: n.detail, first: time, last: time });
587
+ }
588
+ }
589
+ const lines = [...groups.values()].map((g) => {
590
+ const span = g.first === g.last ? g.first : `${g.first}\u2013${g.last}`;
591
+ const plural = g.count === 1 ? "turn" : "turns";
592
+ return `- ${g.count} ${plural} failed (${span}): ${g.detail}`;
593
+ });
594
+ return `${NOTICE_HEADER}
595
+ ${lines.join("\n")}`;
596
+ }
597
+ function localHM(createdAt) {
598
+ const iso = createdAt.endsWith("Z") ? createdAt : `${createdAt.replace(" ", "T")}Z`;
599
+ return new Date(iso).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
600
+ }
601
+
461
602
  // packages/daemon/src/lib/daemon/restart-tracker.ts
462
603
  var DEFAULT_MAX_ATTEMPTS = 5;
463
604
  var DEFAULT_BASE_DELAY = 3e3;
@@ -505,10 +646,10 @@ var RestartTracker = class {
505
646
 
506
647
  // packages/daemon/src/lib/daemon/turn-tracker.ts
507
648
  import { randomUUID as randomUUID2 } from "crypto";
508
- import { eq as eq3 } from "drizzle-orm";
649
+ import { eq as eq4 } from "drizzle-orm";
509
650
 
510
651
  // packages/daemon/src/lib/daemon/summarizer.ts
511
- import { and, desc, eq as eq2, gte, inArray, like, lt, sql } from "drizzle-orm";
652
+ import { and as and2, desc, eq as eq3, gte, inArray, like, lt, sql as sql2 } from "drizzle-orm";
512
653
 
513
654
  // packages/daemon/src/lib/events/mind-events.ts
514
655
  var subscribers = /* @__PURE__ */ new Map();
@@ -675,18 +816,18 @@ function getTimeRange(periodKey, period) {
675
816
  async function gatherTurnEvents(mind, session, doneId) {
676
817
  const db = await getDb();
677
818
  const subConditions = [
678
- eq2(mindHistory.mind, mind),
679
- eq2(mindHistory.type, "done"),
819
+ eq3(mindHistory.mind, mind),
820
+ eq3(mindHistory.type, "done"),
680
821
  lt(mindHistory.id, doneId)
681
822
  ];
682
- if (session) subConditions.push(eq2(mindHistory.session, session));
683
- const prevDoneSubquery = db.select({ id: mindHistory.id }).from(mindHistory).where(and(...subConditions)).orderBy(desc(mindHistory.id)).limit(1);
823
+ if (session) subConditions.push(eq3(mindHistory.session, session));
824
+ const prevDoneSubquery = db.select({ id: mindHistory.id }).from(mindHistory).where(and2(...subConditions)).orderBy(desc(mindHistory.id)).limit(1);
684
825
  const turnConditions = [
685
- eq2(mindHistory.mind, mind),
686
- sql`${mindHistory.id} > COALESCE((${prevDoneSubquery}), 0)`,
687
- sql`${mindHistory.id} <= ${doneId}`
826
+ eq3(mindHistory.mind, mind),
827
+ sql2`${mindHistory.id} > COALESCE((${prevDoneSubquery}), 0)`,
828
+ sql2`${mindHistory.id} <= ${doneId}`
688
829
  ];
689
- if (session) turnConditions.push(eq2(mindHistory.session, session));
830
+ if (session) turnConditions.push(eq3(mindHistory.session, session));
690
831
  const events = await db.select({
691
832
  id: mindHistory.id,
692
833
  type: mindHistory.type,
@@ -695,7 +836,7 @@ async function gatherTurnEvents(mind, session, doneId) {
695
836
  content: mindHistory.content,
696
837
  metadata: mindHistory.metadata,
697
838
  created_at: mindHistory.created_at
698
- }).from(mindHistory).where(and(...turnConditions)).orderBy(mindHistory.id);
839
+ }).from(mindHistory).where(and2(...turnConditions)).orderBy(mindHistory.id);
699
840
  return {
700
841
  events,
701
842
  fromId: events.length > 0 ? events[0].id : doneId,
@@ -712,7 +853,7 @@ async function gatherTurnEventsByTurnId(turnId) {
712
853
  content: mindHistory.content,
713
854
  metadata: mindHistory.metadata,
714
855
  created_at: mindHistory.created_at
715
- }).from(mindHistory).where(eq2(mindHistory.turn_id, turnId)).orderBy(mindHistory.id);
856
+ }).from(mindHistory).where(eq3(mindHistory.turn_id, turnId)).orderBy(mindHistory.id);
716
857
  return {
717
858
  events,
718
859
  fromId: events.length > 0 ? events[0].id : 0,
@@ -812,8 +953,8 @@ async function summarizeTurn(mind, session, channel, doneId, turnId) {
812
953
  if (turnId) {
813
954
  try {
814
955
  const db2 = await getDb();
815
- await db2.update(mindHistory).set({ turn_id: null }).where(and(eq2(mindHistory.turn_id, turnId), eq2(mindHistory.type, "inbound")));
816
- await db2.update(messages).set({ turn_id: null }).where(eq2(messages.turn_id, turnId));
956
+ await db2.update(mindHistory).set({ turn_id: null }).where(and2(eq3(mindHistory.turn_id, turnId), eq3(mindHistory.type, "inbound")));
957
+ await db2.update(messages).set({ turn_id: null }).where(eq3(messages.turn_id, turnId));
817
958
  } catch (err) {
818
959
  sLog.error(`failed to un-tag events for interrupted turn ${turnId}`, logger_default.errorData(err));
819
960
  }
@@ -870,10 +1011,10 @@ async function summarizeTurn(mind, session, channel, doneId, turnId) {
870
1011
  summaryId = result[0]?.id;
871
1012
  if (summaryId == null) {
872
1013
  const existing = await db.select({ id: summaries.id }).from(summaries).where(
873
- and(
874
- eq2(summaries.mind, mind),
875
- eq2(summaries.period, "turn"),
876
- eq2(summaries.period_key, periodKey)
1014
+ and2(
1015
+ eq3(summaries.mind, mind),
1016
+ eq3(summaries.period, "turn"),
1017
+ eq3(summaries.period_key, periodKey)
877
1018
  )
878
1019
  ).get();
879
1020
  summaryId = existing?.id;
@@ -902,7 +1043,7 @@ async function summarizeTurn(mind, session, channel, doneId, turnId) {
902
1043
  }
903
1044
  async function setSummaryId(turnId, summaryId) {
904
1045
  const db = await getDb();
905
- await db.update(turns).set({ summary_id: summaryId }).where(eq2(turns.id, turnId));
1046
+ await db.update(turns).set({ summary_id: summaryId }).where(eq3(turns.id, turnId));
906
1047
  }
907
1048
  function getChildPeriod(period) {
908
1049
  switch (period) {
@@ -946,9 +1087,9 @@ async function gatherChildSummaries(mind, period, periodKey) {
946
1087
  if (period === "hour") {
947
1088
  const { start: start2, end: end2 } = getTimeRange(periodKey, "hour");
948
1089
  const rows2 = await db.select({ id: summaries.id, content: summaries.content }).from(summaries).where(
949
- and(
950
- eq2(summaries.mind, mind),
951
- eq2(summaries.period, childPeriod),
1090
+ and2(
1091
+ eq3(summaries.mind, mind),
1092
+ eq3(summaries.period, childPeriod),
952
1093
  gte(summaries.created_at, start2),
953
1094
  lt(summaries.created_at, end2)
954
1095
  )
@@ -960,9 +1101,9 @@ async function gatherChildSummaries(mind, period, periodKey) {
960
1101
  }
961
1102
  if (period === "day") {
962
1103
  const rows2 = await db.select({ id: summaries.id, content: summaries.content }).from(summaries).where(
963
- and(
964
- eq2(summaries.mind, mind),
965
- eq2(summaries.period, childPeriod),
1104
+ and2(
1105
+ eq3(summaries.mind, mind),
1106
+ eq3(summaries.period, childPeriod),
966
1107
  like(summaries.period_key, `${periodKey}%`)
967
1108
  )
968
1109
  ).orderBy(summaries.period_key);
@@ -975,11 +1116,11 @@ async function gatherChildSummaries(mind, period, periodKey) {
975
1116
  const startKey = start.slice(0, 10);
976
1117
  const endKey = end.slice(0, 10);
977
1118
  const rows = await db.select({ id: summaries.id, content: summaries.content }).from(summaries).where(
978
- and(
979
- eq2(summaries.mind, mind),
980
- eq2(summaries.period, childPeriod),
1119
+ and2(
1120
+ eq3(summaries.mind, mind),
1121
+ eq3(summaries.period, childPeriod),
981
1122
  gte(summaries.period_key, startKey),
982
- sql`${summaries.period_key} <= ${endKey}`
1123
+ sql2`${summaries.period_key} <= ${endKey}`
983
1124
  )
984
1125
  ).orderBy(summaries.period_key);
985
1126
  return {
@@ -1059,10 +1200,10 @@ async function summarizeSystem(period, periodKey) {
1059
1200
  if (await summaryExists(SYSTEM_MIND, period, periodKey)) return;
1060
1201
  const db = await getDb();
1061
1202
  const rows = await db.select({ mind: summaries.mind, content: summaries.content }).from(summaries).where(
1062
- and(
1063
- eq2(summaries.period, period),
1064
- eq2(summaries.period_key, periodKey),
1065
- sql`${summaries.mind} != ${SYSTEM_MIND}`
1203
+ and2(
1204
+ eq3(summaries.period, period),
1205
+ eq3(summaries.period_key, periodKey),
1206
+ sql2`${summaries.mind} != ${SYSTEM_MIND}`
1066
1207
  )
1067
1208
  ).orderBy(summaries.mind);
1068
1209
  if (rows.length === 0) return;
@@ -1097,11 +1238,11 @@ async function summarizeSystem(period, periodKey) {
1097
1238
  async function mindsWithTurnSummaries(start, end) {
1098
1239
  const db = await getDb();
1099
1240
  const rows = await db.select({ mind: summaries.mind }).from(summaries).where(
1100
- and(
1101
- eq2(summaries.period, "turn"),
1241
+ and2(
1242
+ eq3(summaries.period, "turn"),
1102
1243
  gte(summaries.created_at, start),
1103
1244
  lt(summaries.created_at, end),
1104
- sql`${summaries.mind} != ${SYSTEM_MIND}`
1245
+ sql2`${summaries.mind} != ${SYSTEM_MIND}`
1105
1246
  )
1106
1247
  ).groupBy(summaries.mind);
1107
1248
  return rows.map((r) => r.mind);
@@ -1109,10 +1250,10 @@ async function mindsWithTurnSummaries(start, end) {
1109
1250
  async function mindsWithSummaries(period, keyPattern) {
1110
1251
  const db = await getDb();
1111
1252
  const rows = await db.select({ mind: summaries.mind }).from(summaries).where(
1112
- and(
1113
- eq2(summaries.period, period),
1253
+ and2(
1254
+ eq3(summaries.period, period),
1114
1255
  like(summaries.period_key, keyPattern),
1115
- sql`${summaries.mind} != ${SYSTEM_MIND}`
1256
+ sql2`${summaries.mind} != ${SYSTEM_MIND}`
1116
1257
  )
1117
1258
  ).groupBy(summaries.mind);
1118
1259
  return rows.map((r) => r.mind);
@@ -1120,11 +1261,11 @@ async function mindsWithSummaries(period, keyPattern) {
1120
1261
  async function mindsWithDailySummariesInRange(startKey, endKey) {
1121
1262
  const db = await getDb();
1122
1263
  const rows = await db.select({ mind: summaries.mind }).from(summaries).where(
1123
- and(
1124
- eq2(summaries.period, "day"),
1264
+ and2(
1265
+ eq3(summaries.period, "day"),
1125
1266
  gte(summaries.period_key, startKey),
1126
- sql`${summaries.period_key} <= ${endKey}`,
1127
- sql`${summaries.mind} != ${SYSTEM_MIND}`
1267
+ sql2`${summaries.period_key} <= ${endKey}`,
1268
+ sql2`${summaries.mind} != ${SYSTEM_MIND}`
1128
1269
  )
1129
1270
  ).groupBy(summaries.mind);
1130
1271
  return rows.map((r) => r.mind);
@@ -1188,10 +1329,10 @@ async function processMonth(periodKey) {
1188
1329
  async function summaryExists(mind, period, periodKey) {
1189
1330
  const db = await getDb();
1190
1331
  const row = await db.select({ id: summaries.id }).from(summaries).where(
1191
- and(
1192
- eq2(summaries.mind, mind),
1193
- eq2(summaries.period, period),
1194
- eq2(summaries.period_key, periodKey)
1332
+ and2(
1333
+ eq3(summaries.mind, mind),
1334
+ eq3(summaries.period, period),
1335
+ eq3(summaries.period_key, periodKey)
1195
1336
  )
1196
1337
  ).get();
1197
1338
  return !!row;
@@ -1221,7 +1362,7 @@ async function backfill() {
1221
1362
  }
1222
1363
  const allKeys = candidates.map((c) => c.key);
1223
1364
  const db = await getDb();
1224
- const existingRows = await db.select({ period: summaries.period, period_key: summaries.period_key }).from(summaries).where(and(eq2(summaries.mind, SYSTEM_MIND), inArray(summaries.period_key, allKeys)));
1365
+ const existingRows = await db.select({ period: summaries.period, period_key: summaries.period_key }).from(summaries).where(and2(eq3(summaries.mind, SYSTEM_MIND), inArray(summaries.period_key, allKeys)));
1225
1366
  const existingSet = new Set(existingRows.map((r) => `${r.period}:${r.period_key}`));
1226
1367
  const processFn = {
1227
1368
  hour: processHour,
@@ -1298,6 +1439,13 @@ var activeTurns = /* @__PURE__ */ new Map();
1298
1439
  function key(mind, session) {
1299
1440
  return `${mind}:${session ?? "*"}`;
1300
1441
  }
1442
+ var erroredSessions = /* @__PURE__ */ new Set();
1443
+ function markErrored(mind, session) {
1444
+ erroredSessions.add(key(mind, session));
1445
+ }
1446
+ function takeErrored(mind, session) {
1447
+ return erroredSessions.delete(key(mind, session));
1448
+ }
1301
1449
  async function createTurn(mind) {
1302
1450
  const k = key(mind);
1303
1451
  const existing = activeTurns.get(k);
@@ -1334,7 +1482,7 @@ async function assignSession(mind, turnId, session) {
1334
1482
  }
1335
1483
  try {
1336
1484
  const db = await getDb();
1337
- await db.update(turns).set({ session }).where(eq3(turns.id, turnId));
1485
+ await db.update(turns).set({ session }).where(eq4(turns.id, turnId));
1338
1486
  } catch (err) {
1339
1487
  tlog.error(`failed to assign session to turn ${turnId}`, logger_default.errorData(err));
1340
1488
  return;
@@ -1349,7 +1497,7 @@ async function completeTurn(mind, session) {
1349
1497
  if (!entry) return void 0;
1350
1498
  try {
1351
1499
  const db = await getDb();
1352
- await db.update(turns).set({ status: "complete" }).where(eq3(turns.id, entry.turnId));
1500
+ await db.update(turns).set({ status: "complete" }).where(eq4(turns.id, entry.turnId));
1353
1501
  } catch (err) {
1354
1502
  tlog.error(`failed to complete turn ${entry.turnId}`, logger_default.errorData(err));
1355
1503
  return void 0;
@@ -1360,10 +1508,10 @@ async function completeTurn(mind, session) {
1360
1508
  }
1361
1509
  async function completeOrphanedTurns() {
1362
1510
  const db = await getDb();
1363
- const active = await db.select({ id: turns.id, mind: turns.mind, session: turns.session }).from(turns).where(eq3(turns.status, "active"));
1511
+ const active = await db.select({ id: turns.id, mind: turns.mind, session: turns.session }).from(turns).where(eq4(turns.status, "active"));
1364
1512
  if (active.length === 0) return [];
1365
1513
  try {
1366
- await db.update(turns).set({ status: "complete" }).where(eq3(turns.status, "active"));
1514
+ await db.update(turns).set({ status: "complete" }).where(eq4(turns.status, "active"));
1367
1515
  } catch (err) {
1368
1516
  tlog.error("failed to complete orphaned turns on startup", logger_default.errorData(err));
1369
1517
  }
@@ -1389,11 +1537,14 @@ async function clearMind(mind) {
1389
1537
  }
1390
1538
  }
1391
1539
  for (const k of toDelete) activeTurns.delete(k);
1540
+ for (const k of [...erroredSessions]) {
1541
+ if (k.startsWith(`${mind}:`)) erroredSessions.delete(k);
1542
+ }
1392
1543
  if (orphaned.length > 0) {
1393
1544
  try {
1394
1545
  const db = await getDb();
1395
1546
  for (const { turnId } of orphaned) {
1396
- await db.update(turns).set({ status: "complete" }).where(eq3(turns.id, turnId));
1547
+ await db.update(turns).set({ status: "complete" }).where(eq4(turns.id, turnId));
1397
1548
  }
1398
1549
  } catch (err) {
1399
1550
  tlog.error(`failed to complete orphaned turns for ${mind}`, logger_default.errorData(err));
@@ -1413,7 +1564,7 @@ function summarizeOrphanedTurns(orphanedTurns) {
1413
1564
  var mlog = logger_default.child("minds");
1414
1565
  var execFileAsync = promisify(execFile);
1415
1566
  function mindPidPath(name) {
1416
- return resolve(stateDir(name), "mind.pid");
1567
+ return resolve2(stateDir(name), "mind.pid");
1417
1568
  }
1418
1569
  var MindManager = class {
1419
1570
  minds = /* @__PURE__ */ new Map();
@@ -1429,7 +1580,7 @@ var MindManager = class {
1429
1580
  return { dir: entry.dir, port: entry.port, baseName: entry.parent, template: entry.template };
1430
1581
  }
1431
1582
  const dir = entry.dir ?? mindDir(name);
1432
- if (!existsSync3(dir)) throw new Error(`Mind directory missing: ${dir}`);
1583
+ if (!existsSync4(dir)) throw new Error(`Mind directory missing: ${dir}`);
1433
1584
  return { dir, port: entry.port, baseName: name, template: entry.template };
1434
1585
  }
1435
1586
  async startMind(name) {
@@ -1441,8 +1592,8 @@ var MindManager = class {
1441
1592
  const port = target.port;
1442
1593
  const pidFile = mindPidPath(name);
1443
1594
  try {
1444
- if (existsSync3(pidFile)) {
1445
- const stalePid = parseInt(readFileSync2(pidFile, "utf-8").trim(), 10);
1595
+ if (existsSync4(pidFile)) {
1596
+ const stalePid = parseInt(readFileSync3(pidFile, "utf-8").trim(), 10);
1446
1597
  if (stalePid > 0) {
1447
1598
  try {
1448
1599
  process.kill(stalePid, 0);
@@ -1475,8 +1626,8 @@ var MindManager = class {
1475
1626
  } catch {
1476
1627
  }
1477
1628
  const mindStateDir = stateDir(name);
1478
- const logsDir = resolve(mindStateDir, "logs");
1479
- mkdirSync(logsDir, { recursive: true });
1629
+ const logsDir = resolve2(mindStateDir, "logs");
1630
+ mkdirSync2(logsDir, { recursive: true });
1480
1631
  if (isIsolationEnabled()) {
1481
1632
  try {
1482
1633
  chownMindDir(mindStateDir, baseName);
@@ -1486,10 +1637,10 @@ var MindManager = class {
1486
1637
  );
1487
1638
  }
1488
1639
  }
1489
- const logStream = new RotatingLog(resolve(logsDir, "mind.log"));
1640
+ const logStream = new RotatingLog(resolve2(logsDir, "mind.log"));
1490
1641
  const mindToken = generateMindToken(name);
1491
1642
  const mindEnv = loadMergedEnv(name);
1492
- const mindLocalBin = resolve(dir, "home", ".local", "bin");
1643
+ const mindLocalBin = resolve2(dir, "home", ".local", "bin");
1493
1644
  const currentPath = process.env.PATH ?? "";
1494
1645
  const env = {
1495
1646
  ...process.env,
@@ -1505,24 +1656,30 @@ var MindManager = class {
1505
1656
  };
1506
1657
  if (target.template === "pi") {
1507
1658
  try {
1508
- const configPath2 = resolve(dir, "home/.config/config.json");
1509
- if (existsSync3(configPath2)) {
1510
- const config = JSON.parse(readFileSync2(configPath2, "utf-8"));
1659
+ const configPath2 = resolve2(dir, "home/.config/config.json");
1660
+ if (existsSync4(configPath2)) {
1661
+ const config = JSON.parse(readFileSync3(configPath2, "utf-8"));
1511
1662
  const modelStr = config.model;
1512
1663
  if (modelStr?.includes(":")) {
1513
1664
  const provider = modelStr.split(":")[0];
1514
1665
  const apiKey = await resolveApiKey(provider);
1515
1666
  if (apiKey) {
1516
- const piAgentDir = resolve(dir, ".mind", "pi-agent");
1517
- mkdirSync(piAgentDir, { recursive: true });
1518
- const authPath = resolve(piAgentDir, "auth.json");
1519
- const authData = existsSync3(authPath) ? JSON.parse(readFileSync2(authPath, "utf-8")) : {};
1520
- authData[provider] = { type: "api_key", key: apiKey };
1521
- writeFileSync2(authPath, JSON.stringify(authData, null, 2), { mode: 384 });
1522
- if (isIsolationEnabled()) {
1523
- chownMindDir(piAgentDir, baseName);
1524
- }
1667
+ const piAgentDir = resolve2(dir, ".mind", "pi-agent");
1668
+ writePiProviderKey(piAgentDir, baseName, provider, apiKey);
1525
1669
  env.PI_CODING_AGENT_DIR = piAgentDir;
1670
+ const providerEnvVars = {
1671
+ openrouter: "OPENROUTER_API_KEY",
1672
+ openai: "OPENAI_API_KEY",
1673
+ anthropic: "ANTHROPIC_API_KEY",
1674
+ google: "GEMINI_API_KEY",
1675
+ groq: "GROQ_API_KEY",
1676
+ cerebras: "CEREBRAS_API_KEY",
1677
+ xai: "XAI_API_KEY",
1678
+ mistral: "MISTRAL_API_KEY",
1679
+ zai: "ZAI_API_KEY"
1680
+ };
1681
+ const providerEnv = providerEnvVars[provider];
1682
+ if (providerEnv) env[providerEnv] = apiKey;
1526
1683
  } else {
1527
1684
  mlog.warn(
1528
1685
  `no API key found for provider "${provider}" \u2014 mind ${name} may fail to start`
@@ -1539,11 +1696,11 @@ var MindManager = class {
1539
1696
  const ai = getAiConfig();
1540
1697
  const codexConfig = ai?.providers["openai-codex"];
1541
1698
  if (codexConfig?.oauth) {
1542
- const codexDir = resolve(dir, ".mind", "codex");
1543
- mkdirSync(codexDir, { recursive: true });
1699
+ const codexDir = resolve2(dir, ".mind", "codex");
1700
+ mkdirSync2(codexDir, { recursive: true });
1544
1701
  env.CODEX_HOME = codexDir;
1545
- const authPath = resolve(codexDir, "auth.json");
1546
- writeFileSync2(
1702
+ const authPath = resolve2(codexDir, "auth.json");
1703
+ writeFileSync3(
1547
1704
  authPath,
1548
1705
  JSON.stringify({
1549
1706
  auth_mode: "chatgpt",
@@ -1556,9 +1713,9 @@ var MindManager = class {
1556
1713
  }),
1557
1714
  { mode: 384 }
1558
1715
  );
1559
- const configTomlPath = resolve(codexDir, "config.toml");
1560
- if (!existsSync3(configTomlPath)) {
1561
- writeFileSync2(configTomlPath, 'cli_auth_credentials_store = "file"\n');
1716
+ const configTomlPath = resolve2(codexDir, "config.toml");
1717
+ if (!existsSync4(configTomlPath)) {
1718
+ writeFileSync3(configTomlPath, 'cli_auth_credentials_store = "file"\n');
1562
1719
  }
1563
1720
  if (isIsolationEnabled()) {
1564
1721
  chownMindDir(codexDir, baseName);
@@ -1577,10 +1734,10 @@ var MindManager = class {
1577
1734
  env.OPENAI_API_KEY = process.env.OPENAI_API_KEY;
1578
1735
  }
1579
1736
  }
1580
- const homeDir = resolve(dir, "home");
1737
+ const homeDir = resolve2(dir, "home");
1581
1738
  const zshenvLines = Object.entries(env).filter(([k, v]) => k.startsWith("VOLUTE_") && v != null).map(([k, v]) => `export ${k}=${JSON.stringify(v)}`);
1582
1739
  zshenvLines.push(`export PATH=${JSON.stringify(env.PATH ?? "")}`);
1583
- writeFileSync2(resolve(homeDir, ".zshenv"), `${zshenvLines.join("\n")}
1740
+ writeFileSync3(resolve2(homeDir, ".zshenv"), `${zshenvLines.join("\n")}
1584
1741
  `, { mode: 384 });
1585
1742
  }
1586
1743
  if (target.template === "claude" || !target.template) {
@@ -1589,27 +1746,10 @@ var MindManager = class {
1589
1746
  const anthropicConfig = ai?.providers.anthropic;
1590
1747
  if (anthropicConfig?.oauth) {
1591
1748
  const key2 = await resolveApiKey("anthropic");
1592
- if (key2) {
1593
- const homeDir = resolve(dir, "home");
1594
- const claudeDir = resolve(homeDir, ".claude");
1595
- mkdirSync(claudeDir, { recursive: true });
1749
+ const oauth = getAiConfig()?.providers.anthropic?.oauth;
1750
+ if (key2 && oauth) {
1751
+ const claudeDir = writeClaudeCredentials(resolve2(dir, "home"), baseName, oauth);
1596
1752
  env.CLAUDE_CONFIG_DIR = claudeDir;
1597
- const credsPath = resolve(claudeDir, ".credentials.json");
1598
- writeFileSync2(
1599
- credsPath,
1600
- JSON.stringify({
1601
- claudeAiOauth: {
1602
- accessToken: key2,
1603
- refreshToken: anthropicConfig.oauth.refresh,
1604
- expiresAt: anthropicConfig.oauth.expires ? new Date(anthropicConfig.oauth.expires).toISOString() : null,
1605
- scopes: ["user:inference", "user:profile"]
1606
- }
1607
- }),
1608
- { mode: 384 }
1609
- );
1610
- if (isIsolationEnabled()) {
1611
- chownMindDir(claudeDir, baseName);
1612
- }
1613
1753
  }
1614
1754
  } else if (anthropicConfig?.apiKey) {
1615
1755
  env.ANTHROPIC_API_KEY = anthropicConfig.apiKey;
@@ -1619,7 +1759,7 @@ var MindManager = class {
1619
1759
  }
1620
1760
  }
1621
1761
  if (isIsolationEnabled()) {
1622
- env.HOME = resolve(dir, "home");
1762
+ env.HOME = resolve2(dir, "home");
1623
1763
  }
1624
1764
  const customNode = process.env.VOLUTE_NODE_PATH;
1625
1765
  let baseBin;
@@ -1627,13 +1767,13 @@ var MindManager = class {
1627
1767
  if (customNode) {
1628
1768
  baseBin = customNode;
1629
1769
  baseArgs = [
1630
- resolve(dir, "node_modules", ".bin", "tsx"),
1770
+ resolve2(dir, "node_modules", ".bin", "tsx"),
1631
1771
  "src/server.ts",
1632
1772
  "--port",
1633
1773
  String(port)
1634
1774
  ];
1635
1775
  } else {
1636
- baseBin = resolve(dir, "node_modules", ".bin", "tsx");
1776
+ baseBin = resolve2(dir, "node_modules", ".bin", "tsx");
1637
1777
  baseArgs = ["src/server.ts", "--port", String(port)];
1638
1778
  }
1639
1779
  let spawnCmd;
@@ -1667,14 +1807,14 @@ var MindManager = class {
1667
1807
  while (recentStderr.length > 20) recentStderr.shift();
1668
1808
  });
1669
1809
  try {
1670
- await new Promise((resolve8, reject) => {
1810
+ await new Promise((resolve9, reject) => {
1671
1811
  const timeout = setTimeout(() => {
1672
1812
  reject(new Error(`Mind ${name} did not start within 30s`));
1673
1813
  }, 3e4);
1674
1814
  function checkOutput(data) {
1675
1815
  if (data.toString().match(/listening on :\d+/)) {
1676
1816
  clearTimeout(timeout);
1677
- resolve8();
1817
+ resolve9();
1678
1818
  }
1679
1819
  }
1680
1820
  child.stdout?.on("data", checkOutput);
@@ -1702,7 +1842,7 @@ var MindManager = class {
1702
1842
  }
1703
1843
  if (child.pid) {
1704
1844
  try {
1705
- writeFileSync2(pidFile, String(child.pid));
1845
+ writeFileSync3(pidFile, String(child.pid));
1706
1846
  } catch (err) {
1707
1847
  mlog.warn(`failed to write PID file for ${name}`, logger_default.errorData(err));
1708
1848
  }
@@ -1770,7 +1910,7 @@ var MindManager = class {
1770
1910
  if (this.shuttingDown || this.stopping.has(name)) return;
1771
1911
  mlog.error(`mind ${name} exited with code ${code}`);
1772
1912
  try {
1773
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-6QRMUNHK.js");
1913
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-5277OBHI.js");
1774
1914
  const sleepState = getSleepManagerIfReady2()?.getState(name);
1775
1915
  if (sleepState?.sleeping) {
1776
1916
  mlog.info(`${name} is sleeping \u2014 skipping crash recovery`);
@@ -1779,19 +1919,30 @@ var MindManager = class {
1779
1919
  } catch (err) {
1780
1920
  mlog.warn(`failed to check sleep state for ${name}`, logger_default.errorData(err));
1781
1921
  }
1782
- clearMind(name).then((orphaned) => summarizeOrphanedTurns(orphaned)).catch(
1922
+ clearMind(name).then((orphaned) => {
1923
+ summarizeOrphanedTurns(orphaned);
1924
+ for (const { session } of orphaned) {
1925
+ void recordNotice({
1926
+ mind: name,
1927
+ session: session ?? "main",
1928
+ kind: "crash",
1929
+ reason: "process_crash",
1930
+ detail: "Your process crashed mid-turn and was automatically restarted. That turn was interrupted before it finished \u2014 check whether you left anything incomplete."
1931
+ });
1932
+ }
1933
+ }).catch(
1783
1934
  (err) => mlog.warn(`failed to clear turn state for ${name} after crash`, logger_default.errorData(err))
1784
1935
  );
1785
1936
  try {
1786
- const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-N34XKUGL.js");
1937
+ const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-VNHLQTTO.js");
1787
1938
  getDeliveryManager2().clearMindSessions(name);
1788
1939
  } catch (err) {
1789
1940
  if (!(err instanceof Error && err.message.includes("not initialized"))) {
1790
1941
  mlog.warn(`failed to clear delivery state for ${name} after crash`, logger_default.errorData(err));
1791
1942
  }
1792
1943
  }
1793
- import("./mind-activity-tracker-Z3KBQTVU.js").then(({ markIdle: markIdle2 }) => markIdle2(name)).catch((err) => mlog.warn(`failed to mark ${name} idle after crash`, logger_default.errorData(err)));
1794
- import("./activity-events-CR4RIHJT.js").then(
1944
+ import("./mind-activity-tracker-XFRVGXFS.js").then(({ markIdle: markIdle2 }) => markIdle2(name)).catch((err) => mlog.warn(`failed to mark ${name} idle after crash`, logger_default.errorData(err)));
1945
+ import("./activity-events-DS4QRWBY.js").then(
1795
1946
  ({ publish: publish4 }) => publish4({ type: "mind_stopped", mind: name, summary: `${name} crashed (exit ${code})` })
1796
1947
  ).catch((err) => mlog.warn(`failed to publish crash event for ${name}`, logger_default.errorData(err)));
1797
1948
  const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(name);
@@ -1818,19 +1969,19 @@ var MindManager = class {
1818
1969
  this.stopping.add(name);
1819
1970
  const { child } = tracked;
1820
1971
  this.minds.delete(name);
1821
- await new Promise((resolve8) => {
1822
- child.on("exit", () => resolve8());
1972
+ await new Promise((resolve9) => {
1973
+ child.on("exit", () => resolve9());
1823
1974
  try {
1824
1975
  process.kill(-child.pid, "SIGTERM");
1825
1976
  } catch {
1826
- resolve8();
1977
+ resolve9();
1827
1978
  }
1828
1979
  setTimeout(() => {
1829
1980
  try {
1830
1981
  process.kill(-child.pid, "SIGKILL");
1831
1982
  } catch {
1832
1983
  }
1833
- resolve8();
1984
+ resolve9();
1834
1985
  }, 5e3);
1835
1986
  });
1836
1987
  this.stopping.delete(name);
@@ -1842,7 +1993,7 @@ var MindManager = class {
1842
1993
  mlog.warn(`failed to clear turn state for ${name} on stop`, logger_default.errorData(err));
1843
1994
  }
1844
1995
  try {
1845
- const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-N34XKUGL.js");
1996
+ const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-VNHLQTTO.js");
1846
1997
  getDeliveryManager2().clearMindSessions(name);
1847
1998
  } catch (err) {
1848
1999
  if (!(err instanceof Error && err.message.includes("not initialized"))) {
@@ -1850,7 +2001,7 @@ var MindManager = class {
1850
2001
  }
1851
2002
  }
1852
2003
  try {
1853
- const { clearEchoTextCache } = await import("./echo-text-N3BC3WNX.js");
2004
+ const { clearEchoTextCache } = await import("./echo-text-QFCH3H6G.js");
1854
2005
  clearEchoTextCache(name);
1855
2006
  } catch (err) {
1856
2007
  mlog.debug(`failed to clear echo-text cache for ${name}`, logger_default.errorData(err));
@@ -1878,7 +2029,7 @@ var MindManager = class {
1878
2029
  return [...this.minds.keys()];
1879
2030
  }
1880
2031
  get crashAttemptsPath() {
1881
- return resolve(voluteSystemDir(), "crash-attempts.json");
2032
+ return resolve2(voluteSystemDir(), "crash-attempts.json");
1882
2033
  }
1883
2034
  loadCrashAttempts() {
1884
2035
  this.restartTracker.load(loadJsonMap(this.crashAttemptsPath));
@@ -1976,20 +2127,20 @@ async function announceToSystem(text) {
1976
2127
  }
1977
2128
 
1978
2129
  // packages/daemon/src/lib/extensions.ts
1979
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
1980
- import { dirname, resolve as resolve3 } from "path";
2130
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4, readdirSync, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
2131
+ import { dirname, resolve as resolve4 } from "path";
1981
2132
 
1982
2133
  // packages/daemon/src/lib/config/systems-config.ts
1983
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
1984
- import { resolve as resolve2 } from "path";
2134
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "fs";
2135
+ import { resolve as resolve3 } from "path";
1985
2136
  var DEFAULT_API_URL = "https://volute.systems";
1986
2137
  function configPath() {
1987
- return resolve2(voluteSystemDir(), "systems.json");
2138
+ return resolve3(voluteSystemDir(), "systems.json");
1988
2139
  }
1989
2140
  function readSystemsConfig() {
1990
2141
  const path = configPath();
1991
- if (!existsSync4(path)) return null;
1992
- const raw = readFileSync3(path, "utf-8");
2142
+ if (!existsSync5(path)) return null;
2143
+ const raw = readFileSync4(path, "utf-8");
1993
2144
  let data;
1994
2145
  try {
1995
2146
  data = JSON.parse(raw);
@@ -2007,8 +2158,8 @@ function readSystemsConfig() {
2007
2158
  };
2008
2159
  }
2009
2160
  function writeSystemsConfig(config) {
2010
- mkdirSync2(voluteSystemDir(), { recursive: true });
2011
- writeFileSync3(configPath(), `${JSON.stringify(config, null, 2)}
2161
+ mkdirSync3(voluteSystemDir(), { recursive: true });
2162
+ writeFileSync4(configPath(), `${JSON.stringify(config, null, 2)}
2012
2163
  `, { mode: 384 });
2013
2164
  }
2014
2165
  function deleteSystemsConfig() {
@@ -2067,19 +2218,19 @@ function parseCommandArgs(rawArgs, argDefs, flagDefs) {
2067
2218
  return { args: namedArgs, flags, rest };
2068
2219
  }
2069
2220
  function extensionsBaseDir() {
2070
- return resolve3(voluteHome(), "extensions");
2221
+ return resolve4(voluteHome(), "extensions");
2071
2222
  }
2072
2223
  function extensionDataDir(id) {
2073
- return resolve3(voluteSystemDir(), "extension-data", id);
2224
+ return resolve4(voluteSystemDir(), "extension-data", id);
2074
2225
  }
2075
2226
  function extensionsConfigPath() {
2076
- return resolve3(voluteHome(), "system", "extensions.json");
2227
+ return resolve4(voluteHome(), "system", "extensions.json");
2077
2228
  }
2078
2229
  function readExtensionsConfig() {
2079
2230
  const configPath2 = extensionsConfigPath();
2080
- if (!existsSync5(configPath2)) return [];
2231
+ if (!existsSync6(configPath2)) return [];
2081
2232
  try {
2082
- const data = JSON.parse(readFileSync4(configPath2, "utf-8"));
2233
+ const data = JSON.parse(readFileSync5(configPath2, "utf-8"));
2083
2234
  return Array.isArray(data) ? data : [];
2084
2235
  } catch (err) {
2085
2236
  logger_default.warn("failed to read extensions config, ignoring installed extensions", {
@@ -2097,7 +2248,7 @@ async function getLibsqlDatabase() {
2097
2248
  return _LibsqlDatabase;
2098
2249
  }
2099
2250
  async function openExtensionDb(_id, dataDir) {
2100
- const dbPath = resolve3(dataDir, "data.db");
2251
+ const dbPath = resolve4(dataDir, "data.db");
2101
2252
  const Database = await getLibsqlDatabase();
2102
2253
  return new Database(dbPath);
2103
2254
  }
@@ -2139,7 +2290,7 @@ async function buildContext(manifest, dataDir, authMw) {
2139
2290
  getMindDir: (name) => {
2140
2291
  try {
2141
2292
  const dir = mindDir(name);
2142
- return existsSync5(dir) ? dir : null;
2293
+ return existsSync6(dir) ? dir : null;
2143
2294
  } catch (err) {
2144
2295
  logger_default.warn(
2145
2296
  `extension ${manifest.id}: failed to resolve mind dir for ${name}`,
@@ -2161,7 +2312,7 @@ async function loadExtension(manifest, app, authMw) {
2161
2312
  return;
2162
2313
  }
2163
2314
  const dataDir = extensionDataDir(manifest.id);
2164
- mkdirSync3(dataDir, { recursive: true });
2315
+ mkdirSync4(dataDir, { recursive: true });
2165
2316
  const context = await buildContext(manifest, dataDir, authMw);
2166
2317
  const routesApp = manifest.routes(context);
2167
2318
  const extApiPath = `/api/ext/${manifest.id}`;
@@ -2224,18 +2375,18 @@ async function loadExtension(manifest, app, authMw) {
2224
2375
  }
2225
2376
  }
2226
2377
  let resolvedAssetsDir = manifest.ui?.assetsDir ?? "";
2227
- if (resolvedAssetsDir && !existsSync5(resolvedAssetsDir)) {
2378
+ if (resolvedAssetsDir && !existsSync6(resolvedAssetsDir)) {
2228
2379
  let searchDir = dirname(new URL(import.meta.url).pathname);
2229
2380
  for (let i = 0; i < 5; i++) {
2230
- const candidate = resolve3(searchDir, "packages", "extensions", manifest.id, "dist", "ui");
2231
- if (existsSync5(candidate)) {
2381
+ const candidate = resolve4(searchDir, "packages", "extensions", manifest.id, "dist", "ui");
2382
+ if (existsSync6(candidate)) {
2232
2383
  resolvedAssetsDir = candidate;
2233
2384
  break;
2234
2385
  }
2235
2386
  searchDir = dirname(searchDir);
2236
2387
  }
2237
2388
  }
2238
- if (resolvedAssetsDir && existsSync5(resolvedAssetsDir)) {
2389
+ if (resolvedAssetsDir && existsSync6(resolvedAssetsDir)) {
2239
2390
  const assetsDir = resolvedAssetsDir;
2240
2391
  const { readFile: readFile2, stat: fsStat } = await import("fs/promises");
2241
2392
  const { extname: ext } = await import("path");
@@ -2252,11 +2403,11 @@ async function loadExtension(manifest, app, authMw) {
2252
2403
  ".woff2": "font/woff2"
2253
2404
  };
2254
2405
  const prefix = `/ext/${manifest.id}`;
2255
- const indexPath = resolve3(assetsDir, "index.html");
2406
+ const indexPath = resolve4(assetsDir, "index.html");
2256
2407
  const serveExtAssets = async (c) => {
2257
2408
  const urlPath = new URL(c.req.url).pathname;
2258
2409
  const relativePath = urlPath.slice(prefix.length).replace(/^\//, "") || "index.html";
2259
- const filePath = resolve3(assetsDir, relativePath);
2410
+ const filePath = resolve4(assetsDir, relativePath);
2260
2411
  if (filePath !== assetsDir && !filePath.startsWith(`${assetsDir}/`))
2261
2412
  return c.text("Forbidden", 403);
2262
2413
  const s = await fsStat(filePath).catch(() => null);
@@ -2265,7 +2416,7 @@ async function loadExtension(manifest, app, authMw) {
2265
2416
  const body = await readFile2(filePath);
2266
2417
  return c.body(body, 200, { "Content-Type": mime });
2267
2418
  }
2268
- if (existsSync5(indexPath)) {
2419
+ if (existsSync6(indexPath)) {
2269
2420
  const body = await readFile2(indexPath, "utf-8");
2270
2421
  return c.html(body);
2271
2422
  }
@@ -2286,10 +2437,10 @@ async function loadExtension(manifest, app, authMw) {
2286
2437
  for (const entry of entries) {
2287
2438
  if (!entry.isDirectory()) continue;
2288
2439
  try {
2289
- const skillPath = resolve3(skillsDir, entry.name);
2440
+ const skillPath = resolve4(skillsDir, entry.name);
2290
2441
  const sourceHash = hashSkillDir(skillPath);
2291
- const destDir = resolve3(sharedSkillsDir(), entry.name);
2292
- if (existsSync5(destDir)) {
2442
+ const destDir = resolve4(sharedSkillsDir(), entry.name);
2443
+ if (existsSync6(destDir)) {
2293
2444
  const destHash = hashSkillDir(destDir);
2294
2445
  if (sourceHash === destHash) continue;
2295
2446
  }
@@ -2316,14 +2467,14 @@ function resolveSkillsDir(manifest) {
2316
2467
  if (cached !== void 0) return cached;
2317
2468
  let searchDir = dirname(new URL(import.meta.url).pathname);
2318
2469
  for (let i = 0; i < 5; i++) {
2319
- const candidate = resolve3(searchDir, "packages", "extensions", manifest.id, "skills");
2320
- if (existsSync5(candidate)) {
2470
+ const candidate = resolve4(searchDir, "packages", "extensions", manifest.id, "skills");
2471
+ if (existsSync6(candidate)) {
2321
2472
  skillsDirCache.set(manifest.id, candidate);
2322
2473
  return candidate;
2323
2474
  }
2324
2475
  searchDir = dirname(searchDir);
2325
2476
  }
2326
- if (existsSync5(manifest.skillsDir)) {
2477
+ if (existsSync6(manifest.skillsDir)) {
2327
2478
  skillsDirCache.set(manifest.id, manifest.skillsDir);
2328
2479
  return manifest.skillsDir;
2329
2480
  }
@@ -2333,9 +2484,9 @@ function resolveSkillsDir(manifest) {
2333
2484
  }
2334
2485
  async function discoverBuiltinExtensions(disabledIds) {
2335
2486
  const builtins = [
2336
- { id: "notes", load: async () => (await import("./src-OYWRPLC6.js")).default },
2337
- { id: "pages", load: async () => (await import("./src-6Z4XYDH5.js")).default },
2338
- { id: "plan", load: async () => (await import("./src-O4PRLMKM.js")).default }
2487
+ { id: "notes", load: async () => (await import("./src-2IMB3V27.js")).default },
2488
+ { id: "pages", load: async () => (await import("./src-OS75U2O7.js")).default },
2489
+ { id: "plan", load: async () => (await import("./src-XNUXP2FP.js")).default }
2339
2490
  ];
2340
2491
  const results = [];
2341
2492
  for (const { id, load } of builtins) {
@@ -2351,14 +2502,14 @@ async function discoverBuiltinExtensions(disabledIds) {
2351
2502
  async function discoverInstalledExtensions() {
2352
2503
  const results = [];
2353
2504
  const packages = readExtensionsConfig();
2354
- const npmDir = resolve3(voluteHome(), "extensions", "_npm");
2505
+ const npmDir = resolve4(voluteHome(), "extensions", "_npm");
2355
2506
  const { createRequire } = await import("module");
2356
2507
  for (const pkg of packages) {
2357
2508
  try {
2358
2509
  let resolved = pkg;
2359
- const npmPkgDir = resolve3(npmDir, "node_modules", pkg);
2360
- if (existsSync5(npmPkgDir)) {
2361
- const require2 = createRequire(resolve3(npmDir, "noop.js"));
2510
+ const npmPkgDir = resolve4(npmDir, "node_modules", pkg);
2511
+ if (existsSync6(npmPkgDir)) {
2512
+ const require2 = createRequire(resolve4(npmDir, "noop.js"));
2362
2513
  resolved = require2.resolve(pkg);
2363
2514
  }
2364
2515
  const mod = await import(resolved);
@@ -2401,7 +2552,7 @@ function validateManifest(manifest, source) {
2401
2552
  }
2402
2553
  async function discoverLocalExtensions() {
2403
2554
  const baseDir = extensionsBaseDir();
2404
- if (!existsSync5(baseDir)) return [];
2555
+ if (!existsSync6(baseDir)) return [];
2405
2556
  const manifests = [];
2406
2557
  let entries;
2407
2558
  try {
@@ -2411,9 +2562,9 @@ async function discoverLocalExtensions() {
2411
2562
  return [];
2412
2563
  }
2413
2564
  for (const dir of entries) {
2414
- const extDir = resolve3(baseDir, dir);
2415
- const candidates = [resolve3(extDir, "src", "index.js"), resolve3(extDir, "index.js")];
2416
- const entryPoint = candidates.find((p) => existsSync5(p));
2565
+ const extDir = resolve4(baseDir, dir);
2566
+ const candidates = [resolve4(extDir, "src", "index.js"), resolve4(extDir, "index.js")];
2567
+ const entryPoint = candidates.find((p) => existsSync6(p));
2417
2568
  if (!entryPoint) continue;
2418
2569
  try {
2419
2570
  const mod = await import(entryPoint);
@@ -2548,21 +2699,21 @@ function setExtensionEnabled(id, enabled) {
2548
2699
  writeGlobalConfig(config);
2549
2700
  }
2550
2701
  function extensionsNpmDir() {
2551
- return resolve3(voluteHome(), "extensions", "_npm");
2702
+ return resolve4(voluteHome(), "extensions", "_npm");
2552
2703
  }
2553
2704
  function ensureExtensionsNpmDir() {
2554
2705
  const dir = extensionsNpmDir();
2555
- mkdirSync3(dir, { recursive: true });
2556
- const pkgPath = resolve3(dir, "package.json");
2557
- if (!existsSync5(pkgPath)) {
2558
- writeFileSync4(pkgPath, '{"private":true,"dependencies":{}}\n');
2706
+ mkdirSync4(dir, { recursive: true });
2707
+ const pkgPath = resolve4(dir, "package.json");
2708
+ if (!existsSync6(pkgPath)) {
2709
+ writeFileSync5(pkgPath, '{"private":true,"dependencies":{}}\n');
2559
2710
  }
2560
2711
  return dir;
2561
2712
  }
2562
2713
  function writeExtensionsConfig(packages) {
2563
2714
  const configPath2 = extensionsConfigPath();
2564
- mkdirSync3(resolve3(configPath2, ".."), { recursive: true });
2565
- writeFileSync4(configPath2, `${JSON.stringify(packages, null, 2)}
2715
+ mkdirSync4(resolve4(configPath2, ".."), { recursive: true });
2716
+ writeFileSync5(configPath2, `${JSON.stringify(packages, null, 2)}
2566
2717
  `);
2567
2718
  }
2568
2719
  var VALID_NPM_PACKAGE = /^(@[a-z0-9-~][a-z0-9._-~]*\/)?[a-z0-9-~][a-z0-9._-~]*(@[^\s]+)?$/;
@@ -2575,7 +2726,7 @@ async function installNpmExtension(pkg) {
2575
2726
  throw new Error(`Extension "${pkg}" is already installed`);
2576
2727
  }
2577
2728
  const dir = ensureExtensionsNpmDir();
2578
- const { exec: exec2 } = await import("./exec-2MFHTGOS.js");
2729
+ const { exec: exec2 } = await import("./exec-5DGKQ5V3.js");
2579
2730
  try {
2580
2731
  await exec2("npm", ["install", pkg], { cwd: dir });
2581
2732
  } catch (err) {
@@ -2596,7 +2747,7 @@ async function uninstallNpmExtension(pkg) {
2596
2747
  packages.splice(idx, 1);
2597
2748
  writeExtensionsConfig(packages);
2598
2749
  try {
2599
- const { exec: exec2 } = await import("./exec-2MFHTGOS.js");
2750
+ const { exec: exec2 } = await import("./exec-5DGKQ5V3.js");
2600
2751
  await exec2("npm", ["uninstall", pkg], { cwd: extensionsNpmDir() });
2601
2752
  } catch (err) {
2602
2753
  logger_default.warn(
@@ -2608,13 +2759,13 @@ async function uninstallNpmExtension(pkg) {
2608
2759
  }
2609
2760
  async function cleanupExtensionSkills(pkg) {
2610
2761
  try {
2611
- const pkgDir = resolve3(extensionsNpmDir(), "node_modules", pkg);
2612
- if (!existsSync5(pkgDir)) return;
2762
+ const pkgDir = resolve4(extensionsNpmDir(), "node_modules", pkg);
2763
+ if (!existsSync6(pkgDir)) return;
2613
2764
  const { createRequire } = await import("module");
2614
- const require2 = createRequire(resolve3(extensionsNpmDir(), "noop.js"));
2765
+ const require2 = createRequire(resolve4(extensionsNpmDir(), "noop.js"));
2615
2766
  const mod = require2(pkg);
2616
2767
  const manifest = mod.default ?? mod.extension ?? mod;
2617
- if (!manifest?.skillsDir || !existsSync5(manifest.skillsDir)) return;
2768
+ if (!manifest?.skillsDir || !existsSync6(manifest.skillsDir)) return;
2618
2769
  const skillDirs = readdirSync(manifest.skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
2619
2770
  for (const skillId of skillDirs) {
2620
2771
  try {
@@ -2923,9 +3074,9 @@ async function ensureMailAddress(mindName) {
2923
3074
  }
2924
3075
 
2925
3076
  // packages/daemon/src/lib/daemon/scheduler.ts
2926
- import { resolve as resolve4 } from "path";
3077
+ import { resolve as resolve5 } from "path";
2927
3078
  import { CronExpressionParser } from "cron-parser";
2928
- var slog = logger_default.child("scheduler");
3079
+ var slog2 = logger_default.child("scheduler");
2929
3080
  var Scheduler = class {
2930
3081
  schedules = /* @__PURE__ */ new Map();
2931
3082
  mindDirs = /* @__PURE__ */ new Map();
@@ -2934,12 +3085,12 @@ var Scheduler = class {
2934
3085
  lastFired = /* @__PURE__ */ new Map();
2935
3086
  // "mind:scheduleId" → epoch minute
2936
3087
  get statePath() {
2937
- return resolve4(voluteSystemDir(), "scheduler-state.json");
3088
+ return resolve5(voluteSystemDir(), "scheduler-state.json");
2938
3089
  }
2939
3090
  start() {
2940
3091
  this.loadState();
2941
3092
  this.interval = setInterval(() => {
2942
- this.tick().catch((err) => slog.error("scheduler tick failed", logger_default.errorData(err)));
3093
+ this.tick().catch((err) => slog2.error("scheduler tick failed", logger_default.errorData(err)));
2943
3094
  }, 6e4);
2944
3095
  }
2945
3096
  stop() {
@@ -3006,7 +3157,7 @@ var Scheduler = class {
3006
3157
  prevMinute = Math.floor(prev.getTime() / 6e4);
3007
3158
  cronCache.set(schedule.cron, prevMinute);
3008
3159
  } catch (err) {
3009
- slog.warn(`invalid cron "${schedule.cron}" for ${mind}:${schedule.id}`, logger_default.errorData(err));
3160
+ slog2.warn(`invalid cron "${schedule.cron}" for ${mind}:${schedule.id}`, logger_default.errorData(err));
3010
3161
  return false;
3011
3162
  }
3012
3163
  }
@@ -3020,11 +3171,11 @@ var Scheduler = class {
3020
3171
  try {
3021
3172
  let text;
3022
3173
  if (schedule.script) {
3023
- const homeDir = resolve4(this.mindDirs.get(mindName) ?? mindDir(mindName), "home");
3174
+ const homeDir = resolve5(this.mindDirs.get(mindName) ?? mindDir(mindName), "home");
3024
3175
  try {
3025
3176
  const output = await this.runScript(schedule.script, homeDir, mindName);
3026
3177
  if (!output.trim()) {
3027
- slog.info(`fired script "${schedule.id}" for ${mindName} (no output)`);
3178
+ slog2.info(`fired script "${schedule.id}" for ${mindName} (no output)`);
3028
3179
  return;
3029
3180
  }
3030
3181
  text = output;
@@ -3032,24 +3183,24 @@ var Scheduler = class {
3032
3183
  const stderr = err.stderr ?? "";
3033
3184
  text = `[script error] ${err.message}${stderr ? `
3034
3185
  ${stderr}` : ""}`;
3035
- slog.warn(`script "${schedule.id}" failed for ${mindName}`, logger_default.errorData(err));
3186
+ slog2.warn(`script "${schedule.id}" failed for ${mindName}`, logger_default.errorData(err));
3036
3187
  }
3037
3188
  } else if (schedule.message) {
3038
3189
  text = schedule.message;
3039
3190
  } else {
3040
- slog.warn(`schedule "${schedule.id}" for ${mindName} has no message or script`);
3191
+ slog2.warn(`schedule "${schedule.id}" for ${mindName} has no message or script`);
3041
3192
  return;
3042
3193
  }
3043
3194
  await this.deliverSystem(mindName, `[${schedule.id}] ${text}`, {
3044
3195
  whileSleeping: schedule.whileSleeping,
3045
3196
  session: schedule.session
3046
3197
  });
3047
- slog.info(`fired "${schedule.id}" for ${mindName}`);
3198
+ slog2.info(`fired "${schedule.id}" for ${mindName}`);
3048
3199
  if (schedule.fireAt) {
3049
3200
  this.removeSchedule(mindName, schedule.id);
3050
3201
  }
3051
3202
  } catch (err) {
3052
- slog.warn(`failed to fire "${schedule.id}" for ${mindName}`, logger_default.errorData(err));
3203
+ slog2.warn(`failed to fire "${schedule.id}" for ${mindName}`, logger_default.errorData(err));
3053
3204
  }
3054
3205
  }
3055
3206
  removeSchedule(mindName, scheduleId) {
@@ -3069,9 +3220,9 @@ ${stderr}` : ""}`;
3069
3220
  config.schedules = config.schedules.filter((s) => s.id !== scheduleId);
3070
3221
  if (config.schedules.length === 0) config.schedules = void 0;
3071
3222
  writeVoluteConfig(dir, config);
3072
- slog.info(`removed one-time schedule "${scheduleId}" for ${mindName}`);
3223
+ slog2.info(`removed one-time schedule "${scheduleId}" for ${mindName}`);
3073
3224
  } catch (err) {
3074
- slog.error(
3225
+ slog2.error(
3075
3226
  `failed to persist removal of schedule "${scheduleId}" for ${mindName} (removed from memory)`,
3076
3227
  logger_default.errorData(err)
3077
3228
  );
@@ -3096,9 +3247,9 @@ function getScheduler() {
3096
3247
  }
3097
3248
 
3098
3249
  // packages/daemon/src/lib/daemon/token-budget.ts
3099
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
3250
+ import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
3100
3251
  import { mkdir, writeFile as writeFile2 } from "fs/promises";
3101
- import { resolve as resolve5 } from "path";
3252
+ import { resolve as resolve6 } from "path";
3102
3253
  var tlog2 = logger_default.child("token-budget");
3103
3254
  var DEFAULT_BUDGET_PERIOD_MINUTES = 60;
3104
3255
  var MAX_QUEUE_SIZE = 100;
@@ -3135,7 +3286,8 @@ var TokenBudget = class {
3135
3286
  periodMinutes,
3136
3287
  tokenLimit,
3137
3288
  queue: [],
3138
- warningInjected: false
3289
+ warningInjected: false,
3290
+ exceededNotified: false
3139
3291
  });
3140
3292
  }
3141
3293
  }
@@ -3163,6 +3315,20 @@ var TokenBudget = class {
3163
3315
  const state = this.budgets.get(mind);
3164
3316
  if (state) state.warningInjected = true;
3165
3317
  }
3318
+ /**
3319
+ * Returns true exactly once per budget period when the mind first crosses its limit,
3320
+ * so callers can record a single "budget exceeded" notice without repeating it on
3321
+ * every subsequent usage event. The flag resets when the period rolls over.
3322
+ */
3323
+ noteExceeded(mind) {
3324
+ const state = this.budgets.get(mind);
3325
+ if (!state) return false;
3326
+ if (state.tokensUsed < state.tokenLimit) return false;
3327
+ if (state.exceededNotified) return false;
3328
+ state.exceededNotified = true;
3329
+ this.dirty.add(mind);
3330
+ return true;
3331
+ }
3166
3332
  enqueue(mind, message) {
3167
3333
  const state = this.budgets.get(mind);
3168
3334
  if (!state) return;
@@ -3198,6 +3364,7 @@ var TokenBudget = class {
3198
3364
  state.tokensUsed = 0;
3199
3365
  state.periodStart = now;
3200
3366
  state.warningInjected = false;
3367
+ state.exceededNotified = false;
3201
3368
  this.dirty.add(mind);
3202
3369
  const queued = this.drain(mind);
3203
3370
  if (queued.length > 0) {
@@ -3221,7 +3388,7 @@ var TokenBudget = class {
3221
3388
  await Promise.all(writes);
3222
3389
  }
3223
3390
  budgetStatePath(mind) {
3224
- return resolve5(stateDir(mind), "budget.json");
3391
+ return resolve6(stateDir(mind), "budget.json");
3225
3392
  }
3226
3393
  async saveBudgetState(mind, state) {
3227
3394
  try {
@@ -3231,6 +3398,7 @@ var TokenBudget = class {
3231
3398
  periodStart: state.periodStart,
3232
3399
  tokensUsed: state.tokensUsed,
3233
3400
  warningInjected: state.warningInjected,
3401
+ exceededNotified: state.exceededNotified,
3234
3402
  queue: state.queue
3235
3403
  };
3236
3404
  await writeFile2(this.budgetStatePath(mind), `${JSON.stringify(data)}
@@ -3242,13 +3410,14 @@ var TokenBudget = class {
3242
3410
  loadBudgetState(mind) {
3243
3411
  try {
3244
3412
  const path = this.budgetStatePath(mind);
3245
- if (!existsSync6(path)) return null;
3246
- const data = JSON.parse(readFileSync5(path, "utf-8"));
3413
+ if (!existsSync7(path)) return null;
3414
+ const data = JSON.parse(readFileSync6(path, "utf-8"));
3247
3415
  if (typeof data.periodStart !== "number" || typeof data.tokensUsed !== "number") return null;
3248
3416
  return {
3249
3417
  periodStart: data.periodStart,
3250
3418
  tokensUsed: data.tokensUsed,
3251
3419
  warningInjected: data.warningInjected ?? false,
3420
+ exceededNotified: data.exceededNotified ?? false,
3252
3421
  queue: Array.isArray(data.queue) ? data.queue : [],
3253
3422
  periodMinutes: 0,
3254
3423
  // will be overwritten by caller
@@ -3371,7 +3540,7 @@ async function wakeMind(name) {
3371
3540
  async function startSpiritFull(name) {
3372
3541
  const entry = await findMind(name);
3373
3542
  if (entry?.dir) {
3374
- const { registerMindDir } = await import("./delivery-router-EUW4RIWG.js");
3543
+ const { registerMindDir } = await import("./delivery-router-T6CYTS3M.js");
3375
3544
  registerMindDir(name, entry.dir);
3376
3545
  }
3377
3546
  await getMindManager().startMind(name);
@@ -3393,8 +3562,8 @@ async function stopSpiritFull(name) {
3393
3562
  }).catch((err) => logger_default.error("failed to publish spirit_stopped activity", logger_default.errorData(err)));
3394
3563
  }
3395
3564
  async function ensureCreatorDM(mindName, creatorUsername) {
3396
- const { getOrCreateMindUser: getOrCreateMindUser2, getUserByUsername: getUserByUsername2 } = await import("./auth-OJ2YW3NR.js");
3397
- const { findDMConversation: findDMConversation2, createConversation: createConversation2 } = await import("./conversations-EUXHBWJD.js");
3565
+ const { getOrCreateMindUser: getOrCreateMindUser2, getUserByUsername: getUserByUsername2 } = await import("./auth-X6ZITZ7D.js");
3566
+ const { findDMConversation: findDMConversation2, createConversation: createConversation2 } = await import("./conversations-AYLXPOGC.js");
3398
3567
  const mindUser = await getOrCreateMindUser2(mindName);
3399
3568
  const creatorUser = await getUserByUsername2(creatorUsername);
3400
3569
  if (!creatorUser) {
@@ -3426,7 +3595,7 @@ async function stopMindFull(name) {
3426
3595
  }
3427
3596
 
3428
3597
  // packages/daemon/src/lib/daemon/sleep-manager.ts
3429
- var slog2 = logger_default.child("sleep");
3598
+ var slog3 = logger_default.child("sleep");
3430
3599
  function defaultState() {
3431
3600
  return {
3432
3601
  sleeping: false,
@@ -3469,7 +3638,7 @@ var SleepManager = class {
3469
3638
  transitioning = /* @__PURE__ */ new Set();
3470
3639
  sleepConfigs = /* @__PURE__ */ new Map();
3471
3640
  get statePath() {
3472
- return resolve6(voluteSystemDir(), "sleep-state.json");
3641
+ return resolve7(voluteSystemDir(), "sleep-state.json");
3473
3642
  }
3474
3643
  start() {
3475
3644
  this.loadState();
@@ -3485,15 +3654,15 @@ var SleepManager = class {
3485
3654
  // --- State persistence ---
3486
3655
  loadState() {
3487
3656
  try {
3488
- if (existsSync7(this.statePath)) {
3489
- const data = JSON.parse(readFileSync6(this.statePath, "utf-8"));
3657
+ if (existsSync8(this.statePath)) {
3658
+ const data = JSON.parse(readFileSync7(this.statePath, "utf-8"));
3490
3659
  for (const [name, state] of Object.entries(data)) {
3491
3660
  state.triggerWakeHistory ??= [];
3492
3661
  this.states.set(name, state);
3493
3662
  }
3494
3663
  }
3495
3664
  } catch (err) {
3496
- slog2.warn("failed to load sleep state", logger_default.errorData(err));
3665
+ slog3.warn("failed to load sleep state", logger_default.errorData(err));
3497
3666
  }
3498
3667
  }
3499
3668
  saveState() {
@@ -3502,10 +3671,10 @@ var SleepManager = class {
3502
3671
  if (state.sleeping) data[name] = state;
3503
3672
  }
3504
3673
  try {
3505
- writeFileSync5(this.statePath, `${JSON.stringify(data, null, 2)}
3674
+ writeFileSync6(this.statePath, `${JSON.stringify(data, null, 2)}
3506
3675
  `);
3507
3676
  } catch (err) {
3508
- slog2.error("failed to save sleep state", logger_default.errorData(err));
3677
+ slog3.error("failed to save sleep state", logger_default.errorData(err));
3509
3678
  }
3510
3679
  }
3511
3680
  // --- Public API ---
@@ -3526,7 +3695,7 @@ var SleepManager = class {
3526
3695
  const state = this.states.get(name);
3527
3696
  if (!state?.sleeping || !state.wokenByTrigger) return;
3528
3697
  this.markAwake(name);
3529
- slog2.info(`${name} trigger-wake converted to full wake`);
3698
+ slog3.info(`${name} trigger-wake converted to full wake`);
3530
3699
  }
3531
3700
  getSleepConfig(name) {
3532
3701
  if (this.sleepConfigs.has(name)) {
@@ -3569,7 +3738,7 @@ var SleepManager = class {
3569
3738
  const result = await sendSystemMessageDirect(name, preSleepMsg);
3570
3739
  conversationId = result.conversationId;
3571
3740
  } catch (err) {
3572
- slog2.error(`failed to persist pre-sleep message for ${name}`, logger_default.errorData(err));
3741
+ slog3.error(`failed to persist pre-sleep message for ${name}`, logger_default.errorData(err));
3573
3742
  }
3574
3743
  try {
3575
3744
  await fetch(`http://127.0.0.1:${entry.port}/message`, {
@@ -3586,7 +3755,7 @@ var SleepManager = class {
3586
3755
  })
3587
3756
  });
3588
3757
  } catch (err) {
3589
- slog2.warn(`failed to send pre-sleep message to ${name}`, logger_default.errorData(err));
3758
+ slog3.warn(`failed to send pre-sleep message to ${name}`, logger_default.errorData(err));
3590
3759
  }
3591
3760
  await this.waitForIdle(name, 12e4);
3592
3761
  await new Promise((r) => setTimeout(r, 3e3));
@@ -3594,7 +3763,7 @@ var SleepManager = class {
3594
3763
  await this.killOrphanOnPort(entry.port);
3595
3764
  await this.archiveSessions(name);
3596
3765
  this.markSleeping(name, opts);
3597
- slog2.info(`${name} is now sleeping`);
3766
+ slog3.info(`${name} is now sleeping`);
3598
3767
  } finally {
3599
3768
  this.transitioning.delete(name);
3600
3769
  }
@@ -3613,7 +3782,7 @@ var SleepManager = class {
3613
3782
  try {
3614
3783
  await wakeMind(name);
3615
3784
  } catch (err) {
3616
- slog2.error(`failed to wake ${name}`, logger_default.errorData(err));
3785
+ slog3.error(`failed to wake ${name}`, logger_default.errorData(err));
3617
3786
  return;
3618
3787
  }
3619
3788
  }
@@ -3654,7 +3823,7 @@ var SleepManager = class {
3654
3823
  const result = await sendSystemMessageDirect(name, summaryText);
3655
3824
  wakeConvId = result.conversationId;
3656
3825
  } catch (err) {
3657
- slog2.error(`failed to persist wake summary for ${name}`, logger_default.errorData(err));
3826
+ slog3.error(`failed to persist wake summary for ${name}`, logger_default.errorData(err));
3658
3827
  }
3659
3828
  try {
3660
3829
  await fetch(`http://127.0.0.1:${entry.port}/message`, {
@@ -3671,17 +3840,17 @@ var SleepManager = class {
3671
3840
  })
3672
3841
  });
3673
3842
  } catch (err) {
3674
- slog2.warn(`failed to deliver wake summary to ${name}`, logger_default.errorData(err));
3843
+ slog3.warn(`failed to deliver wake summary to ${name}`, logger_default.errorData(err));
3675
3844
  }
3676
3845
  }
3677
3846
  const flushed = await this.flushQueuedMessages(name);
3678
3847
  if (flushed > 0) {
3679
- slog2.info(`flushed ${flushed} queued message(s) for ${name}`);
3848
+ slog3.info(`flushed ${flushed} queued message(s) for ${name}`);
3680
3849
  }
3681
3850
  if (!opts?.trigger) {
3682
3851
  this.markAwake(name);
3683
3852
  }
3684
- slog2.info(`${name} is now awake${opts?.trigger ? " (trigger wake)" : ""}`);
3853
+ slog3.info(`${name} is now awake${opts?.trigger ? " (trigger wake)" : ""}`);
3685
3854
  } finally {
3686
3855
  this.transitioning.delete(name);
3687
3856
  }
@@ -3736,16 +3905,16 @@ var SleepManager = class {
3736
3905
  async flushQueuedMessages(name) {
3737
3906
  try {
3738
3907
  const db = await getDb();
3739
- const rows = await db.select().from(deliveryQueue).where(and2(eq4(deliveryQueue.mind, name), eq4(deliveryQueue.status, "sleep-queued"))).all();
3908
+ const rows = await db.select().from(deliveryQueue).where(and3(eq5(deliveryQueue.mind, name), eq5(deliveryQueue.status, "sleep-queued"))).all();
3740
3909
  if (rows.length === 0) return 0;
3741
- const { deliverMessage: deliverMessage2 } = await import("./message-delivery-X7MKA3TA.js");
3910
+ const { deliverMessage: deliverMessage2 } = await import("./message-delivery-7BCYJLH2.js");
3742
3911
  const delivered = [];
3743
3912
  for (const row of rows) {
3744
3913
  try {
3745
3914
  await deliverMessage2(name, JSON.parse(row.payload));
3746
3915
  delivered.push(row.id);
3747
3916
  } catch (err) {
3748
- slog2.warn(`failed to flush queued message ${row.id} for ${name}`, logger_default.errorData(err));
3917
+ slog3.warn(`failed to flush queued message ${row.id} for ${name}`, logger_default.errorData(err));
3749
3918
  }
3750
3919
  }
3751
3920
  if (delivered.length > 0) {
@@ -3757,7 +3926,7 @@ var SleepManager = class {
3757
3926
  }
3758
3927
  return delivered.length;
3759
3928
  } catch (err) {
3760
- slog2.warn(`failed to flush queued messages for ${name}`, logger_default.errorData(err));
3929
+ slog3.warn(`failed to flush queued messages for ${name}`, logger_default.errorData(err));
3761
3930
  return 0;
3762
3931
  }
3763
3932
  }
@@ -3786,7 +3955,7 @@ var SleepManager = class {
3786
3955
  const interval = CronExpressionParser2.parse(config.schedule.wake);
3787
3956
  return interval.next().toDate().toISOString();
3788
3957
  } catch (err) {
3789
- slog2.warn(`invalid wake cron "${config.schedule.wake}"`, logger_default.errorData(err));
3958
+ slog3.warn(`invalid wake cron "${config.schedule.wake}"`, logger_default.errorData(err));
3790
3959
  return null;
3791
3960
  }
3792
3961
  }
@@ -3806,7 +3975,7 @@ var SleepManager = class {
3806
3975
  const wakeAt = new Date(state.voluntaryWakeAt);
3807
3976
  if (now >= wakeAt) {
3808
3977
  this.initiateWake(name).catch(
3809
- (err) => slog2.error(`failed voluntary wake for ${name}`, logger_default.errorData(err))
3978
+ (err) => slog3.error(`failed voluntary wake for ${name}`, logger_default.errorData(err))
3810
3979
  );
3811
3980
  continue;
3812
3981
  }
@@ -3815,7 +3984,7 @@ var SleepManager = class {
3815
3984
  const wakeAt = new Date(state.scheduledWakeAt);
3816
3985
  if (now >= wakeAt) {
3817
3986
  this.initiateWake(name).catch(
3818
- (err) => slog2.error(`failed scheduled wake for ${name}`, logger_default.errorData(err))
3987
+ (err) => slog3.error(`failed scheduled wake for ${name}`, logger_default.errorData(err))
3819
3988
  );
3820
3989
  continue;
3821
3990
  }
@@ -3823,7 +3992,7 @@ var SleepManager = class {
3823
3992
  if (!state?.sleeping) {
3824
3993
  if (this.shouldSleep(config.schedule.sleep, epochMinute)) {
3825
3994
  this.initiateSleep(name).catch(
3826
- (err) => slog2.error(`failed to initiate sleep for ${name}`, logger_default.errorData(err))
3995
+ (err) => slog3.error(`failed to initiate sleep for ${name}`, logger_default.errorData(err))
3827
3996
  );
3828
3997
  }
3829
3998
  }
@@ -3836,22 +4005,22 @@ var SleepManager = class {
3836
4005
  const prevMinute = Math.floor(prev.getTime() / 6e4);
3837
4006
  return prevMinute === epochMinute;
3838
4007
  } catch (err) {
3839
- slog2.warn(`invalid sleep cron "${cronExpr}"`, logger_default.errorData(err));
4008
+ slog3.warn(`invalid sleep cron "${cronExpr}"`, logger_default.errorData(err));
3840
4009
  return false;
3841
4010
  }
3842
4011
  }
3843
4012
  async waitForIdle(name, timeoutMs) {
3844
- return new Promise((resolve8) => {
4013
+ return new Promise((resolve9) => {
3845
4014
  const timeout = setTimeout(() => {
3846
4015
  unsub();
3847
- resolve8();
4016
+ resolve9();
3848
4017
  }, timeoutMs);
3849
4018
  const unsub = subscribe((event) => {
3850
4019
  if (event.mind !== name) return;
3851
4020
  if (event.type === "mind_done" || event.type === "mind_idle") {
3852
4021
  clearTimeout(timeout);
3853
4022
  unsub();
3854
- resolve8();
4023
+ resolve9();
3855
4024
  }
3856
4025
  });
3857
4026
  });
@@ -3859,41 +4028,41 @@ var SleepManager = class {
3859
4028
  async archiveSessions(name) {
3860
4029
  const dir = mindDir(name);
3861
4030
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 16);
3862
- const sessionsDir = resolve6(dir, ".mind", "sessions");
3863
- if (existsSync7(sessionsDir)) {
3864
- const archiveDir = resolve6(sessionsDir, "archive");
3865
- mkdirSync4(archiveDir, { recursive: true });
4031
+ const sessionsDir = resolve7(dir, ".mind", "sessions");
4032
+ if (existsSync8(sessionsDir)) {
4033
+ const archiveDir = resolve7(sessionsDir, "archive");
4034
+ mkdirSync5(archiveDir, { recursive: true });
3866
4035
  for (const file of readdirSync2(sessionsDir)) {
3867
4036
  if (file === "archive" || !file.endsWith(".json")) continue;
3868
- const src = resolve6(sessionsDir, file);
4037
+ const src = resolve7(sessionsDir, file);
3869
4038
  const base = file.replace(/\.json$/, "");
3870
- const dest = resolve6(archiveDir, `${base}-${timestamp}.json`);
4039
+ const dest = resolve7(archiveDir, `${base}-${timestamp}.json`);
3871
4040
  try {
3872
4041
  renameSync(src, dest);
3873
4042
  } catch (err) {
3874
- slog2.warn(`failed to archive session ${file} for ${name}`, logger_default.errorData(err));
4043
+ slog3.warn(`failed to archive session ${file} for ${name}`, logger_default.errorData(err));
3875
4044
  }
3876
4045
  }
3877
4046
  }
3878
- const piSessionsDir = resolve6(dir, ".mind", "pi-sessions");
3879
- if (existsSync7(piSessionsDir)) {
3880
- const archiveDir = resolve6(piSessionsDir, "archive");
3881
- mkdirSync4(archiveDir, { recursive: true });
4047
+ const piSessionsDir = resolve7(dir, ".mind", "pi-sessions");
4048
+ if (existsSync8(piSessionsDir)) {
4049
+ const archiveDir = resolve7(piSessionsDir, "archive");
4050
+ mkdirSync5(archiveDir, { recursive: true });
3882
4051
  for (const entry of readdirSync2(piSessionsDir, { withFileTypes: true })) {
3883
4052
  if (entry.name === "archive" || !entry.isDirectory()) continue;
3884
- const src = resolve6(piSessionsDir, entry.name);
3885
- const dest = resolve6(archiveDir, `${entry.name}-${timestamp}`);
4053
+ const src = resolve7(piSessionsDir, entry.name);
4054
+ const dest = resolve7(archiveDir, `${entry.name}-${timestamp}`);
3886
4055
  try {
3887
4056
  renameSync(src, dest);
3888
4057
  } catch (err) {
3889
- slog2.warn(`failed to archive pi-session ${entry.name} for ${name}`, logger_default.errorData(err));
4058
+ slog3.warn(`failed to archive pi-session ${entry.name} for ${name}`, logger_default.errorData(err));
3890
4059
  }
3891
4060
  }
3892
4061
  }
3893
4062
  }
3894
4063
  async runWakeContextScript(name, sleepingSince, duration) {
3895
- const scriptPath = resolve6(mindDir(name), "home", ".local", "hooks", "wake-context.sh");
3896
- if (!existsSync7(scriptPath)) return "";
4064
+ const scriptPath = resolve7(mindDir(name), "home", ".local", "hooks", "wake-context.sh");
4065
+ if (!existsSync8(scriptPath)) return "";
3897
4066
  const input = JSON.stringify({
3898
4067
  sleepingSince,
3899
4068
  duration,
@@ -3929,7 +4098,7 @@ var SleepManager = class {
3929
4098
  });
3930
4099
  return result.trim();
3931
4100
  } catch (err) {
3932
- slog2.warn(`wake-context script failed for ${name}`, logger_default.errorData(err));
4101
+ slog3.warn(`wake-context script failed for ${name}`, logger_default.errorData(err));
3933
4102
  return "";
3934
4103
  }
3935
4104
  }
@@ -3943,7 +4112,7 @@ var SleepManager = class {
3943
4112
  async buildQueuedSummary(name) {
3944
4113
  try {
3945
4114
  const db = await getDb();
3946
- const rows = await db.select({ channel: deliveryQueue.channel, sender: deliveryQueue.sender }).from(deliveryQueue).where(and2(eq4(deliveryQueue.mind, name), eq4(deliveryQueue.status, "sleep-queued"))).all();
4115
+ const rows = await db.select({ channel: deliveryQueue.channel, sender: deliveryQueue.sender }).from(deliveryQueue).where(and3(eq5(deliveryQueue.mind, name), eq5(deliveryQueue.status, "sleep-queued"))).all();
3947
4116
  if (rows.length === 0) return "No messages arrived while you slept.";
3948
4117
  const channelCounts = /* @__PURE__ */ new Map();
3949
4118
  const senders = /* @__PURE__ */ new Set();
@@ -3956,7 +4125,7 @@ var SleepManager = class {
3956
4125
  const senderNote = senders.size > 0 ? ` from ${[...senders].join(", ")}` : "";
3957
4126
  return `${rows.length} message${rows.length === 1 ? "" : "s"} arrived while you slept${senderNote} (${parts.join(", ")}). They'll be delivered to your normal channels now.`;
3958
4127
  } catch (err) {
3959
- slog2.error(`failed to build queued summary for ${name}`, logger_default.errorData(err));
4128
+ slog3.error(`failed to build queued summary for ${name}`, logger_default.errorData(err));
3960
4129
  return "Unable to check for queued messages \u2014 there may be messages waiting.";
3961
4130
  }
3962
4131
  }
@@ -3971,7 +4140,7 @@ var SleepManager = class {
3971
4140
  } catch {
3972
4141
  return;
3973
4142
  }
3974
- slog2.warn(`orphan process found on port ${port} after sleep, killing`);
4143
+ slog3.warn(`orphan process found on port ${port} after sleep, killing`);
3975
4144
  const execFileAsync2 = promisify2(execFile2);
3976
4145
  try {
3977
4146
  const { stdout } = await execFileAsync2("lsof", ["-ti", `:${port}`, "-sTCP:LISTEN"]);
@@ -3982,7 +4151,7 @@ var SleepManager = class {
3982
4151
  process.kill(pid, "SIGTERM");
3983
4152
  } catch (err) {
3984
4153
  if (err.code !== "ESRCH") {
3985
- slog2.warn(`failed to kill orphan pid ${pid}`, logger_default.errorData(err));
4154
+ slog3.warn(`failed to kill orphan pid ${pid}`, logger_default.errorData(err));
3986
4155
  }
3987
4156
  }
3988
4157
  }
@@ -3990,7 +4159,7 @@ var SleepManager = class {
3990
4159
  } catch {
3991
4160
  try {
3992
4161
  const portHex = port.toString(16).toUpperCase().padStart(4, "0");
3993
- const tcp6 = readFileSync6("/proc/net/tcp6", "utf-8");
4162
+ const tcp6 = readFileSync7("/proc/net/tcp6", "utf-8");
3994
4163
  for (const line of tcp6.split("\n")) {
3995
4164
  if (!line.includes(`:${portHex} `)) continue;
3996
4165
  const fields = line.trim().split(/\s+/);
@@ -4014,7 +4183,7 @@ var SleepManager = class {
4014
4183
  }
4015
4184
  }
4016
4185
  } catch (err) {
4017
- slog2.warn(`failed to kill orphan on port ${port} via /proc`, logger_default.errorData(err));
4186
+ slog3.warn(`failed to kill orphan on port ${port} via /proc`, logger_default.errorData(err));
4018
4187
  }
4019
4188
  }
4020
4189
  await new Promise((r) => setTimeout(r, 1e3));
@@ -4024,7 +4193,7 @@ var SleepManager = class {
4024
4193
  if (!state?.sleeping || !state.wokenByTrigger) return;
4025
4194
  if (this.transitioning.has(event.mind)) return;
4026
4195
  if (event.type === "mind_idle") {
4027
- slog2.info(`${event.mind} going back to sleep after trigger wake`);
4196
+ slog3.info(`${event.mind} going back to sleep after trigger wake`);
4028
4197
  state.wokenByTrigger = false;
4029
4198
  this.transitioning.add(event.mind);
4030
4199
  sleepMind(event.mind).then(() => this.archiveSessions(event.mind)).then(() => {
@@ -4033,9 +4202,9 @@ var SleepManager = class {
4033
4202
  const sleepConfig = this.getSleepConfig(event.mind);
4034
4203
  state.scheduledWakeAt = this.getNextWakeTime(sleepConfig);
4035
4204
  this.saveState();
4036
- slog2.info(`${event.mind} returned to sleep`);
4205
+ slog3.info(`${event.mind} returned to sleep`);
4037
4206
  }).catch((err) => {
4038
- slog2.error(`failed to return ${event.mind} to sleep`, logger_default.errorData(err));
4207
+ slog3.error(`failed to return ${event.mind} to sleep`, logger_default.errorData(err));
4039
4208
  }).finally(() => {
4040
4209
  this.transitioning.delete(event.mind);
4041
4210
  });
@@ -4058,8 +4227,8 @@ function getSleepManagerIfReady() {
4058
4227
 
4059
4228
  // packages/daemon/src/lib/delivery/delivery-manager.ts
4060
4229
  import { readFile, realpath } from "fs/promises";
4061
- import { extname, resolve as resolve7 } from "path";
4062
- import { and as and3, eq as eq5, sql as sql2 } from "drizzle-orm";
4230
+ import { extname, resolve as resolve8 } from "path";
4231
+ import { and as and4, eq as eq6, sql as sql3 } from "drizzle-orm";
4063
4232
 
4064
4233
  // packages/daemon/src/lib/chat/typing.ts
4065
4234
  var DEFAULT_TTL_MS = 1e4;
@@ -4257,7 +4426,7 @@ var DeliveryManager = class {
4257
4426
  async restoreFromDb() {
4258
4427
  try {
4259
4428
  const db = await getDb();
4260
- const rows = await db.select().from(deliveryQueue).where(eq5(deliveryQueue.status, "pending"));
4429
+ const rows = await db.select().from(deliveryQueue).where(eq6(deliveryQueue.status, "pending"));
4261
4430
  for (const row of rows) {
4262
4431
  let payload;
4263
4432
  try {
@@ -4275,7 +4444,7 @@ var DeliveryManager = class {
4275
4444
  this.addToBatchBuffer(row.mind, row.session, payload, sessionConfig);
4276
4445
  } else {
4277
4446
  try {
4278
- await db.delete(deliveryQueue).where(eq5(deliveryQueue.id, row.id));
4447
+ await db.delete(deliveryQueue).where(eq6(deliveryQueue.id, row.id));
4279
4448
  } catch (err) {
4280
4449
  dlog.warn(`failed to delete queue row ${row.id} for ${row.mind}`, logger_default.errorData(err));
4281
4450
  }
@@ -4296,7 +4465,7 @@ var DeliveryManager = class {
4296
4465
  */
4297
4466
  async getPending(mindName) {
4298
4467
  const db = await getDb();
4299
- const rows = await db.select().from(deliveryQueue).where(and3(eq5(deliveryQueue.mind, mindName), eq5(deliveryQueue.status, "gated")));
4468
+ const rows = await db.select().from(deliveryQueue).where(and4(eq6(deliveryQueue.mind, mindName), eq6(deliveryQueue.status, "gated")));
4300
4469
  const byChannel = /* @__PURE__ */ new Map();
4301
4470
  for (const row of rows) {
4302
4471
  const ch = row.channel ?? "unknown";
@@ -4491,10 +4660,10 @@ var DeliveryManager = class {
4491
4660
  try {
4492
4661
  const db = await getDb();
4493
4662
  await db.delete(deliveryQueue).where(
4494
- and3(
4495
- eq5(deliveryQueue.mind, baseName),
4496
- eq5(deliveryQueue.session, session),
4497
- eq5(deliveryQueue.status, "pending")
4663
+ and4(
4664
+ eq6(deliveryQueue.mind, baseName),
4665
+ eq6(deliveryQueue.session, session),
4666
+ eq6(deliveryQueue.status, "pending")
4498
4667
  )
4499
4668
  );
4500
4669
  } catch (err) {
@@ -4620,11 +4789,11 @@ var DeliveryManager = class {
4620
4789
  await this.persistToQueue(baseName, session, payload, "gated");
4621
4790
  try {
4622
4791
  const db = await getDb();
4623
- const count = await db.select({ count: sql2`count(*)` }).from(deliveryQueue).where(
4624
- and3(
4625
- eq5(deliveryQueue.mind, baseName),
4626
- eq5(deliveryQueue.channel, payload.channel),
4627
- eq5(deliveryQueue.status, "gated")
4792
+ const count = await db.select({ count: sql3`count(*)` }).from(deliveryQueue).where(
4793
+ and4(
4794
+ eq6(deliveryQueue.mind, baseName),
4795
+ eq6(deliveryQueue.channel, payload.channel),
4796
+ eq6(deliveryQueue.status, "gated")
4628
4797
  )
4629
4798
  );
4630
4799
  if ((count[0]?.count ?? 0) <= 1) {
@@ -4649,7 +4818,7 @@ var DeliveryManager = class {
4649
4818
  `To accept this channel, add a routing rule for "${channel}" to your routes.json.`,
4650
4819
  `Messages are being held until a route is configured.`
4651
4820
  ].filter((line) => line !== null).join("\n");
4652
- const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-D343HYGR.js");
4821
+ const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-LQSJVY55.js");
4653
4822
  await sendSystemMessage2(mindName, notification);
4654
4823
  }
4655
4824
  async persistToQueue(mindName, session, payload, status = "pending") {
@@ -4723,8 +4892,8 @@ var DeliveryManager = class {
4723
4892
  const dir = mindDir(p.username);
4724
4893
  const config = readVoluteConfig(dir);
4725
4894
  if (!config?.profile?.avatar) continue;
4726
- filePath = resolve7(dir, "home", config.profile.avatar);
4727
- const homeDir = resolve7(dir, "home");
4895
+ filePath = resolve8(dir, "home", config.profile.avatar);
4896
+ const homeDir = resolve8(dir, "home");
4728
4897
  if (!filePath.startsWith(`${homeDir}/`)) {
4729
4898
  dlog.warn(`avatar path for ${p.username} escapes home directory, skipping`);
4730
4899
  continue;
@@ -4743,7 +4912,7 @@ var DeliveryManager = class {
4743
4912
  throw err;
4744
4913
  }
4745
4914
  } else {
4746
- filePath = resolve7(voluteHome(), "avatars", p.avatar);
4915
+ filePath = resolve8(voluteHome(), "avatars", p.avatar);
4747
4916
  }
4748
4917
  const ext = extname(filePath).toLowerCase();
4749
4918
  const mimeMap = {
@@ -4885,18 +5054,18 @@ async function linkToolResultToTurn(mind, turnId, toolResultContent, toolUseEven
4885
5054
  channel: mindHistory.channel,
4886
5055
  content: mindHistory.content,
4887
5056
  message_id: mindHistory.message_id
4888
- }).from(mindHistory).where(and4(eq6(mindHistory.id, outboundId), eq6(mindHistory.mind, mind))).limit(1);
5057
+ }).from(mindHistory).where(and5(eq7(mindHistory.id, outboundId), eq7(mindHistory.mind, mind))).limit(1);
4889
5058
  const row = rows[0];
4890
5059
  if (!row) {
4891
5060
  dlog2.warn(`outbound marker references missing record: mind=${mind} id=${outboundId}`);
4892
5061
  continue;
4893
5062
  }
4894
- await db.update(mindHistory).set({ turn_id: turnId }).where(eq6(mindHistory.id, outboundId));
5063
+ await db.update(mindHistory).set({ turn_id: turnId }).where(eq7(mindHistory.id, outboundId));
4895
5064
  if (row.message_id) {
4896
5065
  await db.update(messages).set({
4897
5066
  turn_id: turnId,
4898
5067
  ...toolUseEventId != null ? { source_event_id: toolUseEventId } : {}
4899
- }).where(eq6(messages.id, Number(row.message_id)));
5068
+ }).where(eq7(messages.id, Number(row.message_id)));
4900
5069
  }
4901
5070
  publish3(mind, {
4902
5071
  mind,
@@ -4940,19 +5109,19 @@ async function linkToolResultToTurn(mind, turnId, toolResultContent, toolUseEven
4940
5109
  async function tagUntaggedOutbound(mind, turnId) {
4941
5110
  const db = await getDb();
4942
5111
  const range = await db.select({
4943
- minId: sql3`MIN(${mindHistory.id})`,
4944
- maxId: sql3`MAX(${mindHistory.id})`
4945
- }).from(mindHistory).where(and4(eq6(mindHistory.mind, mind), eq6(mindHistory.turn_id, turnId)));
5112
+ minId: sql4`MIN(${mindHistory.id})`,
5113
+ maxId: sql4`MAX(${mindHistory.id})`
5114
+ }).from(mindHistory).where(and5(eq7(mindHistory.mind, mind), eq7(mindHistory.turn_id, turnId)));
4946
5115
  const minId = range[0]?.minId;
4947
5116
  const maxId = range[0]?.maxId;
4948
5117
  if (minId == null || maxId == null) return;
4949
5118
  const orphans = await db.select({ id: mindHistory.id, message_id: mindHistory.message_id }).from(mindHistory).where(
4950
- and4(
4951
- eq6(mindHistory.mind, mind),
4952
- eq6(mindHistory.type, "outbound"),
4953
- sql3`${mindHistory.turn_id} IS NULL`,
4954
- sql3`${mindHistory.id} >= ${minId}`,
4955
- sql3`${mindHistory.id} <= ${maxId}`
5119
+ and5(
5120
+ eq7(mindHistory.mind, mind),
5121
+ eq7(mindHistory.type, "outbound"),
5122
+ sql4`${mindHistory.turn_id} IS NULL`,
5123
+ sql4`${mindHistory.id} >= ${minId}`,
5124
+ sql4`${mindHistory.id} <= ${maxId}`
4956
5125
  )
4957
5126
  );
4958
5127
  if (orphans.length === 0) return;
@@ -4961,10 +5130,10 @@ async function tagUntaggedOutbound(mind, turnId) {
4961
5130
  const orphansWithMessages = orphans.filter((o) => o.message_id);
4962
5131
  if (orphansWithMessages.length > 0) {
4963
5132
  const toolUseEvents = await db.select({ id: mindHistory.id }).from(mindHistory).where(
4964
- and4(
4965
- eq6(mindHistory.mind, mind),
4966
- eq6(mindHistory.turn_id, turnId),
4967
- eq6(mindHistory.type, "tool_use")
5133
+ and5(
5134
+ eq7(mindHistory.mind, mind),
5135
+ eq7(mindHistory.turn_id, turnId),
5136
+ eq7(mindHistory.type, "tool_use")
4968
5137
  )
4969
5138
  ).orderBy(mindHistory.id);
4970
5139
  for (const orphan of orphansWithMessages) {
@@ -4978,7 +5147,7 @@ async function tagUntaggedOutbound(mind, turnId) {
4978
5147
  await db.update(messages).set({
4979
5148
  turn_id: turnId,
4980
5149
  ...sourceEventId != null ? { source_event_id: sourceEventId } : {}
4981
- }).where(eq6(messages.id, Number(orphan.message_id)));
5150
+ }).where(eq7(messages.id, Number(orphan.message_id)));
4982
5151
  }
4983
5152
  }
4984
5153
  dlog2.info(`tagged ${orphans.length} orphaned outbound record(s) for ${mind} with turn ${turnId}`);
@@ -4992,22 +5161,22 @@ async function tagUntaggedInbound(mind, turnId, {
4992
5161
  const tagHistoryPromise = (async () => {
4993
5162
  if (!channel) return;
4994
5163
  const historyConditions = [
4995
- eq6(mindHistory.mind, mind),
4996
- eq6(mindHistory.type, "inbound"),
4997
- sql3`${mindHistory.turn_id} IS NULL`,
4998
- sql3`${mindHistory.created_at} > datetime('now', '-60 seconds')`,
4999
- eq6(mindHistory.channel, channel)
5164
+ eq7(mindHistory.mind, mind),
5165
+ eq7(mindHistory.type, "inbound"),
5166
+ sql4`${mindHistory.turn_id} IS NULL`,
5167
+ sql4`${mindHistory.created_at} > datetime('now', '-60 seconds')`,
5168
+ eq7(mindHistory.channel, channel)
5000
5169
  ];
5001
- const recentInbounds = await db.select({ id: mindHistory.id }).from(mindHistory).where(and4(...historyConditions)).orderBy(desc2(mindHistory.id)).limit(limit);
5170
+ const recentInbounds = await db.select({ id: mindHistory.id }).from(mindHistory).where(and5(...historyConditions)).orderBy(desc2(mindHistory.id)).limit(limit);
5002
5171
  if (recentInbounds.length > 0) {
5003
5172
  const ids = recentInbounds.map((r) => r.id);
5004
5173
  await db.update(mindHistory).set({ turn_id: turnId }).where(inArray3(mindHistory.id, ids));
5005
5174
  if (setTrigger) {
5006
- await db.update(turns).set({ trigger_event_id: recentInbounds[0].id }).where(eq6(turns.id, turnId));
5175
+ await db.update(turns).set({ trigger_event_id: recentInbounds[0].id }).where(eq7(turns.id, turnId));
5007
5176
  }
5008
5177
  }
5009
5178
  })();
5010
- const mindUserPromise = db.select({ id: users.id }).from(users).where(and4(eq6(users.username, mind), eq6(users.user_type, "mind"))).get();
5179
+ const mindUserPromise = db.select({ id: users.id }).from(users).where(and5(eq7(users.username, mind), eq7(users.user_type, "mind"))).get();
5011
5180
  const [tagResult, mindUserResult] = await Promise.allSettled([
5012
5181
  tagHistoryPromise,
5013
5182
  mindUserPromise
@@ -5016,13 +5185,13 @@ async function tagUntaggedInbound(mind, turnId, {
5016
5185
  dlog2.error("failed to tag history inbound", logger_default.errorData(tagResult.reason));
5017
5186
  }
5018
5187
  const mindUser = mindUserResult.status === "fulfilled" ? mindUserResult.value : void 0;
5019
- const mindConvIds = mindUser ? (await db.select({ conversation_id: conversationParticipants.conversation_id }).from(conversationParticipants).where(eq6(conversationParticipants.user_id, mindUser.id))).map((r) => r.conversation_id) : [];
5188
+ const mindConvIds = mindUser ? (await db.select({ conversation_id: conversationParticipants.conversation_id }).from(conversationParticipants).where(eq7(conversationParticipants.user_id, mindUser.id))).map((r) => r.conversation_id) : [];
5020
5189
  const recentMsgs = mindConvIds.length > 0 ? await db.select({ id: messages.id }).from(messages).where(
5021
- and4(
5190
+ and5(
5022
5191
  inArray3(messages.conversation_id, mindConvIds),
5023
- sql3`${messages.turn_id} IS NULL`,
5024
- sql3`${messages.sender_name} != ${mind}`,
5025
- sql3`${messages.created_at} > datetime('now', '-60 seconds')`
5192
+ sql4`${messages.turn_id} IS NULL`,
5193
+ sql4`${messages.sender_name} != ${mind}`,
5194
+ sql4`${messages.created_at} > datetime('now', '-60 seconds')`
5026
5195
  )
5027
5196
  ).orderBy(desc2(messages.id)).limit(limit) : [];
5028
5197
  if (recentMsgs.length > 0) {
@@ -5083,7 +5252,7 @@ async function deliverMessage(mindName, payload) {
5083
5252
  }
5084
5253
 
5085
5254
  // packages/daemon/src/lib/chat/system-chat.ts
5086
- var slog3 = logger_default.child("system-chat");
5255
+ var slog4 = logger_default.child("system-chat");
5087
5256
  var dmCache = /* @__PURE__ */ new Map();
5088
5257
  function resetSystemDMCache() {
5089
5258
  dmCache.clear();
@@ -5151,7 +5320,7 @@ async function generateSystemReply(conversationId, mindName, message) {
5151
5320
  });
5152
5321
  return;
5153
5322
  } catch (err) {
5154
- slog3.warn(`failed to route to spirit, falling back to aiCompleteUtility`, logger_default.errorData(err));
5323
+ slog4.warn(`failed to route to spirit, falling back to aiCompleteUtility`, logger_default.errorData(err));
5155
5324
  }
5156
5325
  }
5157
5326
  const entry = await findMind(mindName);
@@ -5172,7 +5341,7 @@ async function generateSystemReply(conversationId, mindName, message) {
5172
5341
  if (config.sleep.schedule?.wake) contextParts.push(`Wake cron: ${config.sleep.schedule.wake}`);
5173
5342
  }
5174
5343
  try {
5175
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-6QRMUNHK.js");
5344
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-5277OBHI.js");
5176
5345
  const sm = getSleepManagerIfReady2();
5177
5346
  if (sm) {
5178
5347
  const state = sm.getState(mindName);
@@ -5181,7 +5350,7 @@ async function generateSystemReply(conversationId, mindName, message) {
5181
5350
  }
5182
5351
  }
5183
5352
  } catch (err) {
5184
- slog3.debug("could not retrieve sleep state for system reply", logger_default.errorData(err));
5353
+ slog4.debug("could not retrieve sleep state for system reply", logger_default.errorData(err));
5185
5354
  }
5186
5355
  try {
5187
5356
  const schedules = config?.schedules;
@@ -5194,12 +5363,12 @@ async function generateSystemReply(conversationId, mindName, message) {
5194
5363
  }
5195
5364
  }
5196
5365
  } catch (err) {
5197
- slog3.debug("could not retrieve schedules for system reply", logger_default.errorData(err));
5366
+ slog4.debug("could not retrieve schedules for system reply", logger_default.errorData(err));
5198
5367
  }
5199
5368
  const systemPrompt = contextParts.join("\n");
5200
5369
  const response = await aiCompleteUtility(systemPrompt, message);
5201
5370
  if (!response) {
5202
- slog3.warn(`no AI model available for system reply to ${mindName}`);
5371
+ slog4.warn(`no AI model available for system reply to ${mindName}`);
5203
5372
  const fallback = "I can't reply right now \u2014 no AI model is configured for system responses. An admin can set one up in Settings.";
5204
5373
  await addMessage(conversationId, "assistant", "volute", [{ type: "text", text: fallback }]);
5205
5374
  return;
@@ -5229,13 +5398,20 @@ export {
5229
5398
  getPromptIfCustom,
5230
5399
  getMindPromptDefaults,
5231
5400
  RotatingLog,
5401
+ syncProviderToMinds,
5232
5402
  resolveMindToken,
5403
+ recordNotice,
5404
+ drainNotices,
5405
+ clearDeliveredNotices,
5406
+ formatNotices,
5233
5407
  RestartTracker,
5234
5408
  subscribe2 as subscribe,
5235
5409
  subscribeAll,
5236
5410
  publish3 as publish,
5237
5411
  summarizeTurn,
5238
5412
  initSummarizer,
5413
+ markErrored,
5414
+ takeErrored,
5239
5415
  createTurn,
5240
5416
  getActiveTurnId,
5241
5417
  trackToolUse,