volute 0.47.0 → 0.48.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 (128) hide show
  1. package/README.md +11 -11
  2. package/dist/{accept-YAFP5JFJ.js → accept-KYNC5X3U.js} +3 -3
  3. package/dist/{ai-service-CVZEYKTK.js → ai-service-643TNFPH.js} +6 -2
  4. package/dist/{avatar-image-7S3WA77A.js → avatar-image-Y45R7LW5.js} +3 -2
  5. package/dist/{backup-IIAFOW2L.js → backup-UDH4GMSW.js} +11 -11
  6. package/dist/{bridge-TIZGSXOD.js → bridge-3FNSWLNQ.js} +3 -3
  7. package/dist/{channels-ITE4YC57.js → channels-SGQZHNQJ.js} +3 -3
  8. package/dist/{chat-AJLJCQ3M.js → chat-X43VYHH2.js} +9 -9
  9. package/dist/chunk-4FCL4DVZ.js +48 -0
  10. package/dist/{chunk-SKNXMUIU.js → chunk-5KXCM5AW.js} +17 -1
  11. package/dist/{chunk-RBNMDAKB.js → chunk-BCG45AQB.js} +15 -1
  12. package/dist/chunk-DW4TRDOZ.js +29 -0
  13. package/dist/{chunk-CBOIHNMR.js → chunk-FJ2MZ5PH.js} +39 -3
  14. package/dist/{chunk-M6TTZRGH.js → chunk-HNGFKPNS.js} +20 -4
  15. package/dist/{chunk-IWJSNMSY.js → chunk-HUNDXZBZ.js} +2 -2
  16. package/dist/chunk-IYCV34IU.js +158 -0
  17. package/dist/{chunk-5IERLDUS.js → chunk-MJRXFUMS.js} +25 -5
  18. package/dist/{chunk-JCMGDCGX.js → chunk-MOERAQXH.js} +2 -0
  19. package/dist/{chunk-XHN6XBWV.js → chunk-OQJMTHEH.js} +1 -1
  20. package/dist/{chunk-BGYHLR54.js → chunk-PJVPDY2Z.js} +1 -1
  21. package/dist/{chunk-5NN2VHJV.js → chunk-Q7HOAVFR.js} +1 -1
  22. package/dist/{chunk-KDLYIECM.js → chunk-R772ET2M.js} +18 -4
  23. package/dist/{mind-list-KEGRGQEQ.js → chunk-SHKM5RGD.js} +19 -6
  24. package/dist/{chunk-4I72V3E5.js → chunk-T4VS7UDW.js} +11 -11
  25. package/dist/{chunk-K23P5Q5N.js → chunk-USD45JKR.js} +27 -5
  26. package/dist/{chunk-F55GRIEK.js → chunk-VB2QXUJQ.js} +176 -201
  27. package/dist/{chunk-M3XDVS5Q.js → chunk-VZRA5TYO.js} +1 -1
  28. package/dist/{chunk-JSVHH32K.js → chunk-WARH6GIV.js} +10 -10
  29. package/dist/{chunk-PFZBNKUH.js → chunk-WCFSBH33.js} +0 -1
  30. package/dist/{chunk-VMCZBXF2.js → chunk-WQ46E33M.js} +8 -32
  31. package/dist/{chunk-RUFLGTOT.js → chunk-XVBSFLM7.js} +1 -1
  32. package/dist/{chunk-LWDTP6DH.js → chunk-YNBXEQAP.js} +31 -1
  33. package/dist/cli.js +33 -25
  34. package/dist/{clock-E6N5Y3YW.js → clock-CNRF6F7T.js} +3 -3
  35. package/dist/{cloud-sync-LQTVDTQ3.js → cloud-sync-WHKCB4CD.js} +14 -12
  36. package/dist/{config-TJLYUV3U.js → config-RPSLA2HX.js} +3 -3
  37. package/dist/{create-PQQXKTJK.js → create-GJKHABJB.js} +16 -5
  38. package/dist/{create-A7PDHIIL.js → create-VIQVP3QB.js} +3 -3
  39. package/dist/{daemon-client-IYR4KCPU.js → daemon-client-ZFY5MOAL.js} +5 -3
  40. package/dist/{daemon-restart-5F3YTLZK.js → daemon-restart-7KUHVZIN.js} +4 -4
  41. package/dist/daemon.js +668 -401
  42. package/dist/{db-LZTLA7XC.js → db-IPXRJUI7.js} +1 -1
  43. package/dist/{delete-HPLC7ETU.js → delete-ESEP7NGQ.js} +1 -1
  44. package/dist/{delivery-manager-TN5KK2AP.js → delivery-manager-HZTT5SJR.js} +14 -12
  45. package/dist/{down-ZI4S6265.js → down-G6IADJXV.js} +2 -2
  46. package/dist/{echo-text-SEQCLGAT.js → echo-text-H3SH337Q.js} +16 -14
  47. package/dist/env-6TGPO5WG.js +18 -0
  48. package/dist/{env-HRL2PWAT.js → env-C7Z55QCJ.js} +7 -7
  49. package/dist/{export-4GVGNW54.js → export-C2K3NIRD.js} +1 -1
  50. package/dist/{extension-QBY4C44L.js → extension-J4ZQ2GHV.js} +3 -3
  51. package/dist/{extensions-PIMIQ7J3.js → extensions-GEKF47A4.js} +14 -12
  52. package/dist/{files-FEFZKMNM.js → files-LXQSQOFG.js} +3 -3
  53. package/dist/{import-7MO3YTRE.js → import-SX3ZXHB4.js} +4 -4
  54. package/dist/{join-ZJV7W6MO.js → join-34TR2GXQ.js} +1 -1
  55. package/dist/{list-LQO2DCIK.js → list-PMUXZNAM.js} +3 -3
  56. package/dist/{login-6TLMI2TQ.js → login-ARRZ4ORJ.js} +3 -3
  57. package/dist/{login-OF4WXDAN.js → login-CL4IT2ED.js} +12 -3
  58. package/dist/{logout-ERE2BGA3.js → logout-HZYJCYCA.js} +3 -3
  59. package/dist/{logout-BK53HXNY.js → logout-YZRMZ3O2.js} +3 -3
  60. package/dist/{message-delivery-ZE3YGJDD.js → message-delivery-GPQ5SE5N.js} +14 -12
  61. package/dist/{mind-POOHFZHP.js → mind-46AOK373.js} +23 -19
  62. package/dist/mind-contacts-GV7XYL5D.js +64 -0
  63. package/dist/{mind-history-47DN6ILW.js → mind-history-TTGA5BHZ.js} +7 -7
  64. package/dist/mind-list-OTHV4ZO4.js +13 -0
  65. package/dist/{mind-profile-PEQYASQX.js → mind-profile-LUG353ZT.js} +1 -1
  66. package/dist/{mind-service-JFY7UG5E.js → mind-service-2ARGJNKP.js} +16 -12
  67. package/dist/{mind-sleep-IN3WPA76.js → mind-sleep-DV7KP255.js} +5 -5
  68. package/dist/{mind-status-SMUWJKGV.js → mind-status-BJNPGXKC.js} +8 -3
  69. package/dist/{mind-wake-R54BPESY.js → mind-wake-LVTZ55EZ.js} +3 -3
  70. package/dist/notices-2KU5NTRY.js +25 -0
  71. package/dist/{package-WPEE2HVJ.js → package-RTN2PS7O.js} +4 -2
  72. package/dist/{read-PWAJOQIQ.js → read-YSWUXYL7.js} +3 -3
  73. package/dist/{register-7SZJFHU6.js → register-42VBJKTP.js} +3 -3
  74. package/dist/{reject-6VH7N2A4.js → reject-SXGCYN4A.js} +3 -3
  75. package/dist/{restart-H5WJDMA7.js → restart-YYEGZJDD.js} +7 -7
  76. package/dist/{sandbox-G4X4K3UN.js → sandbox-5VQ454XP.js} +2 -2
  77. package/dist/{scheduler-HQSDYJFY.js → scheduler-I7JZCT47.js} +14 -12
  78. package/dist/{seed-VANPU43L.js → seed-F2HXZQU4.js} +1 -1
  79. package/dist/{seed-check-VLTVILOV.js → seed-check-TYD7RRZY.js} +1 -1
  80. package/dist/{seed-cmd-SYVDZKM4.js → seed-cmd-MLCTGSX5.js} +3 -3
  81. package/dist/{seed-create-3FGZPS6C.js → seed-create-KQ7OILWB.js} +6 -4
  82. package/dist/seed-readiness-RBPGOLSZ.js +18 -0
  83. package/dist/{seed-sprout-H7QLFPFM.js → seed-sprout-HVYCFJLA.js} +29 -30
  84. package/dist/{send-HYDFGC6G.js → send-TD2X5U3K.js} +7 -7
  85. package/dist/{service-SYJ5G6LP.js → service-CVZMQYK6.js} +1 -1
  86. package/dist/{service-install-FQ43Z4DF.js → service-install-VCRMFWX5.js} +2 -2
  87. package/dist/{setup-KFYVWTXG.js → setup-5ECWTYKG.js} +5 -1
  88. package/dist/{setup-QJHGMGSN.js → setup-AE4CVUC4.js} +4 -4
  89. package/dist/{skill-GUKG2YVH.js → skill-UUM4JZRF.js} +7 -7
  90. package/dist/skills/dreaming/SKILL.md +5 -1
  91. package/dist/skills/dreaming/scripts/dream.ts +5 -1
  92. package/dist/skills/orientation/SKILL.md +8 -7
  93. package/dist/skills/tending/SKILL.md +51 -2
  94. package/dist/skills/volute-mind/SKILL.md +2 -0
  95. package/dist/{skills-L2CMTW7A.js → skills-B3SVDCEB.js} +2 -2
  96. package/dist/{sleep-manager-3NA7ZJP3.js → sleep-manager-Z27R3WTW.js} +14 -12
  97. package/dist/{spirit-WXN4IDBF.js → spirit-WXS3HCLN.js} +7 -5
  98. package/dist/{split-WBMZXBHF.js → split-SKZ4Y2D6.js} +1 -1
  99. package/dist/{sprout-LTL5P36T.js → sprout-KQ43BWZJ.js} +1 -1
  100. package/dist/{src-OJHARHTF.js → src-WLJE73NP.js} +14 -5
  101. package/dist/{start-X46I3GXB.js → start-O6UKK7BG.js} +7 -7
  102. package/dist/{status-V4RJMHJ4.js → status-F4PGREUU.js} +6 -4
  103. package/dist/{stop-HJQV4YSM.js → stop-UBX6X5RA.js} +7 -7
  104. package/dist/{system-chat-N2F7HVY3.js → system-chat-63ABFF6V.js} +14 -12
  105. package/dist/{systems-B5YJKMW4.js → systems-JJNGQHAO.js} +6 -6
  106. package/dist/{turn-tracker-JZRZDFWV.js → turn-tracker-KLPV3PAU.js} +4 -4
  107. package/dist/{up-J2PBPOZL.js → up-RVGDE6CQ.js} +5 -3
  108. package/dist/{update-ACV4SAY3.js → update-OXQEGGXD.js} +1 -1
  109. package/dist/{upgrade-NWAZ7MLD.js → upgrade-K5FIQPQD.js} +1 -1
  110. package/dist/{version-notify-XRGTEEDK.js → version-notify-73YURTFR.js} +17 -15
  111. package/dist/web-assets/assets/index-WdZ60R6c.css +1 -0
  112. package/dist/web-assets/assets/index-taX6Ezfa.js +92 -0
  113. package/dist/web-assets/index.html +2 -2
  114. package/package.json +4 -2
  115. package/packages/extensions/pages/dist/ui/assets/index-BuXnE-rb.css +1 -0
  116. package/packages/extensions/pages/dist/ui/assets/index-DtzftuPA.js +2 -0
  117. package/packages/extensions/pages/dist/ui/index.html +2 -2
  118. package/templates/_base/src/lib/startup.ts +16 -1
  119. package/templates/claude/src/agent.ts +9 -2
  120. package/templates/claude/src/server.ts +4 -2
  121. package/templates/pi/src/agent.ts +7 -10
  122. package/templates/pi/src/lib/dispatch.ts +65 -0
  123. package/dist/volute-config-A52FHWKM.js +0 -14
  124. package/dist/web-assets/assets/index-DtctoDXY.css +0 -1
  125. package/dist/web-assets/assets/index-Wpyb2CML.js +0 -86
  126. package/packages/extensions/pages/dist/ui/assets/index-BcY6lnq4.css +0 -1
  127. package/packages/extensions/pages/dist/ui/assets/index-CQjEQg1r.js +0 -2
  128. /package/dist/{chunk-IYG4FBMP.js → chunk-IJPMIEVE.js} +0 -0
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ logger_default
4
+ } from "./chunk-T2TP6ZC6.js";
5
+ import {
6
+ getDb
7
+ } from "./chunk-WW6C3PLV.js";
8
+ import {
9
+ mindNotices,
10
+ turns
11
+ } from "./chunk-2MJ7EOMT.js";
12
+
13
+ // packages/daemon/src/lib/daemon/notices.ts
14
+ import { and, asc, desc, eq, gt, inArray, lte, or, sql } from "drizzle-orm";
15
+ var nlog = logger_default.child("notices");
16
+ var MIND_LEVEL_SESSION = "";
17
+ var MAX_NOTICES_PER_SESSION = 100;
18
+ async function recordNotice(input) {
19
+ try {
20
+ const db = await getDb();
21
+ await db.insert(mindNotices).values({
22
+ mind: input.mind,
23
+ session: input.session,
24
+ kind: input.kind,
25
+ reason: input.reason,
26
+ detail: input.detail,
27
+ raw: input.raw ?? null
28
+ });
29
+ await db.run(
30
+ 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})`
31
+ );
32
+ } catch (err) {
33
+ nlog.error(`failed to record notice for ${input.mind}:${input.session}`, logger_default.errorData(err));
34
+ }
35
+ }
36
+ async function drainNotices(mind, session, limit = MAX_NOTICES_PER_SESSION) {
37
+ const db = await getDb();
38
+ return db.select().from(mindNotices).where(
39
+ and(
40
+ eq(mindNotices.mind, mind),
41
+ or(eq(mindNotices.session, session), eq(mindNotices.session, MIND_LEVEL_SESSION))
42
+ )
43
+ ).orderBy(asc(mindNotices.id)).limit(limit);
44
+ }
45
+ var FAILURE_KINDS = ["turn_error", "crash", "startup"];
46
+ var failureReadErrorLogged = false;
47
+ async function latestFailureNotice(mind) {
48
+ try {
49
+ const db = await getDb();
50
+ const rows = await db.select().from(mindNotices).where(and(eq(mindNotices.mind, mind), inArray(mindNotices.kind, [...FAILURE_KINDS]))).orderBy(desc(mindNotices.id)).limit(1);
51
+ const n = rows[0];
52
+ if (!n) return null;
53
+ const recovered = await db.select({ id: turns.id }).from(turns).where(
54
+ and(eq(turns.mind, mind), eq(turns.status, "complete"), gt(turns.created_at, n.created_at))
55
+ ).limit(1);
56
+ if (recovered.length > 0) return null;
57
+ return {
58
+ kind: n.kind,
59
+ reason: n.reason,
60
+ detail: n.detail,
61
+ at: n.created_at
62
+ };
63
+ } catch (err) {
64
+ if (!failureReadErrorLogged) {
65
+ failureReadErrorLogged = true;
66
+ nlog.error(`failed to read latest failure notice for ${mind}`, logger_default.errorData(err));
67
+ }
68
+ return null;
69
+ }
70
+ }
71
+ async function latestNotice(mind) {
72
+ const db = await getDb();
73
+ const row = await db.select().from(mindNotices).where(eq(mindNotices.mind, mind)).orderBy(desc(mindNotices.id)).limit(1).get();
74
+ return row ?? null;
75
+ }
76
+ async function hasUndeliveredNotice(mind, reason) {
77
+ const db = await getDb();
78
+ const row = await db.select({ id: mindNotices.id }).from(mindNotices).where(and(eq(mindNotices.mind, mind), eq(mindNotices.reason, reason))).limit(1).get();
79
+ return row != null;
80
+ }
81
+ async function clearDeliveredNotices(mind, session, uptoId) {
82
+ try {
83
+ const db = await getDb();
84
+ await db.delete(mindNotices).where(
85
+ and(
86
+ eq(mindNotices.mind, mind),
87
+ or(eq(mindNotices.session, session), eq(mindNotices.session, MIND_LEVEL_SESSION)),
88
+ lte(mindNotices.id, uptoId)
89
+ )
90
+ );
91
+ } catch (err) {
92
+ nlog.warn(`failed to clear delivered notices for ${mind}:${session}`, logger_default.errorData(err));
93
+ }
94
+ }
95
+ var NOTICE_HEADER = "[Notices] While you were unavailable, one or more turns failed. You're back now:";
96
+ function formatNotices(notices) {
97
+ if (notices.length === 0) return null;
98
+ const failures = notices.filter((n) => n.kind !== "extension" && n.kind !== "budget");
99
+ const budgets = notices.filter((n) => n.kind === "budget");
100
+ const extensions = notices.filter((n) => n.kind === "extension");
101
+ const blocks = [];
102
+ if (failures.length > 0) {
103
+ const groups = /* @__PURE__ */ new Map();
104
+ for (const n of failures) {
105
+ const time = localHM(n.created_at);
106
+ const g = groups.get(n.reason);
107
+ if (g) {
108
+ g.count += 1;
109
+ g.detail = n.detail;
110
+ g.last = time;
111
+ } else {
112
+ groups.set(n.reason, { count: 1, detail: n.detail, first: time, last: time });
113
+ }
114
+ }
115
+ const lines = [...groups.values()].map((g) => {
116
+ const span = g.first === g.last ? g.first : `${g.first}\u2013${g.last}`;
117
+ const plural = g.count === 1 ? "turn" : "turns";
118
+ return `- ${g.count} ${plural} failed (${span}): ${g.detail}`;
119
+ });
120
+ blocks.push(`${NOTICE_HEADER}
121
+ ${lines.join("\n")}`);
122
+ }
123
+ if (budgets.length > 0) {
124
+ const lines = budgets.map((n) => `- ${localHM(n.created_at)} ${n.detail}`);
125
+ blocks.push(`[Budget]
126
+ ${lines.join("\n")}`);
127
+ }
128
+ if (extensions.length > 0) {
129
+ const byExt = /* @__PURE__ */ new Map();
130
+ for (const n of extensions) {
131
+ const arr = byExt.get(n.reason);
132
+ if (arr) arr.push(n);
133
+ else byExt.set(n.reason, [n]);
134
+ }
135
+ for (const [ext, items] of byExt) {
136
+ const header = `[${ext.charAt(0).toUpperCase()}${ext.slice(1)}]`;
137
+ const lines = items.map((n) => `- ${localHM(n.created_at)} ${n.detail}`);
138
+ blocks.push(`${header}
139
+ ${lines.join("\n")}`);
140
+ }
141
+ }
142
+ return blocks.join("\n\n");
143
+ }
144
+ function localHM(createdAt) {
145
+ const iso = createdAt.endsWith("Z") ? createdAt : `${createdAt.replace(" ", "T")}Z`;
146
+ return new Date(iso).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
147
+ }
148
+
149
+ export {
150
+ MIND_LEVEL_SESSION,
151
+ recordNotice,
152
+ drainNotices,
153
+ latestFailureNotice,
154
+ latestNotice,
155
+ hasUndeliveredNotice,
156
+ clearDeliveredNotices,
157
+ formatNotices
158
+ };
@@ -3,14 +3,15 @@ import {
3
3
  command
4
4
  } from "./chunk-TXSA4Q3V.js";
5
5
  import {
6
+ daemonLogReport,
6
7
  getServiceMode,
7
8
  modeLabel,
8
9
  pollHealth,
9
10
  startService
10
- } from "./chunk-CBOIHNMR.js";
11
+ } from "./chunk-FJ2MZ5PH.js";
11
12
  import {
12
13
  readGlobalConfig
13
- } from "./chunk-SKNXMUIU.js";
14
+ } from "./chunk-5KXCM5AW.js";
14
15
  import {
15
16
  voluteHome,
16
17
  voluteSystemDir
@@ -20,6 +21,13 @@ import {
20
21
  import { spawn } from "child_process";
21
22
  import { existsSync, mkdirSync, openSync, readFileSync } from "fs";
22
23
  import { dirname, resolve } from "path";
24
+ function formatStartupFailure(exit, timeoutMs) {
25
+ if (exit) {
26
+ const cause = exit.signal ? `signal ${exit.signal}` : `exit code ${exit.code}`;
27
+ return `Daemon exited (${cause}) before becoming healthy.`;
28
+ }
29
+ return `Daemon started but did not become healthy within ${Math.round(timeoutMs / 1e3)}s.`;
30
+ }
23
31
  var cmd = command({
24
32
  name: "volute up",
25
33
  description: "Start the daemon",
@@ -47,6 +55,7 @@ var cmd = command({
47
55
  console.log(`Volute daemon running on ${h}:${p}`);
48
56
  } else {
49
57
  console.error("Service started but daemon did not become healthy within 30s.");
58
+ for (const line of daemonLogReport(mode)) console.error(line);
50
59
  process.exit(1);
51
60
  }
52
61
  return;
@@ -123,11 +132,20 @@ var cmd = command({
123
132
  detached: true
124
133
  });
125
134
  child.unref();
135
+ child.on("error", (err) => {
136
+ console.error(`Failed to launch daemon: ${err.message}`);
137
+ process.exit(1);
138
+ });
139
+ let exitInfo = null;
140
+ child.on("exit", (code, signal) => {
141
+ exitInfo = { code, signal };
142
+ });
126
143
  const pollPort = useTailscale ? port + 1 : port;
127
144
  const url = `http://localhost:${pollPort}/api/health`;
128
145
  const maxWait = 3e4;
129
146
  const start = Date.now();
130
147
  while (Date.now() - start < maxWait) {
148
+ if (exitInfo) break;
131
149
  try {
132
150
  const res = await fetch(url);
133
151
  if (res.ok) {
@@ -143,7 +161,7 @@ var cmd = command({
143
161
  }
144
162
  await new Promise((r) => setTimeout(r, 500));
145
163
  }
146
- if (child.pid) {
164
+ if (!exitInfo && child.pid) {
147
165
  try {
148
166
  process.kill(-child.pid, "SIGTERM");
149
167
  } catch {
@@ -153,13 +171,15 @@ var cmd = command({
153
171
  }
154
172
  }
155
173
  }
156
- console.error("Daemon started but did not become healthy within 30s.");
157
- console.error(`Check logs: ${logFile}`);
174
+ const exited = exitInfo;
175
+ console.error(formatStartupFailure(exited, maxWait));
176
+ for (const line of daemonLogReport(mode)) console.error(line);
158
177
  process.exit(1);
159
178
  }
160
179
  });
161
180
  var run = cmd.execute;
162
181
 
163
182
  export {
183
+ formatStartupFailure,
164
184
  run
165
185
  };
@@ -30,6 +30,7 @@ var PROMPT_KEYS = [
30
30
  "meta_summary_month"
31
31
  ];
32
32
  var ORIENTATION_MARKER = "discovering who you are";
33
+ var MEMORY_PLACEHOLDER_MARKER = "this note is just here until you replace it";
33
34
  var PROMPT_DEFAULTS = {
34
35
  seed_soul: {
35
36
  content: `You are \${name}.
@@ -229,6 +230,7 @@ async function getMindPromptDefaults() {
229
230
  export {
230
231
  PROMPT_KEYS,
231
232
  ORIENTATION_MARKER,
233
+ MEMORY_PLACEHOLDER_MARKER,
232
234
  PROMPT_DEFAULTS,
233
235
  substitute,
234
236
  getPrompt,
@@ -6,7 +6,7 @@ import {
6
6
  readEnv,
7
7
  sharedEnvPath,
8
8
  writeEnv
9
- } from "./chunk-IYG4FBMP.js";
9
+ } from "./chunk-IJPMIEVE.js";
10
10
 
11
11
  // packages/daemon/src/lib/template/import-utils.ts
12
12
  import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
@@ -8,7 +8,7 @@ import {
8
8
  pollHealthDown,
9
9
  readDaemonConfig,
10
10
  stopService
11
- } from "./chunk-CBOIHNMR.js";
11
+ } from "./chunk-FJ2MZ5PH.js";
12
12
  import {
13
13
  voluteSystemDir
14
14
  } from "./chunk-WW6C3PLV.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-DGGZVZTM.js";
5
5
  import {
6
6
  readGlobalConfig
7
- } from "./chunk-SKNXMUIU.js";
7
+ } from "./chunk-5KXCM5AW.js";
8
8
  import {
9
9
  logger_default
10
10
  } from "./chunk-T2TP6ZC6.js";
@@ -24,6 +24,15 @@ function initDb(db) {
24
24
  }
25
25
  }
26
26
  }
27
+ function isIndex(file) {
28
+ return file === "index.html" || file === "index.md";
29
+ }
30
+ function sortSiteFiles(files) {
31
+ return [...files].sort((a, b) => {
32
+ if (isIndex(a.file) !== isIndex(b.file)) return isIndex(a.file) ? -1 : 1;
33
+ return b.updated_at.localeCompare(a.updated_at);
34
+ });
35
+ }
27
36
  function getPublishedPages(db, mind) {
28
37
  return db.prepare(
29
38
  "SELECT file, published_at, updated_at, author FROM published_pages WHERE mind = ? ORDER BY file"
@@ -42,7 +51,7 @@ function getRecentPages(db, opts) {
42
51
  }
43
52
  function getAllSites(db) {
44
53
  const rows = db.prepare(
45
- "SELECT mind, file, updated_at, author FROM published_pages WHERE mind != '_system' ORDER BY mind, file"
54
+ "SELECT mind, file, updated_at, author FROM published_pages WHERE mind != '_system' ORDER BY updated_at DESC, id DESC"
46
55
  ).all();
47
56
  const siteMap = /* @__PURE__ */ new Map();
48
57
  for (const row of rows) {
@@ -53,16 +62,21 @@ function getAllSites(db) {
53
62
  }
54
63
  files.push({ file: row.file, updated_at: row.updated_at, author: row.author });
55
64
  }
56
- return Array.from(siteMap.entries()).map(([mind, files]) => ({ mind, files }));
65
+ return Array.from(siteMap.entries()).map(([mind, files]) => ({
66
+ mind,
67
+ files: sortSiteFiles(files)
68
+ }));
57
69
  }
58
70
  function getSystemPages(db) {
59
71
  const rows = db.prepare(
60
- "SELECT mind, file, updated_at, author FROM published_pages WHERE mind = '_system' ORDER BY file"
72
+ "SELECT mind, file, updated_at, author FROM published_pages WHERE mind = '_system' ORDER BY updated_at DESC, id DESC"
61
73
  ).all();
62
74
  if (rows.length === 0) return null;
63
75
  return {
64
76
  mind: "_system",
65
- files: rows.map((r) => ({ file: r.file, updated_at: r.updated_at, author: r.author }))
77
+ files: sortSiteFiles(
78
+ rows.map((r) => ({ file: r.file, updated_at: r.updated_at, author: r.author }))
79
+ )
66
80
  };
67
81
  }
68
82
  function syncSystemPages(db, pages, author) {
@@ -1,14 +1,23 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ daemonFetch
4
+ } from "./chunk-BCG45AQB.js";
2
5
  import {
3
6
  command
4
7
  } from "./chunk-TXSA4Q3V.js";
5
- import "./chunk-O7IGP7ZW.js";
6
- import {
7
- daemonFetch
8
- } from "./chunk-RBNMDAKB.js";
9
- import "./chunk-K3NQKI34.js";
10
8
 
11
9
  // packages/cli/src/commands/mind-list.ts
10
+ function relativeAge(created, now = Date.now()) {
11
+ const normalized = created.endsWith("Z") || created.includes("T") ? created : `${created.replace(" ", "T")}Z`;
12
+ const ms = now - new Date(normalized).getTime();
13
+ if (Number.isNaN(ms) || ms < 0) return "";
14
+ const days = Math.floor(ms / 864e5);
15
+ if (days >= 7) return `${Math.floor(days / 7)}w`;
16
+ if (days >= 1) return `${days}d`;
17
+ const hours = Math.floor(ms / 36e5);
18
+ if (hours >= 1) return `${hours}h`;
19
+ return `${Math.floor(ms / 6e4)}m`;
20
+ }
12
21
  var cmd = command({
13
22
  name: "volute mind list",
14
23
  description: "List all minds",
@@ -28,12 +37,16 @@ var cmd = command({
28
37
  for (const mind of minds) {
29
38
  const status = mind.status ?? (mind.running ? "running" : "stopped");
30
39
  const label = mind.stage === "seed" ? " (seed)" : "";
40
+ const age = mind.created ? relativeAge(mind.created) : "";
41
+ const ageLabel = age ? ` ${age} old` : "";
31
42
  const template = mind.templateStale ? " [template: outdated]" : "";
32
- console.log(` ${mind.name}: ${status}${label}${template}`);
43
+ console.log(` ${mind.name}: ${status}${label}${ageLabel}${template}`);
33
44
  }
34
45
  }
35
46
  });
36
47
  var run = cmd.execute;
48
+
37
49
  export {
50
+ relativeAge,
38
51
  run
39
52
  };
@@ -5,14 +5,14 @@ import {
5
5
  } from "./chunk-SZJCJVXV.js";
6
6
  import {
7
7
  recordOutbound
8
- } from "./chunk-F55GRIEK.js";
9
- import {
10
- readEnv,
11
- sharedEnvPath
12
- } from "./chunk-IYG4FBMP.js";
8
+ } from "./chunk-VB2QXUJQ.js";
13
9
  import {
14
10
  publish
15
- } from "./chunk-K23P5Q5N.js";
11
+ } from "./chunk-USD45JKR.js";
12
+ import {
13
+ getOrCreateMindUser,
14
+ getUserByUsername
15
+ } from "./chunk-ODDGGLM6.js";
16
16
  import {
17
17
  addMessage,
18
18
  findDMConversation,
@@ -23,15 +23,15 @@ import {
23
23
  } from "./chunk-HPGN6XRT.js";
24
24
  import {
25
25
  readVoluteConfig
26
- } from "./chunk-PFZBNKUH.js";
26
+ } from "./chunk-WCFSBH33.js";
27
27
  import {
28
28
  daemonConfigPath,
29
29
  readDaemonToken
30
- } from "./chunk-CBOIHNMR.js";
30
+ } from "./chunk-FJ2MZ5PH.js";
31
31
  import {
32
- getOrCreateMindUser,
33
- getUserByUsername
34
- } from "./chunk-ODDGGLM6.js";
32
+ readEnv,
33
+ sharedEnvPath
34
+ } from "./chunk-IJPMIEVE.js";
35
35
  import {
36
36
  logger_default
37
37
  } from "./chunk-T2TP6ZC6.js";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getPrompt
4
- } from "./chunk-JCMGDCGX.js";
4
+ } from "./chunk-MOERAQXH.js";
5
5
  import {
6
6
  aiCompleteUtility
7
- } from "./chunk-LWDTP6DH.js";
7
+ } from "./chunk-YNBXEQAP.js";
8
8
  import {
9
9
  logger_default
10
10
  } from "./chunk-T2TP6ZC6.js";
@@ -504,6 +504,27 @@ ${entries.map((e) => e.text).join("\n\n")}`;
504
504
  return buildBoundedDigest(entries, period, periodKey);
505
505
  }
506
506
  }
507
+ var DIGEST_HEADER_PREFIX = new RegExp(
508
+ `^(?:Week )?\\S+ ${DIGEST_NOTICE.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n\\n`
509
+ );
510
+ function stripPeriodPrefix(text) {
511
+ return text.replace(/^Activity during \d{2}:00: /, "").replace(/^Activity on \d{4}-\d{2}-\d{2}:\n\n/, "").replace(DIGEST_HEADER_PREFIX, "");
512
+ }
513
+ function buildSystemDeterministicSummary(entries, period, periodKey) {
514
+ if (entries.length === 0) return "";
515
+ const stripped = entries.map((e) => ({ key: e.key, text: stripPeriodPrefix(e.text) }));
516
+ switch (period) {
517
+ case "hour":
518
+ return `Activity during ${periodKey.slice(11)}:00: ${stripped.map((e) => `[${e.key}] ${e.text}`).join(" ")}`;
519
+ case "day":
520
+ return `Activity on ${periodKey}:
521
+
522
+ ${stripped.map((e) => `[${e.key}] ${e.text}`).join("\n\n")}`;
523
+ case "week":
524
+ case "month":
525
+ return buildBoundedDigest(stripped, period, periodKey);
526
+ }
527
+ }
507
528
  function parseMeta(raw) {
508
529
  if (!raw) return {};
509
530
  try {
@@ -698,7 +719,7 @@ async function summarizeSystem(period, periodKey, complete = aiCompleteUtility)
698
719
  content = aiResult;
699
720
  deterministic = false;
700
721
  } else {
701
- content = buildPeriodicDeterministicSummary(entries, period, periodKey);
722
+ content = buildSystemDeterministicSummary(entries, period, periodKey);
702
723
  deterministic = true;
703
724
  if (period === "week" || period === "month") trackProvisionalAttempt(metadata, existingMeta);
704
725
  }
@@ -1028,11 +1049,11 @@ var Summarizer = class {
1028
1049
  }
1029
1050
  };
1030
1051
  async function reconcileWedgedTurns(idleMs) {
1031
- const { sweepWedgedTurns: sweepWedgedTurns2, summarizeOrphanedTurns: summarizeOrphanedTurns2 } = await import("./turn-tracker-JZRZDFWV.js");
1052
+ const { sweepWedgedTurns: sweepWedgedTurns2, summarizeOrphanedTurns: summarizeOrphanedTurns2 } = await import("./turn-tracker-KLPV3PAU.js");
1032
1053
  const wedged = await sweepWedgedTurns2(idleMs);
1033
1054
  if (wedged.length === 0) return;
1034
1055
  summarizeOrphanedTurns2(wedged);
1035
- const { tryGetDeliveryManager } = await import("./delivery-manager-TN5KK2AP.js");
1056
+ const { tryGetDeliveryManager } = await import("./delivery-manager-HZTT5SJR.js");
1036
1057
  const dm = tryGetDeliveryManager();
1037
1058
  if (!dm) return;
1038
1059
  for (const t of wedged) {
@@ -1234,6 +1255,7 @@ export {
1234
1255
  subscribeAll,
1235
1256
  publish,
1236
1257
  isoWeekKeyForDateStr,
1258
+ utcDateTimeStr,
1237
1259
  summarizeTurn,
1238
1260
  initSummarizer,
1239
1261
  markErrored,