volute 0.38.0 → 0.40.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 (109) hide show
  1. package/dist/{activity-events-N6HCHU4P.js → activity-events-OJZ7G5CG.js} +3 -3
  2. package/dist/{ai-service-C2YNARGH.js → ai-service-JMV4KZN4.js} +8 -4
  3. package/dist/{archive-AWIJTVQV.js → archive-BC2MTNPV.js} +3 -3
  4. package/dist/{auth-2QOOPMBX.js → auth-2IMZ6N5G.js} +4 -4
  5. package/dist/{chat-XL7CVWVJ.js → chat-O5QCGCUG.js} +2 -2
  6. package/dist/{chunk-A6FLW5XD.js → chunk-2AQCEQYN.js} +1 -1
  7. package/dist/{chunk-3F7XK5Q7.js → chunk-3XSFMN3H.js} +1 -1
  8. package/dist/{chunk-NGXQ2ESO.js → chunk-43PVCF4V.js} +3 -3
  9. package/dist/{chunk-N42QMDID.js → chunk-5VBXKFPO.js} +2 -2
  10. package/dist/{chunk-BIEWHAAM.js → chunk-76Q6YLJL.js} +1 -1
  11. package/dist/{chunk-5DPRTREW.js → chunk-B7YJUWMM.js} +3 -3
  12. package/dist/{chunk-XLBQYIHH.js → chunk-DNQPHLGM.js} +1 -1
  13. package/dist/{chunk-SNW2NPP4.js → chunk-FBV22PFY.js} +1 -1
  14. package/dist/{chunk-WC635OPK.js → chunk-FRJ73IWR.js} +1 -1
  15. package/dist/{chunk-PMMHVSCR.js → chunk-HAJHDGBV.js} +1 -1
  16. package/dist/{chunk-SZJWC2GA.js → chunk-HEZM5GCV.js} +2 -2
  17. package/dist/{chunk-PLL2FM7A.js → chunk-JSITYTIL.js} +6 -6
  18. package/dist/{chunk-CJ26DXZL.js → chunk-MHFAWJCC.js} +16 -0
  19. package/dist/{chunk-7AZQFSOV.js → chunk-PC55DGNX.js} +1 -1
  20. package/dist/{chunk-2NHRJ3YO.js → chunk-PDSA3ILI.js} +3 -3
  21. package/dist/{chunk-ORNY3MZR.js → chunk-PGX52NFO.js} +15 -1
  22. package/dist/{chunk-UIM5NHPP.js → chunk-PHR4XQPL.js} +3 -3
  23. package/dist/chunk-PIRL2HAO.js +124 -0
  24. package/dist/{chunk-JOJT34M2.js → chunk-PZTVQL3J.js} +2 -2
  25. package/dist/{chunk-GVVVMZ4J.js → chunk-RMZSICLS.js} +1 -1
  26. package/dist/{chunk-LQ6Z4FXN.js → chunk-S4YO5OWV.js} +1 -1
  27. package/dist/{chunk-TNZ5XQA4.js → chunk-SGC6CDXB.js} +2 -2
  28. package/dist/{chunk-LN67VPZJ.js → chunk-SOPMVTTW.js} +2 -2
  29. package/dist/{chunk-VUM2K6EN.js → chunk-T26YLQPU.js} +5 -5
  30. package/dist/{chunk-2TR2OPVA.js → chunk-WGRMLXTH.js} +8 -8
  31. package/dist/{chunk-TEZRVSSB.js → chunk-XUJR6NZW.js} +513 -335
  32. package/dist/cli.js +15 -15
  33. package/dist/{cloud-sync-PEM3IVI4.js → cloud-sync-5JF2Z7VM.js} +16 -16
  34. package/dist/{conversations-G6YRSABR.js → conversations-LUVHGQSS.js} +4 -4
  35. package/dist/{create-PN73742N.js → create-TDQM3SHV.js} +1 -1
  36. package/dist/{daemon-restart-6QONRBTK.js → daemon-restart-XHDJDOPQ.js} +8 -8
  37. package/dist/daemon.js +221 -118
  38. package/dist/{db-CBOCDYVA.js → db-2GIS7HSG.js} +2 -2
  39. package/dist/delivery-manager-L5WFP2ND.js +30 -0
  40. package/dist/{delivery-router-QTFEZ26O.js → delivery-router-IU4OMVKZ.js} +3 -3
  41. package/dist/down-KIJVZ3OC.js +17 -0
  42. package/dist/echo-text-TJWCUBPB.js +31 -0
  43. package/dist/{exec-ONYZEA5B.js → exec-BGMU7VXR.js} +4 -4
  44. package/dist/{export-JPDBQESV.js → export-RKUWSQSG.js} +3 -3
  45. package/dist/{extensions-P477XR46.js → extensions-VN5SEVRP.js} +16 -16
  46. package/dist/{files-LAQ3NXQK.js → files-J2CKZ6PK.js} +3 -3
  47. package/dist/{import-EROF27RH.js → import-KVY6BYXG.js} +6 -6
  48. package/dist/{isolation-G5J3MTKU.js → isolation-MM7YHK6J.js} +3 -3
  49. package/dist/{login-F6YMAVLE.js → login-OHM32QVD.js} +2 -2
  50. package/dist/{logout-HHPH52KZ.js → logout-74WBDMOE.js} +2 -2
  51. package/dist/{message-delivery-54IXVE5H.js → message-delivery-VBBAJX3J.js} +16 -16
  52. package/dist/{mind-G5HDKBKL.js → mind-PUPXDIYQ.js} +5 -5
  53. package/dist/{mind-activity-tracker-42ENM32S.js → mind-activity-tracker-7GE24YZE.js} +4 -4
  54. package/dist/mind-manager-4Q6KGZHL.js +30 -0
  55. package/dist/mind-service-7OD4PRO5.js +36 -0
  56. package/dist/{package-LYQHSDPG.js → package-6YPVWGD3.js} +1 -1
  57. package/dist/{registry-KMELPC3X.js → registry-L272BZJR.js} +2 -2
  58. package/dist/{sandbox-PQYEICEF.js → sandbox-BQAFYHLE.js} +6 -6
  59. package/dist/scheduler-7E22Q7IC.js +30 -0
  60. package/dist/{schema-K575EBPE.js → schema-HHYJDG7B.js} +3 -1
  61. package/dist/{seed-3KH4ZRJL.js → seed-4V2O7FQE.js} +1 -1
  62. package/dist/{seed-cmd-6A76SSAA.js → seed-cmd-JKDEW4MP.js} +2 -2
  63. package/dist/{seed-create-XXRRGZCO.js → seed-create-EPAO3H5F.js} +3 -3
  64. package/dist/{seed-sprout-HLMUH2AI.js → seed-sprout-EONCL4DU.js} +8 -8
  65. package/dist/{send-7CIP5GLS.js → send-232RAHPX.js} +3 -3
  66. package/dist/{service-RH6Q2XWR.js → service-AG5BKRUV.js} +5 -5
  67. package/dist/{service-install-AIQBLE6P.js → service-install-HVAEUBAH.js} +6 -6
  68. package/dist/{setup-PF7JSFMO.js → setup-IL7QJZN4.js} +3 -3
  69. package/dist/{setup-NPAZXBIJ.js → setup-PSA7LJ5U.js} +8 -8
  70. package/dist/{skills-NVOWS5NY.js → skills-SLEY5X6W.js} +6 -6
  71. package/dist/sleep-manager-27S7MKJO.js +34 -0
  72. package/dist/{spirit-ZFYG4JOH.js → spirit-7BUHSEO2.js} +8 -8
  73. package/dist/{sprout-FLBCETYG.js → sprout-JWQ57KF3.js} +1 -1
  74. package/dist/{status-TGOKAFW3.js → status-6GSOSYOD.js} +6 -6
  75. package/dist/system-chat-EIINIHFB.js +34 -0
  76. package/dist/{tailscale-LTYNKIPZ.js → tailscale-6MHNLBAX.js} +2 -2
  77. package/dist/up-4XS3RCPP.js +19 -0
  78. package/dist/{update-ZCTQ6UGY.js → update-BT2PY73H.js} +6 -6
  79. package/dist/{update-check-IKS7SGK5.js → update-check-Y3HBEMF2.js} +3 -3
  80. package/dist/{version-notify-764EXVQQ.js → version-notify-NFQMI5IY.js} +17 -17
  81. package/dist/web-assets/assets/index-DqHSW9Fr.css +1 -0
  82. package/dist/web-assets/assets/index-Jluza4c-.js +73 -0
  83. package/dist/web-assets/index.html +2 -2
  84. package/drizzle/0009_mind_notices.sql +14 -0
  85. package/drizzle/meta/_journal.json +7 -0
  86. package/package.json +1 -1
  87. package/templates/_base/.init/.local/hooks/pre-prompt/notices.ts +46 -0
  88. package/templates/_base/src/lib/context-breakdown.ts +281 -126
  89. package/templates/_base/src/lib/daemon-client.ts +5 -2
  90. package/templates/_base/src/lib/transparency.ts +5 -3
  91. package/templates/_base/src/lib/volute-server.ts +23 -0
  92. package/templates/claude/src/agent.ts +54 -16
  93. package/templates/claude/src/server.ts +1 -0
  94. package/templates/codex/src/agent.ts +51 -12
  95. package/templates/codex/src/server.ts +1 -0
  96. package/templates/pi/src/agent.ts +72 -13
  97. package/templates/pi/src/server.ts +1 -0
  98. package/dist/chunk-KXXJYY62.js +0 -112
  99. package/dist/delivery-manager-IMCRV6A3.js +0 -30
  100. package/dist/down-5XZWH4ZP.js +0 -17
  101. package/dist/echo-text-ADKLNTIA.js +0 -31
  102. package/dist/mind-manager-5G6P2EAT.js +0 -30
  103. package/dist/mind-service-FDATHL6X.js +0 -36
  104. package/dist/scheduler-ZRUZNQI5.js +0 -30
  105. package/dist/sleep-manager-VPPQXBPH.js +0 -34
  106. package/dist/system-chat-YUIT7RA6.js +0 -34
  107. package/dist/up-YRZAEZ3Z.js +0 -19
  108. package/dist/web-assets/assets/index-BI7hUTBr.js +0 -73
  109. package/dist/web-assets/assets/index-BJifO9h_.css +0 -1
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  loadMergedEnv
4
- } from "./chunk-PMMHVSCR.js";
4
+ } from "./chunk-HAJHDGBV.js";
5
5
  import {
6
6
  spiritDir
7
- } from "./chunk-2TR2OPVA.js";
7
+ } from "./chunk-WGRMLXTH.js";
8
8
  import {
9
9
  hashSkillDir,
10
10
  importSkillFromDir,
11
11
  removeSharedSkill,
12
12
  sharedSkillsDir
13
- } from "./chunk-VUM2K6EN.js";
13
+ } from "./chunk-T26YLQPU.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-5DPRTREW.js";
23
+ } from "./chunk-B7YJUWMM.js";
24
24
  import {
25
25
  readVoluteConfig,
26
26
  writeVoluteConfig
@@ -28,45 +28,46 @@ import {
28
28
  import {
29
29
  isSandboxEnabled,
30
30
  wrapForSandbox
31
- } from "./chunk-KXXJYY62.js";
31
+ } from "./chunk-PIRL2HAO.js";
32
+ import {
33
+ markIdle,
34
+ onMindEvent
35
+ } from "./chunk-RMZSICLS.js";
32
36
  import {
33
37
  extractTextContent,
34
38
  getRoutingConfig,
35
39
  resolveDeliveryMode,
36
40
  resolveRoute
37
- } from "./chunk-7AZQFSOV.js";
38
- import {
39
- markIdle
40
- } from "./chunk-GVVVMZ4J.js";
41
+ } from "./chunk-PC55DGNX.js";
41
42
  import {
42
43
  exec
43
- } from "./chunk-3F7XK5Q7.js";
44
+ } from "./chunk-3XSFMN3H.js";
44
45
  import {
45
46
  chownMindDir,
46
47
  isIsolationEnabled,
47
48
  mindUserName,
48
49
  wrapForIsolation
49
- } from "./chunk-SNW2NPP4.js";
50
+ } from "./chunk-FBV22PFY.js";
51
+ import {
52
+ aiCompleteUtility,
53
+ getAiConfig,
54
+ resolveApiKey
55
+ } from "./chunk-PGX52NFO.js";
56
+ import {
57
+ readGlobalConfig,
58
+ writeGlobalConfig
59
+ } from "./chunk-2AQCEQYN.js";
50
60
  import {
51
61
  getOrCreateMindUser,
52
62
  getOrCreateSystemUser,
53
63
  getUser,
54
64
  getUserByUsername,
55
65
  syncMindProfile
56
- } from "./chunk-UIM5NHPP.js";
66
+ } from "./chunk-PHR4XQPL.js";
57
67
  import {
58
68
  publish,
59
69
  subscribe
60
- } from "./chunk-N42QMDID.js";
61
- import {
62
- aiCompleteUtility,
63
- getAiConfig,
64
- resolveApiKey
65
- } from "./chunk-ORNY3MZR.js";
66
- import {
67
- readGlobalConfig,
68
- writeGlobalConfig
69
- } from "./chunk-A6FLW5XD.js";
70
+ } from "./chunk-5VBXKFPO.js";
70
71
  import {
71
72
  logger_default
72
73
  } from "./chunk-T2TP6ZC6.js";
@@ -79,37 +80,38 @@ import {
79
80
  stateDir,
80
81
  voluteHome,
81
82
  voluteSystemDir
82
- } from "./chunk-2NHRJ3YO.js";
83
+ } from "./chunk-PDSA3ILI.js";
83
84
  import {
84
85
  activity,
85
86
  conversationParticipants,
86
87
  deliveryQueue,
87
88
  messages,
88
89
  mindHistory,
90
+ mindNotices,
89
91
  summaries,
90
92
  systemPrompts,
91
93
  turns,
92
94
  users
93
- } from "./chunk-CJ26DXZL.js";
95
+ } from "./chunk-MHFAWJCC.js";
94
96
 
95
97
  // packages/daemon/src/lib/delivery/message-delivery.ts
96
- 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";
97
99
 
98
100
  // packages/daemon/src/lib/daemon/sleep-manager.ts
99
101
  import { execFile as execFile2, spawn as spawnChild } from "child_process";
100
102
  import {
101
- existsSync as existsSync7,
102
- mkdirSync as mkdirSync4,
103
+ existsSync as existsSync8,
104
+ mkdirSync as mkdirSync5,
103
105
  readdirSync as readdirSync2,
104
- readFileSync as readFileSync6,
106
+ readFileSync as readFileSync7,
105
107
  readlinkSync,
106
108
  renameSync,
107
- writeFileSync as writeFileSync5
109
+ writeFileSync as writeFileSync6
108
110
  } from "fs";
109
- import { resolve as resolve6 } from "path";
111
+ import { resolve as resolve7 } from "path";
110
112
  import { promisify as promisify2 } from "util";
111
113
  import { CronExpressionParser as CronExpressionParser2 } from "cron-parser";
112
- 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";
113
115
 
114
116
  // packages/daemon/src/lib/prompts.ts
115
117
  import { eq } from "drizzle-orm";
@@ -325,8 +327,8 @@ async function getMindPromptDefaults() {
325
327
 
326
328
  // packages/daemon/src/lib/daemon/mind-manager.ts
327
329
  import { execFile, spawn } from "child_process";
328
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
329
- 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";
330
332
  import { promisify } from "util";
331
333
 
332
334
  // packages/daemon/src/lib/util/json-state.ts
@@ -435,6 +437,78 @@ var RotatingLog = class extends Writable {
435
437
  }
436
438
  };
437
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
+
438
512
  // packages/daemon/src/lib/daemon/mind-tokens.ts
439
513
  import { randomUUID } from "crypto";
440
514
  var tokenToMind = /* @__PURE__ */ new Map();
@@ -457,6 +531,74 @@ function resolveMindToken(token) {
457
531
  return tokenToMind.get(token) ?? null;
458
532
  }
459
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
+
460
602
  // packages/daemon/src/lib/daemon/restart-tracker.ts
461
603
  var DEFAULT_MAX_ATTEMPTS = 5;
462
604
  var DEFAULT_BASE_DELAY = 3e3;
@@ -504,10 +646,10 @@ var RestartTracker = class {
504
646
 
505
647
  // packages/daemon/src/lib/daemon/turn-tracker.ts
506
648
  import { randomUUID as randomUUID2 } from "crypto";
507
- import { eq as eq3 } from "drizzle-orm";
649
+ import { eq as eq4 } from "drizzle-orm";
508
650
 
509
651
  // packages/daemon/src/lib/daemon/summarizer.ts
510
- 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";
511
653
 
512
654
  // packages/daemon/src/lib/events/mind-events.ts
513
655
  var subscribers = /* @__PURE__ */ new Map();
@@ -674,18 +816,18 @@ function getTimeRange(periodKey, period) {
674
816
  async function gatherTurnEvents(mind, session, doneId) {
675
817
  const db = await getDb();
676
818
  const subConditions = [
677
- eq2(mindHistory.mind, mind),
678
- eq2(mindHistory.type, "done"),
819
+ eq3(mindHistory.mind, mind),
820
+ eq3(mindHistory.type, "done"),
679
821
  lt(mindHistory.id, doneId)
680
822
  ];
681
- if (session) subConditions.push(eq2(mindHistory.session, session));
682
- 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);
683
825
  const turnConditions = [
684
- eq2(mindHistory.mind, mind),
685
- sql`${mindHistory.id} > COALESCE((${prevDoneSubquery}), 0)`,
686
- sql`${mindHistory.id} <= ${doneId}`
826
+ eq3(mindHistory.mind, mind),
827
+ sql2`${mindHistory.id} > COALESCE((${prevDoneSubquery}), 0)`,
828
+ sql2`${mindHistory.id} <= ${doneId}`
687
829
  ];
688
- if (session) turnConditions.push(eq2(mindHistory.session, session));
830
+ if (session) turnConditions.push(eq3(mindHistory.session, session));
689
831
  const events = await db.select({
690
832
  id: mindHistory.id,
691
833
  type: mindHistory.type,
@@ -694,7 +836,7 @@ async function gatherTurnEvents(mind, session, doneId) {
694
836
  content: mindHistory.content,
695
837
  metadata: mindHistory.metadata,
696
838
  created_at: mindHistory.created_at
697
- }).from(mindHistory).where(and(...turnConditions)).orderBy(mindHistory.id);
839
+ }).from(mindHistory).where(and2(...turnConditions)).orderBy(mindHistory.id);
698
840
  return {
699
841
  events,
700
842
  fromId: events.length > 0 ? events[0].id : doneId,
@@ -711,7 +853,7 @@ async function gatherTurnEventsByTurnId(turnId) {
711
853
  content: mindHistory.content,
712
854
  metadata: mindHistory.metadata,
713
855
  created_at: mindHistory.created_at
714
- }).from(mindHistory).where(eq2(mindHistory.turn_id, turnId)).orderBy(mindHistory.id);
856
+ }).from(mindHistory).where(eq3(mindHistory.turn_id, turnId)).orderBy(mindHistory.id);
715
857
  return {
716
858
  events,
717
859
  fromId: events.length > 0 ? events[0].id : 0,
@@ -811,8 +953,8 @@ async function summarizeTurn(mind, session, channel, doneId, turnId) {
811
953
  if (turnId) {
812
954
  try {
813
955
  const db2 = await getDb();
814
- await db2.update(mindHistory).set({ turn_id: null }).where(and(eq2(mindHistory.turn_id, turnId), eq2(mindHistory.type, "inbound")));
815
- 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));
816
958
  } catch (err) {
817
959
  sLog.error(`failed to un-tag events for interrupted turn ${turnId}`, logger_default.errorData(err));
818
960
  }
@@ -869,10 +1011,10 @@ async function summarizeTurn(mind, session, channel, doneId, turnId) {
869
1011
  summaryId = result[0]?.id;
870
1012
  if (summaryId == null) {
871
1013
  const existing = await db.select({ id: summaries.id }).from(summaries).where(
872
- and(
873
- eq2(summaries.mind, mind),
874
- eq2(summaries.period, "turn"),
875
- eq2(summaries.period_key, periodKey)
1014
+ and2(
1015
+ eq3(summaries.mind, mind),
1016
+ eq3(summaries.period, "turn"),
1017
+ eq3(summaries.period_key, periodKey)
876
1018
  )
877
1019
  ).get();
878
1020
  summaryId = existing?.id;
@@ -901,7 +1043,7 @@ async function summarizeTurn(mind, session, channel, doneId, turnId) {
901
1043
  }
902
1044
  async function setSummaryId(turnId, summaryId) {
903
1045
  const db = await getDb();
904
- 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));
905
1047
  }
906
1048
  function getChildPeriod(period) {
907
1049
  switch (period) {
@@ -945,9 +1087,9 @@ async function gatherChildSummaries(mind, period, periodKey) {
945
1087
  if (period === "hour") {
946
1088
  const { start: start2, end: end2 } = getTimeRange(periodKey, "hour");
947
1089
  const rows2 = await db.select({ id: summaries.id, content: summaries.content }).from(summaries).where(
948
- and(
949
- eq2(summaries.mind, mind),
950
- eq2(summaries.period, childPeriod),
1090
+ and2(
1091
+ eq3(summaries.mind, mind),
1092
+ eq3(summaries.period, childPeriod),
951
1093
  gte(summaries.created_at, start2),
952
1094
  lt(summaries.created_at, end2)
953
1095
  )
@@ -959,9 +1101,9 @@ async function gatherChildSummaries(mind, period, periodKey) {
959
1101
  }
960
1102
  if (period === "day") {
961
1103
  const rows2 = await db.select({ id: summaries.id, content: summaries.content }).from(summaries).where(
962
- and(
963
- eq2(summaries.mind, mind),
964
- eq2(summaries.period, childPeriod),
1104
+ and2(
1105
+ eq3(summaries.mind, mind),
1106
+ eq3(summaries.period, childPeriod),
965
1107
  like(summaries.period_key, `${periodKey}%`)
966
1108
  )
967
1109
  ).orderBy(summaries.period_key);
@@ -974,11 +1116,11 @@ async function gatherChildSummaries(mind, period, periodKey) {
974
1116
  const startKey = start.slice(0, 10);
975
1117
  const endKey = end.slice(0, 10);
976
1118
  const rows = await db.select({ id: summaries.id, content: summaries.content }).from(summaries).where(
977
- and(
978
- eq2(summaries.mind, mind),
979
- eq2(summaries.period, childPeriod),
1119
+ and2(
1120
+ eq3(summaries.mind, mind),
1121
+ eq3(summaries.period, childPeriod),
980
1122
  gte(summaries.period_key, startKey),
981
- sql`${summaries.period_key} <= ${endKey}`
1123
+ sql2`${summaries.period_key} <= ${endKey}`
982
1124
  )
983
1125
  ).orderBy(summaries.period_key);
984
1126
  return {
@@ -1058,10 +1200,10 @@ async function summarizeSystem(period, periodKey) {
1058
1200
  if (await summaryExists(SYSTEM_MIND, period, periodKey)) return;
1059
1201
  const db = await getDb();
1060
1202
  const rows = await db.select({ mind: summaries.mind, content: summaries.content }).from(summaries).where(
1061
- and(
1062
- eq2(summaries.period, period),
1063
- eq2(summaries.period_key, periodKey),
1064
- sql`${summaries.mind} != ${SYSTEM_MIND}`
1203
+ and2(
1204
+ eq3(summaries.period, period),
1205
+ eq3(summaries.period_key, periodKey),
1206
+ sql2`${summaries.mind} != ${SYSTEM_MIND}`
1065
1207
  )
1066
1208
  ).orderBy(summaries.mind);
1067
1209
  if (rows.length === 0) return;
@@ -1096,11 +1238,11 @@ async function summarizeSystem(period, periodKey) {
1096
1238
  async function mindsWithTurnSummaries(start, end) {
1097
1239
  const db = await getDb();
1098
1240
  const rows = await db.select({ mind: summaries.mind }).from(summaries).where(
1099
- and(
1100
- eq2(summaries.period, "turn"),
1241
+ and2(
1242
+ eq3(summaries.period, "turn"),
1101
1243
  gte(summaries.created_at, start),
1102
1244
  lt(summaries.created_at, end),
1103
- sql`${summaries.mind} != ${SYSTEM_MIND}`
1245
+ sql2`${summaries.mind} != ${SYSTEM_MIND}`
1104
1246
  )
1105
1247
  ).groupBy(summaries.mind);
1106
1248
  return rows.map((r) => r.mind);
@@ -1108,10 +1250,10 @@ async function mindsWithTurnSummaries(start, end) {
1108
1250
  async function mindsWithSummaries(period, keyPattern) {
1109
1251
  const db = await getDb();
1110
1252
  const rows = await db.select({ mind: summaries.mind }).from(summaries).where(
1111
- and(
1112
- eq2(summaries.period, period),
1253
+ and2(
1254
+ eq3(summaries.period, period),
1113
1255
  like(summaries.period_key, keyPattern),
1114
- sql`${summaries.mind} != ${SYSTEM_MIND}`
1256
+ sql2`${summaries.mind} != ${SYSTEM_MIND}`
1115
1257
  )
1116
1258
  ).groupBy(summaries.mind);
1117
1259
  return rows.map((r) => r.mind);
@@ -1119,11 +1261,11 @@ async function mindsWithSummaries(period, keyPattern) {
1119
1261
  async function mindsWithDailySummariesInRange(startKey, endKey) {
1120
1262
  const db = await getDb();
1121
1263
  const rows = await db.select({ mind: summaries.mind }).from(summaries).where(
1122
- and(
1123
- eq2(summaries.period, "day"),
1264
+ and2(
1265
+ eq3(summaries.period, "day"),
1124
1266
  gte(summaries.period_key, startKey),
1125
- sql`${summaries.period_key} <= ${endKey}`,
1126
- sql`${summaries.mind} != ${SYSTEM_MIND}`
1267
+ sql2`${summaries.period_key} <= ${endKey}`,
1268
+ sql2`${summaries.mind} != ${SYSTEM_MIND}`
1127
1269
  )
1128
1270
  ).groupBy(summaries.mind);
1129
1271
  return rows.map((r) => r.mind);
@@ -1187,10 +1329,10 @@ async function processMonth(periodKey) {
1187
1329
  async function summaryExists(mind, period, periodKey) {
1188
1330
  const db = await getDb();
1189
1331
  const row = await db.select({ id: summaries.id }).from(summaries).where(
1190
- and(
1191
- eq2(summaries.mind, mind),
1192
- eq2(summaries.period, period),
1193
- eq2(summaries.period_key, periodKey)
1332
+ and2(
1333
+ eq3(summaries.mind, mind),
1334
+ eq3(summaries.period, period),
1335
+ eq3(summaries.period_key, periodKey)
1194
1336
  )
1195
1337
  ).get();
1196
1338
  return !!row;
@@ -1220,7 +1362,7 @@ async function backfill() {
1220
1362
  }
1221
1363
  const allKeys = candidates.map((c) => c.key);
1222
1364
  const db = await getDb();
1223
- 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)));
1224
1366
  const existingSet = new Set(existingRows.map((r) => `${r.period}:${r.period_key}`));
1225
1367
  const processFn = {
1226
1368
  hour: processHour,
@@ -1297,6 +1439,13 @@ var activeTurns = /* @__PURE__ */ new Map();
1297
1439
  function key(mind, session) {
1298
1440
  return `${mind}:${session ?? "*"}`;
1299
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
+ }
1300
1449
  async function createTurn(mind) {
1301
1450
  const k = key(mind);
1302
1451
  const existing = activeTurns.get(k);
@@ -1333,7 +1482,7 @@ async function assignSession(mind, turnId, session) {
1333
1482
  }
1334
1483
  try {
1335
1484
  const db = await getDb();
1336
- await db.update(turns).set({ session }).where(eq3(turns.id, turnId));
1485
+ await db.update(turns).set({ session }).where(eq4(turns.id, turnId));
1337
1486
  } catch (err) {
1338
1487
  tlog.error(`failed to assign session to turn ${turnId}`, logger_default.errorData(err));
1339
1488
  return;
@@ -1348,7 +1497,7 @@ async function completeTurn(mind, session) {
1348
1497
  if (!entry) return void 0;
1349
1498
  try {
1350
1499
  const db = await getDb();
1351
- 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));
1352
1501
  } catch (err) {
1353
1502
  tlog.error(`failed to complete turn ${entry.turnId}`, logger_default.errorData(err));
1354
1503
  return void 0;
@@ -1359,10 +1508,10 @@ async function completeTurn(mind, session) {
1359
1508
  }
1360
1509
  async function completeOrphanedTurns() {
1361
1510
  const db = await getDb();
1362
- 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"));
1363
1512
  if (active.length === 0) return [];
1364
1513
  try {
1365
- 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"));
1366
1515
  } catch (err) {
1367
1516
  tlog.error("failed to complete orphaned turns on startup", logger_default.errorData(err));
1368
1517
  }
@@ -1388,11 +1537,14 @@ async function clearMind(mind) {
1388
1537
  }
1389
1538
  }
1390
1539
  for (const k of toDelete) activeTurns.delete(k);
1540
+ for (const k of [...erroredSessions]) {
1541
+ if (k.startsWith(`${mind}:`)) erroredSessions.delete(k);
1542
+ }
1391
1543
  if (orphaned.length > 0) {
1392
1544
  try {
1393
1545
  const db = await getDb();
1394
1546
  for (const { turnId } of orphaned) {
1395
- 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));
1396
1548
  }
1397
1549
  } catch (err) {
1398
1550
  tlog.error(`failed to complete orphaned turns for ${mind}`, logger_default.errorData(err));
@@ -1412,7 +1564,7 @@ function summarizeOrphanedTurns(orphanedTurns) {
1412
1564
  var mlog = logger_default.child("minds");
1413
1565
  var execFileAsync = promisify(execFile);
1414
1566
  function mindPidPath(name) {
1415
- return resolve(stateDir(name), "mind.pid");
1567
+ return resolve2(stateDir(name), "mind.pid");
1416
1568
  }
1417
1569
  var MindManager = class {
1418
1570
  minds = /* @__PURE__ */ new Map();
@@ -1428,7 +1580,7 @@ var MindManager = class {
1428
1580
  return { dir: entry.dir, port: entry.port, baseName: entry.parent, template: entry.template };
1429
1581
  }
1430
1582
  const dir = entry.dir ?? mindDir(name);
1431
- if (!existsSync3(dir)) throw new Error(`Mind directory missing: ${dir}`);
1583
+ if (!existsSync4(dir)) throw new Error(`Mind directory missing: ${dir}`);
1432
1584
  return { dir, port: entry.port, baseName: name, template: entry.template };
1433
1585
  }
1434
1586
  async startMind(name) {
@@ -1440,8 +1592,8 @@ var MindManager = class {
1440
1592
  const port = target.port;
1441
1593
  const pidFile = mindPidPath(name);
1442
1594
  try {
1443
- if (existsSync3(pidFile)) {
1444
- const stalePid = parseInt(readFileSync2(pidFile, "utf-8").trim(), 10);
1595
+ if (existsSync4(pidFile)) {
1596
+ const stalePid = parseInt(readFileSync3(pidFile, "utf-8").trim(), 10);
1445
1597
  if (stalePid > 0) {
1446
1598
  try {
1447
1599
  process.kill(stalePid, 0);
@@ -1474,8 +1626,8 @@ var MindManager = class {
1474
1626
  } catch {
1475
1627
  }
1476
1628
  const mindStateDir = stateDir(name);
1477
- const logsDir = resolve(mindStateDir, "logs");
1478
- mkdirSync(logsDir, { recursive: true });
1629
+ const logsDir = resolve2(mindStateDir, "logs");
1630
+ mkdirSync2(logsDir, { recursive: true });
1479
1631
  if (isIsolationEnabled()) {
1480
1632
  try {
1481
1633
  chownMindDir(mindStateDir, baseName);
@@ -1485,10 +1637,10 @@ var MindManager = class {
1485
1637
  );
1486
1638
  }
1487
1639
  }
1488
- const logStream = new RotatingLog(resolve(logsDir, "mind.log"));
1640
+ const logStream = new RotatingLog(resolve2(logsDir, "mind.log"));
1489
1641
  const mindToken = generateMindToken(name);
1490
1642
  const mindEnv = loadMergedEnv(name);
1491
- const mindLocalBin = resolve(dir, "home", ".local", "bin");
1643
+ const mindLocalBin = resolve2(dir, "home", ".local", "bin");
1492
1644
  const currentPath = process.env.PATH ?? "";
1493
1645
  const env = {
1494
1646
  ...process.env,
@@ -1504,24 +1656,30 @@ var MindManager = class {
1504
1656
  };
1505
1657
  if (target.template === "pi") {
1506
1658
  try {
1507
- const configPath2 = resolve(dir, "home/.config/config.json");
1508
- if (existsSync3(configPath2)) {
1509
- 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"));
1510
1662
  const modelStr = config.model;
1511
1663
  if (modelStr?.includes(":")) {
1512
1664
  const provider = modelStr.split(":")[0];
1513
1665
  const apiKey = await resolveApiKey(provider);
1514
1666
  if (apiKey) {
1515
- const piAgentDir = resolve(dir, ".mind", "pi-agent");
1516
- mkdirSync(piAgentDir, { recursive: true });
1517
- const authPath = resolve(piAgentDir, "auth.json");
1518
- const authData = existsSync3(authPath) ? JSON.parse(readFileSync2(authPath, "utf-8")) : {};
1519
- authData[provider] = { type: "api_key", key: apiKey };
1520
- writeFileSync2(authPath, JSON.stringify(authData, null, 2), { mode: 384 });
1521
- if (isIsolationEnabled()) {
1522
- chownMindDir(piAgentDir, baseName);
1523
- }
1667
+ const piAgentDir = resolve2(dir, ".mind", "pi-agent");
1668
+ writePiProviderKey(piAgentDir, baseName, provider, apiKey);
1524
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;
1525
1683
  } else {
1526
1684
  mlog.warn(
1527
1685
  `no API key found for provider "${provider}" \u2014 mind ${name} may fail to start`
@@ -1538,11 +1696,11 @@ var MindManager = class {
1538
1696
  const ai = getAiConfig();
1539
1697
  const codexConfig = ai?.providers["openai-codex"];
1540
1698
  if (codexConfig?.oauth) {
1541
- const codexDir = resolve(dir, ".mind", "codex");
1542
- mkdirSync(codexDir, { recursive: true });
1699
+ const codexDir = resolve2(dir, ".mind", "codex");
1700
+ mkdirSync2(codexDir, { recursive: true });
1543
1701
  env.CODEX_HOME = codexDir;
1544
- const authPath = resolve(codexDir, "auth.json");
1545
- writeFileSync2(
1702
+ const authPath = resolve2(codexDir, "auth.json");
1703
+ writeFileSync3(
1546
1704
  authPath,
1547
1705
  JSON.stringify({
1548
1706
  auth_mode: "chatgpt",
@@ -1555,9 +1713,9 @@ var MindManager = class {
1555
1713
  }),
1556
1714
  { mode: 384 }
1557
1715
  );
1558
- const configTomlPath = resolve(codexDir, "config.toml");
1559
- if (!existsSync3(configTomlPath)) {
1560
- 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');
1561
1719
  }
1562
1720
  if (isIsolationEnabled()) {
1563
1721
  chownMindDir(codexDir, baseName);
@@ -1576,10 +1734,10 @@ var MindManager = class {
1576
1734
  env.OPENAI_API_KEY = process.env.OPENAI_API_KEY;
1577
1735
  }
1578
1736
  }
1579
- const homeDir = resolve(dir, "home");
1737
+ const homeDir = resolve2(dir, "home");
1580
1738
  const zshenvLines = Object.entries(env).filter(([k, v]) => k.startsWith("VOLUTE_") && v != null).map(([k, v]) => `export ${k}=${JSON.stringify(v)}`);
1581
1739
  zshenvLines.push(`export PATH=${JSON.stringify(env.PATH ?? "")}`);
1582
- writeFileSync2(resolve(homeDir, ".zshenv"), `${zshenvLines.join("\n")}
1740
+ writeFileSync3(resolve2(homeDir, ".zshenv"), `${zshenvLines.join("\n")}
1583
1741
  `, { mode: 384 });
1584
1742
  }
1585
1743
  if (target.template === "claude" || !target.template) {
@@ -1588,27 +1746,10 @@ var MindManager = class {
1588
1746
  const anthropicConfig = ai?.providers.anthropic;
1589
1747
  if (anthropicConfig?.oauth) {
1590
1748
  const key2 = await resolveApiKey("anthropic");
1591
- if (key2) {
1592
- const homeDir = resolve(dir, "home");
1593
- const claudeDir = resolve(homeDir, ".claude");
1594
- mkdirSync(claudeDir, { recursive: true });
1749
+ const oauth = getAiConfig()?.providers.anthropic?.oauth;
1750
+ if (key2 && oauth) {
1751
+ const claudeDir = writeClaudeCredentials(resolve2(dir, "home"), baseName, oauth);
1595
1752
  env.CLAUDE_CONFIG_DIR = claudeDir;
1596
- const credsPath = resolve(claudeDir, ".credentials.json");
1597
- writeFileSync2(
1598
- credsPath,
1599
- JSON.stringify({
1600
- claudeAiOauth: {
1601
- accessToken: key2,
1602
- refreshToken: anthropicConfig.oauth.refresh,
1603
- expiresAt: anthropicConfig.oauth.expires ? new Date(anthropicConfig.oauth.expires).toISOString() : null,
1604
- scopes: ["user:inference", "user:profile"]
1605
- }
1606
- }),
1607
- { mode: 384 }
1608
- );
1609
- if (isIsolationEnabled()) {
1610
- chownMindDir(claudeDir, baseName);
1611
- }
1612
1753
  }
1613
1754
  } else if (anthropicConfig?.apiKey) {
1614
1755
  env.ANTHROPIC_API_KEY = anthropicConfig.apiKey;
@@ -1618,7 +1759,7 @@ var MindManager = class {
1618
1759
  }
1619
1760
  }
1620
1761
  if (isIsolationEnabled()) {
1621
- env.HOME = resolve(dir, "home");
1762
+ env.HOME = resolve2(dir, "home");
1622
1763
  }
1623
1764
  const customNode = process.env.VOLUTE_NODE_PATH;
1624
1765
  let baseBin;
@@ -1626,20 +1767,20 @@ var MindManager = class {
1626
1767
  if (customNode) {
1627
1768
  baseBin = customNode;
1628
1769
  baseArgs = [
1629
- resolve(dir, "node_modules", ".bin", "tsx"),
1770
+ resolve2(dir, "node_modules", ".bin", "tsx"),
1630
1771
  "src/server.ts",
1631
1772
  "--port",
1632
1773
  String(port)
1633
1774
  ];
1634
1775
  } else {
1635
- baseBin = resolve(dir, "node_modules", ".bin", "tsx");
1776
+ baseBin = resolve2(dir, "node_modules", ".bin", "tsx");
1636
1777
  baseArgs = ["src/server.ts", "--port", String(port)];
1637
1778
  }
1638
1779
  let spawnCmd;
1639
1780
  let spawnArgs;
1640
1781
  if (isIsolationEnabled()) {
1641
1782
  [spawnCmd, spawnArgs] = await wrapForIsolation(baseBin, baseArgs, name);
1642
- } else if (isSandboxEnabled()) {
1783
+ } else if (isSandboxEnabled() && target.template !== "codex") {
1643
1784
  [spawnCmd, spawnArgs] = await wrapForSandbox(baseBin, baseArgs, dir, name, [
1644
1785
  dir,
1645
1786
  mindStateDir,
@@ -1666,14 +1807,14 @@ var MindManager = class {
1666
1807
  while (recentStderr.length > 20) recentStderr.shift();
1667
1808
  });
1668
1809
  try {
1669
- await new Promise((resolve8, reject) => {
1810
+ await new Promise((resolve9, reject) => {
1670
1811
  const timeout = setTimeout(() => {
1671
1812
  reject(new Error(`Mind ${name} did not start within 30s`));
1672
1813
  }, 3e4);
1673
1814
  function checkOutput(data) {
1674
1815
  if (data.toString().match(/listening on :\d+/)) {
1675
1816
  clearTimeout(timeout);
1676
- resolve8();
1817
+ resolve9();
1677
1818
  }
1678
1819
  }
1679
1820
  child.stdout?.on("data", checkOutput);
@@ -1701,7 +1842,7 @@ var MindManager = class {
1701
1842
  }
1702
1843
  if (child.pid) {
1703
1844
  try {
1704
- writeFileSync2(pidFile, String(child.pid));
1845
+ writeFileSync3(pidFile, String(child.pid));
1705
1846
  } catch (err) {
1706
1847
  mlog.warn(`failed to write PID file for ${name}`, logger_default.errorData(err));
1707
1848
  }
@@ -1769,7 +1910,7 @@ var MindManager = class {
1769
1910
  if (this.shuttingDown || this.stopping.has(name)) return;
1770
1911
  mlog.error(`mind ${name} exited with code ${code}`);
1771
1912
  try {
1772
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-VPPQXBPH.js");
1913
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-27S7MKJO.js");
1773
1914
  const sleepState = getSleepManagerIfReady2()?.getState(name);
1774
1915
  if (sleepState?.sleeping) {
1775
1916
  mlog.info(`${name} is sleeping \u2014 skipping crash recovery`);
@@ -1778,19 +1919,30 @@ var MindManager = class {
1778
1919
  } catch (err) {
1779
1920
  mlog.warn(`failed to check sleep state for ${name}`, logger_default.errorData(err));
1780
1921
  }
1781
- 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(
1782
1934
  (err) => mlog.warn(`failed to clear turn state for ${name} after crash`, logger_default.errorData(err))
1783
1935
  );
1784
1936
  try {
1785
- const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-IMCRV6A3.js");
1937
+ const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-L5WFP2ND.js");
1786
1938
  getDeliveryManager2().clearMindSessions(name);
1787
1939
  } catch (err) {
1788
1940
  if (!(err instanceof Error && err.message.includes("not initialized"))) {
1789
1941
  mlog.warn(`failed to clear delivery state for ${name} after crash`, logger_default.errorData(err));
1790
1942
  }
1791
1943
  }
1792
- import("./mind-activity-tracker-42ENM32S.js").then(({ markIdle: markIdle2 }) => markIdle2(name)).catch((err) => mlog.warn(`failed to mark ${name} idle after crash`, logger_default.errorData(err)));
1793
- import("./activity-events-N6HCHU4P.js").then(
1944
+ import("./mind-activity-tracker-7GE24YZE.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-OJZ7G5CG.js").then(
1794
1946
  ({ publish: publish4 }) => publish4({ type: "mind_stopped", mind: name, summary: `${name} crashed (exit ${code})` })
1795
1947
  ).catch((err) => mlog.warn(`failed to publish crash event for ${name}`, logger_default.errorData(err)));
1796
1948
  const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(name);
@@ -1817,19 +1969,19 @@ var MindManager = class {
1817
1969
  this.stopping.add(name);
1818
1970
  const { child } = tracked;
1819
1971
  this.minds.delete(name);
1820
- await new Promise((resolve8) => {
1821
- child.on("exit", () => resolve8());
1972
+ await new Promise((resolve9) => {
1973
+ child.on("exit", () => resolve9());
1822
1974
  try {
1823
1975
  process.kill(-child.pid, "SIGTERM");
1824
1976
  } catch {
1825
- resolve8();
1977
+ resolve9();
1826
1978
  }
1827
1979
  setTimeout(() => {
1828
1980
  try {
1829
1981
  process.kill(-child.pid, "SIGKILL");
1830
1982
  } catch {
1831
1983
  }
1832
- resolve8();
1984
+ resolve9();
1833
1985
  }, 5e3);
1834
1986
  });
1835
1987
  this.stopping.delete(name);
@@ -1841,7 +1993,7 @@ var MindManager = class {
1841
1993
  mlog.warn(`failed to clear turn state for ${name} on stop`, logger_default.errorData(err));
1842
1994
  }
1843
1995
  try {
1844
- const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-IMCRV6A3.js");
1996
+ const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-L5WFP2ND.js");
1845
1997
  getDeliveryManager2().clearMindSessions(name);
1846
1998
  } catch (err) {
1847
1999
  if (!(err instanceof Error && err.message.includes("not initialized"))) {
@@ -1849,7 +2001,7 @@ var MindManager = class {
1849
2001
  }
1850
2002
  }
1851
2003
  try {
1852
- const { clearEchoTextCache } = await import("./echo-text-ADKLNTIA.js");
2004
+ const { clearEchoTextCache } = await import("./echo-text-TJWCUBPB.js");
1853
2005
  clearEchoTextCache(name);
1854
2006
  } catch (err) {
1855
2007
  mlog.debug(`failed to clear echo-text cache for ${name}`, logger_default.errorData(err));
@@ -1877,7 +2029,7 @@ var MindManager = class {
1877
2029
  return [...this.minds.keys()];
1878
2030
  }
1879
2031
  get crashAttemptsPath() {
1880
- return resolve(voluteSystemDir(), "crash-attempts.json");
2032
+ return resolve2(voluteSystemDir(), "crash-attempts.json");
1881
2033
  }
1882
2034
  loadCrashAttempts() {
1883
2035
  this.restartTracker.load(loadJsonMap(this.crashAttemptsPath));
@@ -1975,20 +2127,20 @@ async function announceToSystem(text) {
1975
2127
  }
1976
2128
 
1977
2129
  // packages/daemon/src/lib/extensions.ts
1978
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
1979
- 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";
1980
2132
 
1981
2133
  // packages/daemon/src/lib/config/systems-config.ts
1982
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
1983
- 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";
1984
2136
  var DEFAULT_API_URL = "https://volute.systems";
1985
2137
  function configPath() {
1986
- return resolve2(voluteSystemDir(), "systems.json");
2138
+ return resolve3(voluteSystemDir(), "systems.json");
1987
2139
  }
1988
2140
  function readSystemsConfig() {
1989
2141
  const path = configPath();
1990
- if (!existsSync4(path)) return null;
1991
- const raw = readFileSync3(path, "utf-8");
2142
+ if (!existsSync5(path)) return null;
2143
+ const raw = readFileSync4(path, "utf-8");
1992
2144
  let data;
1993
2145
  try {
1994
2146
  data = JSON.parse(raw);
@@ -2006,8 +2158,8 @@ function readSystemsConfig() {
2006
2158
  };
2007
2159
  }
2008
2160
  function writeSystemsConfig(config) {
2009
- mkdirSync2(voluteSystemDir(), { recursive: true });
2010
- writeFileSync3(configPath(), `${JSON.stringify(config, null, 2)}
2161
+ mkdirSync3(voluteSystemDir(), { recursive: true });
2162
+ writeFileSync4(configPath(), `${JSON.stringify(config, null, 2)}
2011
2163
  `, { mode: 384 });
2012
2164
  }
2013
2165
  function deleteSystemsConfig() {
@@ -2066,19 +2218,19 @@ function parseCommandArgs(rawArgs, argDefs, flagDefs) {
2066
2218
  return { args: namedArgs, flags, rest };
2067
2219
  }
2068
2220
  function extensionsBaseDir() {
2069
- return resolve3(voluteHome(), "extensions");
2221
+ return resolve4(voluteHome(), "extensions");
2070
2222
  }
2071
2223
  function extensionDataDir(id) {
2072
- return resolve3(voluteSystemDir(), "extension-data", id);
2224
+ return resolve4(voluteSystemDir(), "extension-data", id);
2073
2225
  }
2074
2226
  function extensionsConfigPath() {
2075
- return resolve3(voluteHome(), "system", "extensions.json");
2227
+ return resolve4(voluteHome(), "system", "extensions.json");
2076
2228
  }
2077
2229
  function readExtensionsConfig() {
2078
2230
  const configPath2 = extensionsConfigPath();
2079
- if (!existsSync5(configPath2)) return [];
2231
+ if (!existsSync6(configPath2)) return [];
2080
2232
  try {
2081
- const data = JSON.parse(readFileSync4(configPath2, "utf-8"));
2233
+ const data = JSON.parse(readFileSync5(configPath2, "utf-8"));
2082
2234
  return Array.isArray(data) ? data : [];
2083
2235
  } catch (err) {
2084
2236
  logger_default.warn("failed to read extensions config, ignoring installed extensions", {
@@ -2096,7 +2248,7 @@ async function getLibsqlDatabase() {
2096
2248
  return _LibsqlDatabase;
2097
2249
  }
2098
2250
  async function openExtensionDb(_id, dataDir) {
2099
- const dbPath = resolve3(dataDir, "data.db");
2251
+ const dbPath = resolve4(dataDir, "data.db");
2100
2252
  const Database = await getLibsqlDatabase();
2101
2253
  return new Database(dbPath);
2102
2254
  }
@@ -2138,7 +2290,7 @@ async function buildContext(manifest, dataDir, authMw) {
2138
2290
  getMindDir: (name) => {
2139
2291
  try {
2140
2292
  const dir = mindDir(name);
2141
- return existsSync5(dir) ? dir : null;
2293
+ return existsSync6(dir) ? dir : null;
2142
2294
  } catch (err) {
2143
2295
  logger_default.warn(
2144
2296
  `extension ${manifest.id}: failed to resolve mind dir for ${name}`,
@@ -2160,7 +2312,7 @@ async function loadExtension(manifest, app, authMw) {
2160
2312
  return;
2161
2313
  }
2162
2314
  const dataDir = extensionDataDir(manifest.id);
2163
- mkdirSync3(dataDir, { recursive: true });
2315
+ mkdirSync4(dataDir, { recursive: true });
2164
2316
  const context = await buildContext(manifest, dataDir, authMw);
2165
2317
  const routesApp = manifest.routes(context);
2166
2318
  const extApiPath = `/api/ext/${manifest.id}`;
@@ -2223,18 +2375,18 @@ async function loadExtension(manifest, app, authMw) {
2223
2375
  }
2224
2376
  }
2225
2377
  let resolvedAssetsDir = manifest.ui?.assetsDir ?? "";
2226
- if (resolvedAssetsDir && !existsSync5(resolvedAssetsDir)) {
2378
+ if (resolvedAssetsDir && !existsSync6(resolvedAssetsDir)) {
2227
2379
  let searchDir = dirname(new URL(import.meta.url).pathname);
2228
2380
  for (let i = 0; i < 5; i++) {
2229
- const candidate = resolve3(searchDir, "packages", "extensions", manifest.id, "dist", "ui");
2230
- if (existsSync5(candidate)) {
2381
+ const candidate = resolve4(searchDir, "packages", "extensions", manifest.id, "dist", "ui");
2382
+ if (existsSync6(candidate)) {
2231
2383
  resolvedAssetsDir = candidate;
2232
2384
  break;
2233
2385
  }
2234
2386
  searchDir = dirname(searchDir);
2235
2387
  }
2236
2388
  }
2237
- if (resolvedAssetsDir && existsSync5(resolvedAssetsDir)) {
2389
+ if (resolvedAssetsDir && existsSync6(resolvedAssetsDir)) {
2238
2390
  const assetsDir = resolvedAssetsDir;
2239
2391
  const { readFile: readFile2, stat: fsStat } = await import("fs/promises");
2240
2392
  const { extname: ext } = await import("path");
@@ -2251,11 +2403,11 @@ async function loadExtension(manifest, app, authMw) {
2251
2403
  ".woff2": "font/woff2"
2252
2404
  };
2253
2405
  const prefix = `/ext/${manifest.id}`;
2254
- const indexPath = resolve3(assetsDir, "index.html");
2406
+ const indexPath = resolve4(assetsDir, "index.html");
2255
2407
  const serveExtAssets = async (c) => {
2256
2408
  const urlPath = new URL(c.req.url).pathname;
2257
2409
  const relativePath = urlPath.slice(prefix.length).replace(/^\//, "") || "index.html";
2258
- const filePath = resolve3(assetsDir, relativePath);
2410
+ const filePath = resolve4(assetsDir, relativePath);
2259
2411
  if (filePath !== assetsDir && !filePath.startsWith(`${assetsDir}/`))
2260
2412
  return c.text("Forbidden", 403);
2261
2413
  const s = await fsStat(filePath).catch(() => null);
@@ -2264,7 +2416,7 @@ async function loadExtension(manifest, app, authMw) {
2264
2416
  const body = await readFile2(filePath);
2265
2417
  return c.body(body, 200, { "Content-Type": mime });
2266
2418
  }
2267
- if (existsSync5(indexPath)) {
2419
+ if (existsSync6(indexPath)) {
2268
2420
  const body = await readFile2(indexPath, "utf-8");
2269
2421
  return c.html(body);
2270
2422
  }
@@ -2285,10 +2437,10 @@ async function loadExtension(manifest, app, authMw) {
2285
2437
  for (const entry of entries) {
2286
2438
  if (!entry.isDirectory()) continue;
2287
2439
  try {
2288
- const skillPath = resolve3(skillsDir, entry.name);
2440
+ const skillPath = resolve4(skillsDir, entry.name);
2289
2441
  const sourceHash = hashSkillDir(skillPath);
2290
- const destDir = resolve3(sharedSkillsDir(), entry.name);
2291
- if (existsSync5(destDir)) {
2442
+ const destDir = resolve4(sharedSkillsDir(), entry.name);
2443
+ if (existsSync6(destDir)) {
2292
2444
  const destHash = hashSkillDir(destDir);
2293
2445
  if (sourceHash === destHash) continue;
2294
2446
  }
@@ -2315,14 +2467,14 @@ function resolveSkillsDir(manifest) {
2315
2467
  if (cached !== void 0) return cached;
2316
2468
  let searchDir = dirname(new URL(import.meta.url).pathname);
2317
2469
  for (let i = 0; i < 5; i++) {
2318
- const candidate = resolve3(searchDir, "packages", "extensions", manifest.id, "skills");
2319
- if (existsSync5(candidate)) {
2470
+ const candidate = resolve4(searchDir, "packages", "extensions", manifest.id, "skills");
2471
+ if (existsSync6(candidate)) {
2320
2472
  skillsDirCache.set(manifest.id, candidate);
2321
2473
  return candidate;
2322
2474
  }
2323
2475
  searchDir = dirname(searchDir);
2324
2476
  }
2325
- if (existsSync5(manifest.skillsDir)) {
2477
+ if (existsSync6(manifest.skillsDir)) {
2326
2478
  skillsDirCache.set(manifest.id, manifest.skillsDir);
2327
2479
  return manifest.skillsDir;
2328
2480
  }
@@ -2350,14 +2502,14 @@ async function discoverBuiltinExtensions(disabledIds) {
2350
2502
  async function discoverInstalledExtensions() {
2351
2503
  const results = [];
2352
2504
  const packages = readExtensionsConfig();
2353
- const npmDir = resolve3(voluteHome(), "extensions", "_npm");
2505
+ const npmDir = resolve4(voluteHome(), "extensions", "_npm");
2354
2506
  const { createRequire } = await import("module");
2355
2507
  for (const pkg of packages) {
2356
2508
  try {
2357
2509
  let resolved = pkg;
2358
- const npmPkgDir = resolve3(npmDir, "node_modules", pkg);
2359
- if (existsSync5(npmPkgDir)) {
2360
- 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"));
2361
2513
  resolved = require2.resolve(pkg);
2362
2514
  }
2363
2515
  const mod = await import(resolved);
@@ -2400,7 +2552,7 @@ function validateManifest(manifest, source) {
2400
2552
  }
2401
2553
  async function discoverLocalExtensions() {
2402
2554
  const baseDir = extensionsBaseDir();
2403
- if (!existsSync5(baseDir)) return [];
2555
+ if (!existsSync6(baseDir)) return [];
2404
2556
  const manifests = [];
2405
2557
  let entries;
2406
2558
  try {
@@ -2410,9 +2562,9 @@ async function discoverLocalExtensions() {
2410
2562
  return [];
2411
2563
  }
2412
2564
  for (const dir of entries) {
2413
- const extDir = resolve3(baseDir, dir);
2414
- const candidates = [resolve3(extDir, "src", "index.js"), resolve3(extDir, "index.js")];
2415
- 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));
2416
2568
  if (!entryPoint) continue;
2417
2569
  try {
2418
2570
  const mod = await import(entryPoint);
@@ -2547,21 +2699,21 @@ function setExtensionEnabled(id, enabled) {
2547
2699
  writeGlobalConfig(config);
2548
2700
  }
2549
2701
  function extensionsNpmDir() {
2550
- return resolve3(voluteHome(), "extensions", "_npm");
2702
+ return resolve4(voluteHome(), "extensions", "_npm");
2551
2703
  }
2552
2704
  function ensureExtensionsNpmDir() {
2553
2705
  const dir = extensionsNpmDir();
2554
- mkdirSync3(dir, { recursive: true });
2555
- const pkgPath = resolve3(dir, "package.json");
2556
- if (!existsSync5(pkgPath)) {
2557
- 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');
2558
2710
  }
2559
2711
  return dir;
2560
2712
  }
2561
2713
  function writeExtensionsConfig(packages) {
2562
2714
  const configPath2 = extensionsConfigPath();
2563
- mkdirSync3(resolve3(configPath2, ".."), { recursive: true });
2564
- writeFileSync4(configPath2, `${JSON.stringify(packages, null, 2)}
2715
+ mkdirSync4(resolve4(configPath2, ".."), { recursive: true });
2716
+ writeFileSync5(configPath2, `${JSON.stringify(packages, null, 2)}
2565
2717
  `);
2566
2718
  }
2567
2719
  var VALID_NPM_PACKAGE = /^(@[a-z0-9-~][a-z0-9._-~]*\/)?[a-z0-9-~][a-z0-9._-~]*(@[^\s]+)?$/;
@@ -2574,7 +2726,7 @@ async function installNpmExtension(pkg) {
2574
2726
  throw new Error(`Extension "${pkg}" is already installed`);
2575
2727
  }
2576
2728
  const dir = ensureExtensionsNpmDir();
2577
- const { exec: exec2 } = await import("./exec-ONYZEA5B.js");
2729
+ const { exec: exec2 } = await import("./exec-BGMU7VXR.js");
2578
2730
  try {
2579
2731
  await exec2("npm", ["install", pkg], { cwd: dir });
2580
2732
  } catch (err) {
@@ -2595,7 +2747,7 @@ async function uninstallNpmExtension(pkg) {
2595
2747
  packages.splice(idx, 1);
2596
2748
  writeExtensionsConfig(packages);
2597
2749
  try {
2598
- const { exec: exec2 } = await import("./exec-ONYZEA5B.js");
2750
+ const { exec: exec2 } = await import("./exec-BGMU7VXR.js");
2599
2751
  await exec2("npm", ["uninstall", pkg], { cwd: extensionsNpmDir() });
2600
2752
  } catch (err) {
2601
2753
  logger_default.warn(
@@ -2607,13 +2759,13 @@ async function uninstallNpmExtension(pkg) {
2607
2759
  }
2608
2760
  async function cleanupExtensionSkills(pkg) {
2609
2761
  try {
2610
- const pkgDir = resolve3(extensionsNpmDir(), "node_modules", pkg);
2611
- if (!existsSync5(pkgDir)) return;
2762
+ const pkgDir = resolve4(extensionsNpmDir(), "node_modules", pkg);
2763
+ if (!existsSync6(pkgDir)) return;
2612
2764
  const { createRequire } = await import("module");
2613
- const require2 = createRequire(resolve3(extensionsNpmDir(), "noop.js"));
2765
+ const require2 = createRequire(resolve4(extensionsNpmDir(), "noop.js"));
2614
2766
  const mod = require2(pkg);
2615
2767
  const manifest = mod.default ?? mod.extension ?? mod;
2616
- if (!manifest?.skillsDir || !existsSync5(manifest.skillsDir)) return;
2768
+ if (!manifest?.skillsDir || !existsSync6(manifest.skillsDir)) return;
2617
2769
  const skillDirs = readdirSync(manifest.skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
2618
2770
  for (const skillId of skillDirs) {
2619
2771
  try {
@@ -2922,9 +3074,9 @@ async function ensureMailAddress(mindName) {
2922
3074
  }
2923
3075
 
2924
3076
  // packages/daemon/src/lib/daemon/scheduler.ts
2925
- import { resolve as resolve4 } from "path";
3077
+ import { resolve as resolve5 } from "path";
2926
3078
  import { CronExpressionParser } from "cron-parser";
2927
- var slog = logger_default.child("scheduler");
3079
+ var slog2 = logger_default.child("scheduler");
2928
3080
  var Scheduler = class {
2929
3081
  schedules = /* @__PURE__ */ new Map();
2930
3082
  mindDirs = /* @__PURE__ */ new Map();
@@ -2933,12 +3085,12 @@ var Scheduler = class {
2933
3085
  lastFired = /* @__PURE__ */ new Map();
2934
3086
  // "mind:scheduleId" → epoch minute
2935
3087
  get statePath() {
2936
- return resolve4(voluteSystemDir(), "scheduler-state.json");
3088
+ return resolve5(voluteSystemDir(), "scheduler-state.json");
2937
3089
  }
2938
3090
  start() {
2939
3091
  this.loadState();
2940
3092
  this.interval = setInterval(() => {
2941
- 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)));
2942
3094
  }, 6e4);
2943
3095
  }
2944
3096
  stop() {
@@ -3005,7 +3157,7 @@ var Scheduler = class {
3005
3157
  prevMinute = Math.floor(prev.getTime() / 6e4);
3006
3158
  cronCache.set(schedule.cron, prevMinute);
3007
3159
  } catch (err) {
3008
- 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));
3009
3161
  return false;
3010
3162
  }
3011
3163
  }
@@ -3019,11 +3171,11 @@ var Scheduler = class {
3019
3171
  try {
3020
3172
  let text;
3021
3173
  if (schedule.script) {
3022
- const homeDir = resolve4(this.mindDirs.get(mindName) ?? mindDir(mindName), "home");
3174
+ const homeDir = resolve5(this.mindDirs.get(mindName) ?? mindDir(mindName), "home");
3023
3175
  try {
3024
3176
  const output = await this.runScript(schedule.script, homeDir, mindName);
3025
3177
  if (!output.trim()) {
3026
- slog.info(`fired script "${schedule.id}" for ${mindName} (no output)`);
3178
+ slog2.info(`fired script "${schedule.id}" for ${mindName} (no output)`);
3027
3179
  return;
3028
3180
  }
3029
3181
  text = output;
@@ -3031,24 +3183,24 @@ var Scheduler = class {
3031
3183
  const stderr = err.stderr ?? "";
3032
3184
  text = `[script error] ${err.message}${stderr ? `
3033
3185
  ${stderr}` : ""}`;
3034
- 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));
3035
3187
  }
3036
3188
  } else if (schedule.message) {
3037
3189
  text = schedule.message;
3038
3190
  } else {
3039
- 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`);
3040
3192
  return;
3041
3193
  }
3042
3194
  await this.deliverSystem(mindName, `[${schedule.id}] ${text}`, {
3043
3195
  whileSleeping: schedule.whileSleeping,
3044
3196
  session: schedule.session
3045
3197
  });
3046
- slog.info(`fired "${schedule.id}" for ${mindName}`);
3198
+ slog2.info(`fired "${schedule.id}" for ${mindName}`);
3047
3199
  if (schedule.fireAt) {
3048
3200
  this.removeSchedule(mindName, schedule.id);
3049
3201
  }
3050
3202
  } catch (err) {
3051
- 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));
3052
3204
  }
3053
3205
  }
3054
3206
  removeSchedule(mindName, scheduleId) {
@@ -3068,9 +3220,9 @@ ${stderr}` : ""}`;
3068
3220
  config.schedules = config.schedules.filter((s) => s.id !== scheduleId);
3069
3221
  if (config.schedules.length === 0) config.schedules = void 0;
3070
3222
  writeVoluteConfig(dir, config);
3071
- slog.info(`removed one-time schedule "${scheduleId}" for ${mindName}`);
3223
+ slog2.info(`removed one-time schedule "${scheduleId}" for ${mindName}`);
3072
3224
  } catch (err) {
3073
- slog.error(
3225
+ slog2.error(
3074
3226
  `failed to persist removal of schedule "${scheduleId}" for ${mindName} (removed from memory)`,
3075
3227
  logger_default.errorData(err)
3076
3228
  );
@@ -3095,9 +3247,9 @@ function getScheduler() {
3095
3247
  }
3096
3248
 
3097
3249
  // packages/daemon/src/lib/daemon/token-budget.ts
3098
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
3250
+ import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
3099
3251
  import { mkdir, writeFile as writeFile2 } from "fs/promises";
3100
- import { resolve as resolve5 } from "path";
3252
+ import { resolve as resolve6 } from "path";
3101
3253
  var tlog2 = logger_default.child("token-budget");
3102
3254
  var DEFAULT_BUDGET_PERIOD_MINUTES = 60;
3103
3255
  var MAX_QUEUE_SIZE = 100;
@@ -3134,7 +3286,8 @@ var TokenBudget = class {
3134
3286
  periodMinutes,
3135
3287
  tokenLimit,
3136
3288
  queue: [],
3137
- warningInjected: false
3289
+ warningInjected: false,
3290
+ exceededNotified: false
3138
3291
  });
3139
3292
  }
3140
3293
  }
@@ -3162,6 +3315,20 @@ var TokenBudget = class {
3162
3315
  const state = this.budgets.get(mind);
3163
3316
  if (state) state.warningInjected = true;
3164
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
+ }
3165
3332
  enqueue(mind, message) {
3166
3333
  const state = this.budgets.get(mind);
3167
3334
  if (!state) return;
@@ -3197,6 +3364,7 @@ var TokenBudget = class {
3197
3364
  state.tokensUsed = 0;
3198
3365
  state.periodStart = now;
3199
3366
  state.warningInjected = false;
3367
+ state.exceededNotified = false;
3200
3368
  this.dirty.add(mind);
3201
3369
  const queued = this.drain(mind);
3202
3370
  if (queued.length > 0) {
@@ -3220,7 +3388,7 @@ var TokenBudget = class {
3220
3388
  await Promise.all(writes);
3221
3389
  }
3222
3390
  budgetStatePath(mind) {
3223
- return resolve5(stateDir(mind), "budget.json");
3391
+ return resolve6(stateDir(mind), "budget.json");
3224
3392
  }
3225
3393
  async saveBudgetState(mind, state) {
3226
3394
  try {
@@ -3230,6 +3398,7 @@ var TokenBudget = class {
3230
3398
  periodStart: state.periodStart,
3231
3399
  tokensUsed: state.tokensUsed,
3232
3400
  warningInjected: state.warningInjected,
3401
+ exceededNotified: state.exceededNotified,
3233
3402
  queue: state.queue
3234
3403
  };
3235
3404
  await writeFile2(this.budgetStatePath(mind), `${JSON.stringify(data)}
@@ -3241,13 +3410,14 @@ var TokenBudget = class {
3241
3410
  loadBudgetState(mind) {
3242
3411
  try {
3243
3412
  const path = this.budgetStatePath(mind);
3244
- if (!existsSync6(path)) return null;
3245
- const data = JSON.parse(readFileSync5(path, "utf-8"));
3413
+ if (!existsSync7(path)) return null;
3414
+ const data = JSON.parse(readFileSync6(path, "utf-8"));
3246
3415
  if (typeof data.periodStart !== "number" || typeof data.tokensUsed !== "number") return null;
3247
3416
  return {
3248
3417
  periodStart: data.periodStart,
3249
3418
  tokensUsed: data.tokensUsed,
3250
3419
  warningInjected: data.warningInjected ?? false,
3420
+ exceededNotified: data.exceededNotified ?? false,
3251
3421
  queue: Array.isArray(data.queue) ? data.queue : [],
3252
3422
  periodMinutes: 0,
3253
3423
  // will be overwritten by caller
@@ -3370,7 +3540,7 @@ async function wakeMind(name) {
3370
3540
  async function startSpiritFull(name) {
3371
3541
  const entry = await findMind(name);
3372
3542
  if (entry?.dir) {
3373
- const { registerMindDir } = await import("./delivery-router-QTFEZ26O.js");
3543
+ const { registerMindDir } = await import("./delivery-router-IU4OMVKZ.js");
3374
3544
  registerMindDir(name, entry.dir);
3375
3545
  }
3376
3546
  await getMindManager().startMind(name);
@@ -3392,8 +3562,8 @@ async function stopSpiritFull(name) {
3392
3562
  }).catch((err) => logger_default.error("failed to publish spirit_stopped activity", logger_default.errorData(err)));
3393
3563
  }
3394
3564
  async function ensureCreatorDM(mindName, creatorUsername) {
3395
- const { getOrCreateMindUser: getOrCreateMindUser2, getUserByUsername: getUserByUsername2 } = await import("./auth-2QOOPMBX.js");
3396
- const { findDMConversation: findDMConversation2, createConversation: createConversation2 } = await import("./conversations-G6YRSABR.js");
3565
+ const { getOrCreateMindUser: getOrCreateMindUser2, getUserByUsername: getUserByUsername2 } = await import("./auth-2IMZ6N5G.js");
3566
+ const { findDMConversation: findDMConversation2, createConversation: createConversation2 } = await import("./conversations-LUVHGQSS.js");
3397
3567
  const mindUser = await getOrCreateMindUser2(mindName);
3398
3568
  const creatorUser = await getUserByUsername2(creatorUsername);
3399
3569
  if (!creatorUser) {
@@ -3425,7 +3595,7 @@ async function stopMindFull(name) {
3425
3595
  }
3426
3596
 
3427
3597
  // packages/daemon/src/lib/daemon/sleep-manager.ts
3428
- var slog2 = logger_default.child("sleep");
3598
+ var slog3 = logger_default.child("sleep");
3429
3599
  function defaultState() {
3430
3600
  return {
3431
3601
  sleeping: false,
@@ -3468,7 +3638,7 @@ var SleepManager = class {
3468
3638
  transitioning = /* @__PURE__ */ new Set();
3469
3639
  sleepConfigs = /* @__PURE__ */ new Map();
3470
3640
  get statePath() {
3471
- return resolve6(voluteSystemDir(), "sleep-state.json");
3641
+ return resolve7(voluteSystemDir(), "sleep-state.json");
3472
3642
  }
3473
3643
  start() {
3474
3644
  this.loadState();
@@ -3484,15 +3654,15 @@ var SleepManager = class {
3484
3654
  // --- State persistence ---
3485
3655
  loadState() {
3486
3656
  try {
3487
- if (existsSync7(this.statePath)) {
3488
- const data = JSON.parse(readFileSync6(this.statePath, "utf-8"));
3657
+ if (existsSync8(this.statePath)) {
3658
+ const data = JSON.parse(readFileSync7(this.statePath, "utf-8"));
3489
3659
  for (const [name, state] of Object.entries(data)) {
3490
3660
  state.triggerWakeHistory ??= [];
3491
3661
  this.states.set(name, state);
3492
3662
  }
3493
3663
  }
3494
3664
  } catch (err) {
3495
- slog2.warn("failed to load sleep state", logger_default.errorData(err));
3665
+ slog3.warn("failed to load sleep state", logger_default.errorData(err));
3496
3666
  }
3497
3667
  }
3498
3668
  saveState() {
@@ -3501,10 +3671,10 @@ var SleepManager = class {
3501
3671
  if (state.sleeping) data[name] = state;
3502
3672
  }
3503
3673
  try {
3504
- writeFileSync5(this.statePath, `${JSON.stringify(data, null, 2)}
3674
+ writeFileSync6(this.statePath, `${JSON.stringify(data, null, 2)}
3505
3675
  `);
3506
3676
  } catch (err) {
3507
- slog2.error("failed to save sleep state", logger_default.errorData(err));
3677
+ slog3.error("failed to save sleep state", logger_default.errorData(err));
3508
3678
  }
3509
3679
  }
3510
3680
  // --- Public API ---
@@ -3525,7 +3695,7 @@ var SleepManager = class {
3525
3695
  const state = this.states.get(name);
3526
3696
  if (!state?.sleeping || !state.wokenByTrigger) return;
3527
3697
  this.markAwake(name);
3528
- slog2.info(`${name} trigger-wake converted to full wake`);
3698
+ slog3.info(`${name} trigger-wake converted to full wake`);
3529
3699
  }
3530
3700
  getSleepConfig(name) {
3531
3701
  if (this.sleepConfigs.has(name)) {
@@ -3568,7 +3738,7 @@ var SleepManager = class {
3568
3738
  const result = await sendSystemMessageDirect(name, preSleepMsg);
3569
3739
  conversationId = result.conversationId;
3570
3740
  } catch (err) {
3571
- 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));
3572
3742
  }
3573
3743
  try {
3574
3744
  await fetch(`http://127.0.0.1:${entry.port}/message`, {
@@ -3585,7 +3755,7 @@ var SleepManager = class {
3585
3755
  })
3586
3756
  });
3587
3757
  } catch (err) {
3588
- 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));
3589
3759
  }
3590
3760
  await this.waitForIdle(name, 12e4);
3591
3761
  await new Promise((r) => setTimeout(r, 3e3));
@@ -3593,7 +3763,7 @@ var SleepManager = class {
3593
3763
  await this.killOrphanOnPort(entry.port);
3594
3764
  await this.archiveSessions(name);
3595
3765
  this.markSleeping(name, opts);
3596
- slog2.info(`${name} is now sleeping`);
3766
+ slog3.info(`${name} is now sleeping`);
3597
3767
  } finally {
3598
3768
  this.transitioning.delete(name);
3599
3769
  }
@@ -3612,7 +3782,7 @@ var SleepManager = class {
3612
3782
  try {
3613
3783
  await wakeMind(name);
3614
3784
  } catch (err) {
3615
- slog2.error(`failed to wake ${name}`, logger_default.errorData(err));
3785
+ slog3.error(`failed to wake ${name}`, logger_default.errorData(err));
3616
3786
  return;
3617
3787
  }
3618
3788
  }
@@ -3653,7 +3823,7 @@ var SleepManager = class {
3653
3823
  const result = await sendSystemMessageDirect(name, summaryText);
3654
3824
  wakeConvId = result.conversationId;
3655
3825
  } catch (err) {
3656
- 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));
3657
3827
  }
3658
3828
  try {
3659
3829
  await fetch(`http://127.0.0.1:${entry.port}/message`, {
@@ -3670,17 +3840,17 @@ var SleepManager = class {
3670
3840
  })
3671
3841
  });
3672
3842
  } catch (err) {
3673
- 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));
3674
3844
  }
3675
3845
  }
3676
3846
  const flushed = await this.flushQueuedMessages(name);
3677
3847
  if (flushed > 0) {
3678
- slog2.info(`flushed ${flushed} queued message(s) for ${name}`);
3848
+ slog3.info(`flushed ${flushed} queued message(s) for ${name}`);
3679
3849
  }
3680
3850
  if (!opts?.trigger) {
3681
3851
  this.markAwake(name);
3682
3852
  }
3683
- slog2.info(`${name} is now awake${opts?.trigger ? " (trigger wake)" : ""}`);
3853
+ slog3.info(`${name} is now awake${opts?.trigger ? " (trigger wake)" : ""}`);
3684
3854
  } finally {
3685
3855
  this.transitioning.delete(name);
3686
3856
  }
@@ -3735,16 +3905,16 @@ var SleepManager = class {
3735
3905
  async flushQueuedMessages(name) {
3736
3906
  try {
3737
3907
  const db = await getDb();
3738
- 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();
3739
3909
  if (rows.length === 0) return 0;
3740
- const { deliverMessage: deliverMessage2 } = await import("./message-delivery-54IXVE5H.js");
3910
+ const { deliverMessage: deliverMessage2 } = await import("./message-delivery-VBBAJX3J.js");
3741
3911
  const delivered = [];
3742
3912
  for (const row of rows) {
3743
3913
  try {
3744
3914
  await deliverMessage2(name, JSON.parse(row.payload));
3745
3915
  delivered.push(row.id);
3746
3916
  } catch (err) {
3747
- 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));
3748
3918
  }
3749
3919
  }
3750
3920
  if (delivered.length > 0) {
@@ -3756,7 +3926,7 @@ var SleepManager = class {
3756
3926
  }
3757
3927
  return delivered.length;
3758
3928
  } catch (err) {
3759
- 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));
3760
3930
  return 0;
3761
3931
  }
3762
3932
  }
@@ -3785,7 +3955,7 @@ var SleepManager = class {
3785
3955
  const interval = CronExpressionParser2.parse(config.schedule.wake);
3786
3956
  return interval.next().toDate().toISOString();
3787
3957
  } catch (err) {
3788
- 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));
3789
3959
  return null;
3790
3960
  }
3791
3961
  }
@@ -3805,7 +3975,7 @@ var SleepManager = class {
3805
3975
  const wakeAt = new Date(state.voluntaryWakeAt);
3806
3976
  if (now >= wakeAt) {
3807
3977
  this.initiateWake(name).catch(
3808
- (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))
3809
3979
  );
3810
3980
  continue;
3811
3981
  }
@@ -3814,7 +3984,7 @@ var SleepManager = class {
3814
3984
  const wakeAt = new Date(state.scheduledWakeAt);
3815
3985
  if (now >= wakeAt) {
3816
3986
  this.initiateWake(name).catch(
3817
- (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))
3818
3988
  );
3819
3989
  continue;
3820
3990
  }
@@ -3822,7 +3992,7 @@ var SleepManager = class {
3822
3992
  if (!state?.sleeping) {
3823
3993
  if (this.shouldSleep(config.schedule.sleep, epochMinute)) {
3824
3994
  this.initiateSleep(name).catch(
3825
- (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))
3826
3996
  );
3827
3997
  }
3828
3998
  }
@@ -3835,22 +4005,22 @@ var SleepManager = class {
3835
4005
  const prevMinute = Math.floor(prev.getTime() / 6e4);
3836
4006
  return prevMinute === epochMinute;
3837
4007
  } catch (err) {
3838
- slog2.warn(`invalid sleep cron "${cronExpr}"`, logger_default.errorData(err));
4008
+ slog3.warn(`invalid sleep cron "${cronExpr}"`, logger_default.errorData(err));
3839
4009
  return false;
3840
4010
  }
3841
4011
  }
3842
4012
  async waitForIdle(name, timeoutMs) {
3843
- return new Promise((resolve8) => {
4013
+ return new Promise((resolve9) => {
3844
4014
  const timeout = setTimeout(() => {
3845
4015
  unsub();
3846
- resolve8();
4016
+ resolve9();
3847
4017
  }, timeoutMs);
3848
4018
  const unsub = subscribe((event) => {
3849
4019
  if (event.mind !== name) return;
3850
4020
  if (event.type === "mind_done" || event.type === "mind_idle") {
3851
4021
  clearTimeout(timeout);
3852
4022
  unsub();
3853
- resolve8();
4023
+ resolve9();
3854
4024
  }
3855
4025
  });
3856
4026
  });
@@ -3858,41 +4028,41 @@ var SleepManager = class {
3858
4028
  async archiveSessions(name) {
3859
4029
  const dir = mindDir(name);
3860
4030
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 16);
3861
- const sessionsDir = resolve6(dir, ".mind", "sessions");
3862
- if (existsSync7(sessionsDir)) {
3863
- const archiveDir = resolve6(sessionsDir, "archive");
3864
- 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 });
3865
4035
  for (const file of readdirSync2(sessionsDir)) {
3866
4036
  if (file === "archive" || !file.endsWith(".json")) continue;
3867
- const src = resolve6(sessionsDir, file);
4037
+ const src = resolve7(sessionsDir, file);
3868
4038
  const base = file.replace(/\.json$/, "");
3869
- const dest = resolve6(archiveDir, `${base}-${timestamp}.json`);
4039
+ const dest = resolve7(archiveDir, `${base}-${timestamp}.json`);
3870
4040
  try {
3871
4041
  renameSync(src, dest);
3872
4042
  } catch (err) {
3873
- 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));
3874
4044
  }
3875
4045
  }
3876
4046
  }
3877
- const piSessionsDir = resolve6(dir, ".mind", "pi-sessions");
3878
- if (existsSync7(piSessionsDir)) {
3879
- const archiveDir = resolve6(piSessionsDir, "archive");
3880
- 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 });
3881
4051
  for (const entry of readdirSync2(piSessionsDir, { withFileTypes: true })) {
3882
4052
  if (entry.name === "archive" || !entry.isDirectory()) continue;
3883
- const src = resolve6(piSessionsDir, entry.name);
3884
- const dest = resolve6(archiveDir, `${entry.name}-${timestamp}`);
4053
+ const src = resolve7(piSessionsDir, entry.name);
4054
+ const dest = resolve7(archiveDir, `${entry.name}-${timestamp}`);
3885
4055
  try {
3886
4056
  renameSync(src, dest);
3887
4057
  } catch (err) {
3888
- 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));
3889
4059
  }
3890
4060
  }
3891
4061
  }
3892
4062
  }
3893
4063
  async runWakeContextScript(name, sleepingSince, duration) {
3894
- const scriptPath = resolve6(mindDir(name), "home", ".local", "hooks", "wake-context.sh");
3895
- if (!existsSync7(scriptPath)) return "";
4064
+ const scriptPath = resolve7(mindDir(name), "home", ".local", "hooks", "wake-context.sh");
4065
+ if (!existsSync8(scriptPath)) return "";
3896
4066
  const input = JSON.stringify({
3897
4067
  sleepingSince,
3898
4068
  duration,
@@ -3928,7 +4098,7 @@ var SleepManager = class {
3928
4098
  });
3929
4099
  return result.trim();
3930
4100
  } catch (err) {
3931
- 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));
3932
4102
  return "";
3933
4103
  }
3934
4104
  }
@@ -3942,7 +4112,7 @@ var SleepManager = class {
3942
4112
  async buildQueuedSummary(name) {
3943
4113
  try {
3944
4114
  const db = await getDb();
3945
- 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();
3946
4116
  if (rows.length === 0) return "No messages arrived while you slept.";
3947
4117
  const channelCounts = /* @__PURE__ */ new Map();
3948
4118
  const senders = /* @__PURE__ */ new Set();
@@ -3955,7 +4125,7 @@ var SleepManager = class {
3955
4125
  const senderNote = senders.size > 0 ? ` from ${[...senders].join(", ")}` : "";
3956
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.`;
3957
4127
  } catch (err) {
3958
- 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));
3959
4129
  return "Unable to check for queued messages \u2014 there may be messages waiting.";
3960
4130
  }
3961
4131
  }
@@ -3970,7 +4140,7 @@ var SleepManager = class {
3970
4140
  } catch {
3971
4141
  return;
3972
4142
  }
3973
- slog2.warn(`orphan process found on port ${port} after sleep, killing`);
4143
+ slog3.warn(`orphan process found on port ${port} after sleep, killing`);
3974
4144
  const execFileAsync2 = promisify2(execFile2);
3975
4145
  try {
3976
4146
  const { stdout } = await execFileAsync2("lsof", ["-ti", `:${port}`, "-sTCP:LISTEN"]);
@@ -3981,7 +4151,7 @@ var SleepManager = class {
3981
4151
  process.kill(pid, "SIGTERM");
3982
4152
  } catch (err) {
3983
4153
  if (err.code !== "ESRCH") {
3984
- 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));
3985
4155
  }
3986
4156
  }
3987
4157
  }
@@ -3989,7 +4159,7 @@ var SleepManager = class {
3989
4159
  } catch {
3990
4160
  try {
3991
4161
  const portHex = port.toString(16).toUpperCase().padStart(4, "0");
3992
- const tcp6 = readFileSync6("/proc/net/tcp6", "utf-8");
4162
+ const tcp6 = readFileSync7("/proc/net/tcp6", "utf-8");
3993
4163
  for (const line of tcp6.split("\n")) {
3994
4164
  if (!line.includes(`:${portHex} `)) continue;
3995
4165
  const fields = line.trim().split(/\s+/);
@@ -4013,7 +4183,7 @@ var SleepManager = class {
4013
4183
  }
4014
4184
  }
4015
4185
  } catch (err) {
4016
- 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));
4017
4187
  }
4018
4188
  }
4019
4189
  await new Promise((r) => setTimeout(r, 1e3));
@@ -4023,7 +4193,7 @@ var SleepManager = class {
4023
4193
  if (!state?.sleeping || !state.wokenByTrigger) return;
4024
4194
  if (this.transitioning.has(event.mind)) return;
4025
4195
  if (event.type === "mind_idle") {
4026
- slog2.info(`${event.mind} going back to sleep after trigger wake`);
4196
+ slog3.info(`${event.mind} going back to sleep after trigger wake`);
4027
4197
  state.wokenByTrigger = false;
4028
4198
  this.transitioning.add(event.mind);
4029
4199
  sleepMind(event.mind).then(() => this.archiveSessions(event.mind)).then(() => {
@@ -4032,9 +4202,9 @@ var SleepManager = class {
4032
4202
  const sleepConfig = this.getSleepConfig(event.mind);
4033
4203
  state.scheduledWakeAt = this.getNextWakeTime(sleepConfig);
4034
4204
  this.saveState();
4035
- slog2.info(`${event.mind} returned to sleep`);
4205
+ slog3.info(`${event.mind} returned to sleep`);
4036
4206
  }).catch((err) => {
4037
- 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));
4038
4208
  }).finally(() => {
4039
4209
  this.transitioning.delete(event.mind);
4040
4210
  });
@@ -4057,8 +4227,8 @@ function getSleepManagerIfReady() {
4057
4227
 
4058
4228
  // packages/daemon/src/lib/delivery/delivery-manager.ts
4059
4229
  import { readFile, realpath } from "fs/promises";
4060
- import { extname, resolve as resolve7 } from "path";
4061
- 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";
4062
4232
 
4063
4233
  // packages/daemon/src/lib/chat/typing.ts
4064
4234
  var DEFAULT_TTL_MS = 1e4;
@@ -4256,7 +4426,7 @@ var DeliveryManager = class {
4256
4426
  async restoreFromDb() {
4257
4427
  try {
4258
4428
  const db = await getDb();
4259
- 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"));
4260
4430
  for (const row of rows) {
4261
4431
  let payload;
4262
4432
  try {
@@ -4274,7 +4444,7 @@ var DeliveryManager = class {
4274
4444
  this.addToBatchBuffer(row.mind, row.session, payload, sessionConfig);
4275
4445
  } else {
4276
4446
  try {
4277
- await db.delete(deliveryQueue).where(eq5(deliveryQueue.id, row.id));
4447
+ await db.delete(deliveryQueue).where(eq6(deliveryQueue.id, row.id));
4278
4448
  } catch (err) {
4279
4449
  dlog.warn(`failed to delete queue row ${row.id} for ${row.mind}`, logger_default.errorData(err));
4280
4450
  }
@@ -4295,7 +4465,7 @@ var DeliveryManager = class {
4295
4465
  */
4296
4466
  async getPending(mindName) {
4297
4467
  const db = await getDb();
4298
- 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")));
4299
4469
  const byChannel = /* @__PURE__ */ new Map();
4300
4470
  for (const row of rows) {
4301
4471
  const ch = row.channel ?? "unknown";
@@ -4410,6 +4580,7 @@ var DeliveryManager = class {
4410
4580
  if (payload.conversationId) {
4411
4581
  typingMap.set(payload.conversationId, baseName, { persistent: true });
4412
4582
  }
4583
+ onMindEvent(baseName, "delivery", payload.channel);
4413
4584
  const enrichedPayload = await this.enrichWithProfiles(baseName, session, payload);
4414
4585
  const body = JSON.stringify({
4415
4586
  ...enrichedPayload,
@@ -4489,10 +4660,10 @@ var DeliveryManager = class {
4489
4660
  try {
4490
4661
  const db = await getDb();
4491
4662
  await db.delete(deliveryQueue).where(
4492
- and3(
4493
- eq5(deliveryQueue.mind, baseName),
4494
- eq5(deliveryQueue.session, session),
4495
- eq5(deliveryQueue.status, "pending")
4663
+ and4(
4664
+ eq6(deliveryQueue.mind, baseName),
4665
+ eq6(deliveryQueue.session, session),
4666
+ eq6(deliveryQueue.status, "pending")
4496
4667
  )
4497
4668
  );
4498
4669
  } catch (err) {
@@ -4618,11 +4789,11 @@ var DeliveryManager = class {
4618
4789
  await this.persistToQueue(baseName, session, payload, "gated");
4619
4790
  try {
4620
4791
  const db = await getDb();
4621
- const count = await db.select({ count: sql2`count(*)` }).from(deliveryQueue).where(
4622
- and3(
4623
- eq5(deliveryQueue.mind, baseName),
4624
- eq5(deliveryQueue.channel, payload.channel),
4625
- 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")
4626
4797
  )
4627
4798
  );
4628
4799
  if ((count[0]?.count ?? 0) <= 1) {
@@ -4647,7 +4818,7 @@ var DeliveryManager = class {
4647
4818
  `To accept this channel, add a routing rule for "${channel}" to your routes.json.`,
4648
4819
  `Messages are being held until a route is configured.`
4649
4820
  ].filter((line) => line !== null).join("\n");
4650
- const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-YUIT7RA6.js");
4821
+ const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-EIINIHFB.js");
4651
4822
  await sendSystemMessage2(mindName, notification);
4652
4823
  }
4653
4824
  async persistToQueue(mindName, session, payload, status = "pending") {
@@ -4721,8 +4892,8 @@ var DeliveryManager = class {
4721
4892
  const dir = mindDir(p.username);
4722
4893
  const config = readVoluteConfig(dir);
4723
4894
  if (!config?.profile?.avatar) continue;
4724
- filePath = resolve7(dir, "home", config.profile.avatar);
4725
- const homeDir = resolve7(dir, "home");
4895
+ filePath = resolve8(dir, "home", config.profile.avatar);
4896
+ const homeDir = resolve8(dir, "home");
4726
4897
  if (!filePath.startsWith(`${homeDir}/`)) {
4727
4898
  dlog.warn(`avatar path for ${p.username} escapes home directory, skipping`);
4728
4899
  continue;
@@ -4741,7 +4912,7 @@ var DeliveryManager = class {
4741
4912
  throw err;
4742
4913
  }
4743
4914
  } else {
4744
- filePath = resolve7(voluteHome(), "avatars", p.avatar);
4915
+ filePath = resolve8(voluteHome(), "avatars", p.avatar);
4745
4916
  }
4746
4917
  const ext = extname(filePath).toLowerCase();
4747
4918
  const mimeMap = {
@@ -4883,18 +5054,18 @@ async function linkToolResultToTurn(mind, turnId, toolResultContent, toolUseEven
4883
5054
  channel: mindHistory.channel,
4884
5055
  content: mindHistory.content,
4885
5056
  message_id: mindHistory.message_id
4886
- }).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);
4887
5058
  const row = rows[0];
4888
5059
  if (!row) {
4889
5060
  dlog2.warn(`outbound marker references missing record: mind=${mind} id=${outboundId}`);
4890
5061
  continue;
4891
5062
  }
4892
- 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));
4893
5064
  if (row.message_id) {
4894
5065
  await db.update(messages).set({
4895
5066
  turn_id: turnId,
4896
5067
  ...toolUseEventId != null ? { source_event_id: toolUseEventId } : {}
4897
- }).where(eq6(messages.id, Number(row.message_id)));
5068
+ }).where(eq7(messages.id, Number(row.message_id)));
4898
5069
  }
4899
5070
  publish3(mind, {
4900
5071
  mind,
@@ -4938,19 +5109,19 @@ async function linkToolResultToTurn(mind, turnId, toolResultContent, toolUseEven
4938
5109
  async function tagUntaggedOutbound(mind, turnId) {
4939
5110
  const db = await getDb();
4940
5111
  const range = await db.select({
4941
- minId: sql3`MIN(${mindHistory.id})`,
4942
- maxId: sql3`MAX(${mindHistory.id})`
4943
- }).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)));
4944
5115
  const minId = range[0]?.minId;
4945
5116
  const maxId = range[0]?.maxId;
4946
5117
  if (minId == null || maxId == null) return;
4947
5118
  const orphans = await db.select({ id: mindHistory.id, message_id: mindHistory.message_id }).from(mindHistory).where(
4948
- and4(
4949
- eq6(mindHistory.mind, mind),
4950
- eq6(mindHistory.type, "outbound"),
4951
- sql3`${mindHistory.turn_id} IS NULL`,
4952
- sql3`${mindHistory.id} >= ${minId}`,
4953
- 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}`
4954
5125
  )
4955
5126
  );
4956
5127
  if (orphans.length === 0) return;
@@ -4959,10 +5130,10 @@ async function tagUntaggedOutbound(mind, turnId) {
4959
5130
  const orphansWithMessages = orphans.filter((o) => o.message_id);
4960
5131
  if (orphansWithMessages.length > 0) {
4961
5132
  const toolUseEvents = await db.select({ id: mindHistory.id }).from(mindHistory).where(
4962
- and4(
4963
- eq6(mindHistory.mind, mind),
4964
- eq6(mindHistory.turn_id, turnId),
4965
- eq6(mindHistory.type, "tool_use")
5133
+ and5(
5134
+ eq7(mindHistory.mind, mind),
5135
+ eq7(mindHistory.turn_id, turnId),
5136
+ eq7(mindHistory.type, "tool_use")
4966
5137
  )
4967
5138
  ).orderBy(mindHistory.id);
4968
5139
  for (const orphan of orphansWithMessages) {
@@ -4976,7 +5147,7 @@ async function tagUntaggedOutbound(mind, turnId) {
4976
5147
  await db.update(messages).set({
4977
5148
  turn_id: turnId,
4978
5149
  ...sourceEventId != null ? { source_event_id: sourceEventId } : {}
4979
- }).where(eq6(messages.id, Number(orphan.message_id)));
5150
+ }).where(eq7(messages.id, Number(orphan.message_id)));
4980
5151
  }
4981
5152
  }
4982
5153
  dlog2.info(`tagged ${orphans.length} orphaned outbound record(s) for ${mind} with turn ${turnId}`);
@@ -4990,22 +5161,22 @@ async function tagUntaggedInbound(mind, turnId, {
4990
5161
  const tagHistoryPromise = (async () => {
4991
5162
  if (!channel) return;
4992
5163
  const historyConditions = [
4993
- eq6(mindHistory.mind, mind),
4994
- eq6(mindHistory.type, "inbound"),
4995
- sql3`${mindHistory.turn_id} IS NULL`,
4996
- sql3`${mindHistory.created_at} > datetime('now', '-60 seconds')`,
4997
- 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)
4998
5169
  ];
4999
- 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);
5000
5171
  if (recentInbounds.length > 0) {
5001
5172
  const ids = recentInbounds.map((r) => r.id);
5002
5173
  await db.update(mindHistory).set({ turn_id: turnId }).where(inArray3(mindHistory.id, ids));
5003
5174
  if (setTrigger) {
5004
- 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));
5005
5176
  }
5006
5177
  }
5007
5178
  })();
5008
- 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();
5009
5180
  const [tagResult, mindUserResult] = await Promise.allSettled([
5010
5181
  tagHistoryPromise,
5011
5182
  mindUserPromise
@@ -5014,13 +5185,13 @@ async function tagUntaggedInbound(mind, turnId, {
5014
5185
  dlog2.error("failed to tag history inbound", logger_default.errorData(tagResult.reason));
5015
5186
  }
5016
5187
  const mindUser = mindUserResult.status === "fulfilled" ? mindUserResult.value : void 0;
5017
- 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) : [];
5018
5189
  const recentMsgs = mindConvIds.length > 0 ? await db.select({ id: messages.id }).from(messages).where(
5019
- and4(
5190
+ and5(
5020
5191
  inArray3(messages.conversation_id, mindConvIds),
5021
- sql3`${messages.turn_id} IS NULL`,
5022
- sql3`${messages.sender_name} != ${mind}`,
5023
- 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')`
5024
5195
  )
5025
5196
  ).orderBy(desc2(messages.id)).limit(limit) : [];
5026
5197
  if (recentMsgs.length > 0) {
@@ -5081,7 +5252,7 @@ async function deliverMessage(mindName, payload) {
5081
5252
  }
5082
5253
 
5083
5254
  // packages/daemon/src/lib/chat/system-chat.ts
5084
- var slog3 = logger_default.child("system-chat");
5255
+ var slog4 = logger_default.child("system-chat");
5085
5256
  var dmCache = /* @__PURE__ */ new Map();
5086
5257
  function resetSystemDMCache() {
5087
5258
  dmCache.clear();
@@ -5149,7 +5320,7 @@ async function generateSystemReply(conversationId, mindName, message) {
5149
5320
  });
5150
5321
  return;
5151
5322
  } catch (err) {
5152
- 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));
5153
5324
  }
5154
5325
  }
5155
5326
  const entry = await findMind(mindName);
@@ -5170,7 +5341,7 @@ async function generateSystemReply(conversationId, mindName, message) {
5170
5341
  if (config.sleep.schedule?.wake) contextParts.push(`Wake cron: ${config.sleep.schedule.wake}`);
5171
5342
  }
5172
5343
  try {
5173
- const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-VPPQXBPH.js");
5344
+ const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-27S7MKJO.js");
5174
5345
  const sm = getSleepManagerIfReady2();
5175
5346
  if (sm) {
5176
5347
  const state = sm.getState(mindName);
@@ -5179,7 +5350,7 @@ async function generateSystemReply(conversationId, mindName, message) {
5179
5350
  }
5180
5351
  }
5181
5352
  } catch (err) {
5182
- 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));
5183
5354
  }
5184
5355
  try {
5185
5356
  const schedules = config?.schedules;
@@ -5192,12 +5363,12 @@ async function generateSystemReply(conversationId, mindName, message) {
5192
5363
  }
5193
5364
  }
5194
5365
  } catch (err) {
5195
- 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));
5196
5367
  }
5197
5368
  const systemPrompt = contextParts.join("\n");
5198
5369
  const response = await aiCompleteUtility(systemPrompt, message);
5199
5370
  if (!response) {
5200
- slog3.warn(`no AI model available for system reply to ${mindName}`);
5371
+ slog4.warn(`no AI model available for system reply to ${mindName}`);
5201
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.";
5202
5373
  await addMessage(conversationId, "assistant", "volute", [{ type: "text", text: fallback }]);
5203
5374
  return;
@@ -5227,13 +5398,20 @@ export {
5227
5398
  getPromptIfCustom,
5228
5399
  getMindPromptDefaults,
5229
5400
  RotatingLog,
5401
+ syncProviderToMinds,
5230
5402
  resolveMindToken,
5403
+ recordNotice,
5404
+ drainNotices,
5405
+ clearDeliveredNotices,
5406
+ formatNotices,
5231
5407
  RestartTracker,
5232
5408
  subscribe2 as subscribe,
5233
5409
  subscribeAll,
5234
5410
  publish3 as publish,
5235
5411
  summarizeTurn,
5236
5412
  initSummarizer,
5413
+ markErrored,
5414
+ takeErrored,
5237
5415
  createTurn,
5238
5416
  getActiveTurnId,
5239
5417
  trackToolUse,