volute 0.52.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/{accept-5NK5XJB5.js → accept-I4GVGWA3.js} +6 -3
  2. package/dist/{chat-VAZ25KVT.js → chat-WK2BLM7B.js} +9 -9
  3. package/dist/{chunk-724DVYHU.js → chunk-23UJGVYP.js} +9 -9
  4. package/dist/{chunk-K2F237KS.js → chunk-5DBGQBQR.js} +138 -13
  5. package/dist/chunk-5RBEEAKW.js +58 -0
  6. package/dist/{chunk-XRWUQPCA.js → chunk-7ARONCZW.js} +24 -2
  7. package/dist/{chunk-FXWBFDQR.js → chunk-AP2KQMMW.js} +48 -9
  8. package/dist/{chunk-DMK5ASKV.js → chunk-F6D766VQ.js} +6 -2
  9. package/dist/{chunk-ZEZQNP2G.js → chunk-HASADR3E.js} +46 -9
  10. package/dist/{chunk-AXFLY5GU.js → chunk-IQ7VNWH6.js} +16 -1
  11. package/dist/{chunk-G7A5LEVI.js → chunk-LN7XJ56R.js} +6 -6
  12. package/dist/{chunk-CW7BQKF6.js → chunk-P2TBUKLW.js} +3 -3
  13. package/dist/{chunk-SW2U6HRB.js → chunk-PIZDPY4G.js} +20 -3
  14. package/dist/{chunk-JHKBALS2.js → chunk-RMADJFA7.js} +1 -1
  15. package/dist/{chunk-RU74YG46.js → chunk-RQRO6PC7.js} +40 -6
  16. package/dist/{chunk-RPPTGPYF.js → chunk-TAWRJ24T.js} +1 -1
  17. package/dist/{chunk-ITK6HV47.js → chunk-UO4MZQNO.js} +1 -1
  18. package/dist/chunk-UTKUO2KY.js +102 -0
  19. package/dist/{chunk-YVR6EHWL.js → chunk-VDZ4I4ZP.js} +160 -18
  20. package/dist/cli.js +16 -16
  21. package/dist/{clock-ZT5YT6HA.js → clock-SH4NQC2F.js} +3 -3
  22. package/dist/{cloud-sync-H7EWZASD.js → cloud-sync-MJVJ33LD.js} +10 -9
  23. package/dist/{daemon-restart-4FWUA5JF.js → daemon-restart-BIGU4OKS.js} +1 -1
  24. package/dist/daemon.js +261 -89
  25. package/dist/{delivery-manager-VYXVKUMP.js → delivery-manager-FDHCZ7PU.js} +7 -5
  26. package/dist/delivery-notices-65TB3CBX.js +18 -0
  27. package/dist/{echo-text-PEEV7FQU.js → echo-text-KU6G4Z7V.js} +11 -10
  28. package/dist/{extensions-N6L5NYTK.js → extensions-VACUKFA5.js} +10 -9
  29. package/dist/{files-BRY5RRIM.js → files-CHPNEQXN.js} +5 -4
  30. package/dist/{message-delivery-7URC52ME.js → message-delivery-TUXM3AAE.js} +14 -11
  31. package/dist/{mind-NEXGT3KE.js → mind-IX5AWUST.js} +11 -11
  32. package/dist/{mind-contacts-QYU4TPEA.js → mind-contacts-BKUOUJPV.js} +5 -5
  33. package/dist/{mind-history-OGNR4L7W.js → mind-history-RVF6KJ7K.js} +83 -11
  34. package/dist/{mind-list-SYRA7CH5.js → mind-list-KNU34SUD.js} +2 -2
  35. package/dist/{mind-service-E26ZQXDS.js → mind-service-WHFBUKZE.js} +10 -9
  36. package/dist/{mind-sleep-LZAFBDZD.js → mind-sleep-D3DEYAWG.js} +5 -5
  37. package/dist/{mind-status-Z2LQFA6F.js → mind-status-BPTLQ5Z6.js} +15 -3
  38. package/dist/{package-2W2XKSIP.js → package-BN5KMU54.js} +1 -1
  39. package/dist/{prompts-NBO3HRK3.js → prompts-HNKGCAEY.js} +1 -1
  40. package/dist/{reject-TWB4QJHG.js → reject-K2A4UK2Y.js} +9 -5
  41. package/dist/{scheduler-JTTWZDYU.js → scheduler-5X5UIQOQ.js} +7 -5
  42. package/dist/{seed-64XEHRUP.js → seed-LHZ33UB4.js} +1 -1
  43. package/dist/{seed-cmd-UEL2QB3Q.js → seed-cmd-U4RVJ3UA.js} +2 -2
  44. package/dist/{seed-create-4JRQDPGA.js → seed-create-OQU4KNCB.js} +1 -1
  45. package/dist/{seed-readiness-DYOVCYHN.js → seed-readiness-WJYYRRCK.js} +2 -2
  46. package/dist/{seed-sprout-NIDIOJXT.js → seed-sprout-SFUYH2RG.js} +7 -7
  47. package/dist/{send-2YKOZJJ5.js → send-FWZAMDBN.js} +35 -20
  48. package/dist/{setup-4IX6PCD3.js → setup-RVSGCIF3.js} +1 -1
  49. package/dist/skills/memory/SKILL.md +47 -43
  50. package/dist/{skills-MPUALV3S.js → skills-QRPU6BWY.js} +1 -1
  51. package/dist/{sleep-manager-OFP2GFXF.js → sleep-manager-NWUCRBZB.js} +10 -9
  52. package/dist/{spirit-4ECYIVGE.js → spirit-I5ECLGRI.js} +16 -2
  53. package/dist/{spirit-availability-Y54Y3675.js → spirit-availability-NIUUYKU2.js} +11 -10
  54. package/dist/{sprout-GJMZFRGZ.js → sprout-A2PMEF7Z.js} +1 -1
  55. package/dist/{system-events-V43HDA3T.js → system-events-YTOU66QI.js} +5 -1
  56. package/dist/{systems-VDRUZXNF.js → systems-2DIJY4RF.js} +6 -6
  57. package/dist/{turn-tracker-C5PVIC3B.js → turn-tracker-NNHS6MAR.js} +4 -2
  58. package/dist/{up-H6LJZDRK.js → up-UGBHH743.js} +1 -1
  59. package/dist/{variant-cleanup-STC6B5HR.js → variant-cleanup-CZDLIY3F.js} +7 -5
  60. package/dist/{version-notify-LBVHH5YV.js → version-notify-SJVAQLZI.js} +4 -4
  61. package/dist/web-assets/assets/index-BHSU9r-4.css +1 -0
  62. package/dist/web-assets/assets/{index-B_eYTa3R.js → index-b7G7ZsVk.js} +13 -13
  63. package/dist/web-assets/index.html +2 -2
  64. package/package.json +1 -1
  65. package/templates/_base/.init/.config/prompts.json +1 -1
  66. package/templates/_base/src/lib/codex-session-seed.ts +463 -0
  67. package/templates/_base/src/lib/daemon-client.ts +35 -0
  68. package/templates/_base/src/lib/pi-session-seed.ts +434 -0
  69. package/templates/_base/src/lib/seed-note.ts +78 -0
  70. package/templates/_base/src/lib/session-seed.ts +375 -0
  71. package/templates/_base/src/lib/startup.ts +108 -4
  72. package/templates/claude/.init/CLAUDE.md +3 -3
  73. package/templates/claude/src/agent.ts +267 -89
  74. package/templates/claude/src/lib/hooks/pre-compact.ts +30 -5
  75. package/templates/claude/src/lib/stream-consumer.ts +13 -0
  76. package/templates/claude/src/server.ts +2 -1
  77. package/templates/codex/.init/AGENTS.md +3 -3
  78. package/templates/codex/src/agent.ts +256 -39
  79. package/templates/codex/src/server.ts +2 -1
  80. package/templates/pi/.init/MINDS.md +3 -3
  81. package/templates/pi/src/agent.ts +269 -43
  82. package/templates/pi/src/lib/event-handler.ts +11 -0
  83. package/templates/pi/src/server.ts +3 -1
  84. package/dist/web-assets/assets/index-DhZrzddW.css +0 -1
  85. package/dist/{backup-YVGV2ZNM.js → backup-WWXVIMYQ.js} +5 -5
  86. package/dist/{bridge-YK7NTRU5.js → bridge-KU2IKSH3.js} +3 -3
  87. package/dist/{channels-FSAHOQWI.js → channels-LW5ZLMSQ.js} +3 -3
  88. package/dist/{chunk-VPOMJMV6.js → chunk-BDHKCLWK.js} +0 -0
  89. package/dist/{chunk-EEOMA4DX.js → chunk-HTB7KDRU.js} +3 -3
  90. package/dist/{create-M727VUDF.js → create-C3XZACTV.js} +3 -3
  91. package/dist/{env-IBW2QI6K.js → env-BJGM6FBA.js} +5 -5
  92. package/dist/{extension-MRYJWSMV.js → extension-B2W52WZY.js} +3 -3
  93. package/dist/{list-UQGIW7OF.js → list-R2GDWOEE.js} +3 -3
  94. package/dist/{login-RJJTCVR3.js → login-EZ4RRDQX.js} +3 -3
  95. package/dist/{login-SB5OENMV.js → login-JDOAK465.js} +4 -4
  96. package/dist/{logout-YFZAJRPY.js → logout-K6ZGAJY5.js} +3 -3
  97. package/dist/{logout-BYV433X6.js → logout-MWSIUOQU.js} +3 -3
  98. package/dist/{mind-wake-LDGPRA42.js → mind-wake-DCDFFQKX.js} +3 -3
  99. package/dist/{read-RJ5NAW5J.js → read-J5RM674N.js} +3 -3
  100. package/dist/{register-OX4HRSGC.js → register-53LBGSDC.js} +3 -3
  101. package/dist/{restart-AGEGNSYQ.js → restart-R2WFNF5K.js} +4 -4
  102. package/dist/{skill-B5OJEQUA.js → skill-DXLLSUHB.js} +5 -5
  103. package/dist/{start-MUMNFR52.js → start-XDOUAWN3.js} +4 -4
  104. package/dist/{status-MWLE3RVC.js → status-EYG4A3OK.js} +3 -3
  105. package/dist/{stop-EKERNYTX.js → stop-O62RTEMD.js} +4 -4
package/dist/daemon.js CHANGED
@@ -14,23 +14,31 @@ import {
14
14
  rejectPending,
15
15
  stageFile,
16
16
  validateFilePath
17
- } from "./chunk-DMK5ASKV.js";
17
+ } from "./chunk-F6D766VQ.js";
18
18
  import {
19
19
  findOpenClawSession,
20
20
  importOpenClawConnectors,
21
21
  importPiSession,
22
22
  parseNameFromIdentity
23
23
  } from "./chunk-I7U5EEZC.js";
24
+ import {
25
+ getMemoryStatus
26
+ } from "./chunk-5RBEEAKW.js";
27
+ import {
28
+ checkForUpdate,
29
+ checkForUpdateCached,
30
+ getCurrentVersion
31
+ } from "./chunk-LAUCO2HC.js";
24
32
  import {
25
33
  SPIRIT_NOTICE_PREFIX,
26
34
  ensureSpiritAvailable
27
- } from "./chunk-CW7BQKF6.js";
35
+ } from "./chunk-P2TBUKLW.js";
28
36
  import {
29
37
  isHomeOnlyArchive
30
38
  } from "./chunk-FLIEXG2T.js";
31
39
  import {
32
40
  evaluateSeedChecklist
33
- } from "./chunk-JHKBALS2.js";
41
+ } from "./chunk-RMADJFA7.js";
34
42
  import {
35
43
  isTemplateStale
36
44
  } from "./chunk-CV6BNGFK.js";
@@ -39,19 +47,14 @@ import {
39
47
  } from "./chunk-HTRSSOHY.js";
40
48
  import {
41
49
  cleanupVariant
42
- } from "./chunk-ITK6HV47.js";
43
- import {
44
- checkForUpdate,
45
- checkForUpdateCached,
46
- getCurrentVersion
47
- } from "./chunk-LAUCO2HC.js";
50
+ } from "./chunk-UO4MZQNO.js";
48
51
  import {
49
52
  PLATFORMS,
50
53
  echoTextToChannel,
51
54
  fixModelEscapes,
52
55
  getPlatformDriver,
53
56
  routeOutboundBridge
54
- } from "./chunk-XRWUQPCA.js";
57
+ } from "./chunk-7ARONCZW.js";
55
58
  import {
56
59
  getBridgeConfig,
57
60
  readBridgesConfig,
@@ -104,9 +107,10 @@ import {
104
107
  startMindFull,
105
108
  stopMindFull,
106
109
  uninstallNpmExtension,
110
+ willGateMessage,
107
111
  writeSystemsConfig
108
- } from "./chunk-ZEZQNP2G.js";
109
- import "./chunk-K2F237KS.js";
112
+ } from "./chunk-HASADR3E.js";
113
+ import "./chunk-5DBGQBQR.js";
110
114
  import {
111
115
  applyInitFiles,
112
116
  applyTemplateHomeFiles,
@@ -119,7 +123,10 @@ import {
119
123
  import {
120
124
  getScheduler,
121
125
  initScheduler
122
- } from "./chunk-SW2U6HRB.js";
126
+ } from "./chunk-PIZDPY4G.js";
127
+ import {
128
+ recordDeliveryFailure
129
+ } from "./chunk-UTKUO2KY.js";
123
130
  import {
124
131
  checkStaleSend,
125
132
  formatHoldNotice,
@@ -128,7 +135,7 @@ import {
128
135
  initDeliveryManager,
129
136
  isConversationId,
130
137
  publishTypingForChannels
131
- } from "./chunk-RU74YG46.js";
138
+ } from "./chunk-RQRO6PC7.js";
132
139
  import {
133
140
  MindStartupError,
134
141
  RestartTracker,
@@ -138,7 +145,7 @@ import {
138
145
  initMindManager,
139
146
  syncProviderToMinds,
140
147
  tryGetMindManager
141
- } from "./chunk-724DVYHU.js";
148
+ } from "./chunk-23UJGVYP.js";
142
149
  import {
143
150
  extractTextContent
144
151
  } from "./chunk-UDZLPR34.js";
@@ -155,13 +162,15 @@ import {
155
162
  initSummarizer,
156
163
  isoWeekKeyForDateStr,
157
164
  markErrored,
165
+ parseDbTimestamp,
158
166
  parseUtcDateTime,
159
167
  summarizeOrphanedTurns,
160
168
  summarizeTurn,
169
+ supersedeTurnSummary,
161
170
  takeErrored,
162
171
  trackToolUse,
163
172
  utcDateTimeStr
164
- } from "./chunk-YVR6EHWL.js";
173
+ } from "./chunk-VDZ4I4ZP.js";
165
174
  import {
166
175
  SEED_SKILLS,
167
176
  STANDARD_SKILLS,
@@ -183,7 +192,7 @@ import {
183
192
  syncBuiltinSkills,
184
193
  uninstallSkill,
185
194
  updateSkill
186
- } from "./chunk-RPPTGPYF.js";
195
+ } from "./chunk-TAWRJ24T.js";
187
196
  import {
188
197
  approveUser,
189
198
  changePassword,
@@ -207,6 +216,7 @@ import {
207
216
  withSenderDisplayNames
208
217
  } from "./chunk-7LT3YZUR.js";
209
218
  import {
219
+ MIND_LEVEL_THREAD,
210
220
  captureReflection,
211
221
  cleanExpiredEvents,
212
222
  clearDeliveredEvents,
@@ -219,7 +229,7 @@ import {
219
229
  listEvents,
220
230
  parseMeta,
221
231
  recordNotice
222
- } from "./chunk-AXFLY5GU.js";
232
+ } from "./chunk-IQ7VNWH6.js";
223
233
  import {
224
234
  publish as publish2,
225
235
  subscribe as subscribe2,
@@ -232,7 +242,7 @@ import {
232
242
  getPrompt,
233
243
  getPromptIfCustom,
234
244
  substitute
235
- } from "./chunk-FXWBFDQR.js";
245
+ } from "./chunk-AP2KQMMW.js";
236
246
  import {
237
247
  isSandboxEnabled,
238
248
  wrapForSandbox
@@ -397,7 +407,7 @@ import "./chunk-K3NQKI34.js";
397
407
 
398
408
  // packages/daemon/src/daemon.ts
399
409
  import { randomBytes as randomBytes3 } from "crypto";
400
- import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync12, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
410
+ import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync12, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "fs";
401
411
  import { homedir as homedir3 } from "os";
402
412
  import { resolve as resolve20 } from "path";
403
413
  import { format } from "util";
@@ -510,7 +520,7 @@ var BackupManager = class {
510
520
  } catch (pubErr) {
511
521
  blog.error("failed to publish backup-failure activity", logger_default.errorData(pubErr));
512
522
  }
513
- const { deliverEvent: deliverEvent2 } = await import("./system-events-V43HDA3T.js");
523
+ const { deliverEvent: deliverEvent2 } = await import("./system-events-YTOU66QI.js");
514
524
  await deliverEvent2(getSpiritName(), {
515
525
  type: "notice",
516
526
  meta: { subtype: "backup" },
@@ -1462,7 +1472,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
1462
1472
  config2.name = name.trim() || void 0;
1463
1473
  writeGlobalConfig(config2);
1464
1474
  if (config2.name !== previousName) {
1465
- const { notifySpiritSystemChange } = await import("./spirit-4ECYIVGE.js");
1475
+ const { notifySpiritSystemChange } = await import("./spirit-I5ECLGRI.js");
1466
1476
  await notifySpiritSystemChange();
1467
1477
  }
1468
1478
  return c.json({ name: config2.name ?? null });
@@ -2674,6 +2684,21 @@ async function fanOutToMinds(opts) {
2674
2684
  const manager = getMindManager();
2675
2685
  const sm = getSleepManagerIfReady();
2676
2686
  const registeredMinds = new Set((await readAllMinds()).map((m) => m.name));
2687
+ const senderIsMind = registeredMinds.has(opts.senderName);
2688
+ let senderCtx;
2689
+ const reportFailure = (reason) => {
2690
+ if (!senderIsMind) return;
2691
+ senderCtx ??= getBaseName(opts.senderName).then((base) => ({
2692
+ base,
2693
+ channel: buildVoluteSlug({
2694
+ participants,
2695
+ mindUsername: base,
2696
+ conversationId: opts.conversationId,
2697
+ ...opts.slugExtra
2698
+ })
2699
+ }));
2700
+ senderCtx.then(({ base, channel }) => recordDeliveryFailure({ mind: base, channel, reason })).catch((err) => logger_default.warn("fan-out: failed to report send failure", logger_default.errorData(err)));
2701
+ };
2677
2702
  const targetMinds = mindParticipants.map((ap) => {
2678
2703
  const key = opts.targetName ? opts.targetName(ap.username) : ap.username;
2679
2704
  if (manager.isRunning(key) || sm?.isSleeping(ap.username)) return ap.username;
@@ -2682,21 +2707,46 @@ async function fanOutToMinds(opts) {
2682
2707
  logger_default.warn(
2683
2708
  `fan-out: skipping ${ap.username} (not running) for conversation ${opts.conversationId}`
2684
2709
  );
2710
+ reportFailure(`${ap.username} is not running`);
2711
+ } else if (ap.userType === "mind") {
2712
+ logger_default.info(
2713
+ `fan-out: skipping ${ap.username} (no registry row \u2014 external mind or stale participant) for conversation ${opts.conversationId}`
2714
+ );
2685
2715
  }
2686
2716
  if (ap.userType === "system") {
2687
- import("./spirit-availability-Y54Y3675.js").then(({ ensureSpiritAvailable: ensureSpiritAvailable2 }) => ensureSpiritAvailable2()).catch((err) => logger_default.warn("fan-out: on-demand spirit start failed", logger_default.errorData(err)));
2717
+ import("./spirit-availability-NIUUYKU2.js").then(({ ensureSpiritAvailable: ensureSpiritAvailable2 }) => ensureSpiritAvailable2()).catch((err) => logger_default.warn("fan-out: on-demand spirit start failed", logger_default.errorData(err)));
2688
2718
  }
2689
2719
  }
2690
2720
  return null;
2691
2721
  }).filter((n) => n !== null && n !== opts.senderName);
2692
- for (const mindName of targetMinds) {
2693
- const target = opts.targetName ? opts.targetName(mindName) : mindName;
2694
- const channel = buildVoluteSlug({
2722
+ const targets = targetMinds.map((mindName) => ({
2723
+ mindName,
2724
+ target: opts.targetName ? opts.targetName(mindName) : mindName,
2725
+ channel: buildVoluteSlug({
2695
2726
  participants,
2696
2727
  mindUsername: mindName,
2697
2728
  conversationId: opts.conversationId,
2698
2729
  ...opts.slugExtra
2699
- });
2730
+ })
2731
+ }));
2732
+ const gatedRecipients = (await Promise.all(
2733
+ targets.map(async ({ mindName, target, channel }) => {
2734
+ if (sm?.isSleeping(mindName)) return null;
2735
+ try {
2736
+ const gated = await willGateMessage(target, {
2737
+ channel,
2738
+ sender: opts.senderName,
2739
+ isDM,
2740
+ participantCount: participants.length
2741
+ });
2742
+ return gated ? mindName : null;
2743
+ } catch (err) {
2744
+ logger_default.warn(`fan-out: will-gate check failed for ${target}`, logger_default.errorData(err));
2745
+ return null;
2746
+ }
2747
+ })
2748
+ )).filter((n) => n !== null);
2749
+ for (const { mindName, target, channel } of targets) {
2700
2750
  const typingMap = getTypingMap();
2701
2751
  const currentlyTyping = typingMap.get(channel).filter((name) => participantNames.includes(name));
2702
2752
  deliverMessage(target, {
@@ -2708,10 +2758,20 @@ async function fanOutToMinds(opts) {
2708
2758
  participantCount: participants.length,
2709
2759
  isDM,
2710
2760
  ...currentlyTyping.length > 0 ? { typing: currentlyTyping } : {}
2711
- }).catch((err) => {
2712
- logger_default.warn(`fan-out delivery failed for ${target}`, logger_default.errorData(err));
2713
- });
2761
+ }).then(
2762
+ (ok) => {
2763
+ if (!ok) {
2764
+ logger_default.warn(`fan-out delivery failed for ${target} (message not delivered)`);
2765
+ reportFailure(`the delivery to ${mindName} failed`);
2766
+ }
2767
+ },
2768
+ (err) => {
2769
+ logger_default.warn(`fan-out delivery failed for ${target}`, logger_default.errorData(err));
2770
+ reportFailure(`the delivery to ${mindName} failed`);
2771
+ }
2772
+ );
2714
2773
  }
2774
+ return { gatedRecipients };
2715
2775
  }
2716
2776
 
2717
2777
  // packages/daemon/src/web/api/bridges.ts
@@ -3069,12 +3129,18 @@ import { resolve as resolve4 } from "path";
3069
3129
  import { Hono as Hono10 } from "hono";
3070
3130
  async function notifyMind(mindName, message) {
3071
3131
  const entry = await findMind(mindName);
3072
- if (!entry) return;
3073
- try {
3074
- const { deliverEvent: deliverEvent2 } = await import("./system-events-V43HDA3T.js");
3075
- await deliverEvent2(mindName, { type: "file-share", body: message });
3132
+ if (!entry) return false;
3133
+ try {
3134
+ const { deliverEvent: deliverEvent2 } = await import("./system-events-YTOU66QI.js");
3135
+ const result = await deliverEvent2(mindName, { type: "file-share", body: message });
3136
+ if (result.delivered) return true;
3137
+ if (result.id == null) return false;
3138
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-NWUCRBZB.js");
3139
+ const { getBaseName: getBaseName2 } = await import("./registry-TRC2HJXR.js");
3140
+ return getSleepManagerIfReady2()?.isSleeping(await getBaseName2(mindName)) ?? false;
3076
3141
  } catch (err) {
3077
3142
  logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
3143
+ return false;
3078
3144
  }
3079
3145
  }
3080
3146
  var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
@@ -3115,11 +3181,11 @@ var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
3115
3181
  const filename = body.filePath;
3116
3182
  const sizeStr = formatFileSize(content.length);
3117
3183
  const { id } = stageFile(body.targetMind, senderName, filename, content, body.filePath);
3118
- await notifyMind(
3184
+ const notified = await notifyMind(
3119
3185
  body.targetMind,
3120
3186
  `[file] ${senderName} sent ${filename} (${sizeStr}) \u2014 run: volute chat accept ${id}`
3121
3187
  );
3122
- return c.json({ status: "pending", id }, 200);
3188
+ return c.json({ status: "pending", id, notified }, 200);
3123
3189
  }).get("/:name/files/pending", requireSelf(), async (c) => {
3124
3190
  const name = c.req.param("name");
3125
3191
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
@@ -3144,8 +3210,8 @@ var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
3144
3210
  }
3145
3211
  return c.json({ error: `Failed to accept file: ${message}` }, 500);
3146
3212
  }
3147
- await notifyMind(result.sender, `[file] ${name} accepted ${result.filename}`);
3148
- return c.json({ ok: true, destPath: result.destPath });
3213
+ const notified = await notifyMind(result.sender, `[file] ${name} accepted ${result.filename}`);
3214
+ return c.json({ ok: true, destPath: result.destPath, notified });
3149
3215
  }).post("/:name/files/reject", requireSelf(), async (c) => {
3150
3216
  const name = c.req.param("name");
3151
3217
  if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
@@ -3161,8 +3227,8 @@ var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
3161
3227
  }
3162
3228
  return c.json({ error: `Failed to reject file: ${message}` }, 500);
3163
3229
  }
3164
- await notifyMind(result.sender, `[file] ${name} rejected ${result.filename}`);
3165
- return c.json({ ok: true });
3230
+ const notified = await notifyMind(result.sender, `[file] ${name} rejected ${result.filename}`);
3231
+ return c.json({ ok: true, notified });
3166
3232
  }).post("/:name/files/stage", requireSelf(), async (c) => {
3167
3233
  const receiverName = c.req.param("name");
3168
3234
  const receiverEntry = await findMind(receiverName);
@@ -3185,11 +3251,11 @@ var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
3185
3251
  }
3186
3252
  const sizeStr = formatFileSize(content.length);
3187
3253
  const { id } = stageFile(receiverName, body.sender, body.filename, content, body.filename);
3188
- await notifyMind(
3254
+ const notified = await notifyMind(
3189
3255
  receiverName,
3190
3256
  `[file] ${body.sender} sent ${body.filename} (${sizeStr}) \u2014 run: volute chat accept ${id}`
3191
3257
  );
3192
- return c.json({ status: "pending", id }, 200);
3258
+ return c.json({ status: "pending", id, notified }, 200);
3193
3259
  });
3194
3260
  var file_sharing_default = app8;
3195
3261
 
@@ -5126,12 +5192,6 @@ function convertAssistantContent(content) {
5126
5192
  return result;
5127
5193
  }
5128
5194
 
5129
- // packages/daemon/src/lib/util/time.ts
5130
- function parseDbTimestamp(ts) {
5131
- if (/[zZ]$|[+-]\d\d:?\d\d$/.test(ts)) return new Date(ts);
5132
- return /* @__PURE__ */ new Date(`${ts.replace(" ", "T")}Z`);
5133
- }
5134
-
5135
5195
  // packages/daemon/src/web/api/minds.ts
5136
5196
  var _lastActiveCache = { map: /* @__PURE__ */ new Map(), ts: 0 };
5137
5197
  var _LAST_ACTIVE_TTL = 6e4;
@@ -5141,7 +5201,7 @@ async function getMindStatus(name, port, registryRunning, seed) {
5141
5201
  let status = "stopped";
5142
5202
  let wakeAt = null;
5143
5203
  try {
5144
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
5204
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-NWUCRBZB.js");
5145
5205
  const sleepManager = getSleepManagerIfReady2();
5146
5206
  if (sleepManager?.isSleeping(name)) {
5147
5207
  status = "sleeping";
@@ -5167,10 +5227,12 @@ async function getMindStatus(name, port, registryRunning, seed) {
5167
5227
  }
5168
5228
  const lastError = await latestFailureEvent(name);
5169
5229
  const seedChecklist = seed?.stage === "seed" ? evaluateSeedChecklist(seed.dir ?? mindDir(name)) : void 0;
5230
+ const memory = getMemoryStatus(seed?.dir ?? mindDir(name));
5170
5231
  return {
5171
5232
  status,
5172
5233
  wakeAt,
5173
5234
  lastError,
5235
+ memory,
5174
5236
  channels: channels2,
5175
5237
  displayName: config2?.profile?.displayName,
5176
5238
  description: config2?.profile?.description,
@@ -5193,6 +5255,7 @@ function toPublicMind(entry, status, extras) {
5193
5255
  // Kind/reason/at only — `detail` can embed the raw error string (unknown
5194
5256
  // classifications), which is mind-private (served behind requireSelf).
5195
5257
  lastError: status.lastError ? { kind: status.lastError.kind, reason: status.lastError.reason, at: status.lastError.at } : null,
5258
+ memory: status.memory,
5196
5259
  channels: status.channels,
5197
5260
  displayName: status.displayName,
5198
5261
  description: status.description,
@@ -5786,7 +5849,7 @@ Your creator described you as: "${body.description}"
5786
5849
  const spiritName = getSpiritName();
5787
5850
  const spiritEntry = await findMind(spiritName);
5788
5851
  if (spiritEntry) {
5789
- const { spiritDir } = await import("./spirit-4ECYIVGE.js");
5852
+ const { spiritDir } = await import("./spirit-I5ECLGRI.js");
5790
5853
  const sDir = spiritEntry.dir ?? spiritDir();
5791
5854
  const spiritConfig = readVoluteConfig(sDir) ?? {};
5792
5855
  const schedules = spiritConfig.schedules ?? [];
@@ -5801,7 +5864,7 @@ Your creator described you as: "${body.description}"
5801
5864
  });
5802
5865
  spiritConfig.schedules = schedules;
5803
5866
  writeVoluteConfig(sDir, spiritConfig);
5804
- const { getScheduler: getScheduler2 } = await import("./scheduler-JTTWZDYU.js");
5867
+ const { getScheduler: getScheduler2 } = await import("./scheduler-5X5UIQOQ.js");
5805
5868
  getScheduler2().loadSchedules(spiritName, sDir);
5806
5869
  }
5807
5870
  }
@@ -6107,7 +6170,7 @@ ${user.trimEnd()}
6107
6170
  const manager = getMindManager();
6108
6171
  try {
6109
6172
  if (context?.type === "reload") {
6110
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6173
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-NWUCRBZB.js");
6111
6174
  const sleepState = getSleepManagerIfReady2()?.getState(name);
6112
6175
  if (sleepState?.sleeping) {
6113
6176
  logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
@@ -6256,7 +6319,7 @@ ${user.trimEnd()}
6256
6319
  const name = c.req.param("name");
6257
6320
  const entry = await findMind(name);
6258
6321
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6259
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6322
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-NWUCRBZB.js");
6260
6323
  const sm = getSleepManagerIfReady2();
6261
6324
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6262
6325
  return c.json(sm.getState(name));
@@ -6264,7 +6327,7 @@ ${user.trimEnd()}
6264
6327
  const name = c.req.param("name");
6265
6328
  const entry = await findMind(name);
6266
6329
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6267
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6330
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-NWUCRBZB.js");
6268
6331
  const sm = getSleepManagerIfReady2();
6269
6332
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6270
6333
  if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
@@ -6284,7 +6347,7 @@ ${user.trimEnd()}
6284
6347
  const name = c.req.param("name");
6285
6348
  const entry = await findMind(name);
6286
6349
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6287
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6350
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-NWUCRBZB.js");
6288
6351
  const sm = getSleepManagerIfReady2();
6289
6352
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6290
6353
  const sleepState = sm.getState(name);
@@ -6299,7 +6362,7 @@ ${user.trimEnd()}
6299
6362
  const name = c.req.param("name");
6300
6363
  const entry = await findMind(name);
6301
6364
  if (!entry) return c.json({ error: "Mind not found" }, 404);
6302
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6365
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-NWUCRBZB.js");
6303
6366
  const sm = getSleepManagerIfReady2();
6304
6367
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
6305
6368
  const flushed = await sm.flushQueuedMessages(name);
@@ -6371,7 +6434,7 @@ ${user.trimEnd()}
6371
6434
  });
6372
6435
  }
6373
6436
  if (!force) {
6374
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-OFP2GFXF.js");
6437
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-NWUCRBZB.js");
6375
6438
  if (getSleepManagerIfReady2()?.isSleeping(name)) {
6376
6439
  return c.json({ output: "" });
6377
6440
  }
@@ -6426,7 +6489,7 @@ ${user.trimEnd()}
6426
6489
  }
6427
6490
  }
6428
6491
  const dir = entry.dir ?? mindDir(name);
6429
- const { evaluateSeedChecklist: evaluateSeedChecklist2 } = await import("./seed-readiness-DYOVCYHN.js");
6492
+ const { evaluateSeedChecklist: evaluateSeedChecklist2 } = await import("./seed-readiness-WJYYRRCK.js");
6430
6493
  const checklist = evaluateSeedChecklist2(dir);
6431
6494
  const done = [];
6432
6495
  const remaining = [];
@@ -6468,7 +6531,7 @@ ${user.trimEnd()}
6468
6531
  try {
6469
6532
  const sproutedDir = entry.dir ?? mindDir(name);
6470
6533
  if (setupDefaultDreaming(sproutedDir).schedulesChanged) {
6471
- const { getScheduler: getScheduler2 } = await import("./scheduler-JTTWZDYU.js");
6534
+ const { getScheduler: getScheduler2 } = await import("./scheduler-5X5UIQOQ.js");
6472
6535
  getScheduler2().loadSchedules(name, sproutedDir);
6473
6536
  }
6474
6537
  } catch (err) {
@@ -6478,7 +6541,7 @@ ${user.trimEnd()}
6478
6541
  const spiritName = getSpiritName();
6479
6542
  const spiritEntry = await findMind(spiritName);
6480
6543
  if (spiritEntry) {
6481
- const { firstWeekSchedules, spiritDir } = await import("./spirit-4ECYIVGE.js");
6544
+ const { firstWeekSchedules, spiritDir } = await import("./spirit-I5ECLGRI.js");
6482
6545
  const sDir = spiritEntry.dir ?? spiritDir();
6483
6546
  const spiritConfig = readVoluteConfig(sDir);
6484
6547
  if (spiritConfig) {
@@ -6492,7 +6555,7 @@ ${user.trimEnd()}
6492
6555
  spiritConfig.schedules = schedules;
6493
6556
  writeVoluteConfig(sDir, spiritConfig);
6494
6557
  try {
6495
- const { getScheduler: getScheduler2 } = await import("./scheduler-JTTWZDYU.js");
6558
+ const { getScheduler: getScheduler2 } = await import("./scheduler-5X5UIQOQ.js");
6496
6559
  getScheduler2().loadSchedules(spiritName, sDir);
6497
6560
  } catch (err) {
6498
6561
  logger_default.warn(
@@ -6933,7 +6996,7 @@ ${user.trimEnd()}
6933
6996
  }
6934
6997
  writeVoluteConfig(dir, existing);
6935
6998
  if (body.unescapeNewlines !== void 0) {
6936
- const { clearEchoTextCache } = await import("./echo-text-PEEV7FQU.js");
6999
+ const { clearEchoTextCache } = await import("./echo-text-KU6G4Z7V.js");
6937
7000
  clearEchoTextCache(name);
6938
7001
  }
6939
7002
  const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.compaction !== void 0;
@@ -7258,6 +7321,35 @@ ${lines.join("\n")}` });
7258
7321
  const maxId = notices.reduce((m, n) => Math.max(m, n.id), 0);
7259
7322
  setNoticeDrainWatermark(baseName, session, maxId);
7260
7323
  return c.json({ context: formatEvents(notices), notices });
7324
+ }).post("/:name/notices", requireSelf(), async (c) => {
7325
+ const MIND_POSTABLE_KINDS = ["context_lost", "delivery_failed"];
7326
+ const name = c.req.param("name");
7327
+ const baseName = await getBaseName(name);
7328
+ let body;
7329
+ try {
7330
+ body = await c.req.json();
7331
+ } catch {
7332
+ return c.json({ error: "Invalid JSON body" }, 400);
7333
+ }
7334
+ const kind = body.kind;
7335
+ if (typeof kind !== "string" || !MIND_POSTABLE_KINDS.includes(kind)) {
7336
+ return c.json({ error: `kind must be one of: ${MIND_POSTABLE_KINDS.join(", ")}` }, 400);
7337
+ }
7338
+ const message = typeof body.message === "string" ? body.message.trim() : "";
7339
+ if (!message) return c.json({ error: "message is required" }, 400);
7340
+ if (body.thread !== void 0 && typeof body.thread !== "string") {
7341
+ return c.json({ error: "thread must be a string" }, 400);
7342
+ }
7343
+ await recordNotice({
7344
+ mind: baseName,
7345
+ thread: body.thread ?? MIND_LEVEL_THREAD,
7346
+ kind,
7347
+ reason: kind,
7348
+ // Bound the size (the body is injected into turn context) without dropping
7349
+ // the notice — a truncated explanation beats a silent 400.
7350
+ detail: message.length > 4e3 ? `${message.slice(0, 4e3)}\u2026` : message
7351
+ });
7352
+ return c.json({ ok: true });
7261
7353
  }).get("/:name/system-events", requireSelf(), async (c) => {
7262
7354
  const name = c.req.param("name");
7263
7355
  const baseName = await getBaseName(name);
@@ -7280,6 +7372,43 @@ ${lines.join("\n")}` });
7280
7372
  };
7281
7373
  })
7282
7374
  });
7375
+ }).put("/:name/turn-summaries", requireSelf(), async (c) => {
7376
+ const name = c.req.param("name");
7377
+ const baseName = await getBaseName(name);
7378
+ let body;
7379
+ try {
7380
+ body = await c.req.json();
7381
+ } catch {
7382
+ return c.json({ error: "Invalid JSON body" }, 400);
7383
+ }
7384
+ const items = body.summaries;
7385
+ if (!Array.isArray(items) || items.length === 0) {
7386
+ return c.json({ error: "summaries must be a non-empty array" }, 400);
7387
+ }
7388
+ let updated = 0;
7389
+ let created = 0;
7390
+ for (const item of items) {
7391
+ if (!item || typeof item.turnId !== "string" || !item.turnId) {
7392
+ return c.json({ error: "each summary needs a turnId" }, 400);
7393
+ }
7394
+ if (typeof item.content !== "string") {
7395
+ return c.json({ error: "each summary needs content" }, 400);
7396
+ }
7397
+ const result = await supersedeTurnSummary(baseName, item.turnId, item.content);
7398
+ switch (result.status) {
7399
+ case "invalid":
7400
+ return c.json({ error: result.error }, 400);
7401
+ case "not_found":
7402
+ return c.json({ error: "Turn not found" }, 404);
7403
+ case "forbidden":
7404
+ return c.json({ error: "Forbidden" }, 403);
7405
+ case "ok":
7406
+ if (result.created) created++;
7407
+ else updated++;
7408
+ break;
7409
+ }
7410
+ }
7411
+ return c.json({ ok: true, updated, created });
7283
7412
  }).get("/:name/history", requireSelf(), async (c) => {
7284
7413
  const name = c.req.param("name");
7285
7414
  const channel = c.req.query("channel");
@@ -7288,6 +7417,7 @@ ${lines.join("\n")}` });
7288
7417
  const preset = c.req.query("preset");
7289
7418
  const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 200);
7290
7419
  const offset = Math.max(parseInt(c.req.query("offset") ?? "0", 10) || 0, 0);
7420
+ const provisional = c.req.query("provisional") === "true";
7291
7421
  const db = await getDb();
7292
7422
  const conditions = [eq5(mindHistory.mind, name)];
7293
7423
  if (channel) {
@@ -7299,6 +7429,9 @@ ${lines.join("\n")}` });
7299
7429
  const effectivePreset = full ? "all" : preset;
7300
7430
  if (!effectivePreset || effectivePreset === "summary") {
7301
7431
  const sumConditions = [eq5(summaries.mind, name), eq5(summaries.period, "turn")];
7432
+ if (provisional) {
7433
+ sumConditions.push(sql3`json_extract(${summaries.metadata}, '$.author') is not ${"mind"}`);
7434
+ }
7302
7435
  if (session) {
7303
7436
  sumConditions.push(eq5(turns.thread, session));
7304
7437
  const sumRows2 = await db.select({
@@ -7707,7 +7840,7 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
7707
7840
  const entry = await findMind(name);
7708
7841
  if (!entry) return c.json({ error: "Mind not found" }, 404);
7709
7842
  const body = await c.req.text();
7710
- const { deliverEvent: deliverEvent2 } = await import("./system-events-V43HDA3T.js");
7843
+ const { deliverEvent: deliverEvent2 } = await import("./system-events-YTOU66QI.js");
7711
7844
  const { id, delivered } = await deliverEvent2(name, {
7712
7845
  type: "webhook",
7713
7846
  body,
@@ -7723,9 +7856,9 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
7723
7856
  var schedules_default = app15;
7724
7857
 
7725
7858
  // packages/daemon/src/web/api/setup.ts
7726
- import { mkdirSync as mkdirSync7 } from "fs";
7859
+ import { mkdirSync as mkdirSync7, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "fs";
7727
7860
  import { homedir as homedir2 } from "os";
7728
- import { resolve as resolve14 } from "path";
7861
+ import { basename, resolve as resolve14 } from "path";
7729
7862
  import { Hono as Hono19 } from "hono";
7730
7863
  import { setCookie as setCookie2 } from "hono/cookie";
7731
7864
  var DEFAULT_API_URL2 = "https://volute.systems";
@@ -8063,6 +8196,39 @@ setup.post("/spirit", async (c) => {
8063
8196
  config2.setup.spiritName = name;
8064
8197
  const temperament = body.temperament?.trim();
8065
8198
  config2.setup.spiritTemperament = temperament || void 0;
8199
+ const description = body.description?.trim();
8200
+ config2.setup.spiritDescription = description || void 0;
8201
+ const clearOldStash = () => {
8202
+ if (config2.setup?.spiritAvatar) {
8203
+ rmSync4(resolve14(voluteSystemDir(), basename(config2.setup.spiritAvatar)), { force: true });
8204
+ config2.setup.spiritAvatar = void 0;
8205
+ }
8206
+ };
8207
+ if (body.avatar) {
8208
+ const match = /^data:image\/(png|jpeg|webp);base64,([A-Za-z0-9+/=]+)$/.exec(body.avatar);
8209
+ if (!match) {
8210
+ return c.json({ error: "Avatar must be a png, jpeg, or webp image" }, 400);
8211
+ }
8212
+ if (match[2].length > 3 * 1024 * 1024) {
8213
+ return c.json({ error: "Avatar must be under 2MB" }, 400);
8214
+ }
8215
+ let bytes = Buffer.from(match[2], "base64");
8216
+ if (bytes.length > 2 * 1024 * 1024) {
8217
+ return c.json({ error: "Avatar must be under 2MB" }, 400);
8218
+ }
8219
+ let ext = match[1] === "jpeg" ? "jpg" : match[1];
8220
+ const normalized = await normalizeAvatar(bytes);
8221
+ if (normalized) {
8222
+ bytes = normalized.buffer;
8223
+ ext = "webp";
8224
+ }
8225
+ clearOldStash();
8226
+ const filename = `spirit-avatar.${ext}`;
8227
+ writeFileSync9(resolve14(voluteSystemDir(), filename), bytes);
8228
+ config2.setup.spiritAvatar = filename;
8229
+ } else {
8230
+ clearOldStash();
8231
+ }
8066
8232
  writeGlobalConfig(config2);
8067
8233
  return c.json({ ok: true });
8068
8234
  });
@@ -8071,8 +8237,8 @@ setup.post("/complete", async (c) => {
8071
8237
  return c.json({ error: "Setup already complete" }, 400);
8072
8238
  }
8073
8239
  try {
8074
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-4ECYIVGE.js");
8075
- const { startSpiritFull } = await import("./mind-service-E26ZQXDS.js");
8240
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-I5ECLGRI.js");
8241
+ const { startSpiritFull } = await import("./mind-service-WHFBUKZE.js");
8076
8242
  await ensureSpiritProject();
8077
8243
  await syncSpiritTemplate();
8078
8244
  const warnings = [];
@@ -8132,15 +8298,13 @@ setup.post("/complete", async (c) => {
8132
8298
  logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
8133
8299
  if (spiritConversationId && spiritStarted) {
8134
8300
  try {
8135
- const { deliverMessage: deliverMessage2 } = await import("./message-delivery-7URC52ME.js");
8301
+ const { deliverMessage: deliverMessage2 } = await import("./message-delivery-TUXM3AAE.js");
8136
8302
  const { listUsersByType: listUsers2 } = await import("./auth-KRDSM55Q.js");
8137
8303
  const admins = await listUsers2("human");
8138
8304
  const admin2 = admins.find((u) => u.role === "admin");
8139
8305
  if (admin2) {
8140
8306
  const adminName = admin2.display_name || admin2.username;
8141
- const cfg = readGlobalConfig();
8142
- const temperament = cfg.setup?.spiritTemperament;
8143
- const welcomePrompt = `Setup is complete. You are ${spiritName}, the spirit of ${cfg.name ?? "this system"}` + (cfg.description ? ` \u2014 ${cfg.description}` : "") + `. ${adminName} chose your name just now` + (temperament ? ` and imagined your temperament as: "${temperament}"` : "") + `, and is now in your chat. Greet ${adminName} by name and help them create their first mind. Keep it brief \u2014 a short greeting in your own voice, then ask what kind of being they'd like to bring into the world. Remember: minds are beings with their own experience, not tools \u2014 ask about personality and character, never about tasks or utility.`;
8307
+ const welcomePrompt = `Setup is complete, and ${adminName} is now in your chat. Greet ${adminName} by name and help them create their first mind. Keep it brief \u2014 a short greeting in your own voice, then ask what kind of being they'd like to bring into the world. Remember: minds are beings with their own experience, not tools \u2014 ask about personality and character, never about tasks or utility.`;
8144
8308
  await deliverMessage2(spiritName, {
8145
8309
  content: [{ type: "text", text: welcomePrompt }],
8146
8310
  channel: `@${admin2.username}`,
@@ -8174,7 +8338,7 @@ setup.post("/complete", async (c) => {
8174
8338
  var setup_default = setup;
8175
8339
 
8176
8340
  // packages/daemon/src/web/api/skills.ts
8177
- import { existsSync as existsSync9, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync4 } from "fs";
8341
+ import { existsSync as existsSync9, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync5 } from "fs";
8178
8342
  import { tmpdir } from "os";
8179
8343
  import { join, resolve as resolve15 } from "path";
8180
8344
  import AdmZip from "adm-zip";
@@ -8281,7 +8445,7 @@ var app16 = new Hono20().get("/", async (c) => {
8281
8445
  }
8282
8446
  throw e;
8283
8447
  } finally {
8284
- rmSync4(tmpDir, { recursive: true, force: true });
8448
+ rmSync5(tmpDir, { recursive: true, force: true });
8285
8449
  }
8286
8450
  }).get("/:id", async (c) => {
8287
8451
  const id = c.req.param("id");
@@ -8908,12 +9072,12 @@ var app21 = new Hono25().use("*", authMiddleware).get("/", async (c) => {
8908
9072
  var feed_default = app21;
8909
9073
 
8910
9074
  // packages/daemon/src/web/api/variants.ts
8911
- import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
9075
+ import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "fs";
8912
9076
  import { resolve as resolve18 } from "path";
8913
9077
  import { Hono as Hono26 } from "hono";
8914
9078
 
8915
9079
  // packages/daemon/src/lib/mind/farewell.ts
8916
- import { existsSync as existsSync10, readFileSync as readFileSync10, rmSync as rmSync5 } from "fs";
9080
+ import { existsSync as existsSync10, readFileSync as readFileSync10, rmSync as rmSync6 } from "fs";
8917
9081
  import { resolve as resolve16 } from "path";
8918
9082
  var flog = logger_default.child("farewell");
8919
9083
  var FAREWELL_RELPATH = ".mind/farewell.md";
@@ -8956,7 +9120,7 @@ async function runFarewellTurn(opts) {
8956
9120
  const timeoutMs = opts.timeoutMs ?? FAREWELL_TIMEOUT_MS;
8957
9121
  if (!running) return readFarewell(variantDir);
8958
9122
  try {
8959
- rmSync5(farewellPath(variantDir), { force: true });
9123
+ rmSync6(farewellPath(variantDir), { force: true });
8960
9124
  } catch (err) {
8961
9125
  flog.warn(`failed to clear stale farewell note for ${variantName}`, logger_default.errorData(err));
8962
9126
  }
@@ -9218,7 +9382,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
9218
9382
  return c.json({ error: `npm install failed: ${msg}` }, 500);
9219
9383
  }
9220
9384
  if (body.soul) {
9221
- writeFileSync9(resolve18(variantDir, "home/SOUL.md"), body.soul);
9385
+ writeFileSync10(resolve18(variantDir, "home/SOUL.md"), body.soul);
9222
9386
  }
9223
9387
  const variantPort = body.port ?? await nextPort();
9224
9388
  try {
@@ -9855,7 +10019,7 @@ var unifiedChatApp = new Hono28().post(
9855
10019
  logger_default.error("spirit availability check failed \u2014 proceeding with delivery", logger_default.errorData(err));
9856
10020
  }
9857
10021
  const isDM = conv.type === "dm";
9858
- await fanOutToMinds({
10022
+ const { gatedRecipients } = await fanOutToMinds({
9859
10023
  conversationId,
9860
10024
  contentBlocks,
9861
10025
  senderName,
@@ -9865,7 +10029,15 @@ var unifiedChatApp = new Hono28().post(
9865
10029
  // Variant-aware targeting: when targetMind is a variant, route to the variant name
9866
10030
  targetName: baseName ? (username) => username === baseName ? variantName : username : void 0
9867
10031
  });
9868
- return c.json({ ok: true, conversationId, outboundId, spirit: spiritStatus, spiritName });
10032
+ const notice = gatedRecipients.length > 0 ? `Note: your message is held for ${gatedRecipients.join(", ")} pending channel approval \u2014 they haven't routed this channel yet. It will be delivered if they accept the channel.` : void 0;
10033
+ return c.json({
10034
+ ok: true,
10035
+ conversationId,
10036
+ outboundId,
10037
+ spirit: spiritStatus,
10038
+ spiritName,
10039
+ ...notice ? { notice } : {}
10040
+ });
9869
10041
  }
9870
10042
  );
9871
10043
  var app24 = new Hono28().get("/:name/conversations/:id/events", async (c) => {
@@ -10146,8 +10318,8 @@ async function startServer({
10146
10318
  const ext = extname3(filePath);
10147
10319
  const mime = MIME_TYPES2[ext] || "application/octet-stream";
10148
10320
  const body = await readFile2(filePath);
10149
- const basename = filePath.slice(filePath.lastIndexOf("/") + 1);
10150
- const nameWithoutExt = basename.slice(0, basename.lastIndexOf("."));
10321
+ const basename2 = filePath.slice(filePath.lastIndexOf("/") + 1);
10322
+ const nameWithoutExt = basename2.slice(0, basename2.lastIndexOf("."));
10151
10323
  const isHashed = /[-.][\da-f]{8,}$/.test(nameWithoutExt);
10152
10324
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
10153
10325
  return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
@@ -10216,11 +10388,11 @@ if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
10216
10388
  }
10217
10389
  function writeDaemonConfig(systemDir, config2, token) {
10218
10390
  const configPath = resolve20(systemDir, "daemon.json");
10219
- writeFileSync10(configPath, `${JSON.stringify(config2, null, 2)}
10391
+ writeFileSync11(configPath, `${JSON.stringify(config2, null, 2)}
10220
10392
  `, { mode: 420 });
10221
10393
  chmodSync(configPath, 420);
10222
10394
  const tokenPath = resolve20(systemDir, "daemon-token");
10223
- writeFileSync10(tokenPath, `${token}
10395
+ writeFileSync11(tokenPath, `${token}
10224
10396
  `, { mode: 384 });
10225
10397
  chmodSync(tokenPath, 384);
10226
10398
  }
@@ -10344,7 +10516,7 @@ async function startDaemon(opts) {
10344
10516
  process.env.VOLUTE_DAEMON_TOKEN = token;
10345
10517
  process.env.VOLUTE_DAEMON_PORT = String(daemonPort);
10346
10518
  process.env.VOLUTE_DAEMON_HOSTNAME = hostname;
10347
- writeFileSync10(DAEMON_PID_PATH, myPid, { mode: 420 });
10519
+ writeFileSync11(DAEMON_PID_PATH, myPid, { mode: 420 });
10348
10520
  const daemonConfig = { port, hostname };
10349
10521
  if (internalPort) daemonConfig.internalPort = internalPort;
10350
10522
  if (tls) daemonConfig.tls = true;
@@ -10371,7 +10543,7 @@ async function startDaemon(opts) {
10371
10543
  const orphanedTurns = await completeOrphanedTurns();
10372
10544
  summarizeOrphanedTurns(orphanedTurns);
10373
10545
  try {
10374
- const { reconcileVariants } = await import("./variant-cleanup-STC6B5HR.js");
10546
+ const { reconcileVariants } = await import("./variant-cleanup-CZDLIY3F.js");
10375
10547
  await reconcileVariants();
10376
10548
  } catch (err) {
10377
10549
  logger_default.error("failed to reconcile variants", logger_default.errorData(err));
@@ -10407,8 +10579,8 @@ async function startDaemon(opts) {
10407
10579
  try {
10408
10580
  const { isSetupComplete: isSetupComplete2, getSpiritName: getSpiritName2 } = await import("./setup-WZSXHHRJ.js");
10409
10581
  if (isSetupComplete2()) {
10410
- const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-4ECYIVGE.js");
10411
- const { startSpiritFull } = await import("./mind-service-E26ZQXDS.js");
10582
+ const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-I5ECLGRI.js");
10583
+ const { startSpiritFull } = await import("./mind-service-WHFBUKZE.js");
10412
10584
  await ensureSpiritProject();
10413
10585
  const spiritName = getSpiritName2();
10414
10586
  const spiritEntry = await findMind(spiritName);
@@ -10427,7 +10599,7 @@ async function startDaemon(opts) {
10427
10599
  bridgeManager.startBridges(daemonPort).catch((err) => {
10428
10600
  logger_default.warn("failed to start bridges", logger_default.errorData(err));
10429
10601
  });
10430
- import("./cloud-sync-H7EWZASD.js").then(
10602
+ import("./cloud-sync-MJVJ33LD.js").then(
10431
10603
  ({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
10432
10604
  logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
10433
10605
  })
@@ -10435,7 +10607,7 @@ async function startDaemon(opts) {
10435
10607
  logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
10436
10608
  });
10437
10609
  try {
10438
- const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-LBVHH5YV.js");
10610
+ const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-SJVAQLZI.js");
10439
10611
  backfillTemplateHashes().then(() => warnStaleTemplates()).catch((err) => {
10440
10612
  logger_default.warn("failed to check template staleness", logger_default.errorData(err));
10441
10613
  });