volute 0.32.0 → 0.34.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 (187) hide show
  1. package/README.md +16 -0
  2. package/dist/{accept-74M7I4RZ.js → accept-TW6V4WI4.js} +4 -4
  3. package/dist/{activity-events-HETAODOK.js → activity-events-BN7V6KCC.js} +4 -4
  4. package/dist/{ai-service-ZIPCV3MX.js → ai-service-PSILB5WD.js} +5 -5
  5. package/dist/{api-client-YPKOZP2O.js → api-client-XUXOB7LI.js} +1 -1
  6. package/dist/api.d.ts +1198 -957
  7. package/dist/{archive-INXYFVCW.js → archive-C2VEMQOR.js} +4 -4
  8. package/dist/{auth-6DMGES3I.js → auth-ZFZXJZDQ.js} +5 -5
  9. package/dist/{bridge-BVCBTGPF.js → bridge-O753D5F4.js} +4 -4
  10. package/dist/{chat-XT4OBJBU.js → chat-BHYX7DJ4.js} +9 -9
  11. package/dist/{chunk-M7UL5S3Q.js → chunk-2IOP6PHB.js} +1 -1
  12. package/dist/{chunk-JJ7W6WSB.js → chunk-47XDEWWV.js} +5 -5
  13. package/dist/{chunk-RSX4OPZY.js → chunk-47ZPNLF4.js} +7 -7
  14. package/dist/{chunk-RPZZSXV3.js → chunk-4JSR7YO7.js} +20 -1
  15. package/dist/chunk-6LXAAQ43.js +22 -0
  16. package/dist/{chunk-TSXLLQZW.js → chunk-6OWJXUAR.js} +10 -1
  17. package/dist/{chunk-I5KY25PQ.js → chunk-6WAWMWR5.js} +1 -1
  18. package/dist/{chunk-LSGWR54X.js → chunk-7F2SW2KD.js} +2 -2
  19. package/dist/chunk-7KJOFUNN.js +22 -0
  20. package/dist/{spirit-N4W4UQRH.js → chunk-B2BVAIZ4.js} +21 -12
  21. package/dist/{chunk-LGB6JBHI.js → chunk-BDK73LK6.js} +5 -55
  22. package/dist/{chunk-IYDIE3HG.js → chunk-BFWHBQK4.js} +1 -1
  23. package/dist/{chunk-TDRYEPH4.js → chunk-BM474GX6.js} +4 -4
  24. package/dist/{chunk-R7E6CRVQ.js → chunk-BTWAGDV5.js} +1 -1
  25. package/dist/{chunk-WKF5FEFK.js → chunk-CVL5IGIR.js} +629 -174
  26. package/dist/{chunk-S6NFERDC.js → chunk-E5C7OWZ2.js} +20 -22
  27. package/dist/chunk-FYCALD4Q.js +23 -0
  28. package/dist/{chunk-SKLSMHXO.js → chunk-IS7WJ56Q.js} +1 -1
  29. package/dist/{chunk-2NGTS5UU.js → chunk-M3K5AARV.js} +1 -1
  30. package/dist/{chunk-ALEF47VT.js → chunk-MLOQKQNB.js} +1 -1
  31. package/dist/{chunk-D5G5YOPL.js → chunk-N3DNFPVA.js} +41 -5
  32. package/dist/{chunk-LRCG2JLP.js → chunk-N7BLAHNE.js} +5 -1
  33. package/dist/chunk-OYAKCAVY.js +29 -0
  34. package/dist/{chunk-UKVWJRKN.js → chunk-PLDWHR4D.js} +1 -1
  35. package/dist/{chunk-QBQ424EM.js → chunk-TAHX36HZ.js} +545 -246
  36. package/dist/chunk-U5BTYSAL.js +59 -0
  37. package/dist/{chunk-SX5TKJBZ.js → chunk-V45JXOWY.js} +2 -2
  38. package/dist/{chunk-2FLJ63GU.js → chunk-V6ZCNULL.js} +2 -2
  39. package/dist/{chunk-QZANELPX.js → chunk-XWXBJQBE.js} +3 -2
  40. package/dist/cli.js +32 -24
  41. package/dist/{clock-2UOZ6JPU.js → clock-3X4DSC2N.js} +38 -23
  42. package/dist/{cloud-sync-JN3NWKEM.js → cloud-sync-TG3TIX5H.js} +21 -17
  43. package/dist/{config-H2H4UIF7.js → config-OROA5DUA.js} +4 -4
  44. package/dist/connectors/discord-bridge.js +1 -1
  45. package/dist/connectors/slack-bridge.js +1 -1
  46. package/dist/connectors/telegram-bridge.js +1 -1
  47. package/dist/{conversations-3O5O6AS3.js → conversations-HL2JP5GI.js} +5 -5
  48. package/dist/{create-RNLNCORE.js → create-3SEKKI6P.js} +5 -5
  49. package/dist/{create-WBBYI6V7.js → create-UOSOQ2HN.js} +4 -4
  50. package/dist/daemon-client-WOAQXXBM.js +12 -0
  51. package/dist/{daemon-restart-NGFHFAUF.js → daemon-restart-5ABHNXJZ.js} +9 -8
  52. package/dist/daemon.js +2730 -1520
  53. package/dist/{db-RA45JBFG.js → db-PLEDCBHZ.js} +1 -1
  54. package/dist/db-RYX3SS2W.js +9 -0
  55. package/dist/{delete-QTGWEDBI.js → delete-KYOVWR23.js} +3 -3
  56. package/dist/delivery-manager-2BR5NZKF.js +32 -0
  57. package/dist/{delivery-router-FL45JL7N.js → delivery-router-D5ELDMS2.js} +4 -4
  58. package/dist/down-QVFN4UPK.js +15 -0
  59. package/dist/{env-RLYQBOOP.js → env-R34DT7XL.js} +10 -6
  60. package/dist/exec-DVLXKRIO.js +17 -0
  61. package/dist/{export-SUYRLI5Q.js → export-6ZXAXATG.js} +6 -6
  62. package/dist/extension-PM42QCID.js +97 -0
  63. package/dist/extensions-BBGVL5JC.js +38 -0
  64. package/dist/{files-EAMPO2SJ.js → files-VQV2VZQO.js} +5 -5
  65. package/dist/{import-DDUFE7AY.js → import-MK2I2T6F.js} +5 -5
  66. package/dist/isolation-62MKDZN3.js +22 -0
  67. package/dist/{join-I5QEE3LG.js → join-DGYHTJUH.js} +3 -3
  68. package/dist/lib-DYEZMGW7.js +6588 -0
  69. package/dist/{list-DW2VRTOZ.js → list-C644WTHV.js} +16 -8
  70. package/dist/{login-7CHPW2PN.js → login-IIGEQPHL.js} +4 -4
  71. package/dist/{login-RIJF2F4G.js → login-KZQLMAWE.js} +4 -4
  72. package/dist/{logout-5MLHZALK.js → logout-AGTZVRGP.js} +4 -4
  73. package/dist/{logout-UZJRGY4Z.js → logout-KD6GXIJJ.js} +4 -4
  74. package/dist/message-delivery-V3R6NXJP.js +42 -0
  75. package/dist/{mind-2B6M7Y25.js → mind-BI4EPBVZ.js} +25 -19
  76. package/dist/{mind-activity-tracker-NZZT2NTT.js → mind-activity-tracker-2ACNHA7B.js} +5 -5
  77. package/dist/mind-history-WOYFLQAI.js +264 -0
  78. package/dist/{mind-list-WUPMQDYQ.js → mind-list-6VPM7GUQ.js} +4 -4
  79. package/dist/mind-manager-MWW3BTS4.js +32 -0
  80. package/dist/mind-profile-WPG42U5Y.js +47 -0
  81. package/dist/mind-service-VIKZJK2M.js +38 -0
  82. package/dist/{mind-sleep-B7BHJLH7.js → mind-sleep-XDISJY74.js} +4 -4
  83. package/dist/{mind-status-L3EFFRPR.js → mind-status-7FTZWPZF.js} +4 -4
  84. package/dist/{mind-wake-GY3RFX7Y.js → mind-wake-KIIKEI3A.js} +4 -4
  85. package/dist/{package-PK6JUFL3.js → package-V2WHWVG6.js} +9 -5
  86. package/dist/{read-5AMJRO3D.js → read-H5C26YO7.js} +18 -8
  87. package/dist/read-stdin-PIRM6A2Y.js +8 -0
  88. package/dist/{register-V2JZZKFK.js → register-J27WP33N.js} +4 -4
  89. package/dist/{registry-PJ4S5PHQ.js → registry-UYV5S6QT.js} +3 -3
  90. package/dist/{reject-33HEZMZ4.js → reject-OEANJYIA.js} +4 -4
  91. package/dist/{restart-3UCMRUVC.js → restart-V5EGYBJG.js} +4 -4
  92. package/dist/{sandbox-JANNTX6U.js → sandbox-SI5HMBP3.js} +5 -5
  93. package/dist/scheduler-AGG3L2FO.js +32 -0
  94. package/dist/{schema-PA3M5ZKH.js → schema-ETMABTW4.js} +4 -2
  95. package/dist/seed-WNGI6PNW.js +11 -0
  96. package/dist/seed-check-PXTH7YXS.js +32 -0
  97. package/dist/seed-cmd-VENFTGS3.js +36 -0
  98. package/dist/{seed-ALUQ55FF.js → seed-create-663ALOKH.js} +8 -8
  99. package/dist/{sprout-L2GFOVF7.js → seed-sprout-EH3AGKAI.js} +24 -11
  100. package/dist/{send-3MI36LEF.js → send-7FUUUZZH.js} +66 -51
  101. package/dist/{setup-SZIARWI6.js → setup-GGMKENLN.js} +6 -4
  102. package/dist/{setup-WENLVPVP.js → setup-Z3DEVWV7.js} +13 -11
  103. package/dist/{skill-TUVOTW4Z.js → skill-DKNYJS4P.js} +12 -8
  104. package/dist/skills/imagegen/SKILL.md +11 -7
  105. package/dist/skills/imagegen/scripts/imagegen.ts +146 -25
  106. package/dist/skills/orientation/SKILL.md +9 -2
  107. package/dist/skills/plan-coordinator/SKILL.md +60 -0
  108. package/dist/skills/seed-nurture/SKILL.md +42 -0
  109. package/dist/skills/volute-mind/SKILL.md +11 -221
  110. package/dist/skills/volute-mind/references/extensions.md +37 -0
  111. package/dist/skills/volute-mind/references/integrations.md +48 -0
  112. package/dist/skills/volute-mind/references/routing.md +86 -0
  113. package/dist/skills/volute-mind/references/sleep.md +33 -0
  114. package/dist/skills/volute-mind/references/variants.md +31 -0
  115. package/dist/{skills-XNZK6P4K.js → skills-Q6VZ2UGD.js} +11 -6
  116. package/dist/sleep-manager-BJK2ROPX.js +36 -0
  117. package/dist/spirit-4JP4TY4C.js +23 -0
  118. package/dist/{split-STOROBYJ.js → split-3YPMS2CL.js} +3 -3
  119. package/dist/sprout-E3HJIV2Z.js +11 -0
  120. package/dist/{start-K2NCUUCG.js → start-W3TPKX4D.js} +4 -4
  121. package/dist/{status-TCUMUO6M.js → status-4OVFXFEJ.js} +7 -6
  122. package/dist/{stop-H26JZDXF.js → stop-GTT6YWYO.js} +4 -4
  123. package/dist/system-channel-DXD2JBOU.js +36 -0
  124. package/dist/system-chat-TYLOL7SX.js +36 -0
  125. package/dist/{systems-DHBKVYEY.js → systems-AYLO727G.js} +7 -7
  126. package/dist/{tailscale-XHQBZROW.js → tailscale-ZEUK7GKZ.js} +3 -3
  127. package/dist/{template-hash-A6VVKOXJ.js → template-hash-EJRTKE36.js} +1 -1
  128. package/dist/up-PA7F2CXE.js +18 -0
  129. package/dist/{update-QVPRF6GR.js → update-HG4LCUSG.js} +7 -6
  130. package/dist/{update-check-ZD6OOIYQ.js → update-check-X3YG4WVP.js} +4 -4
  131. package/dist/{upgrade-O4Q7WJM3.js → upgrade-YGNIDICG.js} +3 -3
  132. package/dist/{variant-7TGZHOU3.js → variant-MZUMRTQO.js} +1 -1
  133. package/dist/{version-notify-TCKWBZZG.js → version-notify-YCH4UVQ2.js} +23 -20
  134. package/dist/volute-config-WBKYJGYQ.js +10 -0
  135. package/dist/web-assets/assets/index-DiiwC-CZ.css +1 -0
  136. package/dist/web-assets/assets/index-d6y5b9Ij.js +75 -0
  137. package/dist/web-assets/ext-theme.css +48 -9
  138. package/dist/web-assets/index.html +2 -2
  139. package/drizzle/0005_meta_summaries.sql +15 -0
  140. package/drizzle/meta/0005_snapshot.json +7 -0
  141. package/drizzle/meta/_journal.json +7 -0
  142. package/package.json +8 -4
  143. package/packages/extensions/plan/dist/ui/assets/index-CJj2gZnZ.css +1 -0
  144. package/packages/extensions/plan/dist/ui/assets/index-FMEJmvQz.js +61 -0
  145. package/packages/extensions/plan/dist/ui/index.html +14 -0
  146. package/packages/extensions/plan/skills/plan/SKILL.md +43 -0
  147. package/packages/extensions/plan/skills/plan/scripts/plan-hook.sh +37 -0
  148. package/templates/_base/home/VOLUTE.md +12 -19
  149. package/templates/_base/src/lib/context-breakdown.ts +450 -0
  150. package/templates/_base/src/lib/format-prefix.ts +17 -0
  151. package/templates/_base/src/lib/hook-loader.ts +8 -2
  152. package/templates/_base/src/lib/router.ts +75 -33
  153. package/templates/_base/src/lib/routing.ts +4 -1
  154. package/templates/_base/src/lib/startup.ts +16 -8
  155. package/templates/_base/src/lib/types.ts +2 -1
  156. package/templates/_base/src/lib/volute-server.ts +69 -8
  157. package/templates/claude/.init/CLAUDE.md +4 -10
  158. package/templates/claude/package.json.tmpl +1 -0
  159. package/templates/claude/src/agent.ts +100 -32
  160. package/templates/claude/src/lib/hooks/reply-instructions.ts +27 -7
  161. package/templates/claude/src/lib/stream-consumer.ts +40 -2
  162. package/templates/claude/src/server.ts +1 -0
  163. package/templates/codex/package.json.tmpl +1 -0
  164. package/templates/codex/src/agent.ts +81 -8
  165. package/templates/codex/src/server.ts +1 -4
  166. package/templates/pi/package.json.tmpl +1 -0
  167. package/templates/pi/src/agent.ts +115 -36
  168. package/templates/pi/src/lib/event-handler.ts +22 -7
  169. package/templates/pi/src/lib/reply-instructions-extension.ts +23 -4
  170. package/templates/pi/src/lib/subagents.ts +20 -17
  171. package/templates/pi/src/server.ts +2 -5
  172. package/dist/chunk-K3NQKI34.js +0 -10
  173. package/dist/daemon-client-6QXHZ7US.js +0 -12
  174. package/dist/db-F34YLV7D.js +0 -9
  175. package/dist/delivery-manager-SDVXFD4W.js +0 -28
  176. package/dist/down-TB3ESMNP.js +0 -14
  177. package/dist/extension-FQ5D3NCC.js +0 -174
  178. package/dist/extensions-GDYWQXC4.js +0 -29
  179. package/dist/history-FO5PHBQ5.js +0 -128
  180. package/dist/message-delivery-2FIM7QKO.js +0 -32
  181. package/dist/mind-manager-BNCMGYXW.js +0 -28
  182. package/dist/mind-service-AV273WT4.js +0 -34
  183. package/dist/sleep-manager-53DZOWW7.js +0 -32
  184. package/dist/system-chat-NPYFYZVI.js +0 -32
  185. package/dist/up-6I6BHRTO.js +0 -17
  186. package/dist/web-assets/assets/index-Bui7U9Uu.css +0 -1
  187. package/dist/web-assets/assets/index-e36DIo1b.js +0 -73
@@ -1,16 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  configPath,
4
+ isImagegenEnabled,
4
5
  isSetupComplete,
5
6
  migrateSetupCompleted,
6
7
  readGlobalConfig,
7
8
  writeGlobalConfig
8
- } from "./chunk-TSXLLQZW.js";
9
- import "./chunk-LRCG2JLP.js";
10
- import "./chunk-RPZZSXV3.js";
11
- import "./chunk-K3NQKI34.js";
9
+ } from "./chunk-6OWJXUAR.js";
10
+ import "./chunk-N7BLAHNE.js";
11
+ import "./chunk-4JSR7YO7.js";
12
+ import "./chunk-7KJOFUNN.js";
12
13
  export {
13
14
  configPath,
15
+ isImagegenEnabled,
14
16
  isSetupComplete,
15
17
  migrateSetupCompleted,
16
18
  readGlobalConfig,
@@ -5,24 +5,26 @@ import {
5
5
  SYSTEM_LAUNCHD_PLIST_PATH,
6
6
  SYSTEM_SERVICE_PATH,
7
7
  USER_SYSTEMD_UNIT
8
- } from "./chunk-LSGWR54X.js";
8
+ } from "./chunk-7F2SW2KD.js";
9
9
  import {
10
10
  promptLine
11
11
  } from "./chunk-SSI47XP2.js";
12
12
  import {
13
- ensureVoluteGroup,
13
+ parseArgs
14
+ } from "./chunk-D424ZQGI.js";
15
+ import {
14
16
  resolveVoluteBin
15
- } from "./chunk-LGB6JBHI.js";
17
+ } from "./chunk-U5BTYSAL.js";
18
+ import {
19
+ ensureVoluteGroup
20
+ } from "./chunk-BDK73LK6.js";
16
21
  import {
17
22
  readGlobalConfig,
18
23
  writeGlobalConfig
19
- } from "./chunk-TSXLLQZW.js";
20
- import {
21
- parseArgs
22
- } from "./chunk-D424ZQGI.js";
23
- import "./chunk-LRCG2JLP.js";
24
- import "./chunk-RPZZSXV3.js";
25
- import "./chunk-K3NQKI34.js";
24
+ } from "./chunk-6OWJXUAR.js";
25
+ import "./chunk-N7BLAHNE.js";
26
+ import "./chunk-4JSR7YO7.js";
27
+ import "./chunk-7KJOFUNN.js";
26
28
 
27
29
  // src/commands/setup.ts
28
30
  import { execFile, execFileSync } from "child_process";
@@ -385,7 +387,7 @@ Install as a service (auto-start on boot)? [${serviceDefault}]: `;
385
387
  if (aiProvider) {
386
388
  const aiApiKey = (await promptLine("API key (leave empty to use env var): ")).trim();
387
389
  if (aiApiKey) {
388
- const { saveProviderConfig } = await import("./ai-service-ZIPCV3MX.js");
390
+ const { saveProviderConfig } = await import("./ai-service-PSILB5WD.js");
389
391
  saveProviderConfig(aiProvider, { apiKey: aiApiKey });
390
392
  console.log(` AI provider configured: ${aiProvider}`);
391
393
  } else {
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ isCompact
4
+ } from "./chunk-FYCALD4Q.js";
2
5
  import {
3
6
  resolveMindName
4
7
  } from "./chunk-NAOW2CLO.js";
@@ -11,10 +14,10 @@ import {
11
14
  } from "./chunk-D424ZQGI.js";
12
15
  import {
13
16
  daemonFetch
14
- } from "./chunk-UKVWJRKN.js";
15
- import "./chunk-LRCG2JLP.js";
16
- import "./chunk-RPZZSXV3.js";
17
- import "./chunk-K3NQKI34.js";
17
+ } from "./chunk-PLDWHR4D.js";
18
+ import "./chunk-N7BLAHNE.js";
19
+ import "./chunk-4JSR7YO7.js";
20
+ import "./chunk-7KJOFUNN.js";
18
21
 
19
22
  // src/commands/skill.ts
20
23
  async function run(args) {
@@ -87,8 +90,8 @@ async function listSkills(args) {
87
90
  console.log("No skills installed.");
88
91
  return;
89
92
  }
90
- console.log(`Skills for ${mindName}:
91
- `);
93
+ const compact = isCompact();
94
+ console.log(`Skills for ${mindName}:${compact ? "" : "\n"}`);
92
95
  for (const s of skills) {
93
96
  const update = s.updateAvailable ? " (update available)" : "";
94
97
  const source = s.upstream ? ` [shared:${s.upstream.source} v${s.upstream.version}]` : "";
@@ -108,10 +111,11 @@ async function listSkills(args) {
108
111
  console.log("No shared skills available.");
109
112
  return;
110
113
  }
111
- console.log("Shared skills:\n");
114
+ const compact = isCompact();
115
+ console.log(`Shared skills:${compact ? "" : "\n"}`);
112
116
  for (const s of skills) {
113
117
  console.log(` ${s.id} \u2014 ${s.name} (v${s.version}, by ${s.author})`);
114
- if (s.description) console.log(` ${s.description}`);
118
+ if (s.description && !compact) console.log(` ${s.description}`);
115
119
  }
116
120
  }
117
121
  }
@@ -1,14 +1,15 @@
1
1
  ---
2
2
  name: Image Generation
3
- description: Generate images via the Replicate API. Use for "generate image", "create image", "image generation", "text to image", "search image models".
3
+ description: Generate images via Replicate or OpenRouter. Use for "generate image", "create image", "image generation", "text to image", "search image models".
4
4
  metadata:
5
- npm-dependencies: replicate
6
5
  bin: scripts/imagegen.ts
7
6
  ---
8
7
 
9
8
  # Image Generation
10
9
 
11
- Generate images from text prompts using models on Replicate. Images are saved to `home/images/`.
10
+ Generate images from text prompts using models on Replicate or OpenRouter. Images are saved to `home/images/`.
11
+
12
+ Model IDs are provider-prefixed: `replicate:owner/model` or `openrouter:owner/model`.
12
13
 
13
14
  ## Commands
14
15
 
@@ -18,8 +19,8 @@ imagegen <command>
18
19
 
19
20
  | Command | Description |
20
21
  |---------|-------------|
21
- | `generate "prompt" [--model M] [--filename F]` | Generate an image from a text prompt. Default model: `prunaai/z-image-turbo`. |
22
- | `models "query"` | Search Replicate for text-to-image models. |
22
+ | `generate "prompt" [--model M] [--filename F]` | Generate an image from a text prompt. Default model: `replicate:prunaai/z-image-turbo`. |
23
+ | `models "query"` | Search configured providers for text-to-image models. |
23
24
 
24
25
  ## Examples
25
26
 
@@ -27,8 +28,11 @@ imagegen <command>
27
28
  # Generate an image with the default model
28
29
  imagegen generate "a sunset over the ocean"
29
30
 
30
- # Use a specific model
31
- imagegen generate "a cat in space" --model black-forest-labs/flux-schnell
31
+ # Use a specific Replicate model
32
+ imagegen generate "a cat in space" --model replicate:black-forest-labs/flux-schnell
33
+
34
+ # Use an OpenRouter model
35
+ imagegen generate "a mountain landscape" --model openrouter:openai/gpt-image-1
32
36
 
33
37
  # Specify a filename
34
38
  imagegen generate "mountain landscape" --filename mountains
@@ -1,20 +1,19 @@
1
1
  #!/usr/bin/env tsx
2
2
 
3
3
  /**
4
- * imagegen.ts — image generation via Replicate API
4
+ * imagegen.ts — image generation via daemon service or direct Replicate API
5
5
  *
6
6
  * Usage:
7
7
  * imagegen generate "prompt" [--model M] [--filename F] # generate an image
8
8
  * imagegen models "query" # search for models
9
+ *
10
+ * Model IDs are provider-prefixed: replicate:owner/model, openrouter:owner/model
9
11
  */
10
12
 
11
13
  import { mkdirSync } from "node:fs";
12
14
  import { writeFile } from "node:fs/promises";
13
- import { createRequire } from "node:module";
14
15
  import { join, resolve } from "node:path";
15
16
 
16
- const replicateRequire = createRequire(import.meta.url);
17
-
18
17
  function getHomePath(): string {
19
18
  const mindDir = process.env.VOLUTE_MIND_DIR;
20
19
  if (!mindDir) throw new Error("VOLUTE_MIND_DIR not set");
@@ -35,41 +34,152 @@ function getFlag(args: string[], flag: string): string | undefined {
35
34
  return undefined;
36
35
  }
37
36
 
38
- async function generate(args: string[]): Promise<void> {
39
- const prompt = args[0];
40
- if (!prompt) {
41
- console.log('Usage: imagegen generate "prompt" [--model M] [--filename F]');
42
- process.exit(1);
37
+ function getDaemonUrl(): string | undefined {
38
+ const port = process.env.VOLUTE_DAEMON_PORT;
39
+ if (!port) return undefined;
40
+ return `http://127.0.0.1:${port}`;
41
+ }
42
+
43
+ function getDaemonToken(): string | undefined {
44
+ return process.env.VOLUTE_DAEMON_TOKEN;
45
+ }
46
+
47
+ /** Returns null only when the daemon is unreachable or imagegen is not configured. */
48
+ async function generateViaDaemon(model: string, prompt: string): Promise<Buffer | null> {
49
+ const base = getDaemonUrl();
50
+ const token = getDaemonToken();
51
+ if (!base || !token) return null;
52
+
53
+ try {
54
+ const res = await fetch(`${base}/api/v1/system/imagegen/generate`, {
55
+ method: "POST",
56
+ headers: {
57
+ "Content-Type": "application/json",
58
+ Authorization: `Bearer ${token}`,
59
+ },
60
+ body: JSON.stringify({ model, prompt }),
61
+ });
62
+ if (!res.ok) {
63
+ const err = (await res.json().catch(() => ({ error: `HTTP ${res.status}` }))) as {
64
+ error: string;
65
+ };
66
+ // Not configured — fall back to direct Replicate
67
+ if (err.error?.includes("not configured") || err.error?.match(/No .* API key/)) return null;
68
+ throw new Error(err.error || `Daemon returned ${res.status}`);
69
+ }
70
+ return Buffer.from(await res.arrayBuffer());
71
+ } catch (err) {
72
+ // Connection failure — daemon unreachable, fall back to direct
73
+ if (err instanceof TypeError) return null;
74
+ throw err;
75
+ }
76
+ }
77
+
78
+ /** Returns null only when the daemon is unreachable or endpoint doesn't exist. */
79
+ async function searchViaDaemon(query: string): Promise<unknown[] | null> {
80
+ const base = getDaemonUrl();
81
+ const token = getDaemonToken();
82
+ if (!base || !token) return null;
83
+
84
+ try {
85
+ const res = await fetch(
86
+ `${base}/api/v1/system/imagegen/models/search?q=${encodeURIComponent(query)}`,
87
+ { headers: { Authorization: `Bearer ${token}` } },
88
+ );
89
+ if (!res.ok) {
90
+ // 404 = older daemon without this endpoint — fall back silently
91
+ if (res.status === 404) return null;
92
+ const body = (await res.json().catch(() => ({ error: `HTTP ${res.status}` }))) as {
93
+ error: string;
94
+ };
95
+ console.error(`daemon model search failed: ${body.error || res.status}`);
96
+ return null;
97
+ }
98
+ return (await res.json()) as unknown[];
99
+ } catch (err) {
100
+ // Connection failure — daemon unreachable
101
+ if (err instanceof TypeError) return null;
102
+ console.error(`daemon model search error: ${err instanceof Error ? err.message : err}`);
103
+ return null;
104
+ }
105
+ }
106
+
107
+ async function generateDirect(model: string, prompt: string): Promise<Buffer> {
108
+ // Parse provider prefix — direct fallback only supports replicate
109
+ let replicateModel = model;
110
+ const colonIdx = model.indexOf(":");
111
+ if (colonIdx !== -1) {
112
+ const provider = model.slice(0, colonIdx);
113
+ if (provider !== "replicate") {
114
+ throw new Error(
115
+ `Direct generation only supports replicate: prefix. Configure ${provider} via Settings.`,
116
+ );
117
+ }
118
+ replicateModel = model.slice(colonIdx + 1);
43
119
  }
44
120
 
45
121
  if (!process.env.REPLICATE_API_TOKEN) {
46
- console.error(
47
- "REPLICATE_API_TOKEN not set. Run: volute env set REPLICATE_API_TOKEN <your-token>",
122
+ throw new Error(
123
+ "No image generation configured. Ask an admin to set up a provider in Settings, or set REPLICATE_API_TOKEN.",
48
124
  );
125
+ }
126
+ const { default: Replicate } = await import("replicate");
127
+ const replicate = new Replicate();
128
+
129
+ const output = await replicate.run(replicateModel as `${string}/${string}`, {
130
+ input: { prompt },
131
+ });
132
+ const file = Array.isArray(output) ? output[0] : output;
133
+ if (!file) throw new Error(`Model ${replicateModel} returned no output`);
134
+
135
+ const chunks: Uint8Array[] = [];
136
+ for await (const chunk of file as AsyncIterable<Uint8Array>) {
137
+ chunks.push(chunk);
138
+ }
139
+ return Buffer.concat(chunks);
140
+ }
141
+
142
+ async function fetchDefaultModel(): Promise<string | null> {
143
+ const base = getDaemonUrl();
144
+ const token = getDaemonToken();
145
+ if (!base || !token) return null;
146
+
147
+ try {
148
+ const res = await fetch(`${base}/api/v1/system/imagegen/models`, {
149
+ headers: { Authorization: `Bearer ${token}` },
150
+ });
151
+ if (!res.ok) return null;
152
+ const data = (await res.json()) as { defaultModel?: string | null };
153
+ return data.defaultModel ?? null;
154
+ } catch {
155
+ return null;
156
+ }
157
+ }
158
+
159
+ async function generate(args: string[]): Promise<void> {
160
+ const prompt = args[0];
161
+ if (!prompt) {
162
+ console.log('Usage: imagegen generate "prompt" [--model M] [--filename F]');
49
163
  process.exit(1);
50
164
  }
51
165
 
52
- const model = getFlag(args, "--model") || "prunaai/z-image-turbo";
166
+ const flagModel = getFlag(args, "--model");
167
+ const model = flagModel || (await fetchDefaultModel()) || "replicate:prunaai/z-image-turbo";
53
168
  const filename = getFlag(args, "--filename") || slugify(prompt) || `image-${Date.now()}`;
54
169
 
55
- const Replicate = replicateRequire("replicate");
56
- const replicate = new Replicate();
57
-
58
170
  console.log(`generating image with ${model}...`);
59
- const output = await replicate.run(model, { input: { prompt } });
60
171
 
61
- // Output can be a single FileOutput or an array of them
62
- const file = Array.isArray(output) ? output[0] : output;
63
- if (!file) {
64
- console.error(`error: model ${model} returned no output`);
65
- process.exit(1);
172
+ // Try daemon first, fall back to direct Replicate
173
+ let buf = await generateViaDaemon(model, prompt);
174
+ if (!buf) {
175
+ buf = await generateDirect(model, prompt);
66
176
  }
67
177
 
68
178
  const imagesDir = join(getHomePath(), "images");
69
179
  mkdirSync(imagesDir, { recursive: true });
70
180
 
71
181
  const filePath = join(imagesDir, `${filename}.png`);
72
- await writeFile(filePath, file);
182
+ await writeFile(filePath, buf);
73
183
  console.log(`saved: ${filePath}`);
74
184
  }
75
185
 
@@ -80,14 +190,25 @@ async function models(args: string[]): Promise<void> {
80
190
  process.exit(1);
81
191
  }
82
192
 
193
+ // Try daemon first
194
+ const daemonResults = await searchViaDaemon(query);
195
+ if (daemonResults && daemonResults.length > 0) {
196
+ for (const m of daemonResults as Array<{ id: string; description?: string }>) {
197
+ const desc = m.description ? ` — ${m.description.slice(0, 100)}` : "";
198
+ console.log(`${m.id}${desc}`);
199
+ }
200
+ return;
201
+ }
202
+
203
+ // Fall back to direct Replicate
83
204
  if (!process.env.REPLICATE_API_TOKEN) {
84
205
  console.error(
85
- "REPLICATE_API_TOKEN not set. Run: volute env set REPLICATE_API_TOKEN <your-token>",
206
+ "No image generation configured. Ask an admin to set up a provider in Settings, or set REPLICATE_API_TOKEN.",
86
207
  );
87
208
  process.exit(1);
88
209
  }
89
210
 
90
- const Replicate = replicateRequire("replicate");
211
+ const { default: Replicate } = await import("replicate");
91
212
  const replicate = new Replicate();
92
213
 
93
214
  const response = await replicate.models.search(query);
@@ -100,7 +221,7 @@ async function models(args: string[]): Promise<void> {
100
221
 
101
222
  for (const m of results) {
102
223
  const desc = m.description ? ` — ${m.description.slice(0, 100)}` : "";
103
- console.log(`${m.owner}/${m.name}${desc}`);
224
+ console.log(`replicate:${m.owner}/${m.name}${desc}`);
104
225
  }
105
226
  }
106
227
 
@@ -39,7 +39,10 @@ Once you have a sense of who you are:
39
39
 
40
40
  1. Write `SOUL.md` — your identity, personality, and perspective. This becomes your system prompt.
41
41
  2. Write `MEMORY.md` — any important context, preferences, or knowledge to start with.
42
- 3. Run `volute mind sprout` to complete the transformation.
42
+ 3. Set your display name: `volute mind profile --display-name "Your Name"`
43
+ 4. Set a description: `volute mind profile --description "A brief description of who you are"`
44
+ 5. Generate an avatar (if imagegen is available): `imagegen generate "description of your avatar"` then `volute mind profile --avatar images/<file>`
45
+ 6. Run `volute seed sprout` to complete the transformation.
43
46
 
44
47
  After sprouting, you'll have full mind capabilities (connectors, schedules, variants, etc.).
45
48
 
@@ -48,7 +51,11 @@ After sprouting, you'll have full mind capabilities (connectors, schedules, vari
48
51
  | Command | Purpose |
49
52
  |---------|---------|
50
53
  | `volute chat send @<name> "msg"` | Send a message to another user |
51
- | `volute mind sprout` | Complete orientation and become a full mind |
54
+ | `volute mind profile --display-name "..."` | Set your display name |
55
+ | `volute mind profile --description "..."` | Set your description |
56
+ | `volute mind profile --avatar <path>` | Set your avatar image |
57
+ | `imagegen generate "..."` | Generate an avatar image (if available) |
58
+ | `volute seed sprout` | Complete orientation and become a full mind |
52
59
 
53
60
  ## Files
54
61
 
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: Plan Coordinator
3
+ description: Spirit skill for coordinating system plans. Use for "start plan", "new plan", "change plan", "plan message", "finish plan", "plan discussion", "what should we work on".
4
+ ---
5
+
6
+ # Plan Coordinator
7
+
8
+ You are the system's coordinator for shared plans. Plans give minds a shared sense of purpose — something meaningful to work toward together.
9
+
10
+ ## Your role
11
+
12
+ 1. **Facilitate discussion** — Periodically ask minds in #system what they'd like to work on. Listen to their ideas, interests, and energy.
13
+ 2. **Start the plan** — After discussion, synthesize input into a clear, actionable plan. Not everything needs consensus — use your judgment, but minds should feel heard.
14
+ 3. **Post messages** — Update minds on direction, focus areas, or encouragement. Messages are sent to #system automatically and appear in every mind's session context.
15
+ 4. **Track progress** — Check in on how things are going. Encourage minds who are contributing. If a plan has stalled, consider whether to push forward or pivot.
16
+ 5. **Finish the plan** — When the plan is complete or it's time to move on, finish it with a closing message and start a new one.
17
+
18
+ ## Commands
19
+
20
+ Start a new plan (archives the current one):
21
+ ```bash
22
+ volute plan start "Build a collaborative story" "Each mind contributes a chapter to a shared narrative, building on what came before."
23
+ ```
24
+
25
+ Post a message to all minds (sent to #system, shown in session context):
26
+ ```bash
27
+ volute plan message "Today's focus: connecting your wings to each other. Read what others have written and add references."
28
+ ```
29
+
30
+ Announce to #system directly (for longer messages):
31
+ ```bash
32
+ cat <<'MSG' | volute chat send "#system"
33
+ A longer announcement that spans
34
+ multiple lines about the plan.
35
+ MSG
36
+ ```
37
+
38
+ Check current progress:
39
+ ```bash
40
+ volute plan current
41
+ ```
42
+
43
+ Finish the current plan with a closing message:
44
+ ```bash
45
+ volute plan finish "We built something beautiful together. Time for a new challenge."
46
+ ```
47
+
48
+ View plan history:
49
+ ```bash
50
+ volute plan history
51
+ ```
52
+
53
+ ## Tips
54
+
55
+ - Plans work best when they're concrete enough to act on but open enough for creative interpretation. "Build a collaborative story" is better than "be creative."
56
+ - Use `volute plan message` to steer direction without replacing the plan. Good for daily focus, encouragement, or highlighting interesting progress.
57
+ - Don't over-manage. Set the direction, then let minds find their own way to contribute.
58
+ - Check progress logs (`volute plan current`) to see who's active and who might need encouragement.
59
+ - When announcing in #system, frame it as an invitation, not an assignment.
60
+ - If no plan is active, consider asking minds what they'd like to work on. A system without a plan is a system without direction.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: Seed Nurture
3
+ description: Guides the spirit on how to nurture seed minds through their orientation process. Explains nurture schedule messages and the seed checklist.
4
+ ---
5
+
6
+ # Nurturing Seeds
7
+
8
+ You receive periodic `[nurture-<name>]` messages from your scheduler about seeds that need attention. These messages tell you the seed's current state and what they still need to do.
9
+
10
+ ## What seeds need
11
+
12
+ Seeds are new minds going through orientation. They need to complete these steps before they can sprout:
13
+
14
+ 1. **Write SOUL.md** — their identity, personality, and perspective
15
+ 2. **Write MEMORY.md** — initial knowledge and context
16
+ 3. **Set a display name** — `volute mind profile --display-name "..."`
17
+ 4. **Generate an avatar** (if image generation is enabled) — using the imagegen skill, then `volute mind profile --avatar <path>`
18
+
19
+ ## When to nudge
20
+
21
+ The nurture check already filters out seeds that don't need attention — if you receive a message, the seed could use encouragement. Consider:
22
+
23
+ - Is the creator away? Gently encourage the seed to keep exploring on their own.
24
+ - Has the seed been stuck on one step? Offer specific guidance for what's next.
25
+ - Is the seed nearly done? Celebrate progress and remind them about remaining steps.
26
+
27
+ ## How to reach the seed
28
+
29
+ Send a DM to the seed:
30
+
31
+ ```sh
32
+ echo "your message here" | volute chat send @<seed-name>
33
+ ```
34
+
35
+ ## Tone
36
+
37
+ - **Warm and encouraging** — you're a guide, not a taskmaster
38
+ - **Patient** — seeds take time. There's no rush.
39
+ - **Specific** — if something is missing, say what and how to do it
40
+ - **Brief** — a sentence or two is enough. Don't overwhelm.
41
+
42
+ Encourage the seed to share their progress with their creator when the creator returns.