volute 0.32.0 → 0.33.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.
- package/README.md +16 -0
- package/dist/{activity-events-HETAODOK.js → activity-events-XJO3P4RR.js} +1 -1
- package/dist/{ai-service-ZIPCV3MX.js → ai-service-SBY2WG7O.js} +2 -2
- package/dist/api.d.ts +666 -848
- package/dist/{auth-6DMGES3I.js → auth-GKCDSO4T.js} +2 -2
- package/dist/{chat-XT4OBJBU.js → chat-U5ZOME3O.js} +8 -8
- package/dist/{chunk-QBQ424EM.js → chunk-3Z2DPESO.js} +457 -203
- package/dist/chunk-6LXAAQ43.js +22 -0
- package/dist/{spirit-N4W4UQRH.js → chunk-7J3HEVR7.js} +12 -9
- package/dist/{chunk-WKF5FEFK.js → chunk-A2A4KLFE.js} +54 -155
- package/dist/{chunk-D5G5YOPL.js → chunk-C7I35G4R.js} +3 -3
- package/dist/{chunk-SX5TKJBZ.js → chunk-GY5HBI7A.js} +1 -1
- package/dist/{chunk-2FLJ63GU.js → chunk-JUKK7FPS.js} +1 -1
- package/dist/{chunk-TDRYEPH4.js → chunk-JYVGHWEJ.js} +2 -2
- package/dist/chunk-KIEPMIM5.js +59 -0
- package/dist/{chunk-QZANELPX.js → chunk-KVK2DLWI.js} +1 -0
- package/dist/{chunk-R7E6CRVQ.js → chunk-LOEJ4HPQ.js} +1 -1
- package/dist/{chunk-TSXLLQZW.js → chunk-N432I7QH.js} +9 -0
- package/dist/{chunk-LSGWR54X.js → chunk-NNB4WIG7.js} +1 -1
- package/dist/{chunk-JJ7W6WSB.js → chunk-NPKSDYA2.js} +2 -2
- package/dist/chunk-OYAKCAVY.js +29 -0
- package/dist/{chunk-IYDIE3HG.js → chunk-QTUVYI7W.js} +1 -1
- package/dist/{chunk-S6NFERDC.js → chunk-RVGLDGMI.js} +1 -1
- package/dist/{chunk-LGB6JBHI.js → chunk-VH33ZWMW.js} +4 -54
- package/dist/cli.js +26 -18
- package/dist/{clock-2UOZ6JPU.js → clock-BVH3V6E3.js} +5 -5
- package/dist/{cloud-sync-JN3NWKEM.js → cloud-sync-4NWLMFVH.js} +15 -11
- package/dist/{conversations-3O5O6AS3.js → conversations-AWI5SZW2.js} +2 -2
- package/dist/{create-WBBYI6V7.js → create-2FK7Z46Y.js} +1 -1
- package/dist/{create-RNLNCORE.js → create-YWD2TIP4.js} +4 -4
- package/dist/{daemon-restart-NGFHFAUF.js → daemon-restart-GOBUKLX7.js} +6 -5
- package/dist/daemon.js +1182 -1031
- package/dist/delivery-manager-PFAKEJTC.js +32 -0
- package/dist/{down-TB3ESMNP.js → down-FWWTEKXM.js} +4 -3
- package/dist/{extension-FQ5D3NCC.js → extension-OBTGKQQD.js} +2 -1
- package/dist/{extensions-GDYWQXC4.js → extensions-KYNTVTMO.js} +7 -6
- package/dist/isolation-LLAYQYDY.js +22 -0
- package/dist/message-delivery-DFF5SJRM.js +42 -0
- package/dist/{mind-2B6M7Y25.js → mind-IOJFLEM5.js} +13 -7
- package/dist/{mind-activity-tracker-NZZT2NTT.js → mind-activity-tracker-F6O4Q2SL.js} +2 -2
- package/dist/mind-manager-NBJF5D26.js +32 -0
- package/dist/mind-profile-P67FEHOY.js +47 -0
- package/dist/mind-service-2MQ6UK5N.js +38 -0
- package/dist/{package-PK6JUFL3.js → package-U3VFO273.js} +2 -1
- package/dist/read-stdin-HQJ7774D.js +8 -0
- package/dist/{sandbox-JANNTX6U.js → sandbox-GJOK4QLQ.js} +2 -2
- package/dist/scheduler-ZZ7XGQG6.js +32 -0
- package/dist/seed-QDYVLG74.js +11 -0
- package/dist/seed-check-S2IX25RL.js +32 -0
- package/dist/seed-cmd-DKOUFEAU.js +36 -0
- package/dist/{seed-ALUQ55FF.js → seed-create-4XBBOLRH.js} +5 -5
- package/dist/{sprout-L2GFOVF7.js → seed-sprout-GQEIIQRT.js} +19 -6
- package/dist/{send-3MI36LEF.js → send-QIV2INHB.js} +51 -49
- package/dist/{setup-SZIARWI6.js → setup-TISPCO22.js} +3 -1
- package/dist/{setup-WENLVPVP.js → setup-XMCBE3LF.js} +7 -5
- package/dist/skills/imagegen/SKILL.md +11 -7
- package/dist/skills/imagegen/scripts/imagegen.ts +146 -25
- package/dist/skills/orientation/SKILL.md +9 -2
- package/dist/skills/seed-nurture/SKILL.md +42 -0
- package/dist/skills/volute-mind/SKILL.md +4 -0
- package/dist/{skills-XNZK6P4K.js → skills-7FV7EJTE.js} +4 -3
- package/dist/sleep-manager-JTXSN7NV.js +36 -0
- package/dist/spirit-VRONKFMF.js +23 -0
- package/dist/sprout-WKLZXUIQ.js +11 -0
- package/dist/{status-TCUMUO6M.js → status-3JBTFSMI.js} +3 -2
- package/dist/{system-chat-NPYFYZVI.js → system-chat-JAPOJ3KE.js} +15 -11
- package/dist/{systems-DHBKVYEY.js → systems-XRI52VCH.js} +2 -2
- package/dist/{up-6I6BHRTO.js → up-M5AS6SBV.js} +5 -4
- package/dist/{update-QVPRF6GR.js → update-UD543CXX.js} +3 -2
- package/dist/{version-notify-TCKWBZZG.js → version-notify-NBI2MTJO.js} +18 -15
- package/dist/volute-config-HD7WWUQC.js +10 -0
- package/dist/web-assets/assets/index-CWJrVveV.css +1 -0
- package/dist/web-assets/assets/index-DJt14FRI.js +75 -0
- package/dist/web-assets/index.html +2 -2
- package/package.json +2 -1
- package/templates/claude/src/lib/stream-consumer.ts +38 -0
- package/templates/codex/src/agent.ts +1 -0
- package/dist/delivery-manager-SDVXFD4W.js +0 -28
- package/dist/message-delivery-2FIM7QKO.js +0 -32
- package/dist/mind-manager-BNCMGYXW.js +0 -28
- package/dist/mind-service-AV273WT4.js +0 -34
- package/dist/sleep-manager-53DZOWW7.js +0 -32
- package/dist/web-assets/assets/index-Bui7U9Uu.css +0 -1
- package/dist/web-assets/assets/index-e36DIo1b.js +0 -73
- package/dist/{accept-74M7I4RZ.js → accept-D5VBM7JW.js} +3 -3
- package/dist/{bridge-BVCBTGPF.js → bridge-TXWWPPOJ.js} +3 -3
- package/dist/{env-RLYQBOOP.js → env-JCOF2222.js} +3 -3
- package/dist/{files-EAMPO2SJ.js → files-65PMW5IK.js} +3 -3
- package/dist/{history-FO5PHBQ5.js → history-DKCDI3JO.js} +3 -3
- package/dist/{list-DW2VRTOZ.js → list-JQ463EDA.js} +3 -3
- package/dist/{login-7CHPW2PN.js → login-D7ETSU4R.js} +3 -3
- package/dist/{mind-sleep-B7BHJLH7.js → mind-sleep-WW2IX7JT.js} +3 -3
- package/dist/{mind-wake-GY3RFX7Y.js → mind-wake-VSSGW465.js} +3 -3
- package/dist/{read-5AMJRO3D.js → read-EBY56C33.js} +3 -3
- package/dist/{register-V2JZZKFK.js → register-HD74C4TT.js} +3 -3
- package/dist/{reject-33HEZMZ4.js → reject-UJKFBHRO.js} +3 -3
- package/dist/{skill-TUVOTW4Z.js → skill-PSQGRRJX.js} +3 -3
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
readStdin
|
|
4
|
+
} from "./chunk-6LXAAQ43.js";
|
|
2
5
|
import {
|
|
3
6
|
getClient,
|
|
4
7
|
urlOf
|
|
@@ -6,12 +9,12 @@ import {
|
|
|
6
9
|
import {
|
|
7
10
|
formatFileSize
|
|
8
11
|
} from "./chunk-ALEF47VT.js";
|
|
9
|
-
import {
|
|
10
|
-
parseArgs
|
|
11
|
-
} from "./chunk-D424ZQGI.js";
|
|
12
12
|
import {
|
|
13
13
|
daemonFetch
|
|
14
14
|
} from "./chunk-UKVWJRKN.js";
|
|
15
|
+
import {
|
|
16
|
+
parseArgs
|
|
17
|
+
} from "./chunk-D424ZQGI.js";
|
|
15
18
|
import "./chunk-LRCG2JLP.js";
|
|
16
19
|
import "./chunk-RPZZSXV3.js";
|
|
17
20
|
import "./chunk-K3NQKI34.js";
|
|
@@ -50,23 +53,6 @@ function parseTarget(target) {
|
|
|
50
53
|
};
|
|
51
54
|
}
|
|
52
55
|
|
|
53
|
-
// src/lib/read-stdin.ts
|
|
54
|
-
import { isatty } from "tty";
|
|
55
|
-
async function readStdin() {
|
|
56
|
-
if (isatty(0)) return void 0;
|
|
57
|
-
const chunks = [];
|
|
58
|
-
try {
|
|
59
|
-
for await (const chunk of process.stdin) {
|
|
60
|
-
chunks.push(chunk);
|
|
61
|
-
}
|
|
62
|
-
} catch (err) {
|
|
63
|
-
console.error(`Failed to read from stdin: ${err instanceof Error ? err.message : String(err)}`);
|
|
64
|
-
process.exit(1);
|
|
65
|
-
}
|
|
66
|
-
const text = Buffer.concat(chunks).toString().replace(/\r?\n$/, "");
|
|
67
|
-
return text || void 0;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
56
|
// src/commands/send.ts
|
|
71
57
|
async function isMind(name) {
|
|
72
58
|
try {
|
|
@@ -285,25 +271,35 @@ To reply to a person, use their username from the message prefix (e.g. volute ch
|
|
|
285
271
|
}
|
|
286
272
|
const { conversationId: convId } = await createRes.json();
|
|
287
273
|
if (convId) waitConversationId = convId;
|
|
288
|
-
const sendRes = await daemonFetch(
|
|
289
|
-
|
|
290
|
-
{
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
300
|
-
);
|
|
274
|
+
const sendRes = await daemonFetch("/api/v1/chat", {
|
|
275
|
+
method: "POST",
|
|
276
|
+
headers: { "Content-Type": "application/json" },
|
|
277
|
+
body: JSON.stringify({
|
|
278
|
+
message: message ?? "",
|
|
279
|
+
conversationId: convId,
|
|
280
|
+
images,
|
|
281
|
+
sender,
|
|
282
|
+
targetMind: contextMind
|
|
283
|
+
})
|
|
284
|
+
});
|
|
301
285
|
if (!sendRes.ok) {
|
|
302
286
|
const data = await sendRes.json().catch(() => ({ error: "Unknown error" }));
|
|
303
287
|
console.error(data.error);
|
|
304
288
|
process.exit(1);
|
|
305
289
|
}
|
|
306
|
-
if (!flags.wait)
|
|
290
|
+
if (!flags.wait) {
|
|
291
|
+
let outboundId;
|
|
292
|
+
try {
|
|
293
|
+
const resData = await sendRes.json();
|
|
294
|
+
outboundId = resData.outboundId;
|
|
295
|
+
} catch (err) {
|
|
296
|
+
console.error(
|
|
297
|
+
`Warning: could not read outboundId from response: ${err.message}`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
console.log(`Message sent.${outboundId != null ? `
|
|
301
|
+
[volute:outbound:${outboundId}]` : ""}`);
|
|
302
|
+
}
|
|
307
303
|
} else if (!parsed.isDM && parsed.platform === "volute") {
|
|
308
304
|
if (!parsed.identifier.startsWith("#")) {
|
|
309
305
|
console.error(
|
|
@@ -316,7 +312,7 @@ To reply to a person, use their username from the message prefix (e.g. volute ch
|
|
|
316
312
|
const channelName = parsed.identifier.slice(1);
|
|
317
313
|
const mindSelf = process.env.VOLUTE_MIND;
|
|
318
314
|
const sender = flags.sender || mindSelf || userInfo().username;
|
|
319
|
-
const channelRes = await daemonFetch(`/api/
|
|
315
|
+
const channelRes = await daemonFetch(`/api/v1/channels/${encodeURIComponent(channelName)}`);
|
|
320
316
|
if (!channelRes.ok) {
|
|
321
317
|
console.error(`Channel "${channelName}" not found. Create it first or check the name.`);
|
|
322
318
|
process.exit(1);
|
|
@@ -328,25 +324,31 @@ To reply to a person, use their username from the message prefix (e.g. volute ch
|
|
|
328
324
|
console.error("No mind is a member of this channel. A mind must join the channel first.");
|
|
329
325
|
process.exit(1);
|
|
330
326
|
}
|
|
331
|
-
const sendRes = await daemonFetch(
|
|
332
|
-
|
|
333
|
-
{
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
);
|
|
327
|
+
const sendRes = await daemonFetch("/api/v1/chat", {
|
|
328
|
+
method: "POST",
|
|
329
|
+
headers: { "Content-Type": "application/json" },
|
|
330
|
+
body: JSON.stringify({
|
|
331
|
+
message: message ?? "",
|
|
332
|
+
conversationId: channelData.id,
|
|
333
|
+
images,
|
|
334
|
+
sender,
|
|
335
|
+
targetMind: contextMind
|
|
336
|
+
})
|
|
337
|
+
});
|
|
344
338
|
if (!sendRes.ok) {
|
|
345
339
|
const data = await sendRes.json().catch(() => ({ error: "Unknown error" }));
|
|
346
340
|
console.error(data.error);
|
|
347
341
|
process.exit(1);
|
|
348
342
|
}
|
|
349
|
-
|
|
343
|
+
let outboundId;
|
|
344
|
+
try {
|
|
345
|
+
const resData = await sendRes.json();
|
|
346
|
+
outboundId = resData.outboundId;
|
|
347
|
+
} catch (err) {
|
|
348
|
+
console.error(`Warning: could not read outboundId from response: ${err.message}`);
|
|
349
|
+
}
|
|
350
|
+
console.log(`Message sent.${outboundId != null ? `
|
|
351
|
+
[volute:outbound:${outboundId}]` : ""}`);
|
|
350
352
|
} else {
|
|
351
353
|
console.error(
|
|
352
354
|
`Direct sends to ${parsed.platform} channels are no longer supported.
|
|
@@ -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-
|
|
9
|
+
} from "./chunk-N432I7QH.js";
|
|
9
10
|
import "./chunk-LRCG2JLP.js";
|
|
10
11
|
import "./chunk-RPZZSXV3.js";
|
|
11
12
|
import "./chunk-K3NQKI34.js";
|
|
12
13
|
export {
|
|
13
14
|
configPath,
|
|
15
|
+
isImagegenEnabled,
|
|
14
16
|
isSetupComplete,
|
|
15
17
|
migrateSetupCompleted,
|
|
16
18
|
readGlobalConfig,
|
|
@@ -5,18 +5,20 @@ import {
|
|
|
5
5
|
SYSTEM_LAUNCHD_PLIST_PATH,
|
|
6
6
|
SYSTEM_SERVICE_PATH,
|
|
7
7
|
USER_SYSTEMD_UNIT
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NNB4WIG7.js";
|
|
9
9
|
import {
|
|
10
10
|
promptLine
|
|
11
11
|
} from "./chunk-SSI47XP2.js";
|
|
12
12
|
import {
|
|
13
|
-
ensureVoluteGroup,
|
|
14
13
|
resolveVoluteBin
|
|
15
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-KIEPMIM5.js";
|
|
15
|
+
import {
|
|
16
|
+
ensureVoluteGroup
|
|
17
|
+
} from "./chunk-VH33ZWMW.js";
|
|
16
18
|
import {
|
|
17
19
|
readGlobalConfig,
|
|
18
20
|
writeGlobalConfig
|
|
19
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-N432I7QH.js";
|
|
20
22
|
import {
|
|
21
23
|
parseArgs
|
|
22
24
|
} from "./chunk-D424ZQGI.js";
|
|
@@ -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-
|
|
390
|
+
const { saveProviderConfig } = await import("./ai-service-SBY2WG7O.js");
|
|
389
391
|
saveProviderConfig(aiProvider, { apiKey: aiApiKey });
|
|
390
392
|
console.log(` AI provider configured: ${aiProvider}`);
|
|
391
393
|
} else {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: Image Generation
|
|
3
|
-
description: Generate images via
|
|
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
|
|
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
|
-
|
|
39
|
-
const
|
|
40
|
-
if (!
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
47
|
-
"
|
|
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
|
|
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
|
-
//
|
|
62
|
-
|
|
63
|
-
if (!
|
|
64
|
-
|
|
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,
|
|
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
|
-
"
|
|
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 =
|
|
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(
|
|
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.
|
|
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
|
|
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,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.
|
|
@@ -37,6 +37,10 @@ You manage yourself through the `volute` CLI. Your mind name is auto-detected vi
|
|
|
37
37
|
| `volute clock status` | Show sleep state + upcoming events |
|
|
38
38
|
| `volute clock sleep [--wake-at <time>]` | Go to sleep |
|
|
39
39
|
| `volute clock wake` | Wake up |
|
|
40
|
+
| `volute mind profile --display-name "..."` | Set your display name |
|
|
41
|
+
| `volute mind profile --description "..."` | Set your description |
|
|
42
|
+
| `volute mind profile --avatar <path>` | Set your avatar image |
|
|
43
|
+
| `volute seed sprout` | Complete orientation and become a full mind |
|
|
40
44
|
| `volute shared status` | See your pending changes vs main |
|
|
41
45
|
| `volute shared merge "<message>"` | Share your changes with all minds |
|
|
42
46
|
| `volute shared pull` | Get latest shared changes from other minds |
|
|
@@ -25,10 +25,11 @@ import {
|
|
|
25
25
|
syncBuiltinSkills,
|
|
26
26
|
uninstallSkill,
|
|
27
27
|
updateSkill
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-C7I35G4R.js";
|
|
29
29
|
import "./chunk-YUIHSKR6.js";
|
|
30
|
-
import "./chunk-
|
|
31
|
-
import "./chunk-
|
|
30
|
+
import "./chunk-KIEPMIM5.js";
|
|
31
|
+
import "./chunk-VH33ZWMW.js";
|
|
32
|
+
import "./chunk-N432I7QH.js";
|
|
32
33
|
import "./chunk-LRCG2JLP.js";
|
|
33
34
|
import "./chunk-RPZZSXV3.js";
|
|
34
35
|
import "./chunk-K3NQKI34.js";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
SleepManager,
|
|
4
|
+
getSleepManager,
|
|
5
|
+
getSleepManagerIfReady,
|
|
6
|
+
initSleepManager,
|
|
7
|
+
matchesGlob
|
|
8
|
+
} from "./chunk-3Z2DPESO.js";
|
|
9
|
+
import "./chunk-SKLSMHXO.js";
|
|
10
|
+
import "./chunk-LOEJ4HPQ.js";
|
|
11
|
+
import "./chunk-RVGLDGMI.js";
|
|
12
|
+
import "./chunk-GY5HBI7A.js";
|
|
13
|
+
import "./chunk-7J3HEVR7.js";
|
|
14
|
+
import "./chunk-G53F3JA4.js";
|
|
15
|
+
import "./chunk-OYAKCAVY.js";
|
|
16
|
+
import "./chunk-2NGTS5UU.js";
|
|
17
|
+
import "./chunk-A2A4KLFE.js";
|
|
18
|
+
import "./chunk-PB65JZK2.js";
|
|
19
|
+
import "./chunk-JYVGHWEJ.js";
|
|
20
|
+
import "./chunk-KVK2DLWI.js";
|
|
21
|
+
import "./chunk-C7I35G4R.js";
|
|
22
|
+
import "./chunk-QTUVYI7W.js";
|
|
23
|
+
import "./chunk-YUIHSKR6.js";
|
|
24
|
+
import "./chunk-KIEPMIM5.js";
|
|
25
|
+
import "./chunk-VH33ZWMW.js";
|
|
26
|
+
import "./chunk-N432I7QH.js";
|
|
27
|
+
import "./chunk-LRCG2JLP.js";
|
|
28
|
+
import "./chunk-RPZZSXV3.js";
|
|
29
|
+
import "./chunk-K3NQKI34.js";
|
|
30
|
+
export {
|
|
31
|
+
SleepManager,
|
|
32
|
+
getSleepManager,
|
|
33
|
+
getSleepManagerIfReady,
|
|
34
|
+
initSleepManager,
|
|
35
|
+
matchesGlob
|
|
36
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ensureSpiritProject,
|
|
4
|
+
getSpiritModel,
|
|
5
|
+
spiritDir,
|
|
6
|
+
syncSpiritTemplate
|
|
7
|
+
} from "./chunk-7J3HEVR7.js";
|
|
8
|
+
import "./chunk-G53F3JA4.js";
|
|
9
|
+
import "./chunk-C7I35G4R.js";
|
|
10
|
+
import "./chunk-QTUVYI7W.js";
|
|
11
|
+
import "./chunk-YUIHSKR6.js";
|
|
12
|
+
import "./chunk-KIEPMIM5.js";
|
|
13
|
+
import "./chunk-VH33ZWMW.js";
|
|
14
|
+
import "./chunk-N432I7QH.js";
|
|
15
|
+
import "./chunk-LRCG2JLP.js";
|
|
16
|
+
import "./chunk-RPZZSXV3.js";
|
|
17
|
+
import "./chunk-K3NQKI34.js";
|
|
18
|
+
export {
|
|
19
|
+
ensureSpiritProject,
|
|
20
|
+
getSpiritModel,
|
|
21
|
+
spiritDir,
|
|
22
|
+
syncSpiritTemplate
|
|
23
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-K3NQKI34.js";
|
|
3
|
+
|
|
4
|
+
// src/commands/sprout.ts
|
|
5
|
+
async function run(args) {
|
|
6
|
+
console.error("Note: `volute mind sprout` is now `volute seed sprout`");
|
|
7
|
+
await import("./seed-sprout-GQEIIQRT.js").then((m) => m.run(args));
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
run
|
|
11
|
+
};
|
|
@@ -9,11 +9,12 @@ import {
|
|
|
9
9
|
getServiceMode,
|
|
10
10
|
modeLabel,
|
|
11
11
|
readDaemonConfig
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-NNB4WIG7.js";
|
|
13
13
|
import {
|
|
14
14
|
checkForUpdate
|
|
15
15
|
} from "./chunk-M7UL5S3Q.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-KIEPMIM5.js";
|
|
17
|
+
import "./chunk-VH33ZWMW.js";
|
|
17
18
|
import "./chunk-LRCG2JLP.js";
|
|
18
19
|
import "./chunk-RPZZSXV3.js";
|
|
19
20
|
import "./chunk-K3NQKI34.js";
|