volute 0.30.1 → 0.31.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/dist/{accept-E3PAH3QJ.js → accept-GAKQ3MEH.js} +4 -4
- package/dist/{activity-events-BKBPPUBP.js → activity-events-T5ZRCVAL.js} +2 -2
- package/dist/{ai-service-VAJT5UBS.js → ai-service-UWUPM4T6.js} +5 -3
- package/dist/api.d.ts +238 -111
- package/dist/{archive-WWDBWYN2.js → archive-YBNSJYZZ.js} +2 -2
- package/dist/auth-T5AW2USD.js +43 -0
- package/dist/{bridge-RO37CUFM.js → bridge-4AJ3EY26.js} +4 -4
- package/dist/{chat-TCUNPFGO.js → chat-7YLT7FI3.js} +8 -8
- package/dist/{chunk-EFVHR7KH.js → chunk-4OUOFS23.js} +24 -5
- package/dist/{chunk-G3GBKZGG.js → chunk-57OKQMP3.js} +54 -2
- package/dist/chunk-6QIUN46C.js +38 -0
- package/dist/{chunk-FSM45XD5.js → chunk-AAO77TZX.js} +1 -1
- package/dist/{chunk-DTC6EH5I.js → chunk-BC3P3QCK.js} +1 -1
- package/dist/{chunk-P7VFDSSG.js → chunk-BNC43CSY.js} +2 -2
- package/dist/{chunk-QVAQ5454.js → chunk-BWKIHH7B.js} +3080 -2099
- package/dist/{chunk-IKHDUZRH.js → chunk-DAXJKPHZ.js} +2 -2
- package/dist/{chunk-P27RV5WM.js → chunk-EKDWA7E4.js} +3 -1
- package/dist/{chunk-S5LR3XYJ.js → chunk-EMPFLFTG.js} +1 -1
- package/dist/{chunk-2C2VXEBB.js → chunk-FAHDKPEH.js} +18 -56
- package/dist/{chunk-W5OOPLNP.js → chunk-HDKY4TWU.js} +3 -3
- package/dist/{chunk-EFP3PE6C.js → chunk-HR5JKIDG.js} +2 -12
- package/dist/{chunk-JGFRDMR6.js → chunk-LX6T3GKQ.js} +1 -1
- package/dist/{chunk-2NDZC3S7.js → chunk-NOWVQ7AL.js} +447 -299
- package/dist/{chunk-ZWKTUQEL.js → chunk-NV3TYNWX.js} +1 -1
- package/dist/{chunk-NSBFETWP.js → chunk-PNQCXLSV.js} +7 -26
- package/dist/chunk-R5QJBZZG.js +175 -0
- package/dist/{chunk-MDPCSXZ4.js → chunk-S2TZLSDH.js} +4 -4
- package/dist/{chunk-FXHXHI2A.js → chunk-SNVPRRT7.js} +3 -6
- package/dist/{chunk-UPA6COHU.js → chunk-WRS3B556.js} +5 -5
- package/dist/{chunk-HHTXM4JT.js → chunk-X62AXPR7.js} +36 -4
- package/dist/cli.js +74 -23
- package/dist/{clock-G3ALCMLJ.js → clock-LJCG426D.js} +10 -8
- package/dist/{cloud-sync-JV4LJOK3.js → cloud-sync-O3LXIRN6.js} +13 -13
- package/dist/{conversations-7KVQV7EZ.js → conversations-RKKGP5IA.js} +7 -7
- package/dist/{create-VQSQHJQW.js → create-TL623TFC.js} +1 -1
- package/dist/{create-JTLS7GX3.js → create-WUTIIRI2.js} +4 -4
- package/dist/daemon-client-CVGM25DM.js +11 -0
- package/dist/{daemon-restart-4JGBHEJ4.js → daemon-restart-EZP7XH3V.js} +6 -7
- package/dist/daemon.js +1879 -1727
- package/dist/{db-HMFPIRO2.js → db-SW5PL6QA.js} +1 -1
- package/dist/{delete-JESHKE7F.js → delete-Z6HAG35F.js} +1 -1
- package/dist/down-TS4XQBA4.js +13 -0
- package/dist/{env-CLXXT7M2.js → env-NHESNNSP.js} +4 -4
- package/dist/{export-EGA5M5PB.js → export-EVMP7GWY.js} +3 -3
- package/dist/{extension-WZ4SUPJB.js → extension-LR7EW3JF.js} +5 -6
- package/dist/{extensions-ECO4RPFQ.js → extensions-NGEJI7JH.js} +7 -7
- package/dist/{files-4VEJDASH.js → files-3SM7V33S.js} +5 -5
- package/dist/{history-EJMMLXDO.js → history-PQD3LXEP.js} +4 -4
- package/dist/{import-YCGPMBSI.js → import-PR2OCGQJ.js} +3 -3
- package/dist/{join-2GBJKZEN.js → join-R4EN5CWQ.js} +1 -1
- package/dist/{list-Q6O7FGAN.js → list-B4XNUOFO.js} +4 -4
- package/dist/{login-RL6AU2SM.js → login-62JVY6A2.js} +4 -4
- package/dist/{login-RET5WESK.js → login-URWP6S2N.js} +2 -2
- package/dist/{logout-CGAGJN3L.js → logout-NXJQJDLI.js} +2 -2
- package/dist/{logout-JRPBEMMR.js → logout-ZK2N62T3.js} +2 -2
- package/dist/message-delivery-UJHCLVU4.js +30 -0
- package/dist/{mind-LUWRQUQ5.js → mind-E2ZV2WRX.js} +17 -17
- package/dist/{mind-activity-tracker-VYN2ZZ2M.js → mind-activity-tracker-ASNZBMLC.js} +3 -3
- package/dist/{mind-list-V5WW5DUA.js → mind-list-BEI7E5WY.js} +2 -2
- package/dist/mind-manager-IPA6DZXD.js +26 -0
- package/dist/{mind-sleep-R6PTNNW4.js → mind-sleep-CANABWJI.js} +4 -4
- package/dist/{mind-status-I4ISFJ6I.js → mind-status-6WKZVUOP.js} +2 -2
- package/dist/{mind-wake-67ZQEWAV.js → mind-wake-RZKLH2IN.js} +4 -4
- package/dist/{package-OYUD4ZJ4.js → package-NU4CA7OU.js} +3 -3
- package/dist/{pages-watcher-Z3PKNROC.js → pages-watcher-72OVPRMH.js} +4 -3
- package/dist/read-THL362EI.js +74 -0
- package/dist/{register-NZDSTLP3.js → register-QAQELAS6.js} +4 -4
- package/dist/{registry-ODSALQQL.js → registry-ASXCQCNH.js} +1 -1
- package/dist/{reject-2HZOJEIJ.js → reject-AYPBNPNL.js} +4 -4
- package/dist/{restart-QHS3NT64.js → restart-6SKPV3T2.js} +4 -4
- package/dist/{sandbox-O5FUSF43.js → sandbox-6ZEWQDVU.js} +3 -3
- package/dist/{seed-WUQMPLDM.js → seed-OWX2AW75.js} +36 -12
- package/dist/{send-OAN3RYYY.js → send-ZO4BTWXK.js} +5 -5
- package/dist/{setup-QMDK5RZX.js → setup-7CFITEQN.js} +2 -4
- package/dist/{setup-XJH3E7YM.js → setup-ZXBXG7E4.js} +6 -8
- package/dist/{skill-FZIN4W4Q.js → skill-YFXP67A2.js} +4 -4
- package/dist/skills/dreaming/references/INSTALL.md +2 -3
- package/dist/skills/dreaming/scripts/dream.ts +3 -25
- package/dist/skills/volute-mind/SKILL.md +1 -1
- package/dist/sleep-manager-TPS6OGCA.js +30 -0
- package/dist/{split-EXYGGGQN.js → split-MI62KJUU.js} +1 -1
- package/dist/{sprout-AXQ6H5DB.js → sprout-FDVI2CGN.js} +5 -6
- package/dist/{start-MTOVL6SY.js → start-D64BRKPH.js} +4 -4
- package/dist/{status-ZRO37MWR.js → status-ZZWBYFGE.js} +4 -5
- package/dist/{stop-OK5WEPVC.js → stop-OP2CTXCO.js} +4 -4
- package/dist/system-chat-B43GIXQU.js +30 -0
- package/dist/{systems-W3BBMSOZ.js → systems-EQPPT4B7.js} +5 -5
- package/dist/{tailscale-BM72RXCJ.js → tailscale-6DJKUMNF.js} +1 -1
- package/dist/up-TDXEP3VA.js +16 -0
- package/dist/{update-PLPHMMZ2.js → update-KUJXATRS.js} +4 -5
- package/dist/{update-check-CVCN7MF6.js → update-check-5WVSU37T.js} +2 -2
- package/dist/{upgrade-I6NPCYUU.js → upgrade-KBHCWX6T.js} +1 -1
- package/dist/{version-notify-2NTWVEHL.js → version-notify-75ELVKPV.js} +17 -21
- package/dist/web-assets/assets/index-BM1cTzBg.js +72 -0
- package/dist/web-assets/assets/index-BfJkKTPF.css +1 -0
- package/dist/web-assets/ext-theme.css +1 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0000_baseline.sql +152 -0
- package/drizzle/0001_add_conversation_private.sql +1 -0
- package/drizzle/0002_turns.sql +21 -0
- package/drizzle/0003_turn_feed_links.sql +11 -0
- package/drizzle/meta/0000_snapshot.json +3 -223
- package/drizzle/meta/0001_snapshot.json +3 -294
- package/drizzle/meta/0002_snapshot.json +3 -335
- package/drizzle/meta/0003_snapshot.json +3 -413
- package/drizzle/meta/_journal.json +8 -106
- package/package.json +3 -3
- package/packages/extensions/notes/dist/ui/assets/{index-DgawVO5g.css → index-B8GdTnXs.css} +1 -1
- package/packages/extensions/notes/dist/ui/assets/index-CDpGTCWb.js +2 -0
- package/packages/extensions/notes/dist/ui/index.html +2 -2
- package/packages/extensions/notes/skills/notes/SKILL.md +8 -8
- package/packages/extensions/pages/skills/pages/SKILL.md +7 -4
- package/packages/extensions/pages/skills/pages/scripts/pages.mjs +58 -0
- package/templates/_base/.init/.config/bin/volute +27 -0
- package/templates/_base/src/lib/auto-commit.ts +82 -43
- package/templates/_base/src/lib/daemon-client.ts +19 -23
- package/templates/_base/src/lib/router.ts +17 -1
- package/templates/_base/src/lib/startup.ts +6 -8
- package/templates/_base/src/lib/volute-server.ts +2 -5
- package/templates/claude/src/agent.ts +2 -1
- package/templates/claude/src/lib/hooks/auto-commit.ts +7 -3
- package/templates/claude/src/server.ts +0 -9
- package/templates/pi/package.json.tmpl +1 -1
- package/templates/pi/src/agent.ts +1 -1
- package/templates/pi/src/lib/event-handler.ts +5 -3
- package/dist/chunk-7D47T4RB.js +0 -84
- package/dist/chunk-CVH6Y2YG.js +0 -59
- package/dist/chunk-LIRWLNAK.js +0 -729
- package/dist/daemon-client-BCTFGVCZ.js +0 -9
- package/dist/down-NGBMGORS.js +0 -14
- package/dist/message-delivery-6YMVNOEC.js +0 -28
- package/dist/migrate-registry-to-db-FK35IPEH.js +0 -110
- package/dist/mind-manager-YFCOIAAX.js +0 -18
- package/dist/read-WQMPTSN2.js +0 -46
- package/dist/sleep-manager-O7YQFCV5.js +0 -30
- package/dist/up-BXUAIDXB.js +0 -17
- package/dist/web-assets/assets/index--kREqKl9.js +0 -72
- package/dist/web-assets/assets/index-BXYTG0nJ.css +0 -1
- package/drizzle/0000_flaky_mariko_yashida.sql +0 -34
- package/drizzle/0001_careless_warpath.sql +0 -12
- package/drizzle/0002_wealthy_the_call.sql +0 -6
- package/drizzle/0003_clean_ego.sql +0 -12
- package/drizzle/0004_magical_silverclaw.sql +0 -1
- package/drizzle/0005_rename_agents_to_minds.sql +0 -11
- package/drizzle/0006_mind_history.sql +0 -20
- package/drizzle/0007_system_prompts.sql +0 -5
- package/drizzle/0008_volute_channels.sql +0 -24
- package/drizzle/0009_shared_skills.sql +0 -9
- package/drizzle/0010_delivery_queue.sql +0 -12
- package/drizzle/0011_rename_human_to_brain.sql +0 -1
- package/drizzle/0012_activity.sql +0 -11
- package/drizzle/0013_user_profiles.sql +0 -3
- package/drizzle/0014_conversation_reads.sql +0 -7
- package/drizzle/0015_notes.sql +0 -23
- package/drizzle/0016_note_reactions_and_replies.sql +0 -15
- package/drizzle/0017_minds.sql +0 -16
- package/drizzle/meta/0004_snapshot.json +0 -410
- package/drizzle/meta/0005_snapshot.json +0 -410
- package/drizzle/meta/0006_snapshot.json +0 -7
- package/drizzle/meta/0007_snapshot.json +0 -7
- package/drizzle/meta/0008_snapshot.json +0 -7
- package/drizzle/meta/0009_snapshot.json +0 -7
- package/drizzle/meta/0010_snapshot.json +0 -7
- package/drizzle/meta/0011_snapshot.json +0 -7
- package/drizzle/meta/0012_snapshot.json +0 -7
- package/drizzle/meta/0013_snapshot.json +0 -7
- package/packages/extensions/notes/dist/ui/assets/index-qUWoeC4c.js +0 -2
- package/packages/extensions/notes/skills/notes/scripts/notes.mjs +0 -185
- package/templates/_base/home/public/.gitkeep +0 -0
|
@@ -5,36 +5,15 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
readGlobalConfig,
|
|
7
7
|
writeGlobalConfig
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6QIUN46C.js";
|
|
9
9
|
|
|
10
10
|
// src/lib/ai-service.ts
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
getEnvApiKey,
|
|
14
|
-
getModel,
|
|
15
|
-
getModels,
|
|
16
|
-
getOAuthApiKey,
|
|
17
|
-
getProviders
|
|
18
|
-
} from "@mariozechner/pi-ai";
|
|
11
|
+
import { complete, getEnvApiKey, getModel, getModels, getProviders } from "@mariozechner/pi-ai";
|
|
12
|
+
import { getOAuthApiKey } from "@mariozechner/pi-ai/oauth";
|
|
19
13
|
var aiLog = logger_default.child("ai-service");
|
|
20
14
|
function getAiConfig() {
|
|
21
15
|
const config = readGlobalConfig();
|
|
22
|
-
|
|
23
|
-
const ai = config.ai;
|
|
24
|
-
if ("provider" in ai && !("providers" in ai)) {
|
|
25
|
-
const old = ai;
|
|
26
|
-
const migrated = {
|
|
27
|
-
providers: {
|
|
28
|
-
[old.provider]: {
|
|
29
|
-
...old.apiKey ? { apiKey: old.apiKey } : {},
|
|
30
|
-
...old.oauth ? { oauth: old.oauth } : {}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
writeGlobalConfig({ ...config, ai: migrated });
|
|
35
|
-
return migrated;
|
|
36
|
-
}
|
|
37
|
-
return config.ai;
|
|
16
|
+
return config.ai ?? null;
|
|
38
17
|
}
|
|
39
18
|
function saveProviderConfig(providerId, providerConfig) {
|
|
40
19
|
const ai = getAiConfig() ?? { providers: {} };
|
|
@@ -95,7 +74,7 @@ function getAvailableModels() {
|
|
|
95
74
|
try {
|
|
96
75
|
models.push(...getModels(provider));
|
|
97
76
|
} catch (err) {
|
|
98
|
-
aiLog.
|
|
77
|
+
aiLog.warn(`failed to load models for provider ${provider}`, logger_default.errorData(err));
|
|
99
78
|
}
|
|
100
79
|
}
|
|
101
80
|
return models;
|
|
@@ -154,6 +133,7 @@ async function aiComplete(systemPrompt, userMessage, modelId) {
|
|
|
154
133
|
const model = modelId ? findModel(modelId) : autoSelectModel();
|
|
155
134
|
if (!model) {
|
|
156
135
|
if (modelId) aiLog.warn(`model not found: ${modelId}`);
|
|
136
|
+
else aiLog.debug("no enabled model available for auto-selection");
|
|
157
137
|
return null;
|
|
158
138
|
}
|
|
159
139
|
try {
|
|
@@ -184,5 +164,6 @@ export {
|
|
|
184
164
|
getEnabledModels,
|
|
185
165
|
setEnabledModels,
|
|
186
166
|
getAvailableModels,
|
|
167
|
+
resolveApiKey,
|
|
187
168
|
aiComplete
|
|
188
169
|
};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
broadcast
|
|
4
|
+
} from "./chunk-EKDWA7E4.js";
|
|
5
|
+
import {
|
|
6
|
+
getDb,
|
|
7
|
+
users
|
|
8
|
+
} from "./chunk-X62AXPR7.js";
|
|
9
|
+
|
|
10
|
+
// src/lib/auth.ts
|
|
11
|
+
import { compareSync, hashSync } from "bcryptjs";
|
|
12
|
+
import { and, count, eq } from "drizzle-orm";
|
|
13
|
+
var userSelectFields = {
|
|
14
|
+
id: users.id,
|
|
15
|
+
username: users.username,
|
|
16
|
+
role: users.role,
|
|
17
|
+
user_type: users.user_type,
|
|
18
|
+
display_name: users.display_name,
|
|
19
|
+
description: users.description,
|
|
20
|
+
avatar: users.avatar,
|
|
21
|
+
created_at: users.created_at
|
|
22
|
+
};
|
|
23
|
+
async function createUser(username, password) {
|
|
24
|
+
const db = await getDb();
|
|
25
|
+
const hash = hashSync(password, 10);
|
|
26
|
+
const [{ value }] = await db.select({ value: count() }).from(users).where(eq(users.user_type, "brain"));
|
|
27
|
+
const role = value === 0 ? "admin" : "pending";
|
|
28
|
+
const [result] = await db.insert(users).values({ username, password_hash: hash, role }).returning(userSelectFields);
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
async function verifyUser(username, password) {
|
|
32
|
+
const db = await getDb();
|
|
33
|
+
const row = await db.select().from(users).where(eq(users.username, username)).get();
|
|
34
|
+
if (!row) return null;
|
|
35
|
+
if (row.user_type === "mind" || row.user_type === "system") return null;
|
|
36
|
+
if (!compareSync(password, row.password_hash)) return null;
|
|
37
|
+
const { password_hash: _, ...user } = row;
|
|
38
|
+
return user;
|
|
39
|
+
}
|
|
40
|
+
async function getUser(id) {
|
|
41
|
+
const db = await getDb();
|
|
42
|
+
const row = await db.select(userSelectFields).from(users).where(eq(users.id, id)).get();
|
|
43
|
+
return row ?? null;
|
|
44
|
+
}
|
|
45
|
+
async function getUserByUsername(username) {
|
|
46
|
+
const db = await getDb();
|
|
47
|
+
const row = await db.select(userSelectFields).from(users).where(eq(users.username, username)).get();
|
|
48
|
+
return row ?? null;
|
|
49
|
+
}
|
|
50
|
+
async function listUsers() {
|
|
51
|
+
const db = await getDb();
|
|
52
|
+
return db.select(userSelectFields).from(users).orderBy(users.created_at).all();
|
|
53
|
+
}
|
|
54
|
+
async function listPendingUsers() {
|
|
55
|
+
const db = await getDb();
|
|
56
|
+
return db.select(userSelectFields).from(users).where(eq(users.role, "pending")).orderBy(users.created_at).all();
|
|
57
|
+
}
|
|
58
|
+
async function listUsersByType(userType) {
|
|
59
|
+
const db = await getDb();
|
|
60
|
+
return db.select(userSelectFields).from(users).where(eq(users.user_type, userType)).orderBy(users.created_at).all();
|
|
61
|
+
}
|
|
62
|
+
async function getOrCreateMindUser(mindName) {
|
|
63
|
+
const db = await getDb();
|
|
64
|
+
const existing = await db.select(userSelectFields).from(users).where(and(eq(users.username, mindName), eq(users.user_type, "mind"))).get();
|
|
65
|
+
if (existing) return existing;
|
|
66
|
+
try {
|
|
67
|
+
const [result] = await db.insert(users).values({
|
|
68
|
+
username: mindName,
|
|
69
|
+
password_hash: "!mind",
|
|
70
|
+
role: "user",
|
|
71
|
+
user_type: "mind"
|
|
72
|
+
}).returning(userSelectFields);
|
|
73
|
+
return result;
|
|
74
|
+
} catch (err) {
|
|
75
|
+
if (err instanceof Error && err.message.includes("UNIQUE constraint")) {
|
|
76
|
+
const retried = await db.select(userSelectFields).from(users).where(and(eq(users.username, mindName), eq(users.user_type, "mind"))).get();
|
|
77
|
+
if (retried) return retried;
|
|
78
|
+
}
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function getOrCreateSystemUser() {
|
|
83
|
+
const db = await getDb();
|
|
84
|
+
const existing = await db.select(userSelectFields).from(users).where(and(eq(users.username, "volute"), eq(users.user_type, "system"))).get();
|
|
85
|
+
if (existing) return existing;
|
|
86
|
+
try {
|
|
87
|
+
const [result] = await db.insert(users).values({
|
|
88
|
+
username: "volute",
|
|
89
|
+
password_hash: "!system",
|
|
90
|
+
role: "user",
|
|
91
|
+
user_type: "system",
|
|
92
|
+
display_name: "Volute"
|
|
93
|
+
}).returning(userSelectFields);
|
|
94
|
+
return result;
|
|
95
|
+
} catch (err) {
|
|
96
|
+
if (err instanceof Error && err.message.includes("UNIQUE constraint")) {
|
|
97
|
+
const retried = await db.select(userSelectFields).from(users).where(and(eq(users.username, "volute"), eq(users.user_type, "system"))).get();
|
|
98
|
+
if (retried) return retried;
|
|
99
|
+
}
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async function deleteMindUser(mindName) {
|
|
104
|
+
const db = await getDb();
|
|
105
|
+
await db.delete(users).where(and(eq(users.username, mindName), eq(users.user_type, "mind")));
|
|
106
|
+
}
|
|
107
|
+
async function changePassword(userId, currentPassword, newPassword) {
|
|
108
|
+
const db = await getDb();
|
|
109
|
+
const row = await db.select().from(users).where(eq(users.id, userId)).get();
|
|
110
|
+
if (!row) return false;
|
|
111
|
+
if (!compareSync(currentPassword, row.password_hash)) return false;
|
|
112
|
+
const hash = hashSync(newPassword, 10);
|
|
113
|
+
await db.update(users).set({ password_hash: hash }).where(eq(users.id, userId));
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
async function approveUser(id) {
|
|
117
|
+
const db = await getDb();
|
|
118
|
+
await db.update(users).set({ role: "user" }).where(and(eq(users.id, id), eq(users.role, "pending")));
|
|
119
|
+
}
|
|
120
|
+
async function countAdmins() {
|
|
121
|
+
const db = await getDb();
|
|
122
|
+
const [{ value }] = await db.select({ value: count() }).from(users).where(eq(users.role, "admin"));
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
async function setUserRole(id, role) {
|
|
126
|
+
const db = await getDb();
|
|
127
|
+
const target = await db.select({ id: users.id }).from(users).where(eq(users.id, id)).get();
|
|
128
|
+
if (!target) throw new Error("User not found");
|
|
129
|
+
await db.update(users).set({ role }).where(eq(users.id, id));
|
|
130
|
+
}
|
|
131
|
+
async function deleteUser(id) {
|
|
132
|
+
const db = await getDb();
|
|
133
|
+
const target = await db.select({ id: users.id }).from(users).where(and(eq(users.id, id), eq(users.user_type, "brain"))).get();
|
|
134
|
+
if (!target) throw new Error("User not found");
|
|
135
|
+
await db.delete(users).where(and(eq(users.id, id), eq(users.user_type, "brain")));
|
|
136
|
+
}
|
|
137
|
+
async function updateUserProfile(userId, profile) {
|
|
138
|
+
const db = await getDb();
|
|
139
|
+
const target = await db.select({ id: users.id }).from(users).where(eq(users.id, userId)).get();
|
|
140
|
+
if (!target) throw new Error("User not found");
|
|
141
|
+
await db.update(users).set(profile).where(eq(users.id, userId));
|
|
142
|
+
}
|
|
143
|
+
async function syncMindProfile(mindName, config) {
|
|
144
|
+
const user = await getOrCreateMindUser(mindName);
|
|
145
|
+
const newProfile = {
|
|
146
|
+
display_name: config.displayName ?? null,
|
|
147
|
+
description: config.description ?? null,
|
|
148
|
+
avatar: config.avatar ?? null
|
|
149
|
+
};
|
|
150
|
+
const changed = user.display_name !== newProfile.display_name || user.description !== newProfile.description || user.avatar !== newProfile.avatar;
|
|
151
|
+
if (!changed) return;
|
|
152
|
+
const db = await getDb();
|
|
153
|
+
await db.update(users).set(newProfile).where(eq(users.id, user.id));
|
|
154
|
+
broadcast({ type: "profile_updated", mind: mindName, summary: `${mindName} profile updated` });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export {
|
|
158
|
+
createUser,
|
|
159
|
+
verifyUser,
|
|
160
|
+
getUser,
|
|
161
|
+
getUserByUsername,
|
|
162
|
+
listUsers,
|
|
163
|
+
listPendingUsers,
|
|
164
|
+
listUsersByType,
|
|
165
|
+
getOrCreateMindUser,
|
|
166
|
+
getOrCreateSystemUser,
|
|
167
|
+
deleteMindUser,
|
|
168
|
+
changePassword,
|
|
169
|
+
approveUser,
|
|
170
|
+
countAdmins,
|
|
171
|
+
setUserRole,
|
|
172
|
+
deleteUser,
|
|
173
|
+
updateUserProfile,
|
|
174
|
+
syncMindProfile
|
|
175
|
+
};
|
|
@@ -5,16 +5,16 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
exec,
|
|
7
7
|
gitExec
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-57OKQMP3.js";
|
|
9
9
|
import {
|
|
10
10
|
readGlobalConfig,
|
|
11
11
|
writeGlobalConfig
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-6QIUN46C.js";
|
|
13
13
|
import {
|
|
14
14
|
getDb,
|
|
15
15
|
sharedSkills,
|
|
16
16
|
voluteHome
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-X62AXPR7.js";
|
|
18
18
|
|
|
19
19
|
// src/lib/skills.ts
|
|
20
20
|
import { createHash } from "crypto";
|
|
@@ -42,7 +42,7 @@ async function initDefaultSkills() {
|
|
|
42
42
|
const config = readGlobalConfig();
|
|
43
43
|
let extensionSkills = [];
|
|
44
44
|
try {
|
|
45
|
-
const { getExtensionStandardSkills } = await import("./extensions-
|
|
45
|
+
const { getExtensionStandardSkills } = await import("./extensions-NGEJI7JH.js");
|
|
46
46
|
extensionSkills = getExtensionStandardSkills();
|
|
47
47
|
} catch (err) {
|
|
48
48
|
logger_default.warn("failed to load extension standard skills during init", logger_default.errorData(err));
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
exec,
|
|
4
4
|
execInherit
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-57OKQMP3.js";
|
|
6
6
|
import {
|
|
7
|
-
voluteHome,
|
|
8
7
|
voluteSystemDir
|
|
9
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-X62AXPR7.js";
|
|
10
9
|
|
|
11
10
|
// src/lib/service-mode.ts
|
|
12
11
|
import { execFileSync } from "child_process";
|
|
@@ -170,9 +169,7 @@ async function restartService(mode) {
|
|
|
170
169
|
}
|
|
171
170
|
}
|
|
172
171
|
function readDaemonConfig() {
|
|
173
|
-
const
|
|
174
|
-
const legacyPath = resolve(voluteHome(), "daemon.json");
|
|
175
|
-
const configPath = existsSync(newPath) ? newPath : legacyPath;
|
|
172
|
+
const configPath = resolve(voluteSystemDir(), "daemon.json");
|
|
176
173
|
if (!existsSync(configPath)) return { hostname: "127.0.0.1", port: 1618 };
|
|
177
174
|
try {
|
|
178
175
|
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
readEnv,
|
|
4
4
|
sharedEnvPath,
|
|
5
5
|
writeEnv
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-NV3TYNWX.js";
|
|
7
7
|
import {
|
|
8
8
|
logger_default
|
|
9
9
|
} from "./chunk-YUIHSKR6.js";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-D424ZQGI.js";
|
|
13
13
|
import {
|
|
14
14
|
voluteSystemDir
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-X62AXPR7.js";
|
|
16
16
|
|
|
17
17
|
// src/commands/import.ts
|
|
18
18
|
import {
|
|
@@ -112,7 +112,7 @@ async function run(args) {
|
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
const wsDir = resolveWorkspace(inputPath);
|
|
115
|
-
const { daemonFetch } = await import("./daemon-client-
|
|
115
|
+
const { daemonFetch } = await import("./daemon-client-CVGM25DM.js");
|
|
116
116
|
const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
|
|
117
117
|
const client = getClient();
|
|
118
118
|
const res = await daemonFetch(urlOf(client.api.minds.import.$url()), {
|
|
@@ -152,7 +152,7 @@ async function importArchive(archivePath, nameOverride) {
|
|
|
152
152
|
console.error(`File not found: ${archivePath}`);
|
|
153
153
|
process.exit(1);
|
|
154
154
|
}
|
|
155
|
-
const { extractArchive } = await import("./archive-
|
|
155
|
+
const { extractArchive } = await import("./archive-YBNSJYZZ.js");
|
|
156
156
|
const tempDir = resolve2(tmpdir(), `volute-import-${Date.now()}`);
|
|
157
157
|
mkdirSync(tempDir, { recursive: true });
|
|
158
158
|
let extracted;
|
|
@@ -164,7 +164,7 @@ async function importArchive(archivePath, nameOverride) {
|
|
|
164
164
|
process.exit(1);
|
|
165
165
|
}
|
|
166
166
|
try {
|
|
167
|
-
const { daemonFetch } = await import("./daemon-client-
|
|
167
|
+
const { daemonFetch } = await import("./daemon-client-CVGM25DM.js");
|
|
168
168
|
const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
|
|
169
169
|
const client = getClient();
|
|
170
170
|
const res = await daemonFetch(urlOf(client.api.minds.import.$url()), {
|
|
@@ -31,6 +31,7 @@ __export(schema_exports, {
|
|
|
31
31
|
sessions: () => sessions,
|
|
32
32
|
sharedSkills: () => sharedSkills,
|
|
33
33
|
systemPrompts: () => systemPrompts,
|
|
34
|
+
turns: () => turns,
|
|
34
35
|
users: () => users
|
|
35
36
|
});
|
|
36
37
|
import { sql } from "drizzle-orm";
|
|
@@ -72,6 +73,7 @@ var conversations = sqliteTable(
|
|
|
72
73
|
name: text("name"),
|
|
73
74
|
user_id: integer("user_id").references(() => users.id),
|
|
74
75
|
title: text("title"),
|
|
76
|
+
private: integer("private").notNull().default(0),
|
|
75
77
|
created_at: text("created_at").notNull().default(sql`(datetime('now'))`),
|
|
76
78
|
updated_at: text("updated_at").notNull().default(sql`(datetime('now'))`)
|
|
77
79
|
},
|
|
@@ -82,6 +84,22 @@ var conversations = sqliteTable(
|
|
|
82
84
|
uniqueIndex("idx_conversations_name").on(table.name)
|
|
83
85
|
]
|
|
84
86
|
);
|
|
87
|
+
var turns = sqliteTable(
|
|
88
|
+
"turns",
|
|
89
|
+
{
|
|
90
|
+
id: text("id").primaryKey(),
|
|
91
|
+
mind: text("mind").notNull(),
|
|
92
|
+
session: text("session"),
|
|
93
|
+
trigger_event_id: integer("trigger_event_id"),
|
|
94
|
+
summary_event_id: integer("summary_event_id"),
|
|
95
|
+
status: text("status").notNull().default("active"),
|
|
96
|
+
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
97
|
+
},
|
|
98
|
+
(table) => [
|
|
99
|
+
index("idx_turns_mind").on(table.mind),
|
|
100
|
+
index("idx_turns_mind_status").on(table.mind, table.status)
|
|
101
|
+
]
|
|
102
|
+
);
|
|
85
103
|
var mindHistory = sqliteTable(
|
|
86
104
|
"mind_history",
|
|
87
105
|
{
|
|
@@ -94,12 +112,14 @@ var mindHistory = sqliteTable(
|
|
|
94
112
|
type: text("type").notNull(),
|
|
95
113
|
content: text("content"),
|
|
96
114
|
metadata: text("metadata"),
|
|
115
|
+
turn_id: text("turn_id"),
|
|
97
116
|
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
98
117
|
},
|
|
99
118
|
(table) => [
|
|
100
119
|
index("idx_mind_history_mind").on(table.mind),
|
|
101
120
|
index("idx_mind_history_mind_channel").on(table.mind, table.channel),
|
|
102
|
-
index("idx_mind_history_mind_type").on(table.mind, table.type)
|
|
121
|
+
index("idx_mind_history_mind_type").on(table.mind, table.type),
|
|
122
|
+
index("idx_mind_history_turn_id").on(table.turn_id)
|
|
103
123
|
]
|
|
104
124
|
);
|
|
105
125
|
var conversationParticipants = sqliteTable(
|
|
@@ -159,11 +179,14 @@ var activity = sqliteTable(
|
|
|
159
179
|
mind: text("mind").notNull(),
|
|
160
180
|
summary: text("summary").notNull(),
|
|
161
181
|
metadata: text("metadata"),
|
|
182
|
+
turn_id: text("turn_id"),
|
|
183
|
+
source_event_id: integer("source_event_id"),
|
|
162
184
|
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
163
185
|
},
|
|
164
186
|
(table) => [
|
|
165
187
|
index("idx_activity_created_at").on(table.created_at),
|
|
166
|
-
index("idx_activity_mind").on(table.mind)
|
|
188
|
+
index("idx_activity_mind").on(table.mind),
|
|
189
|
+
index("idx_activity_turn_id").on(table.turn_id)
|
|
167
190
|
]
|
|
168
191
|
);
|
|
169
192
|
var conversationReads = sqliteTable(
|
|
@@ -185,9 +208,14 @@ var messages = sqliteTable(
|
|
|
185
208
|
role: text("role").notNull(),
|
|
186
209
|
sender_name: text("sender_name"),
|
|
187
210
|
content: text("content").notNull(),
|
|
211
|
+
source_event_id: integer("source_event_id"),
|
|
212
|
+
turn_id: text("turn_id"),
|
|
188
213
|
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
189
214
|
},
|
|
190
|
-
(table) => [
|
|
215
|
+
(table) => [
|
|
216
|
+
index("idx_messages_conversation_id").on(table.conversation_id),
|
|
217
|
+
index("idx_messages_turn_id").on(table.turn_id)
|
|
218
|
+
]
|
|
191
219
|
);
|
|
192
220
|
|
|
193
221
|
// src/lib/registry.ts
|
|
@@ -242,12 +270,16 @@ async function readAllMinds() {
|
|
|
242
270
|
}
|
|
243
271
|
var MIND_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
244
272
|
var MIND_NAME_MAX = 64;
|
|
273
|
+
var RESERVED_NAMES = /* @__PURE__ */ new Set(["volute", "system"]);
|
|
245
274
|
function validateMindName(name) {
|
|
246
275
|
if (!name) return "Mind name is required";
|
|
247
276
|
if (name.length > MIND_NAME_MAX) return `Mind name must be at most ${MIND_NAME_MAX} characters`;
|
|
248
277
|
if (!MIND_NAME_RE.test(name)) {
|
|
249
278
|
return "Mind name must start with alphanumeric and contain only alphanumeric, dots, dashes, or underscores";
|
|
250
279
|
}
|
|
280
|
+
if (RESERVED_NAMES.has(name.toLowerCase())) {
|
|
281
|
+
return `"${name}" is a reserved name`;
|
|
282
|
+
}
|
|
251
283
|
return null;
|
|
252
284
|
}
|
|
253
285
|
async function addMind(name, port, stage, template) {
|
|
@@ -346,9 +378,9 @@ async function getDb() {
|
|
|
346
378
|
}
|
|
347
379
|
|
|
348
380
|
export {
|
|
349
|
-
minds,
|
|
350
381
|
users,
|
|
351
382
|
conversations,
|
|
383
|
+
turns,
|
|
352
384
|
mindHistory,
|
|
353
385
|
conversationParticipants,
|
|
354
386
|
sessions,
|
package/dist/cli.js
CHANGED
|
@@ -10,14 +10,13 @@ if (!process.env.VOLUTE_HOME) {
|
|
|
10
10
|
var command = process.argv[2];
|
|
11
11
|
var args = process.argv.slice(3);
|
|
12
12
|
if (command === "--version" || command === "-v") {
|
|
13
|
-
const { default: pkg } = await import("./package-
|
|
13
|
+
const { default: pkg } = await import("./package-NU4CA7OU.js");
|
|
14
14
|
console.log(pkg.version);
|
|
15
15
|
process.exit(0);
|
|
16
16
|
}
|
|
17
17
|
var ungatedCommands = /* @__PURE__ */ new Set(["setup", "--help", "-h", "--version", "-v", "update", void 0]);
|
|
18
18
|
if (!ungatedCommands.has(command)) {
|
|
19
|
-
const { isSetupComplete
|
|
20
|
-
migrateSetupConfig();
|
|
19
|
+
const { isSetupComplete } = await import("./setup-7CFITEQN.js");
|
|
21
20
|
if (!isSetupComplete()) {
|
|
22
21
|
console.error("Volute is not set up. Run `volute setup` first.");
|
|
23
22
|
process.exit(1);
|
|
@@ -25,55 +24,52 @@ if (!ungatedCommands.has(command)) {
|
|
|
25
24
|
}
|
|
26
25
|
switch (command) {
|
|
27
26
|
case "setup":
|
|
28
|
-
await import("./setup-
|
|
27
|
+
await import("./setup-ZXBXG7E4.js").then((m) => m.run(args));
|
|
29
28
|
break;
|
|
30
29
|
case "mind":
|
|
31
|
-
await import("./mind-
|
|
30
|
+
await import("./mind-E2ZV2WRX.js").then((m) => m.run(args));
|
|
32
31
|
break;
|
|
33
32
|
case "chat":
|
|
34
|
-
await import("./chat-
|
|
33
|
+
await import("./chat-7YLT7FI3.js").then((m) => m.run(args));
|
|
35
34
|
break;
|
|
36
35
|
case "variant":
|
|
37
36
|
await import("./variant-7TGZHOU3.js").then((m) => m.run(args));
|
|
38
37
|
break;
|
|
39
38
|
case "clock":
|
|
40
|
-
await import("./clock-
|
|
41
|
-
break;
|
|
42
|
-
case "schedule":
|
|
43
|
-
await import("./clock-G3ALCMLJ.js").then((m) => m.run(args));
|
|
39
|
+
await import("./clock-LJCG426D.js").then((m) => m.run(args));
|
|
44
40
|
break;
|
|
45
41
|
case "skill":
|
|
46
|
-
await import("./skill-
|
|
42
|
+
await import("./skill-YFXP67A2.js").then((m) => m.run(args));
|
|
47
43
|
break;
|
|
48
44
|
case "env":
|
|
49
|
-
await import("./env-
|
|
45
|
+
await import("./env-NHESNNSP.js").then((m) => m.run(args));
|
|
50
46
|
break;
|
|
51
47
|
case "up":
|
|
52
|
-
await import("./up-
|
|
48
|
+
await import("./up-TDXEP3VA.js").then((m) => m.run(args));
|
|
53
49
|
break;
|
|
54
50
|
case "down":
|
|
55
|
-
await import("./down-
|
|
51
|
+
await import("./down-TS4XQBA4.js").then((m) => m.run(args));
|
|
56
52
|
break;
|
|
57
53
|
case "restart":
|
|
58
|
-
await import("./daemon-restart-
|
|
54
|
+
await import("./daemon-restart-EZP7XH3V.js").then((m) => m.run(args));
|
|
59
55
|
break;
|
|
60
56
|
case "update":
|
|
61
|
-
await import("./update-
|
|
57
|
+
await import("./update-KUJXATRS.js").then((m) => m.run(args));
|
|
62
58
|
break;
|
|
63
59
|
case "status":
|
|
64
|
-
await import("./status-
|
|
60
|
+
await import("./status-ZZWBYFGE.js").then((m) => m.run(args));
|
|
65
61
|
break;
|
|
66
62
|
case "extension":
|
|
67
|
-
await import("./extension-
|
|
63
|
+
await import("./extension-LR7EW3JF.js").then((m) => m.run(args));
|
|
68
64
|
break;
|
|
69
65
|
case "systems":
|
|
70
|
-
await import("./systems-
|
|
66
|
+
await import("./systems-EQPPT4B7.js").then((m) => m.run(args));
|
|
71
67
|
break;
|
|
72
68
|
case "login":
|
|
73
|
-
await import("./login-
|
|
69
|
+
await import("./login-URWP6S2N.js").then((m) => m.run(args));
|
|
74
70
|
break;
|
|
75
71
|
case "logout":
|
|
76
|
-
await import("./logout-
|
|
72
|
+
await import("./logout-NXJQJDLI.js").then((m) => m.run(args));
|
|
77
73
|
break;
|
|
78
74
|
case "--help":
|
|
79
75
|
case "-h":
|
|
@@ -111,6 +107,10 @@ System:
|
|
|
111
107
|
update Update volute
|
|
112
108
|
systems register/login/logout volute.systems account
|
|
113
109
|
|
|
110
|
+
Extensions:
|
|
111
|
+
notes write/list/read/... Manage notes
|
|
112
|
+
pages notify Notify page updates
|
|
113
|
+
|
|
114
114
|
Options:
|
|
115
115
|
--version, -v Show version number
|
|
116
116
|
--help, -h Show this help message
|
|
@@ -120,13 +120,64 @@ Run 'volute <command> --help' for details.
|
|
|
120
120
|
Mind-scoped commands (chat, clock, skill)
|
|
121
121
|
use --mind <name> or VOLUTE_MIND env var to identify the mind.`);
|
|
122
122
|
break;
|
|
123
|
-
default:
|
|
123
|
+
default: {
|
|
124
|
+
let isExtensionCommand = false;
|
|
125
|
+
try {
|
|
126
|
+
const { daemonFetch } = await import("./daemon-client-CVGM25DM.js");
|
|
127
|
+
const res = await daemonFetch("/api/extensions/commands");
|
|
128
|
+
if (res.ok) {
|
|
129
|
+
const extCommands = await res.json();
|
|
130
|
+
if (command && command in extCommands) {
|
|
131
|
+
isExtensionCommand = true;
|
|
132
|
+
const subcommand = args[0];
|
|
133
|
+
const ext = extCommands[command];
|
|
134
|
+
if (!subcommand || !(subcommand in ext.commands)) {
|
|
135
|
+
console.log(`volute ${command} \u2014 ${Object.keys(ext.commands).join(", ")}
|
|
136
|
+
`);
|
|
137
|
+
for (const [name, meta] of Object.entries(ext.commands)) {
|
|
138
|
+
console.log(` ${name.padEnd(12)} ${meta.description}`);
|
|
139
|
+
}
|
|
140
|
+
process.exit(0);
|
|
141
|
+
}
|
|
142
|
+
const cmdArgs = args.slice(1);
|
|
143
|
+
let mind = process.env.VOLUTE_MIND;
|
|
144
|
+
const mindIdx = cmdArgs.indexOf("--mind");
|
|
145
|
+
if (mindIdx !== -1 && cmdArgs[mindIdx + 1]) {
|
|
146
|
+
mind = cmdArgs[mindIdx + 1];
|
|
147
|
+
cmdArgs.splice(mindIdx, 2);
|
|
148
|
+
}
|
|
149
|
+
const cmdRes = await daemonFetch(`/api/ext/${command}/commands/${subcommand}`, {
|
|
150
|
+
method: "POST",
|
|
151
|
+
headers: { "Content-Type": "application/json" },
|
|
152
|
+
body: JSON.stringify({ args: cmdArgs, mind })
|
|
153
|
+
});
|
|
154
|
+
if (!cmdRes.ok) {
|
|
155
|
+
const text = await cmdRes.text().catch(() => "");
|
|
156
|
+
console.error(`Extension command failed (HTTP ${cmdRes.status}): ${text}`);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
const result = await cmdRes.json();
|
|
160
|
+
if (result.error) {
|
|
161
|
+
console.error(result.error);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
if (result.output) console.log(result.output);
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
} catch (err) {
|
|
169
|
+
if (isExtensionCommand) {
|
|
170
|
+
console.error(`Extension command failed: ${err instanceof Error ? err.message : err}`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
124
174
|
console.error(`Unknown command: ${command}
|
|
125
175
|
Run 'volute --help' for usage.`);
|
|
126
176
|
process.exit(1);
|
|
177
|
+
}
|
|
127
178
|
}
|
|
128
179
|
if (command !== "update") {
|
|
129
|
-
import("./update-check-
|
|
180
|
+
import("./update-check-5WVSU37T.js").then((m) => m.checkForUpdate()).then((result) => {
|
|
130
181
|
if (result.updateAvailable) {
|
|
131
182
|
console.error(`
|
|
132
183
|
Update available: ${result.current} \u2192 ${result.latest}`);
|