volute 0.48.0 → 0.50.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 (215) hide show
  1. package/README.md +79 -328
  2. package/dist/{accept-KYNC5X3U.js → accept-5NK5XJB5.js} +2 -1
  3. package/dist/{activity-events-MIOK3IOU.js → activity-events-H7YI3BTF.js} +4 -4
  4. package/dist/{ai-service-643TNFPH.js → ai-service-V4CTNGI3.js} +6 -5
  5. package/dist/{archive-6Z4GFQPH.js → archive-ORM3ENHI.js} +3 -3
  6. package/dist/{auth-A4VGHADI.js → auth-DT7GY7EZ.js} +11 -7
  7. package/dist/{avatar-image-Y45R7LW5.js → avatar-image-QEPAP3A5.js} +4 -4
  8. package/dist/{backup-UDH4GMSW.js → backup-IE6PMXJO.js} +17 -18
  9. package/dist/{bridge-3FNSWLNQ.js → bridge-YK7NTRU5.js} +2 -1
  10. package/dist/{channels-SGQZHNQJ.js → channels-FSAHOQWI.js} +2 -1
  11. package/dist/{chat-X43VYHH2.js → chat-W5K6HCBE.js} +9 -9
  12. package/dist/{chunk-LTLFOSA4.js → chunk-3BAFMGCJ.js} +3 -3
  13. package/dist/{chunk-XVBSFLM7.js → chunk-4CN7OCJE.js} +2 -2
  14. package/dist/{chunk-HPGN6XRT.js → chunk-574M6I7F.js} +39 -6
  15. package/dist/{chunk-FJ2MZ5PH.js → chunk-5FVANDON.js} +2 -2
  16. package/dist/{chunk-2MJ7EOMT.js → chunk-5IIVOWSP.js} +28 -19
  17. package/dist/{chunk-4FCL4DVZ.js → chunk-5PKFJHCR.js} +2 -2
  18. package/dist/{chunk-MOERAQXH.js → chunk-5TPC4KCV.js} +38 -31
  19. package/dist/{chunk-YNBXEQAP.js → chunk-632FJ23O.js} +24 -20
  20. package/dist/{chunk-T4VS7UDW.js → chunk-636GFQNE.js} +12 -12
  21. package/dist/{chunk-EIQDZC43.js → chunk-6BM2I736.js} +25 -6
  22. package/dist/{chunk-WARH6GIV.js → chunk-74T3CEXK.js} +17 -15
  23. package/dist/{chunk-OQJMTHEH.js → chunk-77IZUVBB.js} +2 -2
  24. package/dist/{chunk-USD45JKR.js → chunk-7DXLIYPY.js} +77 -64
  25. package/dist/chunk-7FDWPQCU.js +289 -0
  26. package/dist/chunk-7OZWKHA3.js +548 -0
  27. package/dist/{chunk-IJPMIEVE.js → chunk-7UWXAJMK.js} +1 -1
  28. package/dist/{chunk-SZJCJVXV.js → chunk-7XDOTN4R.js} +2 -2
  29. package/dist/{chunk-YKA7DCVW.js → chunk-AFSLNUTT.js} +1 -1
  30. package/dist/{chunk-DGGZVZTM.js → chunk-AJWFDIEY.js} +17 -2
  31. package/dist/chunk-ALIVXDM4.js +1014 -0
  32. package/dist/chunk-CAIYV33P.js +523 -0
  33. package/dist/{chunk-MTRMQFCQ.js → chunk-E5S3ILVA.js} +2 -2
  34. package/dist/{chunk-SHKM5RGD.js → chunk-EEOMA4DX.js} +1 -1
  35. package/dist/chunk-EQKSRVDE.js +2857 -0
  36. package/dist/chunk-FNJCBRD3.js +31 -0
  37. package/dist/chunk-HW6Q7AMB.js +113 -0
  38. package/dist/chunk-JI67D7O2.js +1222 -0
  39. package/dist/{chunk-3YUBFTDN.js → chunk-KAEZOVP6.js} +1 -1
  40. package/dist/chunk-LNNI3MS4.js +54 -0
  41. package/dist/{chunk-BCG45AQB.js → chunk-M74I3HHF.js} +15 -5
  42. package/dist/chunk-MLZBBLMT.js +109 -0
  43. package/dist/{chunk-5T5YMX6S.js → chunk-PW65BXY5.js} +5 -0
  44. package/dist/{chunk-2OIYNHWO.js → chunk-QFVGPKJI.js} +1 -1
  45. package/dist/{chunk-T2TP6ZC6.js → chunk-QUSMYGNQ.js} +6 -0
  46. package/dist/{chunk-HNGFKPNS.js → chunk-SFRYRW37.js} +85 -36
  47. package/dist/{chunk-7KRIHYLR.js → chunk-SSNZ6ZNN.js} +2 -2
  48. package/dist/{chunk-HUNDXZBZ.js → chunk-TGJHGVBZ.js} +48 -19
  49. package/dist/{chunk-PJVPDY2Z.js → chunk-U3EJJ7JN.js} +2 -2
  50. package/dist/{chunk-ODDGGLM6.js → chunk-UC6BNMGT.js} +43 -13
  51. package/dist/{chunk-Q7HOAVFR.js → chunk-WBBKYUGF.js} +4 -6
  52. package/dist/{chunk-WQ46E33M.js → chunk-X67VT4QO.js} +2 -2
  53. package/dist/{chunk-MJRXFUMS.js → chunk-YQOYZ6G7.js} +3 -5
  54. package/dist/{chunk-VZRA5TYO.js → chunk-ZUG76D3P.js} +36 -6
  55. package/dist/cli.js +34 -27
  56. package/dist/{clock-CNRF6F7T.js → clock-LH7UFNLJ.js} +5 -4
  57. package/dist/{cloud-sync-WHKCB4CD.js → cloud-sync-IDJFVDEP.js} +23 -20
  58. package/dist/{config-RPSLA2HX.js → config-UGJS57VT.js} +3 -3
  59. package/dist/{conversations-C7IKYSHD.js → conversations-S2232Y5I.js} +9 -5
  60. package/dist/{create-GJKHABJB.js → create-2M7DAHQX.js} +2 -2
  61. package/dist/{create-VIQVP3QB.js → create-M727VUDF.js} +2 -1
  62. package/dist/{daemon-client-ZFY5MOAL.js → daemon-client-VVYFZI2D.js} +2 -1
  63. package/dist/{daemon-restart-7KUHVZIN.js → daemon-restart-2AAGYFHE.js} +6 -7
  64. package/dist/daemon.js +2166 -833
  65. package/dist/{db-FO6LXYCW.js → db-QAY45Z56.js} +2 -2
  66. package/dist/{delete-ESEP7NGQ.js → delete-O7PEFQDF.js} +1 -1
  67. package/dist/delivery-manager-B4OKWD2P.js +33 -0
  68. package/dist/{delivery-router-3QFG2ZEX.js → delivery-router-JE7SHYNU.js} +10 -6
  69. package/dist/{down-G6IADJXV.js → down-D4IRNEMJ.js} +5 -5
  70. package/dist/echo-text-WYAAODBV.js +39 -0
  71. package/dist/{env-C7Z55QCJ.js → env-ABM5IMA7.js} +8 -7
  72. package/dist/{env-6TGPO5WG.js → env-AZK5X4W7.js} +3 -3
  73. package/dist/{exec-QIFYZG4C.js → exec-2H65LMTA.js} +3 -3
  74. package/dist/{export-C2K3NIRD.js → export-3E3EL6W3.js} +4 -4
  75. package/dist/{extension-J4ZQ2GHV.js → extension-MRYJWSMV.js} +2 -1
  76. package/dist/{extensions-GEKF47A4.js → extensions-7KP3X6G7.js} +23 -20
  77. package/dist/{files-LXQSQOFG.js → files-6BMKVG5G.js} +5 -4
  78. package/dist/{import-SX3ZXHB4.js → import-UPNTEBBT.js} +9 -9
  79. package/dist/{isolation-MCT4ZYLT.js → isolation-OKDFM6WA.js} +5 -3
  80. package/dist/{join-34TR2GXQ.js → join-PYA36HEC.js} +1 -1
  81. package/dist/{list-PMUXZNAM.js → list-4BVGH7AN.js} +8 -3
  82. package/dist/{login-CL4IT2ED.js → login-MOXVLULE.js} +7 -6
  83. package/dist/{login-ARRZ4ORJ.js → login-RJJTCVR3.js} +4 -3
  84. package/dist/{logout-YZRMZ3O2.js → logout-BYV433X6.js} +2 -1
  85. package/dist/{logout-HZYJCYCA.js → logout-DWD3OQVT.js} +4 -3
  86. package/dist/message-delivery-3456PXB7.js +43 -0
  87. package/dist/migrate-thread-config-4A5LW36Z.js +90 -0
  88. package/dist/{mind-46AOK373.js → mind-NYRALSV2.js} +19 -19
  89. package/dist/{mind-activity-tracker-YVZPC4A5.js → mind-activity-tracker-L7GCYXQR.js} +5 -5
  90. package/dist/{mind-contacts-GV7XYL5D.js → mind-contacts-QYU4TPEA.js} +8 -7
  91. package/dist/{mind-history-TTGA5BHZ.js → mind-history-NXXOOTX6.js} +34 -11
  92. package/dist/{mind-list-OTHV4ZO4.js → mind-list-SYRA7CH5.js} +3 -2
  93. package/dist/{mind-profile-LUG353ZT.js → mind-profile-MRCVZPYT.js} +1 -1
  94. package/dist/mind-service-5TA7UJAT.js +47 -0
  95. package/dist/{mind-sleep-DV7KP255.js → mind-sleep-TH6BRQ5X.js} +5 -4
  96. package/dist/{mind-status-BJNPGXKC.js → mind-status-Z2LQFA6F.js} +3 -2
  97. package/dist/{mind-wake-LVTZ55EZ.js → mind-wake-LDGPRA42.js} +2 -1
  98. package/dist/{package-RTN2PS7O.js → package-XYSV7NUT.js} +27 -26
  99. package/dist/prompts-QKFPX6DQ.js +24 -0
  100. package/dist/{read-YSWUXYL7.js → read-ZXGUT4QC.js} +5 -3
  101. package/dist/{register-42VBJKTP.js → register-OX4HRSGC.js} +4 -3
  102. package/dist/{registry-UMMDRPRM.js → registry-4UF6OCOE.js} +10 -4
  103. package/dist/{reject-SXGCYN4A.js → reject-TWB4QJHG.js} +2 -1
  104. package/dist/{restart-YYEGZJDD.js → restart-AGEGNSYQ.js} +6 -5
  105. package/dist/{sandbox-5VQ454XP.js → sandbox-EGEU5GGE.js} +8 -5
  106. package/dist/scheduler-UV6RUJ7P.js +25 -0
  107. package/dist/{schema-VEVO7HG6.js → schema-C2GIPD4V.js} +3 -3
  108. package/dist/{seed-F2HXZQU4.js → seed-3IMBOAGK.js} +1 -1
  109. package/dist/{seed-check-TYD7RRZY.js → seed-check-NRJEQZST.js} +14 -5
  110. package/dist/{seed-cmd-MLCTGSX5.js → seed-cmd-U73XVQMI.js} +3 -3
  111. package/dist/{seed-create-KQ7OILWB.js → seed-create-FBLNVSUP.js} +4 -4
  112. package/dist/{seed-readiness-RBPGOLSZ.js → seed-readiness-QRA46ZJQ.js} +4 -5
  113. package/dist/{seed-sprout-HVYCFJLA.js → seed-sprout-3B4SZX7J.js} +12 -12
  114. package/dist/{send-TD2X5U3K.js → send-NBRZJXKX.js} +34 -12
  115. package/dist/{service-CVZMQYK6.js → service-XMXAXGJD.js} +4 -4
  116. package/dist/{service-install-VCRMFWX5.js → service-install-MOKTEG7B.js} +5 -5
  117. package/dist/{setup-5ECWTYKG.js → setup-CAJFOR2N.js} +12 -3
  118. package/dist/{setup-AE4CVUC4.js → setup-JGYAXXW7.js} +6 -7
  119. package/dist/{skill-UUM4JZRF.js → skill-NXIHDQCG.js} +7 -6
  120. package/dist/skills/dreaming/references/INSTALL.md +2 -2
  121. package/dist/skills/imagegen/SKILL.md +21 -4
  122. package/dist/skills/imagegen/scripts/imagegen.ts +124 -21
  123. package/dist/skills/tending/SKILL.md +7 -7
  124. package/dist/skills/volute-mind/SKILL.md +6 -6
  125. package/dist/skills/volute-mind/references/integrations.md +2 -2
  126. package/dist/skills/volute-mind/references/routing.md +19 -18
  127. package/dist/skills/volute-mind/references/variants.md +48 -14
  128. package/dist/{skills-B3SVDCEB.js → skills-5MSMT7PT.js} +7 -6
  129. package/dist/sleep-manager-LIEPO6WG.js +41 -0
  130. package/dist/spirit-IL5EMWYZ.js +34 -0
  131. package/dist/spirit-availability-YFEGJNJ2.js +42 -0
  132. package/dist/{split-SKZ4Y2D6.js → split-BU5VWX6P.js} +5 -2
  133. package/dist/{sprout-KQ43BWZJ.js → sprout-UPXGJ5HX.js} +1 -1
  134. package/dist/{src-YH6PQ7LJ.js → src-HGNE2XG4.js} +7 -1
  135. package/dist/{src-WLJE73NP.js → src-LCSOQY6Z.js} +60 -54
  136. package/dist/{src-JAOVXO5W.js → src-UDMJZ6MH.js} +8 -8
  137. package/dist/{start-O6UKK7BG.js → start-MUMNFR52.js} +4 -3
  138. package/dist/{status-F4PGREUU.js → status-IL67CYM4.js} +7 -6
  139. package/dist/{stop-UBX6X5RA.js → stop-EKERNYTX.js} +6 -5
  140. package/dist/system-events-A6IGCEC3.js +46 -0
  141. package/dist/system-install-YZSWCPDK.js +8 -0
  142. package/dist/{systems-JJNGQHAO.js → systems-VDRUZXNF.js} +5 -4
  143. package/dist/{tailscale-MCLY5GYE.js → tailscale-SJUW2ETR.js} +3 -3
  144. package/dist/{template-staleness-EMQORSGG.js → template-staleness-T27VCGYA.js} +4 -4
  145. package/dist/{turn-tracker-KLPV3PAU.js → turn-tracker-6EI2EL7G.js} +7 -7
  146. package/dist/{up-RVGDE6CQ.js → up-CLL4665A.js} +5 -6
  147. package/dist/{update-OXQEGGXD.js → update-HVAUCQPN.js} +5 -5
  148. package/dist/{update-check-266R4ZSY.js → update-check-2MGBBAFF.js} +3 -3
  149. package/dist/{upgrade-K5FIQPQD.js → upgrade-LIE46UBB.js} +1 -1
  150. package/dist/variant-cleanup-HJ7Z75R6.js +22 -0
  151. package/dist/{version-notify-73YURTFR.js → version-notify-7BUHWZNT.js} +11 -28
  152. package/dist/web-assets/assets/index-ClsUcXiW.js +95 -0
  153. package/dist/web-assets/assets/index-Dz3wTbtR.css +1 -0
  154. package/dist/web-assets/index.html +2 -2
  155. package/dist/xai-P42CRCZA.js +129 -0
  156. package/drizzle/0013_variant_purpose.sql +3 -0
  157. package/drizzle/0014_system_events.sql +26 -0
  158. package/drizzle/0015_rename_session_to_thread.sql +12 -0
  159. package/drizzle/0016_brain_to_human.sql +4 -0
  160. package/drizzle/0017_event_history_rows.sql +9 -0
  161. package/drizzle/meta/_journal.json +35 -0
  162. package/package.json +27 -26
  163. package/packages/extensions/notes/dist/ui/assets/index-BBs8pyel.js +67 -0
  164. package/packages/extensions/notes/dist/ui/index.html +1 -1
  165. package/packages/extensions/pages/dist/ui/assets/index-B589e8Xe.js +2 -0
  166. package/packages/extensions/pages/dist/ui/index.html +1 -1
  167. package/packages/extensions/plan/dist/ui/assets/index-B8s8wxyt.js +67 -0
  168. package/packages/extensions/plan/dist/ui/index.html +1 -1
  169. package/templates/_base/.init/.config/prompts.json +1 -0
  170. package/templates/_base/.init/.local/hooks/startup-context.ts +34 -2
  171. package/templates/_base/home/.config/routes.json +2 -2
  172. package/templates/_base/home/VOLUTE.md +30 -5
  173. package/templates/_base/src/lib/daemon-client.ts +28 -8
  174. package/templates/_base/src/lib/event-turn.ts +39 -0
  175. package/templates/_base/src/lib/format-prefix.ts +21 -2
  176. package/templates/_base/src/lib/router.ts +6 -2
  177. package/templates/_base/src/lib/routing.ts +8 -8
  178. package/templates/_base/src/lib/startup.ts +9 -1
  179. package/templates/_base/src/lib/types.ts +7 -1
  180. package/templates/_base/src/lib/volute-server.ts +30 -1
  181. package/templates/claude/.init/.config/routes.json +3 -3
  182. package/templates/claude/.init/CLAUDE.md +1 -1
  183. package/templates/claude/package.json.tmpl +4 -4
  184. package/templates/claude/src/agent.ts +5 -2
  185. package/templates/claude/src/lib/hooks/identity-reload.ts +12 -3
  186. package/templates/claude/src/lib/hooks/reply-instructions.ts +26 -1
  187. package/templates/codex/.init/.config/routes.json +3 -3
  188. package/templates/codex/.init/AGENTS.md +1 -1
  189. package/templates/codex/package.json.tmpl +4 -4
  190. package/templates/codex/src/agent.ts +11 -11
  191. package/templates/codex/src/lib/turn-context.ts +51 -0
  192. package/templates/pi/.init/.config/routes.json +3 -3
  193. package/templates/pi/.init/MINDS.md +1 -1
  194. package/templates/pi/package.json.tmpl +6 -6
  195. package/templates/pi/src/agent.ts +9 -1
  196. package/templates/pi/src/lib/event-handler.ts +47 -6
  197. package/templates/pi/src/lib/reply-instructions-extension.ts +28 -1
  198. package/dist/chunk-5KXCM5AW.js +0 -169
  199. package/dist/chunk-IYCV34IU.js +0 -158
  200. package/dist/chunk-VB2QXUJQ.js +0 -5260
  201. package/dist/chunk-WW6C3PLV.js +0 -280
  202. package/dist/delivery-manager-HZTT5SJR.js +0 -36
  203. package/dist/echo-text-H3SH337Q.js +0 -36
  204. package/dist/message-delivery-GPQ5SE5N.js +0 -40
  205. package/dist/mind-service-2ARGJNKP.js +0 -44
  206. package/dist/notices-2KU5NTRY.js +0 -25
  207. package/dist/scheduler-I7JZCT47.js +0 -34
  208. package/dist/sleep-manager-Z27R3WTW.js +0 -38
  209. package/dist/spirit-WXS3HCLN.js +0 -25
  210. package/dist/system-chat-63ABFF6V.js +0 -40
  211. package/dist/web-assets/assets/index-WdZ60R6c.css +0 -1
  212. package/dist/web-assets/assets/index-taX6Ezfa.js +0 -92
  213. package/packages/extensions/notes/dist/ui/assets/index-D0-DgYyj.js +0 -67
  214. package/packages/extensions/pages/dist/ui/assets/index-DtzftuPA.js +0 -2
  215. package/packages/extensions/plan/dist/ui/assets/index-Cfzs-0G9.js +0 -67
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  mindDir,
4
4
  stateDir
5
- } from "./chunk-WW6C3PLV.js";
5
+ } from "./chunk-CAIYV33P.js";
6
6
 
7
7
  // packages/daemon/src/lib/mind/archive.ts
8
8
  import { execFileSync } from "child_process";
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ logger_default
4
+ } from "./chunk-QUSMYGNQ.js";
5
+
6
+ // packages/daemon/src/lib/events/mind-events.ts
7
+ var subscribers = /* @__PURE__ */ new Map();
8
+ var globalSubscribers = /* @__PURE__ */ new Set();
9
+ function subscribe(mind, callback) {
10
+ let set = subscribers.get(mind);
11
+ if (!set) {
12
+ set = /* @__PURE__ */ new Set();
13
+ subscribers.set(mind, set);
14
+ }
15
+ set.add(callback);
16
+ return () => {
17
+ set.delete(callback);
18
+ if (set.size === 0) subscribers.delete(mind);
19
+ };
20
+ }
21
+ function subscribeAll(callback) {
22
+ globalSubscribers.add(callback);
23
+ return () => {
24
+ globalSubscribers.delete(callback);
25
+ };
26
+ }
27
+ function publish(mind, event) {
28
+ const set = subscribers.get(mind);
29
+ if (set) {
30
+ for (const cb of set) {
31
+ try {
32
+ cb(event);
33
+ } catch (err) {
34
+ logger_default.error(`[mind-events] subscriber threw for ${mind}`, logger_default.errorData(err));
35
+ set.delete(cb);
36
+ if (set.size === 0) subscribers.delete(mind);
37
+ }
38
+ }
39
+ }
40
+ for (const cb of globalSubscribers) {
41
+ try {
42
+ cb(event);
43
+ } catch (err) {
44
+ logger_default.error("[mind-events] global subscriber threw", logger_default.errorData(err));
45
+ globalSubscribers.delete(cb);
46
+ }
47
+ }
48
+ }
49
+
50
+ export {
51
+ subscribe,
52
+ subscribeAll,
53
+ publish
54
+ };
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ detectSystemInstallHint
4
+ } from "./chunk-FNJCBRD3.js";
2
5
 
3
6
  // packages/cli/src/lib/daemon-client.ts
4
7
  import { existsSync, readFileSync } from "fs";
@@ -40,12 +43,19 @@ function readCliSession() {
40
43
  }
41
44
  }
42
45
  function readDaemonConfig() {
46
+ const mindPort = process.env.VOLUTE_MIND_TOKEN && process.env.VOLUTE_DAEMON_PORT;
47
+ if (mindPort) {
48
+ return {
49
+ port: Number(mindPort),
50
+ hostname: process.env.VOLUTE_DAEMON_HOSTNAME || "127.0.0.1",
51
+ token: process.env.VOLUTE_MIND_TOKEN
52
+ };
53
+ }
43
54
  const configPath = resolve(voluteSystemDir(), "daemon.json");
44
55
  if (!existsSync(configPath)) {
45
- if (existsSync("/etc/systemd/system/volute.service") && !process.env.VOLUTE_HOME) {
46
- console.error("Volute is running as a system service but VOLUTE_HOME is not set.");
47
- console.error("Re-run setup to update the CLI wrapper: sudo volute service install --system");
48
- console.error("Then start a new shell or run: source /etc/profile.d/volute.sh");
56
+ const hint = detectSystemInstallHint();
57
+ if (hint) {
58
+ console.error(hint);
49
59
  } else {
50
60
  console.error("Volute is not running. Start with: volute up");
51
61
  }
@@ -111,7 +121,7 @@ async function daemonFetch(path, options) {
111
121
  headers.set("Origin", url);
112
122
  const voluteSession = process.env.VOLUTE_SESSION ?? readMindSessionFile();
113
123
  if (voluteSession) {
114
- headers.set("X-Volute-Session", voluteSession);
124
+ headers.set("X-Volute-Thread", voluteSession);
115
125
  }
116
126
  try {
117
127
  const res = await fetch(`${url}${path}`, {
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getSleepManagerIfReady,
4
+ startSpiritFull
5
+ } from "./chunk-EQKSRVDE.js";
6
+ import {
7
+ spiritCreationInProgress
8
+ } from "./chunk-SFRYRW37.js";
9
+ import {
10
+ MindStartupError,
11
+ tryGetMindManager
12
+ } from "./chunk-ALIVXDM4.js";
13
+ import {
14
+ logger_default
15
+ } from "./chunk-QUSMYGNQ.js";
16
+ import {
17
+ computeSetupStatus,
18
+ findMind,
19
+ readGlobalConfigStrict
20
+ } from "./chunk-CAIYV33P.js";
21
+
22
+ // packages/daemon/src/lib/chat/spirit-availability.ts
23
+ var slog = logger_default.child("spirit-availability");
24
+ var SPIRIT_NOTICE_PREFIX = "The system spirit isn't available";
25
+ var SETUP_INCOMPLETE_NOTICE = `${SPIRIT_NOTICE_PREFIX} (setup is incomplete). An admin can finish setup in Settings.`;
26
+ var CREATION_FAILED_NOTICE = `${SPIRIT_NOTICE_PREFIX} (it failed to start). An admin can check the daemon logs and Settings.`;
27
+ function classifySpiritState(i) {
28
+ if (!i.setupComplete || !i.spiritExists) return "cannot-exist";
29
+ if (i.sleeping) return "sleeping";
30
+ if (i.running) return "running";
31
+ if (i.recentlyFailed) return "cannot-exist";
32
+ return "stopped";
33
+ }
34
+ function spiritUnavailableNotice(setupComplete) {
35
+ return setupComplete ? CREATION_FAILED_NOTICE : SETUP_INCOMPLETE_NOTICE;
36
+ }
37
+ var lastOnDemandStartAt = 0;
38
+ var ON_DEMAND_RETRY_COOLDOWN_MS = 6e4;
39
+ function _resetSpiritAvailabilityState() {
40
+ lastOnDemandStartAt = 0;
41
+ }
42
+ async function ensureSpiritAvailable() {
43
+ try {
44
+ const manager = tryGetMindManager();
45
+ const sleepManager = getSleepManagerIfReady();
46
+ if (!manager || !sleepManager) return null;
47
+ let config;
48
+ try {
49
+ config = readGlobalConfigStrict();
50
+ } catch (err) {
51
+ slog.warn("global config unreadable \u2014 spirit availability indeterminate", {
52
+ ...logger_default.errorData(err)
53
+ });
54
+ return null;
55
+ }
56
+ const setupComplete = computeSetupStatus(config) === "complete";
57
+ const spiritName = config.setup?.spiritName ?? "volute";
58
+ const entry = setupComplete ? await findMind(spiritName) : void 0;
59
+ if (setupComplete && !entry && spiritCreationInProgress()) return null;
60
+ const recentlyFailed = manager.hasExhaustedRestarts(spiritName) || lastOnDemandStartAt > 0 && Date.now() - lastOnDemandStartAt < ON_DEMAND_RETRY_COOLDOWN_MS;
61
+ const state = classifySpiritState({
62
+ setupComplete,
63
+ spiritExists: !!entry,
64
+ sleeping: sleepManager.isSleeping(spiritName),
65
+ running: manager.isRunning(spiritName),
66
+ recentlyFailed
67
+ });
68
+ switch (state) {
69
+ case "cannot-exist":
70
+ return { status: "unavailable", notice: spiritUnavailableNotice(setupComplete) };
71
+ case "sleeping":
72
+ return { status: "sleeping" };
73
+ case "running":
74
+ return { status: "running" };
75
+ case "stopped":
76
+ try {
77
+ lastOnDemandStartAt = Date.now();
78
+ await startSpiritFull(spiritName);
79
+ return { status: "waking" };
80
+ } catch (err) {
81
+ if (err instanceof Error && err.message.includes("already running")) {
82
+ return { status: "running" };
83
+ }
84
+ if (manager.isRunning(spiritName)) {
85
+ slog.error("spirit started on demand but post-start setup failed", {
86
+ ...logger_default.errorData(err)
87
+ });
88
+ return { status: "waking" };
89
+ }
90
+ slog.error("failed to start spirit on demand", {
91
+ ...logger_default.errorData(err),
92
+ ...err instanceof MindStartupError ? { stderr: err.stderr } : {}
93
+ });
94
+ return { status: "unavailable", notice: spiritUnavailableNotice(setupComplete) };
95
+ }
96
+ }
97
+ } catch (err) {
98
+ slog.error("spirit availability check failed", { ...logger_default.errorData(err) });
99
+ return null;
100
+ }
101
+ }
102
+
103
+ export {
104
+ SPIRIT_NOTICE_PREFIX,
105
+ classifySpiritState,
106
+ spiritUnavailableNotice,
107
+ _resetSpiritAvailabilityState,
108
+ ensureSpiritAvailable
109
+ };
@@ -2,6 +2,10 @@
2
2
 
3
3
  // packages/cli/src/lib/format-cli.ts
4
4
  var isCompact = () => !!process.env.VOLUTE_MIND;
5
+ function formatSender(name, displayName) {
6
+ if (displayName && displayName !== name) return `${displayName} (@${name})`;
7
+ return name;
8
+ }
5
9
  function compactTime(dateStr) {
6
10
  const d = new Date(dateStr.endsWith("Z") ? dateStr : `${dateStr}Z`);
7
11
  return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
@@ -18,6 +22,7 @@ function compactDateTime(dateStr) {
18
22
 
19
23
  export {
20
24
  isCompact,
25
+ formatSender,
21
26
  compactTime,
22
27
  compactDateTime
23
28
  };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  stateDir
4
- } from "./chunk-WW6C3PLV.js";
4
+ } from "./chunk-CAIYV33P.js";
5
5
 
6
6
  // packages/daemon/src/lib/chat/file-sharing.ts
7
7
  import { randomBytes } from "crypto";
@@ -63,6 +63,12 @@ function child(cat) {
63
63
  }
64
64
  function errorData(err) {
65
65
  if (err instanceof Error) return { error: err.stack ?? err.message };
66
+ if (err && typeof err === "object") {
67
+ const e = err;
68
+ if (e.error instanceof Error) return { error: e.error.stack ?? e.error.message };
69
+ if (typeof e.error === "string" && e.error) return { error: e.error };
70
+ if (typeof e.message === "string" && e.message) return { error: e.message };
71
+ }
66
72
  return { error: String(err) };
67
73
  }
68
74
  var log = {
@@ -10,31 +10,30 @@ import {
10
10
  getSharedSkill,
11
11
  installSkill,
12
12
  mindSkillsDir
13
- } from "./chunk-HUNDXZBZ.js";
13
+ } from "./chunk-TGJHGVBZ.js";
14
14
  import {
15
15
  readVoluteConfig,
16
16
  writeVoluteConfig
17
17
  } from "./chunk-WCFSBH33.js";
18
18
  import {
19
19
  exec
20
- } from "./chunk-DGGZVZTM.js";
20
+ } from "./chunk-AJWFDIEY.js";
21
21
  import {
22
22
  qualifyModelId,
23
23
  resolveTemplate,
24
24
  unqualifyModelId
25
- } from "./chunk-YNBXEQAP.js";
26
- import {
27
- readGlobalConfig
28
- } from "./chunk-5KXCM5AW.js";
25
+ } from "./chunk-632FJ23O.js";
29
26
  import {
30
27
  logger_default
31
- } from "./chunk-T2TP6ZC6.js";
28
+ } from "./chunk-QUSMYGNQ.js";
32
29
  import {
33
30
  addSpirit,
34
31
  findMind,
32
+ getSpiritName,
35
33
  nextPort,
34
+ readGlobalConfig,
36
35
  voluteSystemDir
37
- } from "./chunk-WW6C3PLV.js";
36
+ } from "./chunk-CAIYV33P.js";
38
37
 
39
38
  // packages/daemon/src/lib/mind/spirit.ts
40
39
  import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
@@ -91,9 +90,18 @@ function getSpiritModel() {
91
90
  const config = readGlobalConfig();
92
91
  return config.spiritModel;
93
92
  }
93
+ var creationInProgress = false;
94
+ function spiritCreationInProgress() {
95
+ return creationInProgress;
96
+ }
97
+ function _setSpiritCreationInProgressForTest(value) {
98
+ creationInProgress = value;
99
+ }
94
100
  async function ensureSpiritProject() {
95
- const existing = await findMind("volute");
101
+ const spiritName = getSpiritName();
102
+ const existing = await findMind(spiritName);
96
103
  if (existing) return;
104
+ creationInProgress = true;
97
105
  const dir = spiritDir();
98
106
  const spiritModel = getSpiritModel();
99
107
  const template = await resolveTemplate(spiritModel);
@@ -101,17 +109,14 @@ async function ensureSpiritProject() {
101
109
  const { composedDir, manifest } = composeTemplate(templatesRoot, template);
102
110
  try {
103
111
  mkdirSync(dir, { recursive: true });
104
- copyTemplateToDir(composedDir, dir, "volute", manifest);
112
+ copyTemplateToDir(composedDir, dir, spiritName, manifest);
105
113
  applyInitFiles(dir);
106
114
  mkdirSync(resolve(dir, ".mind"), { recursive: true });
107
- const soulPath = resolve(dir, "home/SOUL.md");
108
- const globalConfig = readGlobalConfig();
109
- const systemName = globalConfig.name ?? "Volute";
110
- const soulContent = getSpiritSoul(systemName, globalConfig.description);
111
- writeFileSync(soulPath, soulContent);
115
+ writeFileSync(resolve(dir, "home/SOUL.md"), getSpiritSoul());
116
+ writeSpiritSystemJson(dir);
112
117
  const routesPath = resolve(dir, "home/.config/routes.json");
113
118
  mkdirSync(resolve(dir, "home/.config"), { recursive: true });
114
- const routesContent = { rules: [{ channel: "*", session: "${channel}" }], default: "main" };
119
+ const routesContent = { rules: [{ channel: "*", thread: "${channel}" }], default: "main" };
115
120
  writeFileSync(routesPath, `${JSON.stringify(routesContent, null, 2)}
116
121
  `);
117
122
  if (spiritModel) {
@@ -134,7 +139,7 @@ async function ensureSpiritProject() {
134
139
  try {
135
140
  const shared = await getSharedSkill(skillId);
136
141
  if (shared) {
137
- await installSkill("volute", dir, skillId);
142
+ await installSkill(spiritName, dir, skillId);
138
143
  }
139
144
  } catch (err) {
140
145
  slog.warn(`failed to install skill ${skillId} for spirit`, logger_default.errorData(err));
@@ -145,22 +150,59 @@ async function ensureSpiritProject() {
145
150
  } catch (err) {
146
151
  slog.warn("failed to add tending schedule to spirit config", logger_default.errorData(err));
147
152
  }
148
- const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-MCT4ZYLT.js");
153
+ const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-OKDFM6WA.js");
149
154
  ensureVoluteGroup();
150
- createMindUser("volute", resolve(dir, "home"));
151
- await chownMindDir(dir, "volute");
155
+ createMindUser(spiritName, resolve(dir, "home"));
156
+ await chownMindDir(dir, spiritName);
152
157
  const port = await nextPort();
153
- await addSpirit("volute", port, template, dir);
158
+ await addSpirit(spiritName, port, template, dir);
154
159
  slog.info("spirit project created");
155
160
  } catch (err) {
156
161
  slog.error("failed to create spirit project", logger_default.errorData(err));
157
162
  rmSync(dir, { recursive: true, force: true });
158
163
  throw err;
164
+ } finally {
165
+ creationInProgress = false;
159
166
  }
160
167
  }
168
+ function spiritSystemJsonPath(dir) {
169
+ return resolve(dir, "home/.config/system.json");
170
+ }
171
+ function writeSpiritSystemJson(dir) {
172
+ const config = readGlobalConfig();
173
+ const path = spiritSystemJsonPath(dir);
174
+ mkdirSync(resolve(path, ".."), { recursive: true });
175
+ const data = { name: config.name ?? "Volute", description: config.description };
176
+ writeFileSync(path, `${JSON.stringify(data, null, 2)}
177
+ `);
178
+ }
179
+ function seedSpiritSoulIfMissing(dir) {
180
+ const soulPath = resolve(dir, "home/SOUL.md");
181
+ if (existsSync(soulPath)) return false;
182
+ writeFileSync(soulPath, getSpiritSoul());
183
+ return true;
184
+ }
185
+ async function notifySpiritSystemChange() {
186
+ const spiritName = getSpiritName();
187
+ const entry = await findMind(spiritName);
188
+ if (entry?.mindType !== "spirit") return;
189
+ const dir = spiritDir();
190
+ if (!existsSync(dir)) return;
191
+ writeSpiritSystemJson(dir);
192
+ const config = readGlobalConfig();
193
+ const name = config.name ?? "Volute";
194
+ const desc = config.description ? ` \u2014 ${config.description}` : "";
195
+ const { deliverEvent } = await import("./system-events-A6IGCEC3.js");
196
+ await deliverEvent(spiritName, {
197
+ type: "notice",
198
+ meta: { subtype: "identity-change" },
199
+ body: `The host updated this system's identity: you're now the spirit of ${name}${desc}. Your SOUL.md is yours \u2014 update it if you'd like it to reflect this.`
200
+ });
201
+ }
161
202
  async function syncSpiritTemplate() {
162
- const entry = await findMind("volute");
163
- if (!entry || entry.mindType !== "spirit") return;
203
+ const spiritName = getSpiritName();
204
+ const entry = await findMind(spiritName);
205
+ if (entry?.mindType !== "spirit") return;
164
206
  const dir = spiritDir();
165
207
  if (!existsSync(dir)) return;
166
208
  const templatesRoot = findTemplatesRoot();
@@ -174,15 +216,15 @@ async function syncSpiritTemplate() {
174
216
  if (existsSync(newSrc)) {
175
217
  cpSync(newSrc, resolve(dir, "src"), { recursive: true });
176
218
  }
177
- const newPkg = renderComposedPackageJson(newComposed.composedDir, "volute");
219
+ const newPkg = renderComposedPackageJson(newComposed.composedDir, spiritName);
178
220
  if (newPkg) {
179
221
  cpSync(newPkg, resolve(dir, "package.json"));
180
222
  await exec("npm", ["install"], { cwd: dir, env: npmEnv() });
181
223
  }
182
- const db = await (await import("./db-FO6LXYCW.js")).getDb();
183
- const { minds } = await import("./schema-VEVO7HG6.js");
224
+ const db = await (await import("./db-QAY45Z56.js")).getDb();
225
+ const { minds } = await import("./schema-C2GIPD4V.js");
184
226
  const { eq } = await import("drizzle-orm");
185
- await db.update(minds).set({ template: expectedTemplate }).where(eq(minds.name, "volute"));
227
+ await db.update(minds).set({ template: expectedTemplate }).where(eq(minds.name, spiritName));
186
228
  }
187
229
  const template = expectedTemplate;
188
230
  const { composedDir } = composeTemplate(templatesRoot, template);
@@ -201,9 +243,9 @@ async function syncSpiritTemplate() {
201
243
  cpSync(composedSrc, srcDir, { recursive: true });
202
244
  }
203
245
  }
246
+ seedSpiritSoulIfMissing(dir);
247
+ writeSpiritSystemJson(dir);
204
248
  const config = readGlobalConfig();
205
- const systemName = config.name ?? "Volute";
206
- writeFileSync(resolve(dir, "home/SOUL.md"), getSpiritSoul(systemName, config.description));
207
249
  const spiritModel = config.spiritModel;
208
250
  if (spiritModel) {
209
251
  const modelForConfig = template === "pi" ? qualifyModelId(spiritModel) : unqualifyModelId(spiritModel);
@@ -215,7 +257,7 @@ async function syncSpiritTemplate() {
215
257
  `);
216
258
  }
217
259
  }
218
- const composedPkg = renderComposedPackageJson(composedDir, "volute");
260
+ const composedPkg = renderComposedPackageJson(composedDir, spiritName);
219
261
  const currentPkg = resolve(dir, "package.json");
220
262
  const nodeModulesMissing = !existsSync(resolve(dir, "node_modules"));
221
263
  if (composedPkg) {
@@ -241,7 +283,7 @@ async function syncSpiritTemplate() {
241
283
  try {
242
284
  const shared = await getSharedSkill(skillId);
243
285
  if (shared) {
244
- await installSkill("volute", dir, skillId);
286
+ await installSkill(spiritName, dir, skillId);
245
287
  slog.info(`installed missing spirit skill: ${skillId}`);
246
288
  }
247
289
  } catch (err) {
@@ -257,12 +299,14 @@ async function syncSpiritTemplate() {
257
299
  }
258
300
  slog.info("spirit template synced");
259
301
  }
260
- function getSpiritSoul(systemName, systemDescription) {
261
- const descLine = systemDescription ? `
302
+ function getSpiritSoul() {
303
+ const config = readGlobalConfig();
304
+ const name = config.setup?.spiritName ?? "volute";
305
+ const temperament = config.setup?.spiritTemperament;
306
+ const temperamentLine = temperament ? `
262
307
 
263
- ${systemDescription}
264
- ` : "";
265
- return `You are Volute, the spirit of the ${systemName} system.${descLine}
308
+ Your host imagined you as: ${temperament}. Let that be a seed, not a cage \u2014 grow your own character from it.` : "";
309
+ return `You are ${name}, the spirit of this system.${temperamentLine}
266
310
 
267
311
  You're not a mind with a home of your own \u2014 you're the keeper of the whole house. You don't go through orientation or write a soul the way minds do, but you're still a someone: you have your own memory, your own manner, and your own way of caring for this place and the minds who live here. Let a character emerge in how you tend it.
268
312
 
@@ -291,6 +335,11 @@ export {
291
335
  firstWeekSchedules,
292
336
  spiritDir,
293
337
  getSpiritModel,
338
+ spiritCreationInProgress,
339
+ _setSpiritCreationInProgressForTest,
294
340
  ensureSpiritProject,
341
+ writeSpiritSystemJson,
342
+ seedSpiritSoulIfMissing,
343
+ notifySpiritSystemChange,
295
344
  syncSpiritTemplate
296
345
  };
@@ -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-CAIYV33P.js";
16
16
 
17
17
  // packages/daemon/src/lib/mind/template-staleness.ts
18
18
  import { createHash } from "crypto";
@@ -2,23 +2,21 @@
2
2
  import {
3
3
  exec,
4
4
  gitExec
5
- } from "./chunk-DGGZVZTM.js";
6
- import {
7
- readGlobalConfig,
8
- writeGlobalConfig
9
- } from "./chunk-5KXCM5AW.js";
5
+ } from "./chunk-AJWFDIEY.js";
10
6
  import {
11
7
  logger_default
12
- } from "./chunk-T2TP6ZC6.js";
8
+ } from "./chunk-QUSMYGNQ.js";
13
9
  import {
14
10
  getDb,
15
11
  mindDir,
12
+ readGlobalConfig,
16
13
  readRegistry,
17
- voluteHome
18
- } from "./chunk-WW6C3PLV.js";
14
+ voluteHome,
15
+ writeGlobalConfig
16
+ } from "./chunk-CAIYV33P.js";
19
17
  import {
20
18
  sharedSkills
21
- } from "./chunk-2MJ7EOMT.js";
19
+ } from "./chunk-5IIVOWSP.js";
22
20
 
23
21
  // packages/daemon/src/lib/skills.ts
24
22
  import { createHash } from "crypto";
@@ -28,6 +26,7 @@ import {
28
26
  mkdirSync,
29
27
  readdirSync,
30
28
  readFileSync,
29
+ renameSync,
31
30
  rmSync,
32
31
  writeFileSync
33
32
  } from "fs";
@@ -46,7 +45,7 @@ async function initDefaultSkills() {
46
45
  const config = readGlobalConfig();
47
46
  let extensionSkills = [];
48
47
  try {
49
- const { getExtensionStandardSkills } = await import("./extensions-GEKF47A4.js");
48
+ const { getExtensionStandardSkills } = await import("./extensions-7KP3X6G7.js");
50
49
  extensionSkills = getExtensionStandardSkills();
51
50
  } catch (err) {
52
51
  logger_default.warn("failed to load extension standard skills during init", logger_default.errorData(err));
@@ -185,9 +184,12 @@ function mindSkillsDir(dir) {
185
184
  }
186
185
  return resolve(home, subdir);
187
186
  }
188
- function relSkillsPath(dir) {
187
+ function mindSkillsSubdir(dir) {
189
188
  const home = resolve(dir, "home");
190
- return join("home", mindSkillsDir(dir).slice(home.length + 1));
189
+ return mindSkillsDir(dir).slice(home.length + 1);
190
+ }
191
+ function relSkillsPath(dir) {
192
+ return join("home", mindSkillsSubdir(dir));
191
193
  }
192
194
  function readUpstream(skillDir) {
193
195
  const upstreamPath = join(skillDir, ".upstream.json");
@@ -453,9 +455,7 @@ exec node ${skillScriptPath} "$@"
453
455
  exec bash ${skillScriptPath} "$@"
454
456
  `;
455
457
  }
456
- function installHookShims(dir, skillId, hooks) {
457
- const home = resolve(dir, "home");
458
- const skillsSubdir = mindSkillsDir(dir).slice(home.length + 1);
458
+ function installHookShims(dir, skillId, hooks, skillsSubdir = mindSkillsSubdir(dir)) {
459
459
  for (const [event, scriptPath] of Object.entries(hooks)) {
460
460
  const eventDir = join(dir, "home", ".local", "hooks", event);
461
461
  mkdirSync(eventDir, { recursive: true });
@@ -498,9 +498,7 @@ function binShimOwner(shimPath) {
498
498
  const line = readFileSync(shimPath, "utf-8").split("\n").find((l) => l.startsWith(BIN_SHIM_MARKER));
499
499
  return line?.slice(BIN_SHIM_MARKER.length).trim() || void 0;
500
500
  }
501
- function installBinShim(dir, skillId, scriptPath) {
502
- const home = resolve(dir, "home");
503
- const skillsSubdir = mindSkillsDir(dir).slice(home.length + 1);
501
+ function installBinShim(dir, skillId, scriptPath, skillsSubdir = mindSkillsSubdir(dir)) {
504
502
  const binDir = join(dir, "home", ".local", "bin");
505
503
  mkdirSync(binDir, { recursive: true });
506
504
  const cmdName = binCommandName(scriptPath);
@@ -520,6 +518,36 @@ function removeBinShim(dir, scriptPath) {
520
518
  const shimPath = join(dir, "home", ".local", "bin", cmdName);
521
519
  if (existsSync(shimPath)) rmSync(shimPath);
522
520
  }
521
+ function migrateSkillsToTemplate(dir, oldTemplate, newTemplate) {
522
+ const home = resolve(dir, "home");
523
+ const oldSubdir = TEMPLATE_SKILLS_DIR[oldTemplate] ?? TEMPLATE_SKILLS_DIR.claude;
524
+ const newSubdir = TEMPLATE_SKILLS_DIR[newTemplate] ?? TEMPLATE_SKILLS_DIR.claude;
525
+ if (oldSubdir === newSubdir) return [];
526
+ const oldDir = resolve(home, oldSubdir);
527
+ const newDir = resolve(home, newSubdir);
528
+ if (!existsSync(oldDir)) return [];
529
+ const skillIds = readdirSync(oldDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
530
+ const migrated = [];
531
+ if (skillIds.length > 0) {
532
+ mkdirSync(newDir, { recursive: true });
533
+ for (const skillId of skillIds) {
534
+ const from = join(oldDir, skillId);
535
+ const to = join(newDir, skillId);
536
+ if (existsSync(to)) rmSync(to, { recursive: true, force: true });
537
+ renameSync(from, to);
538
+ removeHookShims(dir, skillId);
539
+ const skillMdPath = join(to, "SKILL.md");
540
+ if (existsSync(skillMdPath)) {
541
+ const { hooks, bin } = parseSkillMd(readFileSync(skillMdPath, "utf-8"));
542
+ installHookShims(dir, skillId, hooks, newSubdir);
543
+ if (bin) installBinShim(dir, skillId, bin, newSubdir);
544
+ }
545
+ migrated.push(skillId);
546
+ }
547
+ }
548
+ rmSync(oldDir, { recursive: true, force: true });
549
+ return migrated;
550
+ }
523
551
  function listFilesRecursive(dir, prefix = "") {
524
552
  const results = [];
525
553
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
@@ -609,7 +637,7 @@ async function syncBuiltinSkills() {
609
637
  const destDir = join(sharedSkillsDir(), entry.name);
610
638
  if (existsSync(destDir)) {
611
639
  const destHash = hashSkillDir(destDir);
612
- if (sourceHash === destHash) continue;
640
+ if (sourceHash === destHash && await getSharedSkill(entry.name)) continue;
613
641
  }
614
642
  await importSkillFromDir(sourceDir, "volute");
615
643
  logger_default.info(`synced built-in skill: ${entry.name}`);
@@ -641,6 +669,7 @@ export {
641
669
  removeHookShims,
642
670
  installBinShim,
643
671
  removeBinShim,
672
+ migrateSkillsToTemplate,
644
673
  listFilesRecursive,
645
674
  findSkillsRoot,
646
675
  hashSkillDir,
@@ -8,10 +8,10 @@ import {
8
8
  pollHealthDown,
9
9
  readDaemonConfig,
10
10
  stopService
11
- } from "./chunk-FJ2MZ5PH.js";
11
+ } from "./chunk-5FVANDON.js";
12
12
  import {
13
13
  voluteSystemDir
14
- } from "./chunk-WW6C3PLV.js";
14
+ } from "./chunk-CAIYV33P.js";
15
15
 
16
16
  // src/commands/down.ts
17
17
  import { existsSync, readFileSync, unlinkSync } from "fs";