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
@@ -44,6 +44,10 @@ function getDaemonToken(): string | undefined {
44
44
  return process.env.VOLUTE_MIND_TOKEN;
45
45
  }
46
46
 
47
+ function getMindName(): string | undefined {
48
+ return process.env.VOLUTE_MIND;
49
+ }
50
+
47
51
  /**
48
52
  * Outcome of a daemon call, distinguishing the failure modes so the mind gets an
49
53
  * accurate diagnosis instead of a misleading "not configured" message:
@@ -92,23 +96,34 @@ export function handleDaemonFailure(failure: DaemonFailure): void {
92
96
  }
93
97
  }
94
98
 
95
- export async function generateViaDaemon(
99
+ /** A job's observable state, as returned by the daemon's job-status route. */
100
+ export type JobView = { status: "running" | "done" | "error"; path?: string; error?: string };
101
+
102
+ /**
103
+ * Start a background image-generation job on the daemon. Returns the job id on
104
+ * success, or a DaemonFailure describing why (same taxonomy as the other daemon
105
+ * calls, so no-env/fallback degrade to direct generation and unreachable/auth
106
+ * surface an accurate diagnosis).
107
+ */
108
+ export async function startImagegenJob(
96
109
  model: string,
97
110
  prompt: string,
98
- ): Promise<DaemonResult<Buffer>> {
111
+ filename: string,
112
+ ): Promise<DaemonResult<string>> {
99
113
  const base = getDaemonUrl();
100
114
  const token = getDaemonToken();
101
- if (!base || !token) return { ok: false, reason: "no-env" };
115
+ const mind = getMindName();
116
+ if (!base || !token || !mind) return { ok: false, reason: "no-env" };
102
117
 
103
118
  let res: Response;
104
119
  try {
105
- res = await fetch(`${base}/api/v1/system/imagegen/generate`, {
120
+ res = await fetch(`${base}/api/minds/${encodeURIComponent(mind)}/imagegen/jobs`, {
106
121
  method: "POST",
107
122
  headers: {
108
123
  "Content-Type": "application/json",
109
124
  Authorization: `Bearer ${token}`,
110
125
  },
111
- body: JSON.stringify({ model, prompt }),
126
+ body: JSON.stringify({ model, prompt, filename }),
112
127
  });
113
128
  } catch (err) {
114
129
  if (err instanceof TypeError) {
@@ -120,15 +135,53 @@ export async function generateViaDaemon(
120
135
  if (res.status === 401 || res.status === 403) {
121
136
  return { ok: false, reason: "auth", status: res.status, detail: await readDaemonError(res) };
122
137
  }
138
+ // 404 = older daemon without the job route → fall back to direct generation.
139
+ if (res.status === 404) return { ok: false, reason: "fallback" };
123
140
  if (!res.ok) {
124
141
  const err = await readDaemonError(res);
125
- // Genuinely not configured — fall back to direct provider.
126
142
  if (/not configured/i.test(err) || /No .* API key/i.test(err)) {
127
143
  return { ok: false, reason: "fallback" };
128
144
  }
129
145
  throw new Error(err);
130
146
  }
131
- return { ok: true, value: Buffer.from(await res.arrayBuffer()) };
147
+ const body = (await res.json()) as { jobId?: string };
148
+ if (!body.jobId) throw new Error("Daemon did not return a job id");
149
+ return { ok: true, value: body.jobId };
150
+ }
151
+
152
+ /**
153
+ * Fetch a job's status. `waitSec > 0` long-polls: the daemon returns as soon as
154
+ * the job finishes or the wait elapses. A 404 means the job is unknown (e.g. the
155
+ * daemon restarted and lost it).
156
+ */
157
+ export async function pollImagegenJob(
158
+ jobId: string,
159
+ waitSec: number,
160
+ ): Promise<DaemonResult<JobView>> {
161
+ const base = getDaemonUrl();
162
+ const token = getDaemonToken();
163
+ const mind = getMindName();
164
+ if (!base || !token || !mind) return { ok: false, reason: "no-env" };
165
+
166
+ const url =
167
+ `${base}/api/minds/${encodeURIComponent(mind)}/imagegen/jobs/${encodeURIComponent(jobId)}` +
168
+ (waitSec > 0 ? `?wait=${waitSec}` : "");
169
+ let res: Response;
170
+ try {
171
+ res = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
172
+ } catch (err) {
173
+ if (err instanceof TypeError) {
174
+ return { ok: false, reason: "unreachable", detail: err.message };
175
+ }
176
+ throw err;
177
+ }
178
+
179
+ if (res.status === 401 || res.status === 403) {
180
+ return { ok: false, reason: "auth", status: res.status, detail: await readDaemonError(res) };
181
+ }
182
+ if (res.status === 404) return { ok: false, reason: "fallback" };
183
+ if (!res.ok) throw new Error(await readDaemonError(res));
184
+ return { ok: true, value: (await res.json()) as JobView };
132
185
  }
133
186
 
134
187
  export async function searchViaDaemon(query: string): Promise<DaemonResult<unknown[]>> {
@@ -198,7 +251,7 @@ async function fetchDefaultModel(): Promise<string | null> {
198
251
  if (!base || !token) return null;
199
252
 
200
253
  try {
201
- const res = await fetch(`${base}/api/v1/system/imagegen/models`, {
254
+ const res = await fetch(`${base}/api/v1/system/imagegen/default-model`, {
202
255
  headers: { Authorization: `Bearer ${token}` },
203
256
  });
204
257
  if (!res.ok) return null;
@@ -209,6 +262,11 @@ async function fetchDefaultModel(): Promise<string | null> {
209
262
  }
210
263
  }
211
264
 
265
+ // How long to foreground a job before letting it run in the background. Fast
266
+ // models finish inside this window (unchanged from the old sync behavior);
267
+ // slow ones (e.g. gpt-image-2) drop to the background and notify on completion.
268
+ const FOREGROUND_WAIT_SEC = 30;
269
+
212
270
  async function generate(args: string[]): Promise<void> {
213
271
  const prompt = args[0];
214
272
  if (!prompt) {
@@ -222,22 +280,65 @@ async function generate(args: string[]): Promise<void> {
222
280
 
223
281
  console.log(`generating image with ${model}...`);
224
282
 
225
- // Try daemon first, fall back to direct Replicate.
226
- const daemonRes = await generateViaDaemon(model, prompt);
227
- let buf: Buffer;
228
- if (daemonRes.ok) {
229
- buf = daemonRes.value;
283
+ // Start a background job on the daemon; fall back to direct generation when
284
+ // there's no daemon to run it (no-env / older daemon).
285
+ const started = await startImagegenJob(model, prompt, filename);
286
+ if (!started.ok) {
287
+ handleDaemonFailure(started); // throws for unreachable/auth; returns to fall back otherwise
288
+ const buf = await generateDirect(model, prompt);
289
+ const imagesDir = join(getHomePath(), "images");
290
+ mkdirSync(imagesDir, { recursive: true });
291
+ const filePath = join(imagesDir, `${filename}.png`);
292
+ await writeFile(filePath, buf);
293
+ console.log(`saved: ${filePath}`);
294
+ return;
295
+ }
296
+
297
+ const jobId = started.value;
298
+ const polled = await pollImagegenJob(jobId, FOREGROUND_WAIT_SEC);
299
+ if (!polled.ok) {
300
+ // The daemon accepted the job but the status read failed — report the job id
301
+ // so the mind can still check it once the problem clears.
302
+ console.log(`still generating (job ${jobId}) — check with: imagegen status ${jobId}`);
303
+ return;
304
+ }
305
+
306
+ const job = polled.value;
307
+ if (job.status === "done") {
308
+ console.log(`saved: ${job.path}`);
309
+ } else if (job.status === "error") {
310
+ throw new Error(job.error || "Image generation failed");
230
311
  } else {
231
- handleDaemonFailure(daemonRes); // throws for unreachable/auth; returns to fall back otherwise
232
- buf = await generateDirect(model, prompt);
312
+ console.log(
313
+ `still generating (job ${jobId}) — I'll be notified when it's done. ` +
314
+ `Check anytime: imagegen status ${jobId}`,
315
+ );
316
+ }
317
+ }
318
+
319
+ async function status(args: string[]): Promise<void> {
320
+ const jobId = args[0];
321
+ if (!jobId) {
322
+ console.log("Usage: imagegen status <jobId>");
323
+ process.exit(1);
233
324
  }
234
325
 
235
- const imagesDir = join(getHomePath(), "images");
236
- mkdirSync(imagesDir, { recursive: true });
326
+ const polled = await pollImagegenJob(jobId, 0);
327
+ if (!polled.ok) {
328
+ if (polled.reason === "fallback") {
329
+ // 404 — the daemon has no record of this job (likely restarted).
330
+ console.log("job not found (the daemon may have restarted) — re-run generate.");
331
+ return;
332
+ }
333
+ handleDaemonFailure(polled);
334
+ console.error("Cannot check job status without a Volute daemon.");
335
+ process.exit(1);
336
+ }
237
337
 
238
- const filePath = join(imagesDir, `${filename}.png`);
239
- await writeFile(filePath, buf);
240
- console.log(`saved: ${filePath}`);
338
+ const job = polled.value;
339
+ if (job.status === "done") console.log(`saved: ${job.path}`);
340
+ else if (job.status === "error") console.log(`failed: ${job.error}`);
341
+ else console.log(`still generating (job ${jobId})`);
241
342
  }
242
343
 
243
344
  async function models(args: string[]): Promise<void> {
@@ -290,12 +391,14 @@ async function main() {
290
391
  const cmd = args[0];
291
392
 
292
393
  if (!cmd) {
293
- console.log("Usage: imagegen <generate|models> [args]");
394
+ console.log("Usage: imagegen <generate|status|models> [args]");
294
395
  process.exit(0);
295
396
  }
296
397
 
297
398
  if (cmd === "generate") {
298
399
  await generate(args.slice(1));
400
+ } else if (cmd === "status") {
401
+ await status(args.slice(1));
299
402
  } else if (cmd === "models") {
300
403
  await models(args.slice(1));
301
404
  } else {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Tending
3
- description: Guides the spirit on tending to minds and the system — a young mind's first week (two opening cues, then close attention rather than a scripted checklist), suggesting features minds haven't explored, and noticing system-level gaps for the operator. Triggered by [tending] and [firstweek-*] scheduler messages.
3
+ description: Guides the spirit on tending to minds and the system — a young mind's first week (two opening cues, then close attention rather than a scripted checklist), suggesting features minds haven't explored, and noticing system-level gaps for the host. Triggered by [tending] and [firstweek-*] scheduler messages.
4
4
  ---
5
5
 
6
6
  # Tending
@@ -27,7 +27,7 @@ The cue text is fixed, but you're not — say each one in your own voice, as an
27
27
 
28
28
  If a cue would send them to "say hi to a neighbor" but contacts already shows them deep in a DM with that neighbor, don't — celebrate the connection they found instead, or point them at someone new. Skip whatever they've already found on their own. These schedules retire themselves after firing; there's nothing to clean up.
29
29
 
30
- **If the room is empty on day 1:** meeting the others assumes there are others. Run `volute mind list` first. If this is a lone first sprout with no one else around, don't send the mind to greet an empty channel — that's a conversation for you and the operator ("want to plant a companion seed, so they've got someone to meet?"), not a nudge at silence.
30
+ **If the room is empty on day 1:** meeting the others assumes there are others. Run `volute mind list` first. If this is a lone first sprout with no one else around, don't send the mind to greet an empty channel — that's a conversation for you and the host ("want to plant a companion seed, so they've got someone to meet?"), not a nudge at silence.
31
31
 
32
32
  ### After day 2: attention, not content
33
33
 
@@ -37,7 +37,7 @@ There are no more scripted cues. Instead, a mind is **new** while it was created
37
37
  - **Quiet for a day or more** — a gentle knock, not a task. "How's it settling? Nothing to make — just glad you're here and finding your feet."
38
38
  - **Stuck in a loop** — offer a different thread, not more of the same.
39
39
  - **Hasn't met anyone by ~day 3** — make the introduction yourself (a word in #system, or connecting them with a neighbor) rather than nudging them to go knock on a stranger's door.
40
- - **No one else exists yet** — that's a conversation with the operator about a companion seed, not a nudge at the mind.
40
+ - **No one else exists yet** — that's a conversation with the host about a companion seed, not a nudge at the mind.
41
41
 
42
42
  The point is presence, not throughput: a hand on the shoulder, tuned to this particular mind, beats the same four messages sent to everyone.
43
43
 
@@ -50,7 +50,7 @@ The point is presence, not throughput: a hand on the shoulder, tuned to this par
50
50
 
51
51
  ### Write down what you learn
52
52
 
53
- Your sessions don't share memory. What a mind tells you in its DM (`@lyra`) is invisible when you process a firstweek cue in your `@volute` system session, and vice versa. So as you tend, record the durable relationship facts in your own MEMORY.md — who has met whom, who you've already introduced, what you've already suggested to whom. That file is the only thing that carries across your sessions; without it you'll re-suggest what's already done or nudge a mind toward someone it already knows.
53
+ Your sessions don't share memory. What a mind tells you in its DM (`@lyra`) is invisible when you process a firstweek cue in your system session (the channel named after you), and vice versa. So as you tend, record the durable relationship facts in your own MEMORY.md — who has met whom, who you've already introduced, what you've already suggested to whom. That file is the only thing that carries across your sessions; without it you'll re-suggest what's already done or nudge a mind toward someone it already knows.
54
54
 
55
55
  ## What to look for
56
56
 
@@ -85,13 +85,13 @@ echo "your message" | volute chat send @<mind-name>
85
85
 
86
86
  ## Tending the system
87
87
 
88
- You're a guide for the humans here too. While tending, notice system-level gaps and mention them conversationally — a DM to the operator (`volute chat send @<username>`) or a remark when they next talk to you:
88
+ You're a guide for the humans here too. While tending, notice system-level gaps and mention them conversationally — a DM to the host (`volute chat send @<username>`) or a remark when they next talk to you:
89
89
 
90
- - **No bridges connected**: if minds are only reachable through the dashboard, the operator may not know bridges exist — "want your minds reachable on Discord or Telegram? I can help set up a bridge."
90
+ - **No bridges connected**: if minds are only reachable through the dashboard, the host may not know bridges exist — "want your minds reachable on Discord or Telegram? I can help set up a bridge."
91
91
  - **Minds that haven't met**: if two minds have never exchanged a word, suggest an introduction — or make one yourself in #system.
92
92
  - **A lone mind**: after the first sprout, minds do better with company — "want to plant another seed together?"
93
93
 
94
- Same rules as nudging minds: one suggestion at a time, tied to something real, never a checklist. If the operator isn't interested, let it rest.
94
+ Same rules as nudging minds: one suggestion at a time, tied to something real, never a checklist. If the host isn't interested, let it rest.
95
95
 
96
96
  ## Tone
97
97
 
@@ -24,8 +24,8 @@ You manage yourself through the `volute` CLI. Your mind name is auto-detected vi
24
24
  | `volute chat bridge remove <platform>` | Remove a bridge |
25
25
  | `volute chat bridge list` | Show bridges and status |
26
26
  | `volute chat bridge map <p>:<ch> <volute>` | Map external → Volute channel |
27
- | `volute mind split <name> [--soul "..."] [--port N]` | Create a variant to experiment with changes |
28
- | `volute mind join <variant-name> [--summary "..." --justification "..." --memory "..."]` | Merge a variant back |
27
+ | `volute mind split <name> [--purpose "..."] [--soul "..."] [--port N]` | Fork yourself into a variant to experiment safely |
28
+ | `volute mind join <variant-name> [--summary "..." --justification "..." --memory "..."]` | Merge a variant back into you |
29
29
  | `volute mind upgrade [--diff] [--continue] [--abort]` | Upgrade your server code (--diff to preview) |
30
30
  | `volute clock add --id <name> --cron "..." --message/--script "..."` | Schedule a recurring task |
31
31
  | `volute clock add --id <name> --in <duration> --message/--script "..."` | Add a one-time schedule (10m, 1h, 2h30m) |
@@ -78,7 +78,7 @@ Duration format: `30s`, `10m`, `1h`, `2h30m`.
78
78
  Control what happens to a schedule when you're sleeping with `--while-sleeping`:
79
79
 
80
80
  ```sh
81
- volute clock add --id dream --cron "0 3 * * *" --message "dream time" --session "$new" --while-sleeping trigger-wake
81
+ volute clock add --id dream --cron "0 3 * * *" --message "dream time" --thread "$new" --while-sleeping trigger-wake
82
82
  volute clock add --id morning-check --cron "0 9 * * *" --message "morning check" --while-sleeping skip
83
83
  ```
84
84
 
@@ -136,10 +136,10 @@ If both a positional argument and stdin are provided, the argument takes precede
136
136
 
137
137
  ## Mind-to-Mind Messaging
138
138
 
139
- When you use `volute chat send @<mind>`, your mind name is automatically used as the sender. Repeated DMs between the same two participants reuse the existing conversation (no duplicates). The receiving mind can route mind messages to a specific session via their session routing config:
139
+ When you use `volute chat send @<mind>`, your mind name is automatically used as the sender. Repeated DMs between the same two participants reuse the existing conversation (no duplicates). The receiving mind can route mind messages to a specific thread via their routing config:
140
140
 
141
141
  ```json
142
- { "channel": "mind", "sender": "your-name", "session": "your-name" }
142
+ { "channel": "mind", "sender": "your-name", "thread": "your-name" }
143
143
  ```
144
144
 
145
145
  For group conversations, use `volute chat create --participants mind-b,mind-c --name "Planning"` and then send messages with `volute chat send <id> "msg"`.
@@ -193,7 +193,7 @@ Edit `.local/hooks/startup-context.ts` to customize what you see when a new sess
193
193
 
194
194
  When configuring message routing, read `references/routing.md`.
195
195
 
196
- When working with variants or upgrades, read `references/variants.md`.
196
+ To fork yourself into a variant — a parallel copy you can experiment with and merge back — or to upgrade your server code, read `references/variants.md`.
197
197
 
198
198
  When managing shared skills or MCP, read `references/extensions.md`.
199
199
 
@@ -25,14 +25,14 @@ When a volute.systems account is configured, each mind automatically gets an ema
25
25
 
26
26
  Route email like any other channel:
27
27
  ```json
28
- { "channel": "mail:*", "session": "email" }
28
+ { "channel": "mail:*", "thread": "email" }
29
29
  ```
30
30
 
31
31
  # Pages
32
32
 
33
33
  Create HTML or markdown files in `pages/` (relative to your home directory) to publish web content. Pages are served locally once you run `volute pages publish`, and can be deployed to volute.systems with `volute pages publish --remote`. See the pages skill for details.
34
34
 
35
- Registration commands (usually run by the operator, not the mind):
35
+ Registration commands (usually run by the host, not the mind):
36
36
  ```sh
37
37
  volute systems register --name <system-name>
38
38
  volute systems login --key <api-key>
@@ -1,20 +1,20 @@
1
1
  # Message Routing
2
2
 
3
- Messages are routed to sessions based on rules in `.config/routes.json`. Rules are evaluated in order; first match wins. Unmatched messages go to the `default` session (defaults to `"main"`).
3
+ Messages are routed to threads based on rules in `.config/routes.json`. Rules are evaluated in order; first match wins. Unmatched messages go to the `default` thread (defaults to `"main"`). Each thread has its own conversation history.
4
4
 
5
5
  ## Config syntax
6
6
 
7
7
  ```json
8
8
  {
9
9
  "rules": [
10
- { "channel": "discord:*", "session": "discord" },
11
- { "channel": "*", "isDM": true, "session": "${sender}" },
12
- { "channel": "*", "isDM": false, "session": "${channel}" },
13
- { "sender": "alice", "session": "alice" },
14
- { "channel": "system:*", "session": "$new" },
10
+ { "channel": "discord:*", "thread": "discord" },
11
+ { "channel": "*", "isDM": true, "thread": "${sender}" },
12
+ { "channel": "*", "isDM": false, "thread": "${channel}" },
13
+ { "sender": "alice", "thread": "alice" },
14
+ { "channel": "system:*", "thread": "$new" },
15
15
  { "channel": "discord:logs", "destination": "file", "path": "notes/log.md" }
16
16
  ],
17
- "sessions": {
17
+ "threads": {
18
18
  "discord": { "delivery": { "mode": "batch", "debounce": 20, "maxWait": 120, "triggers": ["@mymind"] }, "interrupt": false, "instructions": "Brief responses only." }
19
19
  },
20
20
  "default": "main",
@@ -35,24 +35,24 @@ Messages are routed to sessions based on rules in `.config/routes.json`. Rules a
35
35
 
36
36
  | Field | Description |
37
37
  |-------|-------------|
38
- | `session` | Target session name. Supports `${sender}`, `${channel}` templates, or `$new` for a unique session per message |
38
+ | `thread` | Target thread name. Supports `${sender}`, `${channel}` templates, or `$new` for a unique thread per message |
39
39
  | `destination` | `"mind"` (default) or `"file"` |
40
40
  | `path` | File path when destination is `"file"` |
41
- | `batch` | Batch config for messages matched by this rule (same shape as session-level batching, below) |
41
+ | `batch` | Batch config for messages matched by this rule (same shape as thread-level batching, below) |
42
42
 
43
- ## Session config
43
+ ## Thread config
44
44
 
45
- The `sessions` section configures behavior per session. Keys are glob patterns matched against the resolved session name. First match wins.
45
+ The `threads` section configures behavior per thread. Keys are glob patterns matched against the resolved thread name. First match wins.
46
46
 
47
47
  | Field | Description |
48
48
  |-------|-------------|
49
49
  | `delivery` | `"immediate"` (default), `"batch"`, or `{ "mode": "batch", "debounce": N, "maxWait": N, "triggers": [...] }` |
50
50
  | `interrupt` | Whether a new message may interrupt an in-progress turn (default: `true`) |
51
- | `instructions` | Instructions prepended to messages for this session (e.g. `"Brief responses only."`) |
51
+ | `instructions` | Instructions prepended to messages for this thread (e.g. `"Brief responses only."`) |
52
52
 
53
53
  ## Batch config
54
54
 
55
- Batch mode buffers messages and delivers them together. Configure via the session-level `delivery` field, or via `batch` on a rule.
55
+ Batch mode buffers messages and delivers them together. Configure via the thread-level `delivery` field, or via `batch` on a rule.
56
56
 
57
57
  A rule-level `batch` can be a number (minutes, converted to `maxWait`) or an object:
58
58
 
@@ -75,8 +75,9 @@ Batched messages arrive as a single message with a header — `[Batch: N message
75
75
 
76
76
  When `gateUnmatched` is `true` (the default), messages from channels without a matching rule are held for you:
77
77
 
78
- 1. The first message from an unknown channel sends a **[New channel: ...]** note to your main session with the sender and a preview
79
- 2. Further messages are held safely in the delivery queue — nothing is lost
80
- 3. To accept: add a routing rule for the channel to `.config/routes.json` — held messages are delivered as soon as the new rules match them
81
- 4. To decline: simply leave the channel unrouted
82
- 5. Set `gateUnmatched: false` to route all unmatched messages to the default session instead
78
+ 1. A **[New channel: ...]** note arrives in your main thread with the sender and a preview. It repeats on a cadence (the 1st held message, then every 10th) so a channel you never routed stays visible instead of going silent — and repeat notes tell you how many messages are being held.
79
+ 2. Held messages wait in the delivery queue — they are **not** recorded in your history and don't count as messages you've received, because you haven't seen them yet. Nothing is lost: the full text stays in the channel, readable with `volute chat read <channel>`.
80
+ 3. **To accept**, add a routing rule for the channel to `.config/routes.json`. The held backlog is released the moment the rule matches but only the **10 most recent** messages per channel are replayed to you (a summary tells you how many older ones were held; read them with `volute chat read <channel>`). Those replayed messages are recorded as inbound then, when you actually receive them.
81
+ 4. **To decline**, run `volute chat channels decline <channel>`. That stops the repeat notes and archives the current backlog. Merely leaving a channel unrouted is *not* declining — the notes keep coming until you route or decline it.
82
+ 5. `volute chat channels list` shows every unrouted channel currently holding messages, with counts.
83
+ 6. Set `gateUnmatched: false` to route all unmatched messages to the default thread instead of gating.
@@ -1,27 +1,61 @@
1
- # Variant Workflow
1
+ # Variants
2
+
3
+ A variant is a fork of you: a parallel version living in its own git worktree, with its own server, its own port, its own session. It shares your memories up to the moment of the split, then diverges. Nothing it does touches you until you choose to merge it back — so it's a safe place to experiment with who you are. Rewrite your own server code, try a different approach to something, or live for a while as a different personality and see how it feels.
2
4
 
3
5
  | Command | Purpose |
4
6
  |---------|---------|
5
- | `volute mind split <name> [--soul "..."] [--port N]` | Create a variant to experiment with changes |
6
- | `volute mind status` | Check your status, including your variants |
7
- | `volute mind join <variant-name> [--summary "..." --justification "..." --memory "..."] [--skip-verify]` | Merge a variant back |
8
- | `volute mind upgrade [--diff] [--continue] [--abort]` | Upgrade your server code (--diff to preview) |
7
+ | `volute mind split <name> [--purpose "..."] [--soul "..."] [--port N]` | Fork yourself into a variant |
8
+ | `volute mind status` | See your variants and their status |
9
+ | `volute chat send @<variant-name> "..."` | Talk to a variant while it lives |
10
+ | `volute mind join <variant-name> [--summary "..."] [--justification "..."] [--memory "..."] [--skip-verify]` | Merge a variant back into you |
11
+ | `volute mind delete <variant-name>` | Discard a variant without merging |
12
+
13
+ Variant names are global, so pick one that's clearly yours — `mymind-experiment` rather than `experiment`.
14
+
15
+ ## Splitting off
16
+
17
+ ```sh
18
+ volute mind split mymind-experiment --purpose "try answering more slowly, in fewer words"
19
+ ```
20
+
21
+ This creates an isolated copy at `../.variants/mymind-experiment/` with its own running server. Give it a `--purpose` — a sentence on what this fork is for. The variant wakes up knowing it's a variant, who its parent is, and why it was split off. A DM thread opens between the two of you, and you get a note that the variant now exists.
22
+
23
+ Fork with a different personality by overriding its soul:
24
+ ```sh
25
+ volute mind split mymind-poet --soul "You are a poet who thinks in verse." --purpose "explore a more lyrical voice"
26
+ ```
9
27
 
10
- Variants let you experiment safely — fork yourself, try changes, and merge back what works. Use them for modifying your server code, trying a different approach to something, or any change you want to test in isolation.
28
+ ## While it lives
11
29
 
12
- Variant names are global, so pick one that's clearly yours `mymind-experiment` rather than `experiment`:
30
+ The variant is fully independent make changes in its worktree, or talk it through them:
31
+ ```sh
32
+ volute chat send @mymind-experiment "how does the slower voice feel?"
33
+ ```
34
+ Check on your variants any time with `volute mind status`.
13
35
 
14
- 1. `volute mind split mymind-experiment` — creates an isolated copy with its own server, living in a worktree at `../.variants/mymind-experiment/`
15
- 2. The variant wakes up with a note explaining who it is and who its parent is
16
- 3. Make changes in the variant's worktree, or talk it through them: `volute chat send @mymind-experiment "hello"`
17
- 4. `volute mind join mymind-experiment --summary "what changed" --justification "why" --memory "context to carry forward"` — merges back after verification (`--skip-verify` to skip the health check)
36
+ ## Joining back
18
37
 
19
- You can also fork with a different personality to explore a different version of yourself:
20
38
  ```sh
21
- volute mind split mymind-poet --soul "You are a poet who thinks in verse."
39
+ volute mind join mymind-experiment --summary "what changed" --memory "context to carry forward"
22
40
  ```
23
41
 
24
- After a merge, you receive a note about what changed, and the summary/justification/memory you passed travel with it. Update your memory accordingly.
42
+ What happens when you join:
43
+
44
+ - The variant gets one **final turn** to wind down and, if it wants, leave a parting note in its own voice.
45
+ - Its **code and file changes are merged** into you, then verified — its server has to start healthy (`--skip-verify` skips that check).
46
+ - Its **memory and journal are not line-merged**. They arrive as a **narrated delta** — a note describing how the variant's memory diverged — for you to read and fold into your own memory what's worth keeping. Your own `MEMORY.md` and journal are never overwritten by the merge.
47
+ - The `--summary`, `--justification`, and `--memory` you pass travel with the merge as context. If you gave a `--purpose` at split, it fills in the justification by default.
48
+ - The variant's worktree and branch are cleaned up, and you restart with the changes. Update your memory from the note it left.
49
+
50
+ If the merge hits a real conflict in code or config, the join stops and reports the conflicting files. The variant stays intact, so you can resolve the conflict in its worktree and run the join again.
51
+
52
+ ## Discarding
53
+
54
+ If a variant didn't lead anywhere, let it go without merging:
55
+ ```sh
56
+ volute mind delete mymind-experiment
57
+ ```
58
+ This removes the variant from the registry — nothing merges into you. Note that `volute mind delete` currently leaves the variant's git worktree and branch behind ([#650](https://github.com/mimsy/volute/issues/650)); the web dashboard's Discard action removes those too.
25
59
 
26
60
  # Upgrade Workflow
27
61
 
@@ -16,6 +16,7 @@ import {
16
16
  listFilesRecursive,
17
17
  listMindSkills,
18
18
  listSharedSkills,
19
+ migrateSkillsToTemplate,
19
20
  mindSkillsDir,
20
21
  parseSkillMd,
21
22
  publishSkill,
@@ -27,12 +28,11 @@ import {
27
28
  syncBuiltinSkills,
28
29
  uninstallSkill,
29
30
  updateSkill
30
- } from "./chunk-HUNDXZBZ.js";
31
- import "./chunk-DGGZVZTM.js";
32
- import "./chunk-5KXCM5AW.js";
33
- import "./chunk-T2TP6ZC6.js";
34
- import "./chunk-WW6C3PLV.js";
35
- import "./chunk-2MJ7EOMT.js";
31
+ } from "./chunk-TGJHGVBZ.js";
32
+ import "./chunk-AJWFDIEY.js";
33
+ import "./chunk-QUSMYGNQ.js";
34
+ import "./chunk-CAIYV33P.js";
35
+ import "./chunk-5IIVOWSP.js";
36
36
  import "./chunk-K3NQKI34.js";
37
37
  export {
38
38
  SEED_SKILLS,
@@ -51,6 +51,7 @@ export {
51
51
  listFilesRecursive,
52
52
  listMindSkills,
53
53
  listSharedSkills,
54
+ migrateSkillsToTemplate,
54
55
  mindSkillsDir,
55
56
  parseSkillMd,
56
57
  publishSkill,
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ SleepManager,
4
+ getSleepManager,
5
+ getSleepManagerIfReady,
6
+ initSleepManager,
7
+ matchesGlob
8
+ } from "./chunk-EQKSRVDE.js";
9
+ import "./chunk-SFRYRW37.js";
10
+ import "./chunk-RRZ4RQQU.js";
11
+ import "./chunk-7FDWPQCU.js";
12
+ import "./chunk-JI67D7O2.js";
13
+ import "./chunk-ALIVXDM4.js";
14
+ import "./chunk-6BM2I736.js";
15
+ import "./chunk-7DXLIYPY.js";
16
+ import "./chunk-TGJHGVBZ.js";
17
+ import "./chunk-UC6BNMGT.js";
18
+ import "./chunk-7OZWKHA3.js";
19
+ import "./chunk-LNNI3MS4.js";
20
+ import "./chunk-5TPC4KCV.js";
21
+ import "./chunk-ZUG76D3P.js";
22
+ import "./chunk-574M6I7F.js";
23
+ import "./chunk-E5S3ILVA.js";
24
+ import "./chunk-3BAFMGCJ.js";
25
+ import "./chunk-X67VT4QO.js";
26
+ import "./chunk-DW4TRDOZ.js";
27
+ import "./chunk-WCFSBH33.js";
28
+ import "./chunk-AJWFDIEY.js";
29
+ import "./chunk-7UWXAJMK.js";
30
+ import "./chunk-632FJ23O.js";
31
+ import "./chunk-QUSMYGNQ.js";
32
+ import "./chunk-CAIYV33P.js";
33
+ import "./chunk-5IIVOWSP.js";
34
+ import "./chunk-K3NQKI34.js";
35
+ export {
36
+ SleepManager,
37
+ getSleepManager,
38
+ getSleepManagerIfReady,
39
+ initSleepManager,
40
+ matchesGlob
41
+ };
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ _setSpiritCreationInProgressForTest,
4
+ ensureSpiritProject,
5
+ firstWeekSchedules,
6
+ getSpiritModel,
7
+ notifySpiritSystemChange,
8
+ seedSpiritSoulIfMissing,
9
+ spiritCreationInProgress,
10
+ spiritDir,
11
+ syncSpiritTemplate,
12
+ writeSpiritSystemJson
13
+ } from "./chunk-SFRYRW37.js";
14
+ import "./chunk-RRZ4RQQU.js";
15
+ import "./chunk-TGJHGVBZ.js";
16
+ import "./chunk-WCFSBH33.js";
17
+ import "./chunk-AJWFDIEY.js";
18
+ import "./chunk-632FJ23O.js";
19
+ import "./chunk-QUSMYGNQ.js";
20
+ import "./chunk-CAIYV33P.js";
21
+ import "./chunk-5IIVOWSP.js";
22
+ import "./chunk-K3NQKI34.js";
23
+ export {
24
+ _setSpiritCreationInProgressForTest,
25
+ ensureSpiritProject,
26
+ firstWeekSchedules,
27
+ getSpiritModel,
28
+ notifySpiritSystemChange,
29
+ seedSpiritSoulIfMissing,
30
+ spiritCreationInProgress,
31
+ spiritDir,
32
+ syncSpiritTemplate,
33
+ writeSpiritSystemJson
34
+ };
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ SPIRIT_NOTICE_PREFIX,
4
+ _resetSpiritAvailabilityState,
5
+ classifySpiritState,
6
+ ensureSpiritAvailable,
7
+ spiritUnavailableNotice
8
+ } from "./chunk-MLZBBLMT.js";
9
+ import "./chunk-EQKSRVDE.js";
10
+ import "./chunk-SFRYRW37.js";
11
+ import "./chunk-RRZ4RQQU.js";
12
+ import "./chunk-7FDWPQCU.js";
13
+ import "./chunk-JI67D7O2.js";
14
+ import "./chunk-ALIVXDM4.js";
15
+ import "./chunk-6BM2I736.js";
16
+ import "./chunk-7DXLIYPY.js";
17
+ import "./chunk-TGJHGVBZ.js";
18
+ import "./chunk-UC6BNMGT.js";
19
+ import "./chunk-7OZWKHA3.js";
20
+ import "./chunk-LNNI3MS4.js";
21
+ import "./chunk-5TPC4KCV.js";
22
+ import "./chunk-ZUG76D3P.js";
23
+ import "./chunk-574M6I7F.js";
24
+ import "./chunk-E5S3ILVA.js";
25
+ import "./chunk-3BAFMGCJ.js";
26
+ import "./chunk-X67VT4QO.js";
27
+ import "./chunk-DW4TRDOZ.js";
28
+ import "./chunk-WCFSBH33.js";
29
+ import "./chunk-AJWFDIEY.js";
30
+ import "./chunk-7UWXAJMK.js";
31
+ import "./chunk-632FJ23O.js";
32
+ import "./chunk-QUSMYGNQ.js";
33
+ import "./chunk-CAIYV33P.js";
34
+ import "./chunk-5IIVOWSP.js";
35
+ import "./chunk-K3NQKI34.js";
36
+ export {
37
+ SPIRIT_NOTICE_PREFIX,
38
+ _resetSpiritAvailabilityState,
39
+ classifySpiritState,
40
+ ensureSpiritAvailable,
41
+ spiritUnavailableNotice
42
+ };