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
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  spiritDir
4
- } from "./chunk-K2F237KS.js";
4
+ } from "./chunk-5DBGQBQR.js";
5
5
  import {
6
6
  getScheduler
7
- } from "./chunk-SW2U6HRB.js";
7
+ } from "./chunk-PIZDPY4G.js";
8
8
  import {
9
9
  getDeliveryManager
10
- } from "./chunk-RU74YG46.js";
10
+ } from "./chunk-RQRO6PC7.js";
11
11
  import {
12
12
  getMindManager,
13
13
  resolveMindToken
14
- } from "./chunk-724DVYHU.js";
14
+ } from "./chunk-23UJGVYP.js";
15
15
  import {
16
16
  extractTextContent,
17
17
  getRoutingConfig,
@@ -23,7 +23,7 @@ import {
23
23
  importSkillFromDir,
24
24
  removeSharedSkill,
25
25
  sharedSkillsDir
26
- } from "./chunk-RPPTGPYF.js";
26
+ } from "./chunk-TAWRJ24T.js";
27
27
  import {
28
28
  getOrCreateMindUser,
29
29
  getOrCreateSystemUser,
@@ -38,13 +38,13 @@ import {
38
38
  pendingEventCount,
39
39
  pendingEventsLine,
40
40
  recordNotice
41
- } from "./chunk-AXFLY5GU.js";
41
+ } from "./chunk-IQ7VNWH6.js";
42
42
  import {
43
43
  publish as publish2
44
44
  } from "./chunk-LNNI3MS4.js";
45
45
  import {
46
46
  getPrompt
47
- } from "./chunk-FXWBFDQR.js";
47
+ } from "./chunk-AP2KQMMW.js";
48
48
  import {
49
49
  addMessage,
50
50
  createChannel,
@@ -931,7 +931,7 @@ async function startMindFull(name) {
931
931
  }
932
932
  }
933
933
  async function recordMissingCredentialsNotice(mind, template) {
934
- const { hasUndeliveredEvent, recordNotice: recordNotice2, MIND_LEVEL_THREAD: MIND_LEVEL_THREAD2 } = await import("./system-events-V43HDA3T.js");
934
+ const { hasUndeliveredEvent, recordNotice: recordNotice2, MIND_LEVEL_THREAD: MIND_LEVEL_THREAD2 } = await import("./system-events-YTOU66QI.js");
935
935
  const warning = await missingCredentialWarning(template, readMindModel(mind, template), mind);
936
936
  if (!warning) return;
937
937
  if (await hasUndeliveredEvent(mind, "no_credentials")) return;
@@ -1190,6 +1190,13 @@ var SleepManager = class {
1190
1190
  this.transitioning.add(name);
1191
1191
  state.wokenByTrigger = false;
1192
1192
  try {
1193
+ await recordNotice({
1194
+ mind: name,
1195
+ thread: MIND_LEVEL_THREAD,
1196
+ kind: "crash",
1197
+ reason: "trigger_wake_crash",
1198
+ detail: await getPrompt("trigger_wake_crash_notice")
1199
+ });
1193
1200
  try {
1194
1201
  await sleepMind(name);
1195
1202
  } catch (err) {
@@ -1246,6 +1253,15 @@ var SleepManager = class {
1246
1253
  const wakeTime = formatWakeTime(wakeAt);
1247
1254
  const preSleepMsg = await getPrompt("pre_sleep", { wakeTime });
1248
1255
  const { delivered } = await deliverEvent(name, { type: "sleep", body: preSleepMsg });
1256
+ if (!delivered) {
1257
+ await recordNotice({
1258
+ mind: name,
1259
+ thread: MIND_LEVEL_THREAD,
1260
+ kind: "delivery_failed",
1261
+ reason: "pre_sleep_failed",
1262
+ detail: await getPrompt("pre_sleep_failure_notice")
1263
+ });
1264
+ }
1249
1265
  if (delivered) await this.waitForIdle(name, 12e4);
1250
1266
  await new Promise((r) => setTimeout(r, 3e3));
1251
1267
  await sleepMind(name);
@@ -1436,7 +1452,7 @@ var SleepManager = class {
1436
1452
  * the real delivery stack. Returns whether the batch was handed off to the mind.
1437
1453
  */
1438
1454
  async deliverQueuedBatch(name, payloads) {
1439
- const { deliverBatch: deliverBatch2 } = await import("./message-delivery-7URC52ME.js");
1455
+ const { deliverBatch: deliverBatch2 } = await import("./message-delivery-TUXM3AAE.js");
1440
1456
  return deliverBatch2(name, payloads);
1441
1457
  }
1442
1458
  // --- Wake failure handling (#419) ---
@@ -1663,6 +1679,22 @@ var SleepManager = class {
1663
1679
  }
1664
1680
  }
1665
1681
  }
1682
+ const codexSessionsDir = resolve4(dir, ".mind", "codex-sessions");
1683
+ if (existsSync4(codexSessionsDir)) {
1684
+ const archiveDir = resolve4(codexSessionsDir, "archive");
1685
+ mkdirSync2(archiveDir, { recursive: true });
1686
+ for (const file of readdirSync(codexSessionsDir)) {
1687
+ if (file === "archive" || !file.endsWith(".json")) continue;
1688
+ const src = resolve4(codexSessionsDir, file);
1689
+ const base = file.replace(/\.json$/, "");
1690
+ const dest = resolve4(archiveDir, `${base}-${timestamp}.json`);
1691
+ try {
1692
+ renameSync(src, dest);
1693
+ } catch (err) {
1694
+ slog.warn(`failed to archive codex-session ${file} for ${name}`, logger_default.errorData(err));
1695
+ }
1696
+ }
1697
+ }
1666
1698
  }
1667
1699
  async runWakeContextScript(name, sleepingSince, duration) {
1668
1700
  const scriptPath = resolve4(mindDir(name), "home", ".local", "hooks", "wake-context.sh");
@@ -1961,6 +1993,10 @@ function willGate(baseName, payload) {
1961
1993
  });
1962
1994
  return shouldGate(config, route);
1963
1995
  }
1996
+ async function willGateMessage(mindName, payload) {
1997
+ const baseName = await getBaseName(mindName);
1998
+ return willGate(baseName, payload);
1999
+ }
1964
2000
  async function deliverMessage(mindName, payload, opts = {}) {
1965
2001
  try {
1966
2002
  const baseName = await getBaseName(mindName);
@@ -2910,6 +2946,7 @@ export {
2910
2946
  recordOutbound,
2911
2947
  linkToolResultToTurn,
2912
2948
  resolveSleepAction,
2949
+ willGateMessage,
2913
2950
  deliverMessage,
2914
2951
  deliverBatch,
2915
2952
  ensureSystemChannel,
@@ -94,6 +94,8 @@ function eventLabel(type, meta) {
94
94
  return s("reason") ? `Notice: ${s("reason")}` : "Notice";
95
95
  case "delivery_failed":
96
96
  return "Delivery failed";
97
+ case "context_lost":
98
+ return "Context lost";
97
99
  case "join_blocked":
98
100
  return "Variant join blocked";
99
101
  default:
@@ -103,6 +105,16 @@ function eventLabel(type, meta) {
103
105
  return type.charAt(0).toUpperCase() + type.slice(1);
104
106
  }
105
107
  }
108
+ var NOTICE_KINDS = [
109
+ "turn_error",
110
+ "crash",
111
+ "budget",
112
+ "startup",
113
+ "extension",
114
+ "delivery_failed",
115
+ "context_lost",
116
+ "join_blocked"
117
+ ];
106
118
  async function recordNotice(input) {
107
119
  const type = input.kind === "budget" ? "budget" : "notice";
108
120
  await deliverEvent(input.mind, {
@@ -111,6 +123,7 @@ async function recordNotice(input) {
111
123
  thread: input.thread,
112
124
  delivery: "next-turn",
113
125
  meta: {
126
+ ...input.meta ?? {},
114
127
  subtype: input.kind,
115
128
  reason: input.reason,
116
129
  ...input.raw ? { raw: input.raw } : {}
@@ -244,7 +257,7 @@ async function deliverEvent(mind, input) {
244
257
  return { id: eventId, delivered: false };
245
258
  }
246
259
  const baseName = await getBaseName(mind);
247
- const { getSleepManagerIfReady } = await import("./sleep-manager-OFP2GFXF.js");
260
+ const { getSleepManagerIfReady } = await import("./sleep-manager-NWUCRBZB.js");
248
261
  const sleepManager = getSleepManagerIfReady();
249
262
  const sleeping = !input.force && sleepManager?.isSleeping(baseName);
250
263
  const behavior = input.whileSleeping ?? "queue";
@@ -552,6 +565,7 @@ export {
552
565
  MIND_LEVEL_THREAD,
553
566
  parseMeta,
554
567
  eventLabel,
568
+ NOTICE_KINDS,
555
569
  recordNotice,
556
570
  eventChannel,
557
571
  deliverEvent,
@@ -561,6 +575,7 @@ export {
561
575
  pendingEventsLine,
562
576
  drainEvents,
563
577
  formatEvents,
578
+ localHM,
564
579
  clearDeliveredEvents,
565
580
  latestFailureEvent,
566
581
  latestEvent,
@@ -6,6 +6,10 @@ import {
6
6
  import {
7
7
  resolveMindName
8
8
  } from "./chunk-BTY4WNFE.js";
9
+ import {
10
+ command,
11
+ subcommands
12
+ } from "./chunk-TXSA4Q3V.js";
9
13
  import {
10
14
  daemonFetch
11
15
  } from "./chunk-M74I3HHF.js";
@@ -13,10 +17,6 @@ import {
13
17
  getClient,
14
18
  urlOf
15
19
  } from "./chunk-LOPXTW6H.js";
16
- import {
17
- command,
18
- subcommands
19
- } from "./chunk-TXSA4Q3V.js";
20
20
 
21
21
  // packages/cli/src/commands/clock.ts
22
22
  import { CronExpressionParser } from "cron-parser";
@@ -279,11 +279,11 @@ var cmd = subcommands({
279
279
  },
280
280
  sleep: {
281
281
  description: "Put a mind to sleep",
282
- run: (args) => import("./mind-sleep-LZAFBDZD.js").then((m) => m.run(args))
282
+ run: (args) => import("./mind-sleep-D3DEYAWG.js").then((m) => m.run(args))
283
283
  },
284
284
  wake: {
285
285
  description: "Wake a sleeping mind",
286
- run: (args) => import("./mind-wake-LDGPRA42.js").then((m) => m.run(args))
286
+ run: (args) => import("./mind-wake-DCDFFQKX.js").then((m) => m.run(args))
287
287
  }
288
288
  },
289
289
  footer: "Use --mind <name> or VOLUTE_MIND to identify the mind."
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  getSleepManagerIfReady,
4
4
  startSpiritFull
5
- } from "./chunk-ZEZQNP2G.js";
5
+ } from "./chunk-HASADR3E.js";
6
6
  import {
7
7
  spiritCreationInProgress
8
- } from "./chunk-K2F237KS.js";
8
+ } from "./chunk-5DBGQBQR.js";
9
9
  import {
10
10
  MindStartupError,
11
11
  tryGetMindManager
12
- } from "./chunk-724DVYHU.js";
12
+ } from "./chunk-23UJGVYP.js";
13
13
  import {
14
14
  logger_default
15
15
  } from "./chunk-QUSMYGNQ.js";
@@ -6,10 +6,15 @@ import {
6
6
  getMindToken,
7
7
  loadJsonMap,
8
8
  saveJsonMapAsync
9
- } from "./chunk-724DVYHU.js";
9
+ } from "./chunk-23UJGVYP.js";
10
10
  import {
11
- deliverEvent
12
- } from "./chunk-AXFLY5GU.js";
11
+ MIND_LEVEL_THREAD,
12
+ deliverEvent,
13
+ recordNotice
14
+ } from "./chunk-IQ7VNWH6.js";
15
+ import {
16
+ getPrompt
17
+ } from "./chunk-AP2KQMMW.js";
13
18
  import {
14
19
  isSandboxEnabled,
15
20
  wrapForSandbox
@@ -197,6 +202,18 @@ ${stderr}` : ""}`;
197
202
  }
198
203
  } catch (err) {
199
204
  slog.warn(`failed to fire "${schedule.id}" for ${mindName}`, logger_default.errorData(err));
205
+ const detail = await getPrompt("schedule_failure_notice", {
206
+ id: schedule.id,
207
+ reason: err instanceof Error && err.message ? err.message : String(err)
208
+ });
209
+ const thread = schedule.thread && !schedule.thread.startsWith("new-") ? schedule.thread : MIND_LEVEL_THREAD;
210
+ await recordNotice({
211
+ mind: mindName,
212
+ thread,
213
+ kind: "delivery_failed",
214
+ reason: "schedule_failed",
215
+ detail
216
+ });
200
217
  }
201
218
  }
202
219
  removeSchedule(mindName, scheduleId) {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  MEMORY_PLACEHOLDER_MARKER,
4
4
  ORIENTATION_MARKER
5
- } from "./chunk-FXWBFDQR.js";
5
+ } from "./chunk-AP2KQMMW.js";
6
6
  import {
7
7
  safeResolveWithinBase
8
8
  } from "./chunk-DW4TRDOZ.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  tryGetMindManager
4
- } from "./chunk-724DVYHU.js";
4
+ } from "./chunk-23UJGVYP.js";
5
5
  import {
6
6
  extractTextContent,
7
7
  getRoutingConfig,
@@ -12,11 +12,11 @@ import {
12
12
  } from "./chunk-UDZLPR34.js";
13
13
  import {
14
14
  linkInboundToActiveTurn
15
- } from "./chunk-YVR6EHWL.js";
15
+ } from "./chunk-VDZ4I4ZP.js";
16
16
  import {
17
17
  MIND_LEVEL_THREAD,
18
18
  newEphemeralSession
19
- } from "./chunk-AXFLY5GU.js";
19
+ } from "./chunk-IQ7VNWH6.js";
20
20
  import {
21
21
  publish
22
22
  } from "./chunk-LNNI3MS4.js";
@@ -36,6 +36,9 @@ import {
36
36
  import {
37
37
  logger_default
38
38
  } from "./chunk-QUSMYGNQ.js";
39
+ import {
40
+ slugify
41
+ } from "./chunk-LGNUFVMR.js";
39
42
  import {
40
43
  findMind,
41
44
  getBaseName,
@@ -243,14 +246,22 @@ var DeliveryManager = class {
243
246
  isMindRunning = (name) => tryGetMindManager()?.isRunning(name) ?? false;
244
247
  /** Delivers a channel event to a mind (invites, release summaries); overridable in tests. */
245
248
  notify = async (mindName, text) => {
246
- const { deliverEvent } = await import("./system-events-V43HDA3T.js");
249
+ const { deliverEvent } = await import("./system-events-YTOU66QI.js");
247
250
  await deliverEvent(mindName, { type: "channel", body: text });
248
251
  };
249
252
  /** Surfaces a dead-lettered delivery as a next-turn failure notice; overridable in tests. */
250
253
  notifyFailure = async (input) => {
251
- const { recordNotice } = await import("./system-events-V43HDA3T.js");
254
+ const { recordNotice } = await import("./system-events-YTOU66QI.js");
252
255
  await recordNotice(input);
253
256
  };
257
+ /**
258
+ * Tells a mind *sender* its message was dropped (dead-lettered on the recipient's
259
+ * side); no-ops for human senders. Overridable in tests.
260
+ */
261
+ notifySenderFailure = async (sender, channel, reason) => {
262
+ const { recordSenderDeliveryFailure } = await import("./delivery-notices-65TB3CBX.js");
263
+ await recordSenderDeliveryFailure(sender, channel, reason);
264
+ };
254
265
  constructor() {
255
266
  setRoutesChangeListener((mind) => {
256
267
  this.releaseGated(mind).catch(
@@ -270,6 +281,10 @@ var DeliveryManager = class {
270
281
  setFailureNotifier(fn) {
271
282
  this.notifyFailure = fn;
272
283
  }
284
+ /** Test seam: capture/override sender-side dead-letter notices. */
285
+ setSenderFailureNotifier(fn) {
286
+ this.notifySenderFailure = fn;
287
+ }
273
288
  // --- Public API ---
274
289
  /**
275
290
  * Route and deliver a message to a mind. This is the main entry point.
@@ -875,6 +890,25 @@ var DeliveryManager = class {
875
890
  } catch (err) {
876
891
  dlog.warn(`failed to send dead-letter notice for ${mind}`, logger_default.errorData(err));
877
892
  }
893
+ const senderPairs = /* @__PURE__ */ new Map();
894
+ for (const r of rows) {
895
+ if (!r.sender || r.sender === r.mind) continue;
896
+ const recipient = r.target_mind ?? r.mind;
897
+ const channel = !r.channel || r.channel === `@${slugify(r.sender)}` ? `@${recipient}` : r.channel;
898
+ senderPairs.set(`${r.sender}
899
+ ${channel}`, { sender: r.sender, channel });
900
+ }
901
+ for (const { sender, channel } of senderPairs.values()) {
902
+ try {
903
+ await this.notifySenderFailure(
904
+ sender,
905
+ channel,
906
+ `the recipient's process rejected it after ${MAX_DELIVERY_ATTEMPTS} attempts`
907
+ );
908
+ } catch (err) {
909
+ dlog.warn(`failed to send sender dead-letter notice for ${sender}`, logger_default.errorData(err));
910
+ }
911
+ }
878
912
  }
879
913
  async deliverToMind(mindName, session, payload, sessionConfig, queueId) {
880
914
  if (queueId != null) this.inFlight.add(queueId);
@@ -1130,7 +1164,7 @@ var DeliveryManager = class {
1130
1164
  const details = detailLines.length > 0 ? `${detailLines.join("\n")}
1131
1165
 
1132
1166
  ` : "\n";
1133
- const { getPrompt } = await import("./prompts-NBO3HRK3.js");
1167
+ const { getPrompt } = await import("./prompts-HNKGCAEY.js");
1134
1168
  const notification = await getPrompt("channel_invite", {
1135
1169
  channel,
1136
1170
  heldLine,
@@ -45,7 +45,7 @@ async function initDefaultSkills() {
45
45
  const config = readGlobalConfig();
46
46
  let extensionSkills = [];
47
47
  try {
48
- const { getExtensionStandardSkills } = await import("./extensions-N6L5NYTK.js");
48
+ const { getExtensionStandardSkills } = await import("./extensions-VACUKFA5.js");
49
49
  extensionSkills = getExtensionStandardSkills();
50
50
  } catch (err) {
51
51
  logger_default.warn("failed to load extension standard skills during init", logger_default.errorData(err));
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getMindManager
4
- } from "./chunk-724DVYHU.js";
4
+ } from "./chunk-23UJGVYP.js";
5
5
  import {
6
6
  chownMindDir,
7
7
  gitExec
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ MIND_LEVEL_THREAD,
4
+ localHM,
5
+ parseMeta,
6
+ recordNotice
7
+ } from "./chunk-IQ7VNWH6.js";
8
+ import {
9
+ getPrompt
10
+ } from "./chunk-AP2KQMMW.js";
11
+ import {
12
+ logger_default
13
+ } from "./chunk-QUSMYGNQ.js";
14
+ import {
15
+ findMind,
16
+ getDb
17
+ } from "./chunk-H6X6CKDN.js";
18
+ import {
19
+ systemEvents
20
+ } from "./chunk-2RNMBXD2.js";
21
+
22
+ // packages/daemon/src/lib/chat/delivery-notices.ts
23
+ import { and, desc, eq, isNull, sql } from "drizzle-orm";
24
+ var nlog = logger_default.child("delivery-notices");
25
+ var COALESCE_WINDOW_MINUTES = 15;
26
+ var recordChains = /* @__PURE__ */ new Map();
27
+ async function recordDeliveryFailure(input) {
28
+ const key = `${input.mind}
29
+ ${input.channel}`;
30
+ const next = (recordChains.get(key) ?? Promise.resolve()).then(
31
+ () => recordDeliveryFailureUnserialized(input)
32
+ );
33
+ recordChains.set(key, next);
34
+ await next;
35
+ if (recordChains.get(key) === next) recordChains.delete(key);
36
+ }
37
+ async function recordDeliveryFailureUnserialized(input) {
38
+ const thread = input.thread ?? MIND_LEVEL_THREAD;
39
+ try {
40
+ const db = await getDb();
41
+ const existing = await db.select().from(systemEvents).where(
42
+ and(
43
+ eq(systemEvents.mind, input.mind),
44
+ eq(systemEvents.type, "notice"),
45
+ eq(systemEvents.delivery, "next-turn"),
46
+ eq(systemEvents.thread, thread),
47
+ isNull(systemEvents.delivered_at),
48
+ // Literal subtype + bound channel value — not string-built SQL.
49
+ sql`json_extract(${systemEvents.meta}, '$.subtype') = 'delivery_failed'`,
50
+ sql`json_extract(${systemEvents.meta}, '$.channel') = ${input.channel}`,
51
+ sql`${systemEvents.created_at} > datetime('now', ${`-${COALESCE_WINDOW_MINUTES} minutes`})`
52
+ )
53
+ ).orderBy(desc(systemEvents.id)).limit(1).get();
54
+ if (existing) {
55
+ const meta = parseMeta(existing.meta, `event ${existing.id}`);
56
+ const count = (typeof meta.count === "number" ? meta.count : 1) + 1;
57
+ const body2 = await getPrompt("delivery_failure_coalesced", {
58
+ count: String(count),
59
+ channel: input.channel,
60
+ since: localHM(existing.created_at),
61
+ reason: input.reason
62
+ });
63
+ await db.update(systemEvents).set({ body: body2, meta: JSON.stringify({ ...meta, count }) }).where(eq(systemEvents.id, existing.id));
64
+ return;
65
+ }
66
+ const body = await getPrompt("delivery_failure_notice", {
67
+ channel: input.channel,
68
+ reason: input.reason
69
+ });
70
+ await recordNotice({
71
+ mind: input.mind,
72
+ thread,
73
+ kind: "delivery_failed",
74
+ reason: "delivery_failed",
75
+ detail: body,
76
+ meta: { channel: input.channel, count: 1 }
77
+ });
78
+ } catch (err) {
79
+ nlog.warn(
80
+ `failed to record delivery-failure notice for ${input.mind} \u2192 ${input.channel}`,
81
+ logger_default.errorData(err)
82
+ );
83
+ }
84
+ }
85
+ async function recordSenderDeliveryFailure(sender, channel, reason) {
86
+ try {
87
+ const entry = await findMind(sender);
88
+ if (!entry) return;
89
+ await recordDeliveryFailure({ mind: entry.parent ?? entry.name, channel, reason });
90
+ } catch (err) {
91
+ nlog.warn(
92
+ `failed to record sender delivery-failure notice for ${sender} \u2192 ${channel}`,
93
+ logger_default.errorData(err)
94
+ );
95
+ }
96
+ }
97
+
98
+ export {
99
+ COALESCE_WINDOW_MINUTES,
100
+ recordDeliveryFailure,
101
+ recordSenderDeliveryFailure
102
+ };