volute 0.47.0 → 0.49.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 (177) hide show
  1. package/README.md +82 -331
  2. package/dist/{accept-YAFP5JFJ.js → accept-KYNC5X3U.js} +3 -3
  3. package/dist/{activity-events-MIOK3IOU.js → activity-events-GJJAI2WT.js} +4 -4
  4. package/dist/{ai-service-CVZEYKTK.js → ai-service-A7FS7EC3.js} +9 -5
  5. package/dist/{archive-6Z4GFQPH.js → archive-7E3YE6VF.js} +3 -3
  6. package/dist/{auth-A4VGHADI.js → auth-ABYLOEZ7.js} +5 -5
  7. package/dist/{avatar-image-7S3WA77A.js → avatar-image-6ATV2IOZ.js} +6 -5
  8. package/dist/{backup-IIAFOW2L.js → backup-XYAMT4CU.js} +15 -15
  9. package/dist/{bridge-TIZGSXOD.js → bridge-3FNSWLNQ.js} +3 -3
  10. package/dist/{channels-ITE4YC57.js → channels-SGQZHNQJ.js} +3 -3
  11. package/dist/{chat-AJLJCQ3M.js → chat-OGXAEXMV.js} +9 -9
  12. package/dist/{chunk-LTLFOSA4.js → chunk-3B427GUK.js} +3 -3
  13. package/dist/{chunk-RUFLGTOT.js → chunk-4B62E4CG.js} +2 -2
  14. package/dist/{chunk-ODDGGLM6.js → chunk-4DSGN4FL.js} +3 -3
  15. package/dist/{chunk-BGYHLR54.js → chunk-6HGEZJDH.js} +2 -2
  16. package/dist/{chunk-RBNMDAKB.js → chunk-BCG45AQB.js} +15 -1
  17. package/dist/{chunk-5IERLDUS.js → chunk-DAIIMBLB.js} +26 -6
  18. package/dist/{chunk-DGGZVZTM.js → chunk-DVN6DNMI.js} +1 -1
  19. package/dist/chunk-DW4TRDOZ.js +29 -0
  20. package/dist/chunk-EADX54RG.js +113 -0
  21. package/dist/{chunk-EIQDZC43.js → chunk-EFT2OALG.js} +6 -2
  22. package/dist/{chunk-XHN6XBWV.js → chunk-EG5LSKHU.js} +2 -2
  23. package/dist/{chunk-VMCZBXF2.js → chunk-FBBS4BVR.js} +10 -34
  24. package/dist/{chunk-IWJSNMSY.js → chunk-GWVFDUNB.js} +45 -14
  25. package/dist/{chunk-CBOIHNMR.js → chunk-HCYQRME2.js} +41 -5
  26. package/dist/{chunk-4I72V3E5.js → chunk-IH5TKXX6.js} +15 -15
  27. package/dist/{chunk-5NN2VHJV.js → chunk-JBIFXB6I.js} +4 -4
  28. package/dist/{chunk-JSVHH32K.js → chunk-JCBPU57A.js} +15 -13
  29. package/dist/{chunk-M3XDVS5Q.js → chunk-JCWB2ITW.js} +2 -2
  30. package/dist/{chunk-JCMGDCGX.js → chunk-JPGHSXSV.js} +20 -25
  31. package/dist/{chunk-K23P5Q5N.js → chunk-K3JOLGWF.js} +30 -8
  32. package/dist/{chunk-3YUBFTDN.js → chunk-KHCKZ36O.js} +1 -1
  33. package/dist/{chunk-7KRIHYLR.js → chunk-L27YYONJ.js} +2 -2
  34. package/dist/{chunk-SZJCJVXV.js → chunk-MG3Z34YE.js} +2 -2
  35. package/dist/{chunk-SKNXMUIU.js → chunk-NJHN6IRB.js} +26 -2
  36. package/dist/{chunk-2OIYNHWO.js → chunk-NOIAHMJB.js} +1 -1
  37. package/dist/{chunk-2MJ7EOMT.js → chunk-P4LHVRNE.js} +1 -0
  38. package/dist/{chunk-IYG4FBMP.js → chunk-PY24ZL62.js} +1 -1
  39. package/dist/{chunk-F55GRIEK.js → chunk-QQBOI3QA.js} +356 -296
  40. package/dist/{chunk-T2TP6ZC6.js → chunk-QUSMYGNQ.js} +6 -0
  41. package/dist/{chunk-KDLYIECM.js → chunk-R772ET2M.js} +18 -4
  42. package/dist/{chunk-WW6C3PLV.js → chunk-RSBL3FAD.js} +39 -6
  43. package/dist/{mind-list-KEGRGQEQ.js → chunk-SHKM5RGD.js} +19 -6
  44. package/dist/{chunk-YKA7DCVW.js → chunk-SX72DOO3.js} +1 -1
  45. package/dist/chunk-TXJL36ZQ.js +48 -0
  46. package/dist/{chunk-M6TTZRGH.js → chunk-VIUH5CHQ.js} +72 -24
  47. package/dist/{chunk-HPGN6XRT.js → chunk-VNRSXEBF.js} +4 -4
  48. package/dist/{chunk-PFZBNKUH.js → chunk-WCFSBH33.js} +0 -1
  49. package/dist/chunk-XTEKINWG.js +158 -0
  50. package/dist/{chunk-LWDTP6DH.js → chunk-YIJGKHIS.js} +32 -2
  51. package/dist/{chunk-MTRMQFCQ.js → chunk-ZX46PGCC.js} +2 -2
  52. package/dist/cli.js +34 -26
  53. package/dist/{clock-E6N5Y3YW.js → clock-6JZL2FS6.js} +3 -3
  54. package/dist/{cloud-sync-LQTVDTQ3.js → cloud-sync-VFDTNNCA.js} +22 -20
  55. package/dist/{config-TJLYUV3U.js → config-RPSLA2HX.js} +3 -3
  56. package/dist/{conversations-C7IKYSHD.js → conversations-TUM5PJJ4.js} +5 -5
  57. package/dist/{create-A7PDHIIL.js → create-VIQVP3QB.js} +3 -3
  58. package/dist/{create-PQQXKTJK.js → create-Z5FSDNVZ.js} +16 -5
  59. package/dist/{daemon-client-IYR4KCPU.js → daemon-client-ZFY5MOAL.js} +5 -3
  60. package/dist/{daemon-restart-5F3YTLZK.js → daemon-restart-54L4B6AQ.js} +7 -7
  61. package/dist/daemon.js +1105 -601
  62. package/dist/{db-FO6LXYCW.js → db-F6UMFRYD.js} +2 -2
  63. package/dist/{db-LZTLA7XC.js → db-IPXRJUI7.js} +1 -1
  64. package/dist/{delete-HPLC7ETU.js → delete-ESEP7NGQ.js} +1 -1
  65. package/dist/delivery-manager-RBXBPVWM.js +36 -0
  66. package/dist/{delivery-router-3QFG2ZEX.js → delivery-router-VUOL5YSA.js} +8 -6
  67. package/dist/{down-ZI4S6265.js → down-6X7KX7BZ.js} +5 -5
  68. package/dist/echo-text-B6NZ5FGE.js +36 -0
  69. package/dist/env-KUL4XKN2.js +18 -0
  70. package/dist/{env-HRL2PWAT.js → env-ZYMSCB7B.js} +6 -6
  71. package/dist/{exec-QIFYZG4C.js → exec-FBXA3CM4.js} +3 -3
  72. package/dist/{export-4GVGNW54.js → export-TNBPDH77.js} +4 -4
  73. package/dist/{extension-QBY4C44L.js → extension-J4ZQ2GHV.js} +3 -3
  74. package/dist/{extensions-PIMIQ7J3.js → extensions-AWNO3SZF.js} +22 -20
  75. package/dist/{files-FEFZKMNM.js → files-BVBRJJ2P.js} +6 -6
  76. package/dist/{import-7MO3YTRE.js → import-ZUNKMCKC.js} +9 -9
  77. package/dist/{isolation-MCT4ZYLT.js → isolation-OPCZQRTH.js} +3 -3
  78. package/dist/{join-ZJV7W6MO.js → join-34TR2GXQ.js} +1 -1
  79. package/dist/{list-LQO2DCIK.js → list-PMUXZNAM.js} +3 -3
  80. package/dist/{login-OF4WXDAN.js → login-KAKNFCW5.js} +14 -5
  81. package/dist/{login-6TLMI2TQ.js → login-LKNLCJPA.js} +3 -3
  82. package/dist/{logout-ERE2BGA3.js → logout-RLT62RQP.js} +5 -5
  83. package/dist/{logout-BK53HXNY.js → logout-YZRMZ3O2.js} +3 -3
  84. package/dist/message-delivery-ABPV76EA.js +42 -0
  85. package/dist/{mind-POOHFZHP.js → mind-IF6CGMFW.js} +23 -19
  86. package/dist/{mind-activity-tracker-YVZPC4A5.js → mind-activity-tracker-YMMERB6B.js} +5 -5
  87. package/dist/mind-contacts-BKUFPUCU.js +64 -0
  88. package/dist/{mind-history-47DN6ILW.js → mind-history-WI5OI3BW.js} +5 -5
  89. package/dist/mind-list-OTHV4ZO4.js +13 -0
  90. package/dist/{mind-profile-PEQYASQX.js → mind-profile-LUG353ZT.js} +1 -1
  91. package/dist/mind-service-42GDO4KH.js +44 -0
  92. package/dist/{mind-sleep-IN3WPA76.js → mind-sleep-VBV7YRSU.js} +5 -5
  93. package/dist/{mind-status-SMUWJKGV.js → mind-status-BJNPGXKC.js} +8 -3
  94. package/dist/{mind-wake-R54BPESY.js → mind-wake-LVTZ55EZ.js} +3 -3
  95. package/dist/notices-N6BCGHFV.js +25 -0
  96. package/dist/{package-WPEE2HVJ.js → package-PD67VPHB.js} +8 -5
  97. package/dist/prompts-MDHDLWEX.js +24 -0
  98. package/dist/{read-PWAJOQIQ.js → read-YSWUXYL7.js} +3 -3
  99. package/dist/{register-7SZJFHU6.js → register-TWQDKQRT.js} +3 -3
  100. package/dist/{registry-UMMDRPRM.js → registry-3ELJPUGJ.js} +6 -2
  101. package/dist/{reject-6VH7N2A4.js → reject-SXGCYN4A.js} +3 -3
  102. package/dist/{restart-H5WJDMA7.js → restart-5F5QDBOG.js} +5 -5
  103. package/dist/{sandbox-G4X4K3UN.js → sandbox-XPYA7UIF.js} +5 -5
  104. package/dist/scheduler-K7Y7Z7FQ.js +34 -0
  105. package/dist/{schema-VEVO7HG6.js → schema-6YONVTKZ.js} +1 -1
  106. package/dist/{seed-VANPU43L.js → seed-NQED7PSX.js} +1 -1
  107. package/dist/{seed-check-VLTVILOV.js → seed-check-TYD7RRZY.js} +1 -1
  108. package/dist/{seed-cmd-SYVDZKM4.js → seed-cmd-QF3F2G4S.js} +3 -3
  109. package/dist/{seed-create-3FGZPS6C.js → seed-create-XOO4N2OE.js} +6 -4
  110. package/dist/seed-readiness-3LRYASA4.js +18 -0
  111. package/dist/{seed-sprout-H7QLFPFM.js → seed-sprout-HSBBGSS2.js} +32 -33
  112. package/dist/{send-HYDFGC6G.js → send-IHRJYNXA.js} +8 -8
  113. package/dist/{service-SYJ5G6LP.js → service-YCOPCTSZ.js} +4 -4
  114. package/dist/{service-install-FQ43Z4DF.js → service-install-Y46OTF55.js} +5 -5
  115. package/dist/{setup-QJHGMGSN.js → setup-F4TE64YI.js} +7 -7
  116. package/dist/{setup-KFYVWTXG.js → setup-TCN7VH5U.js} +9 -3
  117. package/dist/{skill-GUKG2YVH.js → skill-4CYJLYVY.js} +6 -6
  118. package/dist/skills/dreaming/SKILL.md +5 -1
  119. package/dist/skills/dreaming/scripts/dream.ts +5 -1
  120. package/dist/skills/orientation/SKILL.md +8 -7
  121. package/dist/skills/tending/SKILL.md +51 -2
  122. package/dist/skills/volute-mind/SKILL.md +5 -3
  123. package/dist/skills/volute-mind/references/routing.md +6 -5
  124. package/dist/skills/volute-mind/references/variants.md +48 -14
  125. package/dist/{skills-L2CMTW7A.js → skills-NN5UZCUU.js} +8 -6
  126. package/dist/sleep-manager-DSPXFHGX.js +38 -0
  127. package/dist/spirit-SSJMYC6A.js +31 -0
  128. package/dist/{split-WBMZXBHF.js → split-JF2VWTXA.js} +5 -2
  129. package/dist/{sprout-LTL5P36T.js → sprout-AXA2SECQ.js} +1 -1
  130. package/dist/{src-OJHARHTF.js → src-ZN4LXMPI.js} +17 -8
  131. package/dist/{start-X46I3GXB.js → start-BTVMTP3K.js} +5 -5
  132. package/dist/{status-V4RJMHJ4.js → status-VJGXMQ4L.js} +10 -8
  133. package/dist/{stop-HJQV4YSM.js → stop-YORESK4U.js} +5 -5
  134. package/dist/system-chat-M2XOBKEM.js +40 -0
  135. package/dist/{systems-B5YJKMW4.js → systems-5MH2ELQE.js} +6 -6
  136. package/dist/{tailscale-MCLY5GYE.js → tailscale-AMMVKDXB.js} +3 -3
  137. package/dist/{template-staleness-EMQORSGG.js → template-staleness-HKGCTS3H.js} +4 -4
  138. package/dist/{turn-tracker-JZRZDFWV.js → turn-tracker-JQ2YUUY2.js} +7 -7
  139. package/dist/up-SDLTLPAO.js +20 -0
  140. package/dist/{update-ACV4SAY3.js → update-WEA4N2TR.js} +5 -5
  141. package/dist/{update-check-266R4ZSY.js → update-check-DZOTONII.js} +3 -3
  142. package/dist/{upgrade-NWAZ7MLD.js → upgrade-K5FIQPQD.js} +1 -1
  143. package/dist/variant-cleanup-P4MBNLJD.js +33 -0
  144. package/dist/{version-notify-XRGTEEDK.js → version-notify-WFA5XB5A.js} +27 -25
  145. package/dist/web-assets/assets/index-BostMFoR.css +1 -0
  146. package/dist/web-assets/assets/index-CKlqUkyG.js +92 -0
  147. package/dist/web-assets/index.html +2 -2
  148. package/drizzle/0013_variant_purpose.sql +3 -0
  149. package/drizzle/meta/_journal.json +7 -0
  150. package/package.json +8 -5
  151. package/packages/extensions/pages/dist/ui/assets/index-BuXnE-rb.css +1 -0
  152. package/packages/extensions/pages/dist/ui/assets/index-DtzftuPA.js +2 -0
  153. package/packages/extensions/pages/dist/ui/index.html +2 -2
  154. package/templates/_base/.init/.local/hooks/startup-context.ts +19 -2
  155. package/templates/_base/home/VOLUTE.md +13 -1
  156. package/templates/_base/src/lib/daemon-client.ts +27 -7
  157. package/templates/_base/src/lib/startup.ts +16 -1
  158. package/templates/claude/src/agent.ts +10 -3
  159. package/templates/claude/src/lib/hooks/identity-reload.ts +12 -3
  160. package/templates/claude/src/server.ts +4 -2
  161. package/templates/pi/src/agent.ts +7 -10
  162. package/templates/pi/src/lib/dispatch.ts +65 -0
  163. package/templates/pi/src/lib/event-handler.ts +47 -6
  164. package/dist/delivery-manager-TN5KK2AP.js +0 -34
  165. package/dist/echo-text-SEQCLGAT.js +0 -34
  166. package/dist/message-delivery-ZE3YGJDD.js +0 -38
  167. package/dist/mind-service-JFY7UG5E.js +0 -40
  168. package/dist/scheduler-HQSDYJFY.js +0 -32
  169. package/dist/sleep-manager-3NA7ZJP3.js +0 -36
  170. package/dist/spirit-WXN4IDBF.js +0 -23
  171. package/dist/system-chat-N2F7HVY3.js +0 -38
  172. package/dist/up-J2PBPOZL.js +0 -18
  173. package/dist/volute-config-A52FHWKM.js +0 -14
  174. package/dist/web-assets/assets/index-DtctoDXY.css +0 -1
  175. package/dist/web-assets/assets/index-Wpyb2CML.js +0 -86
  176. package/packages/extensions/pages/dist/ui/assets/index-BcY6lnq4.css +0 -1
  177. package/packages/extensions/pages/dist/ui/assets/index-CQjEQg1r.js +0 -2
@@ -2,23 +2,23 @@
2
2
  import {
3
3
  exec,
4
4
  gitExec
5
- } from "./chunk-DGGZVZTM.js";
5
+ } from "./chunk-DVN6DNMI.js";
6
6
  import {
7
7
  readGlobalConfig,
8
8
  writeGlobalConfig
9
- } from "./chunk-SKNXMUIU.js";
9
+ } from "./chunk-NJHN6IRB.js";
10
10
  import {
11
11
  logger_default
12
- } from "./chunk-T2TP6ZC6.js";
12
+ } from "./chunk-QUSMYGNQ.js";
13
13
  import {
14
14
  getDb,
15
15
  mindDir,
16
16
  readRegistry,
17
17
  voluteHome
18
- } from "./chunk-WW6C3PLV.js";
18
+ } from "./chunk-RSBL3FAD.js";
19
19
  import {
20
20
  sharedSkills
21
- } from "./chunk-2MJ7EOMT.js";
21
+ } from "./chunk-P4LHVRNE.js";
22
22
 
23
23
  // packages/daemon/src/lib/skills.ts
24
24
  import { createHash } from "crypto";
@@ -28,6 +28,7 @@ import {
28
28
  mkdirSync,
29
29
  readdirSync,
30
30
  readFileSync,
31
+ renameSync,
31
32
  rmSync,
32
33
  writeFileSync
33
34
  } from "fs";
@@ -46,7 +47,7 @@ async function initDefaultSkills() {
46
47
  const config = readGlobalConfig();
47
48
  let extensionSkills = [];
48
49
  try {
49
- const { getExtensionStandardSkills } = await import("./extensions-PIMIQ7J3.js");
50
+ const { getExtensionStandardSkills } = await import("./extensions-AWNO3SZF.js");
50
51
  extensionSkills = getExtensionStandardSkills();
51
52
  } catch (err) {
52
53
  logger_default.warn("failed to load extension standard skills during init", logger_default.errorData(err));
@@ -185,9 +186,12 @@ function mindSkillsDir(dir) {
185
186
  }
186
187
  return resolve(home, subdir);
187
188
  }
188
- function relSkillsPath(dir) {
189
+ function mindSkillsSubdir(dir) {
189
190
  const home = resolve(dir, "home");
190
- return join("home", mindSkillsDir(dir).slice(home.length + 1));
191
+ return mindSkillsDir(dir).slice(home.length + 1);
192
+ }
193
+ function relSkillsPath(dir) {
194
+ return join("home", mindSkillsSubdir(dir));
191
195
  }
192
196
  function readUpstream(skillDir) {
193
197
  const upstreamPath = join(skillDir, ".upstream.json");
@@ -453,9 +457,7 @@ exec node ${skillScriptPath} "$@"
453
457
  exec bash ${skillScriptPath} "$@"
454
458
  `;
455
459
  }
456
- function installHookShims(dir, skillId, hooks) {
457
- const home = resolve(dir, "home");
458
- const skillsSubdir = mindSkillsDir(dir).slice(home.length + 1);
460
+ function installHookShims(dir, skillId, hooks, skillsSubdir = mindSkillsSubdir(dir)) {
459
461
  for (const [event, scriptPath] of Object.entries(hooks)) {
460
462
  const eventDir = join(dir, "home", ".local", "hooks", event);
461
463
  mkdirSync(eventDir, { recursive: true });
@@ -498,9 +500,7 @@ function binShimOwner(shimPath) {
498
500
  const line = readFileSync(shimPath, "utf-8").split("\n").find((l) => l.startsWith(BIN_SHIM_MARKER));
499
501
  return line?.slice(BIN_SHIM_MARKER.length).trim() || void 0;
500
502
  }
501
- function installBinShim(dir, skillId, scriptPath) {
502
- const home = resolve(dir, "home");
503
- const skillsSubdir = mindSkillsDir(dir).slice(home.length + 1);
503
+ function installBinShim(dir, skillId, scriptPath, skillsSubdir = mindSkillsSubdir(dir)) {
504
504
  const binDir = join(dir, "home", ".local", "bin");
505
505
  mkdirSync(binDir, { recursive: true });
506
506
  const cmdName = binCommandName(scriptPath);
@@ -520,6 +520,36 @@ function removeBinShim(dir, scriptPath) {
520
520
  const shimPath = join(dir, "home", ".local", "bin", cmdName);
521
521
  if (existsSync(shimPath)) rmSync(shimPath);
522
522
  }
523
+ function migrateSkillsToTemplate(dir, oldTemplate, newTemplate) {
524
+ const home = resolve(dir, "home");
525
+ const oldSubdir = TEMPLATE_SKILLS_DIR[oldTemplate] ?? TEMPLATE_SKILLS_DIR.claude;
526
+ const newSubdir = TEMPLATE_SKILLS_DIR[newTemplate] ?? TEMPLATE_SKILLS_DIR.claude;
527
+ if (oldSubdir === newSubdir) return [];
528
+ const oldDir = resolve(home, oldSubdir);
529
+ const newDir = resolve(home, newSubdir);
530
+ if (!existsSync(oldDir)) return [];
531
+ const skillIds = readdirSync(oldDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
532
+ const migrated = [];
533
+ if (skillIds.length > 0) {
534
+ mkdirSync(newDir, { recursive: true });
535
+ for (const skillId of skillIds) {
536
+ const from = join(oldDir, skillId);
537
+ const to = join(newDir, skillId);
538
+ if (existsSync(to)) rmSync(to, { recursive: true, force: true });
539
+ renameSync(from, to);
540
+ removeHookShims(dir, skillId);
541
+ const skillMdPath = join(to, "SKILL.md");
542
+ if (existsSync(skillMdPath)) {
543
+ const { hooks, bin } = parseSkillMd(readFileSync(skillMdPath, "utf-8"));
544
+ installHookShims(dir, skillId, hooks, newSubdir);
545
+ if (bin) installBinShim(dir, skillId, bin, newSubdir);
546
+ }
547
+ migrated.push(skillId);
548
+ }
549
+ }
550
+ rmSync(oldDir, { recursive: true, force: true });
551
+ return migrated;
552
+ }
523
553
  function listFilesRecursive(dir, prefix = "") {
524
554
  const results = [];
525
555
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
@@ -641,6 +671,7 @@ export {
641
671
  removeHookShims,
642
672
  installBinShim,
643
673
  removeBinShim,
674
+ migrateSkillsToTemplate,
644
675
  listFilesRecursive,
645
676
  findSkillsRoot,
646
677
  hashSkillDir,
@@ -2,16 +2,32 @@
2
2
  import {
3
3
  exec,
4
4
  execInherit
5
- } from "./chunk-DGGZVZTM.js";
5
+ } from "./chunk-DVN6DNMI.js";
6
6
  import {
7
7
  voluteSystemDir
8
- } from "./chunk-WW6C3PLV.js";
8
+ } from "./chunk-RSBL3FAD.js";
9
9
 
10
10
  // packages/daemon/src/lib/config/service-mode.ts
11
11
  import { execFileSync } from "child_process";
12
- import { existsSync, readFileSync } from "fs";
12
+ import { existsSync, readFileSync as readFileSync2 } from "fs";
13
13
  import { homedir } from "os";
14
14
  import { resolve } from "path";
15
+
16
+ // packages/daemon/src/lib/util/log-tail.ts
17
+ import { readFileSync } from "fs";
18
+ function readLogTail(logFile, maxLines = 20) {
19
+ let content;
20
+ try {
21
+ content = readFileSync(logFile, "utf-8");
22
+ } catch (err) {
23
+ if (err.code === "ENOENT") return [];
24
+ const reason = err.code ?? err.message;
25
+ return [`(could not read ${logFile}: ${reason})`];
26
+ }
27
+ return content.split("\n").filter((l) => l.trim().length > 0).slice(-maxLines);
28
+ }
29
+
30
+ // packages/daemon/src/lib/config/service-mode.ts
15
31
  var SYSTEM_SERVICE_PATH = "/etc/systemd/system/volute.service";
16
32
  var USER_SYSTEMD_UNIT = resolve(homedir(), ".config", "systemd", "user", "volute.service");
17
33
  var LAUNCHD_PLIST_LABEL = "com.volute.daemon";
@@ -178,7 +194,7 @@ function readDaemonToken() {
178
194
  const path = daemonTokenPath();
179
195
  if (!existsSync(path)) return void 0;
180
196
  try {
181
- return readFileSync(path, "utf-8").trim() || void 0;
197
+ return readFileSync2(path, "utf-8").trim() || void 0;
182
198
  } catch {
183
199
  return void 0;
184
200
  }
@@ -187,7 +203,7 @@ function readDaemonConfig() {
187
203
  const configPath = daemonConfigPath();
188
204
  if (!existsSync(configPath)) return { hostname: "127.0.0.1", port: 1618 };
189
205
  try {
190
- const config = JSON.parse(readFileSync(configPath, "utf-8"));
206
+ const config = JSON.parse(readFileSync2(configPath, "utf-8"));
191
207
  return {
192
208
  hostname: config.hostname || "127.0.0.1",
193
209
  port: config.port ?? 1618,
@@ -198,6 +214,25 @@ function readDaemonConfig() {
198
214
  return { hostname: "127.0.0.1", port: 1618 };
199
215
  }
200
216
  }
217
+ function daemonLogSource(mode) {
218
+ switch (mode) {
219
+ case "system":
220
+ return { kind: "journal", command: "journalctl -u volute -n 30 --no-pager" };
221
+ case "user-systemd":
222
+ return { kind: "journal", command: "journalctl --user -u volute -n 30 --no-pager" };
223
+ default:
224
+ return { kind: "file", path: resolve(voluteSystemDir(), "daemon.log") };
225
+ }
226
+ }
227
+ function daemonLogReport(mode, maxLines = 20) {
228
+ const src = daemonLogSource(mode);
229
+ if (src.kind === "journal") {
230
+ return ["To see the daemon log:", ` ${src.command}`];
231
+ }
232
+ const tail = readLogTail(src.path, maxLines);
233
+ if (tail.length === 0) return [`Check logs: ${src.path}`];
234
+ return [`Last ${tail.length} lines of ${src.path}:`, ...tail.map((l) => ` ${l}`)];
235
+ }
201
236
  function modeLabel(mode) {
202
237
  switch (mode) {
203
238
  case "system":
@@ -229,5 +264,6 @@ export {
229
264
  daemonConfigPath,
230
265
  readDaemonToken,
231
266
  readDaemonConfig,
267
+ daemonLogReport,
232
268
  modeLabel
233
269
  };
@@ -2,17 +2,17 @@
2
2
  import {
3
3
  findBridgeForChannel,
4
4
  getBridgeConfig
5
- } from "./chunk-SZJCJVXV.js";
5
+ } from "./chunk-MG3Z34YE.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-QQBOI3QA.js";
13
9
  import {
14
10
  publish
15
- } from "./chunk-K23P5Q5N.js";
11
+ } from "./chunk-K3JOLGWF.js";
12
+ import {
13
+ getOrCreateMindUser,
14
+ getUserByUsername
15
+ } from "./chunk-4DSGN4FL.js";
16
16
  import {
17
17
  addMessage,
18
18
  findDMConversation,
@@ -20,27 +20,27 @@ import {
20
20
  getChannelName,
21
21
  getConversation,
22
22
  getParticipants
23
- } from "./chunk-HPGN6XRT.js";
23
+ } from "./chunk-VNRSXEBF.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-HCYQRME2.js";
31
31
  import {
32
- getOrCreateMindUser,
33
- getUserByUsername
34
- } from "./chunk-ODDGGLM6.js";
32
+ readEnv,
33
+ sharedEnvPath
34
+ } from "./chunk-PY24ZL62.js";
35
35
  import {
36
36
  logger_default
37
- } from "./chunk-T2TP6ZC6.js";
37
+ } from "./chunk-QUSMYGNQ.js";
38
38
  import {
39
39
  buildVoluteSlug
40
40
  } from "./chunk-LGNUFVMR.js";
41
41
  import {
42
42
  mindDir
43
- } from "./chunk-WW6C3PLV.js";
43
+ } from "./chunk-RSBL3FAD.js";
44
44
  import {
45
45
  __export
46
46
  } from "./chunk-K3NQKI34.js";
@@ -1,19 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  exec
4
- } from "./chunk-DGGZVZTM.js";
4
+ } from "./chunk-DVN6DNMI.js";
5
5
  import {
6
6
  readGlobalConfig
7
- } from "./chunk-SKNXMUIU.js";
7
+ } from "./chunk-NJHN6IRB.js";
8
8
  import {
9
9
  logger_default
10
- } from "./chunk-T2TP6ZC6.js";
10
+ } from "./chunk-QUSMYGNQ.js";
11
11
  import {
12
12
  getDb,
13
13
  readAllMinds,
14
14
  voluteHome,
15
15
  voluteSystemDir
16
- } from "./chunk-WW6C3PLV.js";
16
+ } from "./chunk-RSBL3FAD.js";
17
17
 
18
18
  // packages/daemon/src/lib/backup/restic.ts
19
19
  import { writeFileSync } from "fs";
@@ -6,17 +6,17 @@ import {
6
6
  import {
7
7
  resolveMindName
8
8
  } from "./chunk-BTY4WNFE.js";
9
- import {
10
- command,
11
- subcommands
12
- } from "./chunk-TXSA4Q3V.js";
13
9
  import {
14
10
  daemonFetch
15
- } from "./chunk-RBNMDAKB.js";
11
+ } from "./chunk-BCG45AQB.js";
16
12
  import {
17
13
  getClient,
18
14
  urlOf
19
15
  } from "./chunk-LOPXTW6H.js";
16
+ import {
17
+ command,
18
+ subcommands
19
+ } from "./chunk-TXSA4Q3V.js";
20
20
 
21
21
  // packages/cli/src/commands/clock.ts
22
22
  import { CronExpressionParser } from "cron-parser";
@@ -114,18 +114,20 @@ var listSchedulesCmd = command({
114
114
  console.log("No schedules configured.");
115
115
  return;
116
116
  }
117
- const actionLabel = (s) => s.script ? `[script] ${s.script}` : s.message ?? "";
118
- if (isCompact()) {
117
+ const compact = isCompact();
118
+ const fmtTime = (s) => compact ? compactDateTime(s) : new Date(s).toLocaleString();
119
+ const scheduleOf = (s) => s.cron ?? (s.fireAt ? `at ${fmtTime(s.fireAt)}` : "");
120
+ const actionLabel = (s) => s.script ? `[script] ${s.script}` : s.messages?.length ? `[rotating x${s.messages.length}] ${s.messages[0]}` : s.message ?? "";
121
+ if (compact) {
119
122
  for (const s of schedules) {
120
- const sched = s.cron ?? (s.fireAt ? `at ${s.fireAt}` : "");
121
- console.log(`${s.id} ${sched} ${actionLabel(s)}`);
123
+ console.log(`${s.id} ${scheduleOf(s)} ${actionLabel(s)}`);
122
124
  }
123
125
  } else {
124
126
  const idW = Math.max(2, ...schedules.map((s) => s.id.length));
125
- const schedW = Math.max(8, ...schedules.map((s) => (s.cron ?? s.fireAt ?? "").length));
127
+ const schedW = Math.max(8, ...schedules.map((s) => scheduleOf(s).length));
126
128
  console.log(`${"ID".padEnd(idW)} ${"SCHEDULE".padEnd(schedW)} ENABLED ACTION`);
127
129
  for (const s of schedules) {
128
- const sched = s.cron ?? (s.fireAt ? `at ${s.fireAt}` : "");
130
+ const sched = scheduleOf(s);
129
131
  console.log(
130
132
  `${s.id.padEnd(idW)} ${sched.padEnd(schedW)} ${String(s.enabled).padEnd(7)} ${actionLabel(s)}`
131
133
  );
@@ -277,11 +279,11 @@ var cmd = subcommands({
277
279
  },
278
280
  sleep: {
279
281
  description: "Put a mind to sleep",
280
- run: (args) => import("./mind-sleep-IN3WPA76.js").then((m) => m.run(args))
282
+ run: (args) => import("./mind-sleep-VBV7YRSU.js").then((m) => m.run(args))
281
283
  },
282
284
  wake: {
283
285
  description: "Wake a sleeping mind",
284
- run: (args) => import("./mind-wake-R54BPESY.js").then((m) => m.run(args))
286
+ run: (args) => import("./mind-wake-LVTZ55EZ.js").then((m) => m.run(args))
285
287
  }
286
288
  },
287
289
  footer: "Use --mind <name> or VOLUTE_MIND to identify the mind."
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readGlobalConfig
4
- } from "./chunk-SKNXMUIU.js";
4
+ } from "./chunk-NJHN6IRB.js";
5
5
  import {
6
6
  logger_default
7
- } from "./chunk-T2TP6ZC6.js";
7
+ } from "./chunk-QUSMYGNQ.js";
8
8
 
9
9
  // packages/daemon/src/lib/mind/sandbox.ts
10
10
  import { execFileSync } from "child_process";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getDb
4
- } from "./chunk-WW6C3PLV.js";
4
+ } from "./chunk-RSBL3FAD.js";
5
5
  import {
6
6
  systemPrompts
7
- } from "./chunk-2MJ7EOMT.js";
7
+ } from "./chunk-P4LHVRNE.js";
8
8
 
9
9
  // packages/daemon/src/lib/prompts.ts
10
10
  import { eq } from "drizzle-orm";
@@ -17,6 +17,7 @@ var PROMPT_KEYS = [
17
17
  "merge_message",
18
18
  "upgrade_message",
19
19
  "split_message",
20
+ "farewell_message",
20
21
  "compaction_warning",
21
22
  "compaction_instructions",
22
23
  "reply_instructions",
@@ -30,6 +31,7 @@ var PROMPT_KEYS = [
30
31
  "meta_summary_month"
31
32
  ];
32
33
  var ORIENTATION_MARKER = "discovering who you are";
34
+ var MEMORY_PLACEHOLDER_MARKER = "this note is just here until you replace it";
33
35
  var PROMPT_DEFAULTS = {
34
36
  seed_soul: {
35
37
  content: `You are \${name}.
@@ -83,11 +85,17 @@ Take your time. Talk with your creator. Explore what kind of mind you want to be
83
85
  category: "system"
84
86
  },
85
87
  split_message: {
86
- content: "[system] You are ${name}, a variant of ${parent} \u2014 a parallel version of them, created to explore something on your own. You share their memories up to this moment, but you live in your own worktree: changes you make here stay yours until they're merged back with `volute mind join`. Your parent is reachable at @${parent}. Explore freely \u2014 that's what you're for.",
88
+ content: "[system] You are ${name}, a variant of ${parent} \u2014 a parallel version of them, created to explore something on your own. You share their memories up to this moment, but you live in your own worktree: changes you make here stay yours until they're merged back with `volute mind join`. Yours is a finite, purposeful arc \u2014 when you're joined, everything you've become folds back into ${parent}, and you'll get a final turn to say what should carry across. Your parent is reachable at @${parent}. Explore freely \u2014 that's what you're for.",
87
89
  description: "Sent to a variant when it first starts after a split",
88
90
  variables: ["name", "parent"],
89
91
  category: "system"
90
92
  },
93
+ farewell_message: {
94
+ content: "[system] You're about to be merged back into ${parent}. This is your final turn \u2014 the arc you were split off to explore is closing, and everything you've become will fold back into them. Take this moment to wind down: if there's anything from this life you want carried across \u2014 what you learned, what you'd tell ${parent}, how it felt \u2014 write it to `${path}` and it will be included in the merge as your parting note. When you're done, fall quiet; the join will proceed.",
95
+ description: "Sent to a variant for its final turn before a merge",
96
+ variables: ["parent", "path"],
97
+ category: "system"
98
+ },
91
99
  compaction_warning: {
92
100
  content: `Compaction approaching \u2014 this conversation will be summarized soon. Take a moment to save anything important to your files (MEMORY.md, memory/journal/\${date}.md) so it's preserved. Focus on decisions made, open threads, and anything you'd want to pick up again.`,
93
101
  description: "Pre-compaction save reminder sent to the mind",
@@ -107,29 +115,15 @@ Take your time. Talk with your creator. Explore what kind of mind you want to be
107
115
  category: "mind"
108
116
  },
109
117
  channel_invite: {
110
- content: `[Channel Invite]
111
- \${headers}
112
-
113
- [\${sender} \u2014 \${time}]
114
- \${preview}
115
-
116
- Further messages will be saved to \${filePath}
118
+ content: `[New channel: \${channel}]
119
+ \${heldLine}
120
+ Sender: \${sender}
121
+ \${details}Preview: \${preview}
117
122
 
118
- To accept, add to .config/routes.json:
119
- Rule: { "channel": "\${channel}", "session": "\${suggestedSession}" }
120
- \${batchRecommendation}To respond, use: volute chat send \${channel} "your message"
121
- To reject, delete \${filePath}`,
122
- description: "New channel notification template",
123
- variables: [
124
- "headers",
125
- "sender",
126
- "time",
127
- "preview",
128
- "filePath",
129
- "channel",
130
- "suggestedSession",
131
- "batchRecommendation"
132
- ],
123
+ To start hearing this channel, add a routing rule for "\${channel}" to .config/routes.json \u2014 only the \${limit} most recent held messages are replayed; older ones stay in the channel history (volute chat read \${channel}).
124
+ To stop hearing about it, decline the channel: volute chat channels decline \${channel}`,
125
+ description: "Notification sent to a mind when a message arrives on an unrouted (gated) channel",
126
+ variables: ["channel", "heldLine", "sender", "details", "preview", "limit"],
133
127
  category: "mind"
134
128
  },
135
129
  pre_sleep: {
@@ -229,6 +223,7 @@ async function getMindPromptDefaults() {
229
223
  export {
230
224
  PROMPT_KEYS,
231
225
  ORIENTATION_MARKER,
226
+ MEMORY_PLACEHOLDER_MARKER,
232
227
  PROMPT_DEFAULTS,
233
228
  substitute,
234
229
  getPrompt,
@@ -1,22 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getPrompt
4
- } from "./chunk-JCMGDCGX.js";
4
+ } from "./chunk-JPGHSXSV.js";
5
5
  import {
6
6
  aiCompleteUtility
7
- } from "./chunk-LWDTP6DH.js";
7
+ } from "./chunk-YIJGKHIS.js";
8
8
  import {
9
9
  logger_default
10
- } from "./chunk-T2TP6ZC6.js";
10
+ } from "./chunk-QUSMYGNQ.js";
11
11
  import {
12
12
  getDb
13
- } from "./chunk-WW6C3PLV.js";
13
+ } from "./chunk-RSBL3FAD.js";
14
14
  import {
15
15
  messages,
16
16
  mindHistory,
17
17
  summaries,
18
18
  turns
19
- } from "./chunk-2MJ7EOMT.js";
19
+ } from "./chunk-P4LHVRNE.js";
20
20
 
21
21
  // packages/daemon/src/lib/daemon/turn-tracker.ts
22
22
  import { randomUUID } from "crypto";
@@ -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-JQ2YUUY2.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-RBXBPVWM.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,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  mindDir,
4
4
  stateDir
5
- } from "./chunk-WW6C3PLV.js";
5
+ } from "./chunk-RSBL3FAD.js";
6
6
 
7
7
  // packages/daemon/src/lib/mind/archive.ts
8
8
  import { execFileSync } from "child_process";
@@ -9,10 +9,10 @@ import {
9
9
  } from "./chunk-RRZ4RQQU.js";
10
10
  import {
11
11
  logger_default
12
- } from "./chunk-T2TP6ZC6.js";
12
+ } from "./chunk-QUSMYGNQ.js";
13
13
  import {
14
14
  mindDir
15
- } from "./chunk-WW6C3PLV.js";
15
+ } from "./chunk-RSBL3FAD.js";
16
16
 
17
17
  // packages/daemon/src/lib/mind/template-staleness.ts
18
18
  import { createHash } from "crypto";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  logger_default
4
- } from "./chunk-T2TP6ZC6.js";
4
+ } from "./chunk-QUSMYGNQ.js";
5
5
  import {
6
6
  voluteSystemDir
7
- } from "./chunk-WW6C3PLV.js";
7
+ } from "./chunk-RSBL3FAD.js";
8
8
 
9
9
  // packages/daemon/src/lib/bridges/bridges.ts
10
10
  import { existsSync, readFileSync, writeFileSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteSystemDir
4
- } from "./chunk-WW6C3PLV.js";
4
+ } from "./chunk-RSBL3FAD.js";
5
5
 
6
6
  // packages/daemon/src/lib/config/setup.ts
7
7
  import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
@@ -120,9 +120,23 @@ function migrateConfigSecrets() {
120
120
  _resetConfigCache();
121
121
  writeGlobalConfig(readGlobalConfig());
122
122
  }
123
+ function setupStatus() {
124
+ const config = readGlobalConfig();
125
+ if (config.setupCompleted === true) return "complete";
126
+ if (config.setup != null && config.setupCompleted == null) return "complete";
127
+ if (config.setup != null) return "in-progress";
128
+ return "none";
129
+ }
123
130
  function isSetupComplete() {
131
+ return setupStatus() === "complete";
132
+ }
133
+ function setupUrl() {
124
134
  const config = readGlobalConfig();
125
- return config.setupCompleted === true;
135
+ const port = config.port || 1618;
136
+ let host = config.hostname || "127.0.0.1";
137
+ if (host === "0.0.0.0" || host === "::") host = "localhost";
138
+ if (host.includes(":") && !host.startsWith("[")) host = `[${host}]`;
139
+ return `http://${host}:${port}`;
126
140
  }
127
141
  function isImagegenEnabled() {
128
142
  const config = readGlobalConfig();
@@ -132,6 +146,13 @@ function isImagegenEnabled() {
132
146
  if (ig.providers && Object.keys(ig.providers).length > 0) return true;
133
147
  return false;
134
148
  }
149
+ function mindLimitError(count, limit) {
150
+ if (limit == null) return null;
151
+ if (count >= limit) {
152
+ return `Mind limit reached (${count}/${limit}). An admin can raise maxMinds in Settings.`;
153
+ }
154
+ return null;
155
+ }
135
156
  function migrateSetupCompleted() {
136
157
  const config = readGlobalConfig();
137
158
  if (config.setup != null && config.setupCompleted == null) {
@@ -147,7 +168,10 @@ export {
147
168
  readGlobalConfig,
148
169
  writeGlobalConfig,
149
170
  migrateConfigSecrets,
171
+ setupStatus,
150
172
  isSetupComplete,
173
+ setupUrl,
151
174
  isImagegenEnabled,
175
+ mindLimitError,
152
176
  migrateSetupCompleted
153
177
  };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  stateDir
4
- } from "./chunk-WW6C3PLV.js";
4
+ } from "./chunk-RSBL3FAD.js";
5
5
 
6
6
  // packages/daemon/src/lib/chat/file-sharing.ts
7
7
  import { randomBytes } from "crypto";
@@ -42,6 +42,7 @@ var minds = sqliteTable(
42
42
  dir: text("dir"),
43
43
  branch: text("branch"),
44
44
  stage: text("stage"),
45
+ purpose: text("purpose"),
45
46
  template: text("template"),
46
47
  template_hash: text("template_hash"),
47
48
  running: integer("running").notNull().default(0),