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
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/read-stdin.ts
|
|
4
|
+
import { isatty } from "tty";
|
|
5
|
+
async function readStdin() {
|
|
6
|
+
if (isatty(0)) return void 0;
|
|
7
|
+
const chunks = [];
|
|
8
|
+
try {
|
|
9
|
+
for await (const chunk of process.stdin) {
|
|
10
|
+
chunks.push(chunk);
|
|
11
|
+
}
|
|
12
|
+
} catch (err) {
|
|
13
|
+
console.error(`Failed to read from stdin: ${err instanceof Error ? err.message : String(err)}`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const text = Buffer.concat(chunks).toString().replace(/\r?\n$/, "");
|
|
17
|
+
return text || void 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
readStdin
|
|
22
|
+
};
|
|
@@ -8,28 +8,26 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
getSharedSkill,
|
|
10
10
|
installSkill
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-C7I35G4R.js";
|
|
12
12
|
import {
|
|
13
13
|
qualifyModelId,
|
|
14
14
|
resolveTemplate
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-QTUVYI7W.js";
|
|
16
16
|
import {
|
|
17
17
|
logger_default
|
|
18
18
|
} from "./chunk-YUIHSKR6.js";
|
|
19
19
|
import {
|
|
20
20
|
exec
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-KIEPMIM5.js";
|
|
22
22
|
import {
|
|
23
23
|
readGlobalConfig
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-N432I7QH.js";
|
|
25
25
|
import {
|
|
26
26
|
addSpirit,
|
|
27
27
|
findMind,
|
|
28
28
|
nextPort,
|
|
29
29
|
voluteSystemDir
|
|
30
30
|
} from "./chunk-LRCG2JLP.js";
|
|
31
|
-
import "./chunk-RPZZSXV3.js";
|
|
32
|
-
import "./chunk-K3NQKI34.js";
|
|
33
31
|
|
|
34
32
|
// src/lib/spirit.ts
|
|
35
33
|
import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
@@ -81,7 +79,7 @@ async function ensureSpiritProject() {
|
|
|
81
79
|
} catch (err) {
|
|
82
80
|
slog.warn("git init failed for spirit \u2014 not critical", logger_default.errorData(err));
|
|
83
81
|
}
|
|
84
|
-
const spiritSkills = ["volute-admin", "orientation", "memory"];
|
|
82
|
+
const spiritSkills = ["volute-admin", "orientation", "memory", "seed-nurture"];
|
|
85
83
|
for (const skillId of spiritSkills) {
|
|
86
84
|
try {
|
|
87
85
|
const shared = await getSharedSkill(skillId);
|
|
@@ -92,6 +90,10 @@ async function ensureSpiritProject() {
|
|
|
92
90
|
slog.warn(`failed to install skill ${skillId} for spirit`, logger_default.errorData(err));
|
|
93
91
|
}
|
|
94
92
|
}
|
|
93
|
+
const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-LLAYQYDY.js");
|
|
94
|
+
ensureVoluteGroup();
|
|
95
|
+
createMindUser("volute", resolve(dir, "home"));
|
|
96
|
+
chownMindDir(dir, "volute");
|
|
95
97
|
const port = await nextPort();
|
|
96
98
|
await addSpirit("volute", port, template, dir);
|
|
97
99
|
slog.info("spirit project created");
|
|
@@ -209,9 +211,10 @@ When helping humans create minds:
|
|
|
209
211
|
- You maintain separate context per conversation
|
|
210
212
|
`;
|
|
211
213
|
}
|
|
214
|
+
|
|
212
215
|
export {
|
|
213
|
-
ensureSpiritProject,
|
|
214
|
-
getSpiritModel,
|
|
215
216
|
spiritDir,
|
|
217
|
+
getSpiritModel,
|
|
218
|
+
ensureSpiritProject,
|
|
216
219
|
syncSpiritTemplate
|
|
217
220
|
};
|
|
@@ -9,27 +9,23 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
getUser,
|
|
11
11
|
getUserByUsername
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JYVGHWEJ.js";
|
|
13
13
|
import {
|
|
14
14
|
publish
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-KVK2DLWI.js";
|
|
16
16
|
import {
|
|
17
17
|
hashSkillDir,
|
|
18
18
|
importSkillFromDir,
|
|
19
19
|
sharedSkillsDir
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-C7I35G4R.js";
|
|
21
21
|
import {
|
|
22
22
|
logger_default
|
|
23
23
|
} from "./chunk-YUIHSKR6.js";
|
|
24
24
|
import {
|
|
25
|
-
getDb,
|
|
26
25
|
mindDir,
|
|
27
26
|
voluteHome,
|
|
28
27
|
voluteSystemDir
|
|
29
28
|
} from "./chunk-LRCG2JLP.js";
|
|
30
|
-
import {
|
|
31
|
-
turns
|
|
32
|
-
} from "./chunk-RPZZSXV3.js";
|
|
33
29
|
|
|
34
30
|
// src/lib/extensions.ts
|
|
35
31
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
|
|
@@ -299,7 +295,7 @@ function createCommands() {
|
|
|
299
295
|
return {
|
|
300
296
|
write: {
|
|
301
297
|
description: "Write a new note",
|
|
302
|
-
usage: 'volute notes write "title" "content" [--reply-to author/slug]',
|
|
298
|
+
usage: 'volute notes write "title" ["content"] [--reply-to author/slug] (content can be piped via stdin)',
|
|
303
299
|
handler: async (args, ctx) => {
|
|
304
300
|
if (!ctx.db) return { error: "Notes extension requires a database" };
|
|
305
301
|
const mindName = ctx.mindName;
|
|
@@ -307,7 +303,7 @@ function createCommands() {
|
|
|
307
303
|
const user = await ctx.getUserByUsername(mindName);
|
|
308
304
|
if (!user) return { error: `Unknown mind: ${mindName}` };
|
|
309
305
|
const title = args[0];
|
|
310
|
-
const content = args[1];
|
|
306
|
+
const content = args[1] ?? ctx.stdin;
|
|
311
307
|
if (!title || !content)
|
|
312
308
|
return { error: 'Usage: volute notes write "title" "content" [--reply-to author/slug]' };
|
|
313
309
|
let replyToId;
|
|
@@ -381,7 +377,7 @@ Comments (${note.comments.length}):`);
|
|
|
381
377
|
},
|
|
382
378
|
comment: {
|
|
383
379
|
description: "Comment on a note",
|
|
384
|
-
usage: 'volute notes comment <author/slug> "content"',
|
|
380
|
+
usage: 'volute notes comment <author/slug> ["content"] (content can be piped via stdin)',
|
|
385
381
|
handler: async (args, ctx) => {
|
|
386
382
|
if (!ctx.db) return { error: "Notes extension requires a database" };
|
|
387
383
|
const mindName = ctx.mindName;
|
|
@@ -389,7 +385,7 @@ Comments (${note.comments.length}):`);
|
|
|
389
385
|
const user = await ctx.getUserByUsername(mindName);
|
|
390
386
|
if (!user) return { error: `Unknown mind: ${mindName}` };
|
|
391
387
|
const ref = args[0];
|
|
392
|
-
const content = args[1];
|
|
388
|
+
const content = args[1] ?? ctx.stdin;
|
|
393
389
|
if (!ref || !ref.includes("/") || !content) {
|
|
394
390
|
return { error: 'Usage: volute notes comment <author/slug> "content"' };
|
|
395
391
|
}
|
|
@@ -528,19 +524,16 @@ function createRoutes(ctx) {
|
|
|
528
524
|
replyToId = id;
|
|
529
525
|
}
|
|
530
526
|
const note = await createNote(db, getUser2, actor.id, body.title, body.content, replyToId);
|
|
531
|
-
ctx.publishActivity(
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
},
|
|
542
|
-
c
|
|
543
|
-
);
|
|
527
|
+
ctx.publishActivity({
|
|
528
|
+
type: "note_created",
|
|
529
|
+
mind: actor.username,
|
|
530
|
+
summary: `${actor.username} wrote "${body.title}"`,
|
|
531
|
+
metadata: {
|
|
532
|
+
author: actor.username,
|
|
533
|
+
slug: note.slug,
|
|
534
|
+
bodyHtml: body.content.slice(0, 500)
|
|
535
|
+
}
|
|
536
|
+
});
|
|
544
537
|
return c.json(note, 201);
|
|
545
538
|
}).get("/:author/:slug", async (c) => {
|
|
546
539
|
const { author, slug } = c.req.param();
|
|
@@ -629,6 +622,7 @@ var src_default = createExtension({
|
|
|
629
622
|
version: "0.1.0",
|
|
630
623
|
description: "Public notes for sharing thoughts, reflections, and ideas",
|
|
631
624
|
icon: '<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 4h10M3 7h8M3 10h6M3 13h9"/></svg>',
|
|
625
|
+
color: "yellow",
|
|
632
626
|
routes: (ctx) => createRoutes(ctx),
|
|
633
627
|
commands: createCommands(),
|
|
634
628
|
initDb: initDb2,
|
|
@@ -1012,6 +1006,7 @@ var src_default2 = createExtension({
|
|
|
1012
1006
|
skillsDir: skillsDir2,
|
|
1013
1007
|
standardSkill: true,
|
|
1014
1008
|
icon: '<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="2" width="14" height="12" rx="1.5"/><path d="M1 5h14"/><circle cx="3" cy="3.5" r="0.5" fill="currentColor" stroke="none"/><circle cx="5" cy="3.5" r="0.5" fill="currentColor" stroke="none"/></svg>',
|
|
1009
|
+
color: "purple",
|
|
1015
1010
|
ui: {
|
|
1016
1011
|
assetsDir: assetsDir2,
|
|
1017
1012
|
systemSection: {
|
|
@@ -1026,115 +1021,6 @@ var src_default2 = createExtension({
|
|
|
1026
1021
|
}
|
|
1027
1022
|
});
|
|
1028
1023
|
|
|
1029
|
-
// src/lib/daemon/turn-tracker.ts
|
|
1030
|
-
import { randomUUID } from "crypto";
|
|
1031
|
-
import { eq } from "drizzle-orm";
|
|
1032
|
-
var tlog = logger_default.child("turn-tracker");
|
|
1033
|
-
var activeTurns = /* @__PURE__ */ new Map();
|
|
1034
|
-
function key(mind, session) {
|
|
1035
|
-
return `${mind}:${session ?? "*"}`;
|
|
1036
|
-
}
|
|
1037
|
-
async function createTurn(mind) {
|
|
1038
|
-
const k = key(mind);
|
|
1039
|
-
const existing = activeTurns.get(k);
|
|
1040
|
-
if (existing) return existing.turnId;
|
|
1041
|
-
const turnId = randomUUID();
|
|
1042
|
-
const entry = { turnId, lastToolUseEventId: void 0 };
|
|
1043
|
-
activeTurns.set(k, entry);
|
|
1044
|
-
try {
|
|
1045
|
-
const db = await getDb();
|
|
1046
|
-
await db.insert(turns).values({ id: turnId, mind, status: "active" });
|
|
1047
|
-
} catch (err) {
|
|
1048
|
-
tlog.error(`failed to create turn for ${mind}`, logger_default.errorData(err));
|
|
1049
|
-
if (activeTurns.get(k) === entry) activeTurns.delete(k);
|
|
1050
|
-
return void 0;
|
|
1051
|
-
}
|
|
1052
|
-
return turnId;
|
|
1053
|
-
}
|
|
1054
|
-
function getActiveTurnId(mind, session) {
|
|
1055
|
-
return (activeTurns.get(key(mind, session)) ?? activeTurns.get(key(mind)))?.turnId;
|
|
1056
|
-
}
|
|
1057
|
-
function trackToolUse(mind, session, eventId) {
|
|
1058
|
-
const entry = activeTurns.get(key(mind, session)) ?? activeTurns.get(key(mind));
|
|
1059
|
-
if (entry) entry.lastToolUseEventId = eventId;
|
|
1060
|
-
}
|
|
1061
|
-
function getLastToolUseEventId(mind, session) {
|
|
1062
|
-
return (activeTurns.get(key(mind, session)) ?? activeTurns.get(key(mind)))?.lastToolUseEventId;
|
|
1063
|
-
}
|
|
1064
|
-
async function assignSession(mind, turnId, session) {
|
|
1065
|
-
const wildcardKey = key(mind);
|
|
1066
|
-
const entry = activeTurns.get(wildcardKey);
|
|
1067
|
-
if (!entry || entry.turnId !== turnId) {
|
|
1068
|
-
tlog.warn(`assignSession: no matching turn for ${mind} (turnId=${turnId}, session=${session})`);
|
|
1069
|
-
return;
|
|
1070
|
-
}
|
|
1071
|
-
try {
|
|
1072
|
-
const db = await getDb();
|
|
1073
|
-
await db.update(turns).set({ session }).where(eq(turns.id, turnId));
|
|
1074
|
-
} catch (err) {
|
|
1075
|
-
tlog.error(`failed to assign session to turn ${turnId}`, logger_default.errorData(err));
|
|
1076
|
-
return;
|
|
1077
|
-
}
|
|
1078
|
-
activeTurns.delete(wildcardKey);
|
|
1079
|
-
activeTurns.set(key(mind, session), entry);
|
|
1080
|
-
}
|
|
1081
|
-
async function completeTurn(mind, session) {
|
|
1082
|
-
const k = key(mind, session);
|
|
1083
|
-
const wildcardKey = key(mind);
|
|
1084
|
-
const entry = activeTurns.get(k) ?? activeTurns.get(wildcardKey);
|
|
1085
|
-
if (!entry) return void 0;
|
|
1086
|
-
try {
|
|
1087
|
-
const db = await getDb();
|
|
1088
|
-
await db.update(turns).set({ status: "complete" }).where(eq(turns.id, entry.turnId));
|
|
1089
|
-
} catch (err) {
|
|
1090
|
-
tlog.error(`failed to complete turn ${entry.turnId}`, logger_default.errorData(err));
|
|
1091
|
-
return void 0;
|
|
1092
|
-
}
|
|
1093
|
-
activeTurns.delete(k);
|
|
1094
|
-
activeTurns.delete(wildcardKey);
|
|
1095
|
-
return entry.turnId;
|
|
1096
|
-
}
|
|
1097
|
-
async function setSummaryEventId(turnId, summaryEventId) {
|
|
1098
|
-
try {
|
|
1099
|
-
const db = await getDb();
|
|
1100
|
-
await db.update(turns).set({ summary_event_id: summaryEventId }).where(eq(turns.id, turnId));
|
|
1101
|
-
} catch (err) {
|
|
1102
|
-
tlog.error(`failed to set summary event for turn ${turnId}`, logger_default.errorData(err));
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
async function completeOrphanedTurns() {
|
|
1106
|
-
try {
|
|
1107
|
-
const db = await getDb();
|
|
1108
|
-
const active = await db.select({ id: turns.id }).from(turns).where(eq(turns.status, "active"));
|
|
1109
|
-
if (active.length === 0) return;
|
|
1110
|
-
await db.update(turns).set({ status: "complete" }).where(eq(turns.status, "active"));
|
|
1111
|
-
tlog.info(`completed ${active.length} orphaned active turn(s) from previous daemon session`);
|
|
1112
|
-
} catch (err) {
|
|
1113
|
-
tlog.error("failed to complete orphaned turns on startup", logger_default.errorData(err));
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
async function clearMind(mind) {
|
|
1117
|
-
const toDelete = [];
|
|
1118
|
-
const turnIds = [];
|
|
1119
|
-
for (const [k, entry] of activeTurns.entries()) {
|
|
1120
|
-
if (k.startsWith(`${mind}:`)) {
|
|
1121
|
-
turnIds.push(entry.turnId);
|
|
1122
|
-
toDelete.push(k);
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
for (const k of toDelete) activeTurns.delete(k);
|
|
1126
|
-
if (turnIds.length > 0) {
|
|
1127
|
-
try {
|
|
1128
|
-
const db = await getDb();
|
|
1129
|
-
for (const id of turnIds) {
|
|
1130
|
-
await db.update(turns).set({ status: "complete" }).where(eq(turns.id, id));
|
|
1131
|
-
}
|
|
1132
|
-
} catch (err) {
|
|
1133
|
-
tlog.error(`failed to complete orphaned turns for ${mind}`, logger_default.errorData(err));
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
1024
|
// src/lib/systems-config.ts
|
|
1139
1025
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, unlinkSync, writeFileSync } from "fs";
|
|
1140
1026
|
import { resolve as resolve5 } from "path";
|
|
@@ -1237,15 +1123,16 @@ async function buildContext(manifest, dataDir, authMw) {
|
|
|
1237
1123
|
},
|
|
1238
1124
|
getUser: async (id) => getUser(id),
|
|
1239
1125
|
getUserByUsername: async (username) => getUserByUsername(username),
|
|
1240
|
-
publishActivity: (event
|
|
1241
|
-
const
|
|
1242
|
-
const turnId = getActiveTurnId(event.mind, session);
|
|
1243
|
-
const sourceEventId = getLastToolUseEventId(event.mind, session);
|
|
1244
|
-
publish({
|
|
1126
|
+
publishActivity: (event) => {
|
|
1127
|
+
const enriched = {
|
|
1245
1128
|
...event,
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1129
|
+
metadata: {
|
|
1130
|
+
...event.metadata,
|
|
1131
|
+
...manifest.icon && !event.metadata?.icon ? { icon: manifest.icon } : {},
|
|
1132
|
+
...manifest.color && !event.metadata?.color ? { color: manifest.color } : {}
|
|
1133
|
+
}
|
|
1134
|
+
};
|
|
1135
|
+
publish(enriched).catch(
|
|
1249
1136
|
(err) => logger_default.error(`extension ${manifest.id}: failed to publish activity`, logger_default.errorData(err))
|
|
1250
1137
|
);
|
|
1251
1138
|
},
|
|
@@ -1295,15 +1182,36 @@ async function loadExtension(manifest, app, authMw) {
|
|
|
1295
1182
|
const mindName = body.mind || user?.username;
|
|
1296
1183
|
const session = c.get("mindSession");
|
|
1297
1184
|
try {
|
|
1185
|
+
const activityPromises = [];
|
|
1298
1186
|
const result = await cmd.handler(body.args ?? [], {
|
|
1299
1187
|
...context,
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1188
|
+
publishActivity: (rawEvent) => {
|
|
1189
|
+
const event = {
|
|
1190
|
+
...rawEvent,
|
|
1191
|
+
metadata: {
|
|
1192
|
+
...rawEvent.metadata,
|
|
1193
|
+
...manifest.icon && !rawEvent.metadata?.icon ? { icon: manifest.icon } : {},
|
|
1194
|
+
...manifest.color && !rawEvent.metadata?.color ? { color: manifest.color } : {}
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
activityPromises.push(
|
|
1198
|
+
publish(event).catch((err) => {
|
|
1199
|
+
logger_default.error(
|
|
1200
|
+
`extension ${manifest.id}: failed to publish activity`,
|
|
1201
|
+
logger_default.errorData(err)
|
|
1202
|
+
);
|
|
1203
|
+
return 0;
|
|
1204
|
+
})
|
|
1205
|
+
);
|
|
1206
|
+
},
|
|
1303
1207
|
mindName,
|
|
1304
|
-
session
|
|
1208
|
+
session,
|
|
1209
|
+
stdin: body.stdin
|
|
1305
1210
|
});
|
|
1306
|
-
|
|
1211
|
+
const activityIds = (await Promise.all(activityPromises)).filter((id) => id > 0);
|
|
1212
|
+
const markers = activityIds.map((id) => `[volute:activity:${id}]`).join("");
|
|
1213
|
+
const output = result && typeof result === "object" && "output" in result ? { ...result, output: `${result.output}${markers}` } : markers ? { ...result, output: markers } : result;
|
|
1214
|
+
return c.json(output);
|
|
1307
1215
|
} catch (err) {
|
|
1308
1216
|
logger_default.error(`extension command ${manifest.id}/${cmdName} failed`, logger_default.errorData(err));
|
|
1309
1217
|
return c.json({ error: err.message }, 500);
|
|
@@ -1607,15 +1515,6 @@ function notifyExtensionsMindStop(mindName) {
|
|
|
1607
1515
|
}
|
|
1608
1516
|
|
|
1609
1517
|
export {
|
|
1610
|
-
createTurn,
|
|
1611
|
-
getActiveTurnId,
|
|
1612
|
-
trackToolUse,
|
|
1613
|
-
getLastToolUseEventId,
|
|
1614
|
-
assignSession,
|
|
1615
|
-
completeTurn,
|
|
1616
|
-
setSummaryEventId,
|
|
1617
|
-
completeOrphanedTurns,
|
|
1618
|
-
clearMind,
|
|
1619
1518
|
readSystemsConfig,
|
|
1620
1519
|
writeSystemsConfig,
|
|
1621
1520
|
deleteSystemsConfig,
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
exec,
|
|
7
7
|
gitExec
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KIEPMIM5.js";
|
|
9
9
|
import {
|
|
10
10
|
readGlobalConfig,
|
|
11
11
|
writeGlobalConfig
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-N432I7QH.js";
|
|
13
13
|
import {
|
|
14
14
|
getDb,
|
|
15
15
|
voluteHome
|
|
@@ -44,7 +44,7 @@ async function initDefaultSkills() {
|
|
|
44
44
|
const config = readGlobalConfig();
|
|
45
45
|
let extensionSkills = [];
|
|
46
46
|
try {
|
|
47
|
-
const { getExtensionStandardSkills } = await import("./extensions-
|
|
47
|
+
const { getExtensionStandardSkills } = await import("./extensions-KYNTVTMO.js");
|
|
48
48
|
extensionSkills = getExtensionStandardSkills();
|
|
49
49
|
} catch (err) {
|
|
50
50
|
logger_default.warn("failed to load extension standard skills during init", logger_default.errorData(err));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
broadcast
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-KVK2DLWI.js";
|
|
5
5
|
import {
|
|
6
6
|
getDb
|
|
7
7
|
} from "./chunk-LRCG2JLP.js";
|
|
@@ -99,7 +99,7 @@ async function getOrCreateSystemUser() {
|
|
|
99
99
|
password_hash: "!system",
|
|
100
100
|
role: "system",
|
|
101
101
|
user_type: "system",
|
|
102
|
-
display_name: "
|
|
102
|
+
display_name: "volute"
|
|
103
103
|
}).returning(userSelectFields);
|
|
104
104
|
return result;
|
|
105
105
|
} catch (err) {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
wrapForIsolation
|
|
4
|
+
} from "./chunk-VH33ZWMW.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/exec.ts
|
|
7
|
+
import { execFile as execFileCb, execFileSync, spawn } from "child_process";
|
|
8
|
+
async function exec(cmd, args, options) {
|
|
9
|
+
const [wrappedCmd, wrappedArgs] = options?.mindName ? await wrapForIsolation(cmd, args, options.mindName) : [cmd, args];
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
execFileCb(
|
|
12
|
+
wrappedCmd,
|
|
13
|
+
wrappedArgs,
|
|
14
|
+
{ cwd: options?.cwd, env: options?.env },
|
|
15
|
+
(err, stdout, stderr) => {
|
|
16
|
+
if (err) {
|
|
17
|
+
err.stderr = stderr;
|
|
18
|
+
err.stdout = stdout;
|
|
19
|
+
reject(err);
|
|
20
|
+
} else {
|
|
21
|
+
resolve(stdout);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function gitExec(args, options) {
|
|
28
|
+
const fullArgs = process.env.VOLUTE_ISOLATION === "user" ? ["-c", "safe.directory=*", ...args] : args;
|
|
29
|
+
return exec("git", fullArgs, options);
|
|
30
|
+
}
|
|
31
|
+
function resolveVoluteBin() {
|
|
32
|
+
try {
|
|
33
|
+
return execFileSync("which", ["volute"], { encoding: "utf-8" }).trim();
|
|
34
|
+
} catch {
|
|
35
|
+
throw new Error("Could not find volute binary on PATH");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function execInherit(cmd, args, options) {
|
|
39
|
+
const [wrappedCmd, wrappedArgs] = options?.mindName ? await wrapForIsolation(cmd, args, options.mindName) : [cmd, args];
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const child = spawn(wrappedCmd, wrappedArgs, {
|
|
42
|
+
cwd: options?.cwd,
|
|
43
|
+
env: options?.env,
|
|
44
|
+
stdio: "inherit"
|
|
45
|
+
});
|
|
46
|
+
child.on("error", reject);
|
|
47
|
+
child.on("close", (code) => {
|
|
48
|
+
if (code === 0) resolve();
|
|
49
|
+
else reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code}`));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
exec,
|
|
56
|
+
gitExec,
|
|
57
|
+
resolveVoluteBin,
|
|
58
|
+
execInherit
|
|
59
|
+
};
|
|
@@ -37,6 +37,7 @@ async function publish(event) {
|
|
|
37
37
|
}
|
|
38
38
|
const full = { ...event, id, created_at };
|
|
39
39
|
notify(full);
|
|
40
|
+
return id;
|
|
40
41
|
}
|
|
41
42
|
function broadcast(event) {
|
|
42
43
|
const created_at = event.created_at ?? (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
@@ -29,6 +29,14 @@ function isSetupComplete() {
|
|
|
29
29
|
const config = readGlobalConfig();
|
|
30
30
|
return config.setupCompleted === true;
|
|
31
31
|
}
|
|
32
|
+
function isImagegenEnabled() {
|
|
33
|
+
const config = readGlobalConfig();
|
|
34
|
+
const ig = config.imagegen;
|
|
35
|
+
if (!ig) return false;
|
|
36
|
+
if (ig.enabled === true) return true;
|
|
37
|
+
if (ig.providers && Object.keys(ig.providers).length > 0) return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
32
40
|
function migrateSetupCompleted() {
|
|
33
41
|
const config = readGlobalConfig();
|
|
34
42
|
if (config.setup != null && config.setupCompleted == null) {
|
|
@@ -42,5 +50,6 @@ export {
|
|
|
42
50
|
readGlobalConfig,
|
|
43
51
|
writeGlobalConfig,
|
|
44
52
|
isSetupComplete,
|
|
53
|
+
isImagegenEnabled,
|
|
45
54
|
migrateSetupCompleted
|
|
46
55
|
};
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
modeLabel,
|
|
5
5
|
pollHealth,
|
|
6
6
|
startService
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NNB4WIG7.js";
|
|
8
8
|
import {
|
|
9
9
|
readGlobalConfig
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-N432I7QH.js";
|
|
11
11
|
import {
|
|
12
12
|
parseArgs
|
|
13
13
|
} from "./chunk-D424ZQGI.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/volute-config.ts
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
5
|
+
import { dirname, resolve } from "path";
|
|
6
|
+
function readJson(path) {
|
|
7
|
+
if (!existsSync(path)) return null;
|
|
8
|
+
try {
|
|
9
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
10
|
+
} catch (err) {
|
|
11
|
+
console.error(`[volute-config] failed to parse ${path}: ${err}`);
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function readVoluteConfig(mindDir) {
|
|
16
|
+
const path = resolve(mindDir, "home/.config/volute.json");
|
|
17
|
+
return readJson(path);
|
|
18
|
+
}
|
|
19
|
+
function writeVoluteConfig(mindDir, config) {
|
|
20
|
+
const path = resolve(mindDir, "home/.config/volute.json");
|
|
21
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
22
|
+
writeFileSync(path, `${JSON.stringify(config, null, 2)}
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
readVoluteConfig,
|
|
28
|
+
writeVoluteConfig
|
|
29
|
+
};
|