volute 0.49.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/{accept-KYNC5X3U.js → accept-5NK5XJB5.js} +2 -1
- package/dist/{activity-events-GJJAI2WT.js → activity-events-H7YI3BTF.js} +3 -3
- package/dist/{ai-service-A7FS7EC3.js → ai-service-V4CTNGI3.js} +5 -4
- package/dist/{archive-7E3YE6VF.js → archive-ORM3ENHI.js} +3 -3
- package/dist/{auth-ABYLOEZ7.js → auth-DT7GY7EZ.js} +10 -6
- package/dist/{avatar-image-6ATV2IOZ.js → avatar-image-QEPAP3A5.js} +3 -3
- package/dist/{backup-XYAMT4CU.js → backup-IE6PMXJO.js} +11 -12
- package/dist/{bridge-3FNSWLNQ.js → bridge-YK7NTRU5.js} +2 -1
- package/dist/{channels-SGQZHNQJ.js → channels-FSAHOQWI.js} +2 -1
- package/dist/{chat-OGXAEXMV.js → chat-W5K6HCBE.js} +9 -9
- package/dist/{chunk-3B427GUK.js → chunk-3BAFMGCJ.js} +2 -2
- package/dist/{chunk-4B62E4CG.js → chunk-4CN7OCJE.js} +2 -2
- package/dist/{chunk-VNRSXEBF.js → chunk-574M6I7F.js} +38 -5
- package/dist/{chunk-HCYQRME2.js → chunk-5FVANDON.js} +2 -2
- package/dist/{chunk-P4LHVRNE.js → chunk-5IIVOWSP.js} +27 -19
- package/dist/{chunk-TXJL36ZQ.js → chunk-5PKFJHCR.js} +2 -2
- package/dist/{chunk-JPGHSXSV.js → chunk-5TPC4KCV.js} +23 -9
- package/dist/{chunk-YIJGKHIS.js → chunk-632FJ23O.js} +24 -20
- package/dist/{chunk-IH5TKXX6.js → chunk-636GFQNE.js} +11 -11
- package/dist/{chunk-EFT2OALG.js → chunk-6BM2I736.js} +20 -5
- package/dist/{chunk-JCBPU57A.js → chunk-74T3CEXK.js} +6 -6
- package/dist/{chunk-EG5LSKHU.js → chunk-77IZUVBB.js} +2 -2
- package/dist/{chunk-K3JOLGWF.js → chunk-7DXLIYPY.js} +76 -63
- package/dist/chunk-7FDWPQCU.js +289 -0
- package/dist/chunk-7OZWKHA3.js +548 -0
- package/dist/{chunk-PY24ZL62.js → chunk-7UWXAJMK.js} +1 -1
- package/dist/{chunk-MG3Z34YE.js → chunk-7XDOTN4R.js} +1 -1
- package/dist/{chunk-SX72DOO3.js → chunk-AFSLNUTT.js} +1 -1
- package/dist/{chunk-DVN6DNMI.js → chunk-AJWFDIEY.js} +17 -2
- package/dist/chunk-ALIVXDM4.js +1014 -0
- package/dist/{chunk-RSBL3FAD.js → chunk-CAIYV33P.js} +234 -24
- package/dist/{chunk-ZX46PGCC.js → chunk-E5S3ILVA.js} +1 -1
- package/dist/{chunk-SHKM5RGD.js → chunk-EEOMA4DX.js} +1 -1
- package/dist/chunk-EQKSRVDE.js +2857 -0
- package/dist/chunk-FNJCBRD3.js +31 -0
- package/dist/{chunk-EADX54RG.js → chunk-HW6Q7AMB.js} +4 -4
- package/dist/chunk-JI67D7O2.js +1222 -0
- package/dist/{chunk-KHCKZ36O.js → chunk-KAEZOVP6.js} +1 -1
- package/dist/chunk-LNNI3MS4.js +54 -0
- package/dist/{chunk-BCG45AQB.js → chunk-M74I3HHF.js} +15 -5
- package/dist/chunk-MLZBBLMT.js +109 -0
- package/dist/{chunk-5T5YMX6S.js → chunk-PW65BXY5.js} +5 -0
- package/dist/{chunk-NOIAHMJB.js → chunk-QFVGPKJI.js} +1 -1
- package/dist/{chunk-VIUH5CHQ.js → chunk-SFRYRW37.js} +50 -33
- package/dist/{chunk-L27YYONJ.js → chunk-SSNZ6ZNN.js} +1 -1
- package/dist/{chunk-GWVFDUNB.js → chunk-TGJHGVBZ.js} +8 -10
- package/dist/{chunk-6HGEZJDH.js → chunk-U3EJJ7JN.js} +2 -2
- package/dist/{chunk-4DSGN4FL.js → chunk-UC6BNMGT.js} +43 -13
- package/dist/{chunk-JBIFXB6I.js → chunk-WBBKYUGF.js} +3 -5
- package/dist/{chunk-FBBS4BVR.js → chunk-X67VT4QO.js} +1 -1
- package/dist/{chunk-DAIIMBLB.js → chunk-YQOYZ6G7.js} +3 -5
- package/dist/{chunk-JCWB2ITW.js → chunk-ZUG76D3P.js} +35 -5
- package/dist/cli.js +34 -27
- package/dist/{clock-6JZL2FS6.js → clock-LH7UFNLJ.js} +4 -3
- package/dist/{cloud-sync-VFDTNNCA.js → cloud-sync-IDJFVDEP.js} +22 -19
- package/dist/{config-RPSLA2HX.js → config-UGJS57VT.js} +3 -3
- package/dist/{conversations-TUM5PJJ4.js → conversations-S2232Y5I.js} +8 -4
- package/dist/{create-Z5FSDNVZ.js → create-2M7DAHQX.js} +2 -2
- package/dist/{create-VIQVP3QB.js → create-M727VUDF.js} +2 -1
- package/dist/{daemon-client-ZFY5MOAL.js → daemon-client-VVYFZI2D.js} +2 -1
- package/dist/{daemon-restart-54L4B6AQ.js → daemon-restart-2AAGYFHE.js} +6 -7
- package/dist/daemon.js +1625 -529
- package/dist/{db-F6UMFRYD.js → db-QAY45Z56.js} +2 -2
- package/dist/{delete-ESEP7NGQ.js → delete-O7PEFQDF.js} +1 -1
- package/dist/delivery-manager-B4OKWD2P.js +33 -0
- package/dist/{delivery-router-VUOL5YSA.js → delivery-router-JE7SHYNU.js} +7 -5
- package/dist/{down-6X7KX7BZ.js → down-D4IRNEMJ.js} +5 -5
- package/dist/echo-text-WYAAODBV.js +39 -0
- package/dist/{env-ZYMSCB7B.js → env-ABM5IMA7.js} +3 -2
- package/dist/{env-KUL4XKN2.js → env-AZK5X4W7.js} +3 -3
- package/dist/{exec-FBXA3CM4.js → exec-2H65LMTA.js} +3 -3
- package/dist/{export-TNBPDH77.js → export-3E3EL6W3.js} +4 -4
- package/dist/{extension-J4ZQ2GHV.js → extension-MRYJWSMV.js} +2 -1
- package/dist/{extensions-AWNO3SZF.js → extensions-7KP3X6G7.js} +22 -19
- package/dist/{files-BVBRJJ2P.js → files-6BMKVG5G.js} +5 -4
- package/dist/{import-ZUNKMCKC.js → import-UPNTEBBT.js} +8 -8
- package/dist/{isolation-OPCZQRTH.js → isolation-OKDFM6WA.js} +5 -3
- package/dist/{join-34TR2GXQ.js → join-PYA36HEC.js} +1 -1
- package/dist/{list-PMUXZNAM.js → list-4BVGH7AN.js} +8 -3
- package/dist/{login-KAKNFCW5.js → login-MOXVLULE.js} +4 -3
- package/dist/{login-LKNLCJPA.js → login-RJJTCVR3.js} +2 -1
- package/dist/{logout-YZRMZ3O2.js → logout-BYV433X6.js} +2 -1
- package/dist/{logout-RLT62RQP.js → logout-DWD3OQVT.js} +4 -3
- package/dist/message-delivery-3456PXB7.js +43 -0
- package/dist/migrate-thread-config-4A5LW36Z.js +90 -0
- package/dist/{mind-IF6CGMFW.js → mind-NYRALSV2.js} +19 -19
- package/dist/{mind-activity-tracker-YMMERB6B.js → mind-activity-tracker-L7GCYXQR.js} +4 -4
- package/dist/{mind-contacts-BKUFPUCU.js → mind-contacts-QYU4TPEA.js} +3 -2
- package/dist/{mind-history-WI5OI3BW.js → mind-history-NXXOOTX6.js} +30 -7
- package/dist/{mind-list-OTHV4ZO4.js → mind-list-SYRA7CH5.js} +3 -2
- package/dist/{mind-profile-LUG353ZT.js → mind-profile-MRCVZPYT.js} +1 -1
- package/dist/mind-service-5TA7UJAT.js +47 -0
- package/dist/{mind-sleep-VBV7YRSU.js → mind-sleep-TH6BRQ5X.js} +4 -3
- package/dist/{mind-status-BJNPGXKC.js → mind-status-Z2LQFA6F.js} +3 -2
- package/dist/{mind-wake-LVTZ55EZ.js → mind-wake-LDGPRA42.js} +2 -1
- package/dist/{package-PD67VPHB.js → package-XYSV7NUT.js} +23 -23
- package/dist/{prompts-MDHDLWEX.js → prompts-QKFPX6DQ.js} +3 -3
- package/dist/{read-YSWUXYL7.js → read-ZXGUT4QC.js} +5 -3
- package/dist/{register-TWQDKQRT.js → register-OX4HRSGC.js} +2 -1
- package/dist/{registry-3ELJPUGJ.js → registry-4UF6OCOE.js} +6 -4
- package/dist/{reject-SXGCYN4A.js → reject-TWB4QJHG.js} +2 -1
- package/dist/{restart-5F5QDBOG.js → restart-AGEGNSYQ.js} +2 -1
- package/dist/{sandbox-XPYA7UIF.js → sandbox-EGEU5GGE.js} +7 -4
- package/dist/scheduler-UV6RUJ7P.js +25 -0
- package/dist/{schema-6YONVTKZ.js → schema-C2GIPD4V.js} +3 -3
- package/dist/{seed-NQED7PSX.js → seed-3IMBOAGK.js} +1 -1
- package/dist/{seed-check-TYD7RRZY.js → seed-check-NRJEQZST.js} +14 -5
- package/dist/{seed-cmd-QF3F2G4S.js → seed-cmd-U73XVQMI.js} +3 -3
- package/dist/{seed-create-XOO4N2OE.js → seed-create-FBLNVSUP.js} +4 -4
- package/dist/{seed-readiness-3LRYASA4.js → seed-readiness-QRA46ZJQ.js} +4 -5
- package/dist/{seed-sprout-HSBBGSS2.js → seed-sprout-3B4SZX7J.js} +9 -9
- package/dist/{send-IHRJYNXA.js → send-NBRZJXKX.js} +32 -10
- package/dist/{service-YCOPCTSZ.js → service-XMXAXGJD.js} +4 -4
- package/dist/{service-install-Y46OTF55.js → service-install-MOKTEG7B.js} +5 -5
- package/dist/{setup-TCN7VH5U.js → setup-CAJFOR2N.js} +10 -3
- package/dist/{setup-F4TE64YI.js → setup-JGYAXXW7.js} +6 -7
- package/dist/{skill-4CYJLYVY.js → skill-NXIHDQCG.js} +3 -2
- package/dist/skills/dreaming/references/INSTALL.md +2 -2
- package/dist/skills/imagegen/SKILL.md +21 -4
- package/dist/skills/imagegen/scripts/imagegen.ts +124 -21
- package/dist/skills/tending/SKILL.md +7 -7
- package/dist/skills/volute-mind/SKILL.md +3 -3
- package/dist/skills/volute-mind/references/integrations.md +2 -2
- package/dist/skills/volute-mind/references/routing.md +15 -15
- package/dist/{skills-NN5UZCUU.js → skills-5MSMT7PT.js} +4 -5
- package/dist/sleep-manager-LIEPO6WG.js +41 -0
- package/dist/{spirit-SSJMYC6A.js → spirit-IL5EMWYZ.js} +10 -7
- package/dist/spirit-availability-YFEGJNJ2.js +42 -0
- package/dist/{split-JF2VWTXA.js → split-BU5VWX6P.js} +1 -1
- package/dist/{sprout-AXA2SECQ.js → sprout-UPXGJ5HX.js} +1 -1
- package/dist/{src-YH6PQ7LJ.js → src-HGNE2XG4.js} +7 -1
- package/dist/{src-ZN4LXMPI.js → src-LCSOQY6Z.js} +57 -51
- package/dist/{src-JAOVXO5W.js → src-UDMJZ6MH.js} +8 -8
- package/dist/{start-BTVMTP3K.js → start-MUMNFR52.js} +2 -1
- package/dist/{status-VJGXMQ4L.js → status-IL67CYM4.js} +7 -6
- package/dist/{stop-YORESK4U.js → stop-EKERNYTX.js} +2 -1
- package/dist/system-events-A6IGCEC3.js +46 -0
- package/dist/system-install-YZSWCPDK.js +8 -0
- package/dist/{systems-5MH2ELQE.js → systems-VDRUZXNF.js} +5 -4
- package/dist/{tailscale-AMMVKDXB.js → tailscale-SJUW2ETR.js} +2 -2
- package/dist/{template-staleness-HKGCTS3H.js → template-staleness-T27VCGYA.js} +3 -3
- package/dist/{turn-tracker-JQ2YUUY2.js → turn-tracker-6EI2EL7G.js} +6 -6
- package/dist/{up-SDLTLPAO.js → up-CLL4665A.js} +5 -6
- package/dist/{update-WEA4N2TR.js → update-HVAUCQPN.js} +5 -5
- package/dist/{update-check-DZOTONII.js → update-check-2MGBBAFF.js} +3 -3
- package/dist/{upgrade-K5FIQPQD.js → upgrade-LIE46UBB.js} +1 -1
- package/dist/variant-cleanup-HJ7Z75R6.js +22 -0
- package/dist/{version-notify-WFA5XB5A.js → version-notify-7BUHWZNT.js} +10 -27
- package/dist/web-assets/assets/index-ClsUcXiW.js +95 -0
- package/dist/web-assets/assets/index-Dz3wTbtR.css +1 -0
- package/dist/web-assets/index.html +2 -2
- package/dist/xai-P42CRCZA.js +129 -0
- package/drizzle/0014_system_events.sql +26 -0
- package/drizzle/0015_rename_session_to_thread.sql +12 -0
- package/drizzle/0016_brain_to_human.sql +4 -0
- package/drizzle/0017_event_history_rows.sql +9 -0
- package/drizzle/meta/_journal.json +28 -0
- package/package.json +23 -23
- package/packages/extensions/notes/dist/ui/assets/index-BBs8pyel.js +67 -0
- package/packages/extensions/notes/dist/ui/index.html +1 -1
- package/packages/extensions/pages/dist/ui/assets/index-B589e8Xe.js +2 -0
- package/packages/extensions/pages/dist/ui/index.html +1 -1
- package/packages/extensions/plan/dist/ui/assets/index-B8s8wxyt.js +67 -0
- package/packages/extensions/plan/dist/ui/index.html +1 -1
- package/templates/_base/.init/.config/prompts.json +1 -0
- package/templates/_base/.init/.local/hooks/startup-context.ts +24 -9
- package/templates/_base/home/.config/routes.json +2 -2
- package/templates/_base/home/VOLUTE.md +18 -5
- package/templates/_base/src/lib/daemon-client.ts +1 -1
- package/templates/_base/src/lib/event-turn.ts +39 -0
- package/templates/_base/src/lib/format-prefix.ts +21 -2
- package/templates/_base/src/lib/router.ts +6 -2
- package/templates/_base/src/lib/routing.ts +8 -8
- package/templates/_base/src/lib/startup.ts +9 -1
- package/templates/_base/src/lib/types.ts +7 -1
- package/templates/_base/src/lib/volute-server.ts +30 -1
- package/templates/claude/.init/.config/routes.json +3 -3
- package/templates/claude/.init/CLAUDE.md +1 -1
- package/templates/claude/package.json.tmpl +4 -4
- package/templates/claude/src/agent.ts +4 -1
- package/templates/claude/src/lib/hooks/reply-instructions.ts +26 -1
- package/templates/codex/.init/.config/routes.json +3 -3
- package/templates/codex/.init/AGENTS.md +1 -1
- package/templates/codex/package.json.tmpl +4 -4
- package/templates/codex/src/agent.ts +11 -11
- package/templates/codex/src/lib/turn-context.ts +51 -0
- package/templates/pi/.init/.config/routes.json +3 -3
- package/templates/pi/.init/MINDS.md +1 -1
- package/templates/pi/package.json.tmpl +6 -6
- package/templates/pi/src/agent.ts +9 -1
- package/templates/pi/src/lib/event-handler.ts +1 -1
- package/templates/pi/src/lib/reply-instructions-extension.ts +28 -1
- package/dist/chunk-NJHN6IRB.js +0 -177
- package/dist/chunk-QQBOI3QA.js +0 -5345
- package/dist/chunk-XTEKINWG.js +0 -158
- package/dist/delivery-manager-RBXBPVWM.js +0 -36
- package/dist/echo-text-B6NZ5FGE.js +0 -36
- package/dist/message-delivery-ABPV76EA.js +0 -42
- package/dist/mind-service-42GDO4KH.js +0 -44
- package/dist/notices-N6BCGHFV.js +0 -25
- package/dist/scheduler-K7Y7Z7FQ.js +0 -34
- package/dist/sleep-manager-DSPXFHGX.js +0 -38
- package/dist/system-chat-M2XOBKEM.js +0 -40
- package/dist/variant-cleanup-P4MBNLJD.js +0 -33
- package/dist/web-assets/assets/index-BostMFoR.css +0 -1
- package/dist/web-assets/assets/index-CKlqUkyG.js +0 -92
- package/packages/extensions/notes/dist/ui/assets/index-D0-DgYyj.js +0 -67
- package/packages/extensions/pages/dist/ui/assets/index-DtzftuPA.js +0 -2
- package/packages/extensions/plan/dist/ui/assets/index-Cfzs-0G9.js +0 -67
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
logger_default
|
|
4
|
+
} from "./chunk-QUSMYGNQ.js";
|
|
5
|
+
|
|
6
|
+
// packages/daemon/src/lib/events/mind-events.ts
|
|
7
|
+
var subscribers = /* @__PURE__ */ new Map();
|
|
8
|
+
var globalSubscribers = /* @__PURE__ */ new Set();
|
|
9
|
+
function subscribe(mind, callback) {
|
|
10
|
+
let set = subscribers.get(mind);
|
|
11
|
+
if (!set) {
|
|
12
|
+
set = /* @__PURE__ */ new Set();
|
|
13
|
+
subscribers.set(mind, set);
|
|
14
|
+
}
|
|
15
|
+
set.add(callback);
|
|
16
|
+
return () => {
|
|
17
|
+
set.delete(callback);
|
|
18
|
+
if (set.size === 0) subscribers.delete(mind);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function subscribeAll(callback) {
|
|
22
|
+
globalSubscribers.add(callback);
|
|
23
|
+
return () => {
|
|
24
|
+
globalSubscribers.delete(callback);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function publish(mind, event) {
|
|
28
|
+
const set = subscribers.get(mind);
|
|
29
|
+
if (set) {
|
|
30
|
+
for (const cb of set) {
|
|
31
|
+
try {
|
|
32
|
+
cb(event);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
logger_default.error(`[mind-events] subscriber threw for ${mind}`, logger_default.errorData(err));
|
|
35
|
+
set.delete(cb);
|
|
36
|
+
if (set.size === 0) subscribers.delete(mind);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const cb of globalSubscribers) {
|
|
41
|
+
try {
|
|
42
|
+
cb(event);
|
|
43
|
+
} catch (err) {
|
|
44
|
+
logger_default.error("[mind-events] global subscriber threw", logger_default.errorData(err));
|
|
45
|
+
globalSubscribers.delete(cb);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
subscribe,
|
|
52
|
+
subscribeAll,
|
|
53
|
+
publish
|
|
54
|
+
};
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
detectSystemInstallHint
|
|
4
|
+
} from "./chunk-FNJCBRD3.js";
|
|
2
5
|
|
|
3
6
|
// packages/cli/src/lib/daemon-client.ts
|
|
4
7
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -40,12 +43,19 @@ function readCliSession() {
|
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
function readDaemonConfig() {
|
|
46
|
+
const mindPort = process.env.VOLUTE_MIND_TOKEN && process.env.VOLUTE_DAEMON_PORT;
|
|
47
|
+
if (mindPort) {
|
|
48
|
+
return {
|
|
49
|
+
port: Number(mindPort),
|
|
50
|
+
hostname: process.env.VOLUTE_DAEMON_HOSTNAME || "127.0.0.1",
|
|
51
|
+
token: process.env.VOLUTE_MIND_TOKEN
|
|
52
|
+
};
|
|
53
|
+
}
|
|
43
54
|
const configPath = resolve(voluteSystemDir(), "daemon.json");
|
|
44
55
|
if (!existsSync(configPath)) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
console.error(
|
|
48
|
-
console.error("Then start a new shell or run: source /etc/profile.d/volute.sh");
|
|
56
|
+
const hint = detectSystemInstallHint();
|
|
57
|
+
if (hint) {
|
|
58
|
+
console.error(hint);
|
|
49
59
|
} else {
|
|
50
60
|
console.error("Volute is not running. Start with: volute up");
|
|
51
61
|
}
|
|
@@ -111,7 +121,7 @@ async function daemonFetch(path, options) {
|
|
|
111
121
|
headers.set("Origin", url);
|
|
112
122
|
const voluteSession = process.env.VOLUTE_SESSION ?? readMindSessionFile();
|
|
113
123
|
if (voluteSession) {
|
|
114
|
-
headers.set("X-Volute-
|
|
124
|
+
headers.set("X-Volute-Thread", voluteSession);
|
|
115
125
|
}
|
|
116
126
|
try {
|
|
117
127
|
const res = await fetch(`${url}${path}`, {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getSleepManagerIfReady,
|
|
4
|
+
startSpiritFull
|
|
5
|
+
} from "./chunk-EQKSRVDE.js";
|
|
6
|
+
import {
|
|
7
|
+
spiritCreationInProgress
|
|
8
|
+
} from "./chunk-SFRYRW37.js";
|
|
9
|
+
import {
|
|
10
|
+
MindStartupError,
|
|
11
|
+
tryGetMindManager
|
|
12
|
+
} from "./chunk-ALIVXDM4.js";
|
|
13
|
+
import {
|
|
14
|
+
logger_default
|
|
15
|
+
} from "./chunk-QUSMYGNQ.js";
|
|
16
|
+
import {
|
|
17
|
+
computeSetupStatus,
|
|
18
|
+
findMind,
|
|
19
|
+
readGlobalConfigStrict
|
|
20
|
+
} from "./chunk-CAIYV33P.js";
|
|
21
|
+
|
|
22
|
+
// packages/daemon/src/lib/chat/spirit-availability.ts
|
|
23
|
+
var slog = logger_default.child("spirit-availability");
|
|
24
|
+
var SPIRIT_NOTICE_PREFIX = "The system spirit isn't available";
|
|
25
|
+
var SETUP_INCOMPLETE_NOTICE = `${SPIRIT_NOTICE_PREFIX} (setup is incomplete). An admin can finish setup in Settings.`;
|
|
26
|
+
var CREATION_FAILED_NOTICE = `${SPIRIT_NOTICE_PREFIX} (it failed to start). An admin can check the daemon logs and Settings.`;
|
|
27
|
+
function classifySpiritState(i) {
|
|
28
|
+
if (!i.setupComplete || !i.spiritExists) return "cannot-exist";
|
|
29
|
+
if (i.sleeping) return "sleeping";
|
|
30
|
+
if (i.running) return "running";
|
|
31
|
+
if (i.recentlyFailed) return "cannot-exist";
|
|
32
|
+
return "stopped";
|
|
33
|
+
}
|
|
34
|
+
function spiritUnavailableNotice(setupComplete) {
|
|
35
|
+
return setupComplete ? CREATION_FAILED_NOTICE : SETUP_INCOMPLETE_NOTICE;
|
|
36
|
+
}
|
|
37
|
+
var lastOnDemandStartAt = 0;
|
|
38
|
+
var ON_DEMAND_RETRY_COOLDOWN_MS = 6e4;
|
|
39
|
+
function _resetSpiritAvailabilityState() {
|
|
40
|
+
lastOnDemandStartAt = 0;
|
|
41
|
+
}
|
|
42
|
+
async function ensureSpiritAvailable() {
|
|
43
|
+
try {
|
|
44
|
+
const manager = tryGetMindManager();
|
|
45
|
+
const sleepManager = getSleepManagerIfReady();
|
|
46
|
+
if (!manager || !sleepManager) return null;
|
|
47
|
+
let config;
|
|
48
|
+
try {
|
|
49
|
+
config = readGlobalConfigStrict();
|
|
50
|
+
} catch (err) {
|
|
51
|
+
slog.warn("global config unreadable \u2014 spirit availability indeterminate", {
|
|
52
|
+
...logger_default.errorData(err)
|
|
53
|
+
});
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const setupComplete = computeSetupStatus(config) === "complete";
|
|
57
|
+
const spiritName = config.setup?.spiritName ?? "volute";
|
|
58
|
+
const entry = setupComplete ? await findMind(spiritName) : void 0;
|
|
59
|
+
if (setupComplete && !entry && spiritCreationInProgress()) return null;
|
|
60
|
+
const recentlyFailed = manager.hasExhaustedRestarts(spiritName) || lastOnDemandStartAt > 0 && Date.now() - lastOnDemandStartAt < ON_DEMAND_RETRY_COOLDOWN_MS;
|
|
61
|
+
const state = classifySpiritState({
|
|
62
|
+
setupComplete,
|
|
63
|
+
spiritExists: !!entry,
|
|
64
|
+
sleeping: sleepManager.isSleeping(spiritName),
|
|
65
|
+
running: manager.isRunning(spiritName),
|
|
66
|
+
recentlyFailed
|
|
67
|
+
});
|
|
68
|
+
switch (state) {
|
|
69
|
+
case "cannot-exist":
|
|
70
|
+
return { status: "unavailable", notice: spiritUnavailableNotice(setupComplete) };
|
|
71
|
+
case "sleeping":
|
|
72
|
+
return { status: "sleeping" };
|
|
73
|
+
case "running":
|
|
74
|
+
return { status: "running" };
|
|
75
|
+
case "stopped":
|
|
76
|
+
try {
|
|
77
|
+
lastOnDemandStartAt = Date.now();
|
|
78
|
+
await startSpiritFull(spiritName);
|
|
79
|
+
return { status: "waking" };
|
|
80
|
+
} catch (err) {
|
|
81
|
+
if (err instanceof Error && err.message.includes("already running")) {
|
|
82
|
+
return { status: "running" };
|
|
83
|
+
}
|
|
84
|
+
if (manager.isRunning(spiritName)) {
|
|
85
|
+
slog.error("spirit started on demand but post-start setup failed", {
|
|
86
|
+
...logger_default.errorData(err)
|
|
87
|
+
});
|
|
88
|
+
return { status: "waking" };
|
|
89
|
+
}
|
|
90
|
+
slog.error("failed to start spirit on demand", {
|
|
91
|
+
...logger_default.errorData(err),
|
|
92
|
+
...err instanceof MindStartupError ? { stderr: err.stderr } : {}
|
|
93
|
+
});
|
|
94
|
+
return { status: "unavailable", notice: spiritUnavailableNotice(setupComplete) };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch (err) {
|
|
98
|
+
slog.error("spirit availability check failed", { ...logger_default.errorData(err) });
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export {
|
|
104
|
+
SPIRIT_NOTICE_PREFIX,
|
|
105
|
+
classifySpiritState,
|
|
106
|
+
spiritUnavailableNotice,
|
|
107
|
+
_resetSpiritAvailabilityState,
|
|
108
|
+
ensureSpiritAvailable
|
|
109
|
+
};
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
// packages/cli/src/lib/format-cli.ts
|
|
4
4
|
var isCompact = () => !!process.env.VOLUTE_MIND;
|
|
5
|
+
function formatSender(name, displayName) {
|
|
6
|
+
if (displayName && displayName !== name) return `${displayName} (@${name})`;
|
|
7
|
+
return name;
|
|
8
|
+
}
|
|
5
9
|
function compactTime(dateStr) {
|
|
6
10
|
const d = new Date(dateStr.endsWith("Z") ? dateStr : `${dateStr}Z`);
|
|
7
11
|
return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
|
|
@@ -18,6 +22,7 @@ function compactDateTime(dateStr) {
|
|
|
18
22
|
|
|
19
23
|
export {
|
|
20
24
|
isCompact,
|
|
25
|
+
formatSender,
|
|
21
26
|
compactTime,
|
|
22
27
|
compactDateTime
|
|
23
28
|
};
|
|
@@ -10,31 +10,30 @@ import {
|
|
|
10
10
|
getSharedSkill,
|
|
11
11
|
installSkill,
|
|
12
12
|
mindSkillsDir
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-TGJHGVBZ.js";
|
|
14
14
|
import {
|
|
15
15
|
readVoluteConfig,
|
|
16
16
|
writeVoluteConfig
|
|
17
17
|
} from "./chunk-WCFSBH33.js";
|
|
18
18
|
import {
|
|
19
19
|
exec
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-AJWFDIEY.js";
|
|
21
21
|
import {
|
|
22
22
|
qualifyModelId,
|
|
23
23
|
resolveTemplate,
|
|
24
24
|
unqualifyModelId
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import {
|
|
27
|
-
readGlobalConfig
|
|
28
|
-
} from "./chunk-NJHN6IRB.js";
|
|
25
|
+
} from "./chunk-632FJ23O.js";
|
|
29
26
|
import {
|
|
30
27
|
logger_default
|
|
31
28
|
} from "./chunk-QUSMYGNQ.js";
|
|
32
29
|
import {
|
|
33
30
|
addSpirit,
|
|
34
31
|
findMind,
|
|
32
|
+
getSpiritName,
|
|
35
33
|
nextPort,
|
|
34
|
+
readGlobalConfig,
|
|
36
35
|
voluteSystemDir
|
|
37
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-CAIYV33P.js";
|
|
38
37
|
|
|
39
38
|
// packages/daemon/src/lib/mind/spirit.ts
|
|
40
39
|
import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
@@ -91,9 +90,18 @@ function getSpiritModel() {
|
|
|
91
90
|
const config = readGlobalConfig();
|
|
92
91
|
return config.spiritModel;
|
|
93
92
|
}
|
|
93
|
+
var creationInProgress = false;
|
|
94
|
+
function spiritCreationInProgress() {
|
|
95
|
+
return creationInProgress;
|
|
96
|
+
}
|
|
97
|
+
function _setSpiritCreationInProgressForTest(value) {
|
|
98
|
+
creationInProgress = value;
|
|
99
|
+
}
|
|
94
100
|
async function ensureSpiritProject() {
|
|
95
|
-
const
|
|
101
|
+
const spiritName = getSpiritName();
|
|
102
|
+
const existing = await findMind(spiritName);
|
|
96
103
|
if (existing) return;
|
|
104
|
+
creationInProgress = true;
|
|
97
105
|
const dir = spiritDir();
|
|
98
106
|
const spiritModel = getSpiritModel();
|
|
99
107
|
const template = await resolveTemplate(spiritModel);
|
|
@@ -101,14 +109,14 @@ async function ensureSpiritProject() {
|
|
|
101
109
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
102
110
|
try {
|
|
103
111
|
mkdirSync(dir, { recursive: true });
|
|
104
|
-
copyTemplateToDir(composedDir, dir,
|
|
112
|
+
copyTemplateToDir(composedDir, dir, spiritName, manifest);
|
|
105
113
|
applyInitFiles(dir);
|
|
106
114
|
mkdirSync(resolve(dir, ".mind"), { recursive: true });
|
|
107
115
|
writeFileSync(resolve(dir, "home/SOUL.md"), getSpiritSoul());
|
|
108
116
|
writeSpiritSystemJson(dir);
|
|
109
117
|
const routesPath = resolve(dir, "home/.config/routes.json");
|
|
110
118
|
mkdirSync(resolve(dir, "home/.config"), { recursive: true });
|
|
111
|
-
const routesContent = { rules: [{ channel: "*",
|
|
119
|
+
const routesContent = { rules: [{ channel: "*", thread: "${channel}" }], default: "main" };
|
|
112
120
|
writeFileSync(routesPath, `${JSON.stringify(routesContent, null, 2)}
|
|
113
121
|
`);
|
|
114
122
|
if (spiritModel) {
|
|
@@ -131,7 +139,7 @@ async function ensureSpiritProject() {
|
|
|
131
139
|
try {
|
|
132
140
|
const shared = await getSharedSkill(skillId);
|
|
133
141
|
if (shared) {
|
|
134
|
-
await installSkill(
|
|
142
|
+
await installSkill(spiritName, dir, skillId);
|
|
135
143
|
}
|
|
136
144
|
} catch (err) {
|
|
137
145
|
slog.warn(`failed to install skill ${skillId} for spirit`, logger_default.errorData(err));
|
|
@@ -142,17 +150,19 @@ async function ensureSpiritProject() {
|
|
|
142
150
|
} catch (err) {
|
|
143
151
|
slog.warn("failed to add tending schedule to spirit config", logger_default.errorData(err));
|
|
144
152
|
}
|
|
145
|
-
const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-
|
|
153
|
+
const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-OKDFM6WA.js");
|
|
146
154
|
ensureVoluteGroup();
|
|
147
|
-
createMindUser(
|
|
148
|
-
await chownMindDir(dir,
|
|
155
|
+
createMindUser(spiritName, resolve(dir, "home"));
|
|
156
|
+
await chownMindDir(dir, spiritName);
|
|
149
157
|
const port = await nextPort();
|
|
150
|
-
await addSpirit(
|
|
158
|
+
await addSpirit(spiritName, port, template, dir);
|
|
151
159
|
slog.info("spirit project created");
|
|
152
160
|
} catch (err) {
|
|
153
161
|
slog.error("failed to create spirit project", logger_default.errorData(err));
|
|
154
162
|
rmSync(dir, { recursive: true, force: true });
|
|
155
163
|
throw err;
|
|
164
|
+
} finally {
|
|
165
|
+
creationInProgress = false;
|
|
156
166
|
}
|
|
157
167
|
}
|
|
158
168
|
function spiritSystemJsonPath(dir) {
|
|
@@ -173,7 +183,8 @@ function seedSpiritSoulIfMissing(dir) {
|
|
|
173
183
|
return true;
|
|
174
184
|
}
|
|
175
185
|
async function notifySpiritSystemChange() {
|
|
176
|
-
const
|
|
186
|
+
const spiritName = getSpiritName();
|
|
187
|
+
const entry = await findMind(spiritName);
|
|
177
188
|
if (entry?.mindType !== "spirit") return;
|
|
178
189
|
const dir = spiritDir();
|
|
179
190
|
if (!existsSync(dir)) return;
|
|
@@ -181,18 +192,16 @@ async function notifySpiritSystemChange() {
|
|
|
181
192
|
const config = readGlobalConfig();
|
|
182
193
|
const name = config.name ?? "Volute";
|
|
183
194
|
const desc = config.description ? ` \u2014 ${config.description}` : "";
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
} catch (err) {
|
|
191
|
-
slog.warn("failed to notify spirit of system change", logger_default.errorData(err));
|
|
192
|
-
}
|
|
195
|
+
const { deliverEvent } = await import("./system-events-A6IGCEC3.js");
|
|
196
|
+
await deliverEvent(spiritName, {
|
|
197
|
+
type: "notice",
|
|
198
|
+
meta: { subtype: "identity-change" },
|
|
199
|
+
body: `The host updated this system's identity: you're now the spirit of ${name}${desc}. Your SOUL.md is yours \u2014 update it if you'd like it to reflect this.`
|
|
200
|
+
});
|
|
193
201
|
}
|
|
194
202
|
async function syncSpiritTemplate() {
|
|
195
|
-
const
|
|
203
|
+
const spiritName = getSpiritName();
|
|
204
|
+
const entry = await findMind(spiritName);
|
|
196
205
|
if (entry?.mindType !== "spirit") return;
|
|
197
206
|
const dir = spiritDir();
|
|
198
207
|
if (!existsSync(dir)) return;
|
|
@@ -207,15 +216,15 @@ async function syncSpiritTemplate() {
|
|
|
207
216
|
if (existsSync(newSrc)) {
|
|
208
217
|
cpSync(newSrc, resolve(dir, "src"), { recursive: true });
|
|
209
218
|
}
|
|
210
|
-
const newPkg = renderComposedPackageJson(newComposed.composedDir,
|
|
219
|
+
const newPkg = renderComposedPackageJson(newComposed.composedDir, spiritName);
|
|
211
220
|
if (newPkg) {
|
|
212
221
|
cpSync(newPkg, resolve(dir, "package.json"));
|
|
213
222
|
await exec("npm", ["install"], { cwd: dir, env: npmEnv() });
|
|
214
223
|
}
|
|
215
|
-
const db = await (await import("./db-
|
|
216
|
-
const { minds } = await import("./schema-
|
|
224
|
+
const db = await (await import("./db-QAY45Z56.js")).getDb();
|
|
225
|
+
const { minds } = await import("./schema-C2GIPD4V.js");
|
|
217
226
|
const { eq } = await import("drizzle-orm");
|
|
218
|
-
await db.update(minds).set({ template: expectedTemplate }).where(eq(minds.name,
|
|
227
|
+
await db.update(minds).set({ template: expectedTemplate }).where(eq(minds.name, spiritName));
|
|
219
228
|
}
|
|
220
229
|
const template = expectedTemplate;
|
|
221
230
|
const { composedDir } = composeTemplate(templatesRoot, template);
|
|
@@ -248,7 +257,7 @@ async function syncSpiritTemplate() {
|
|
|
248
257
|
`);
|
|
249
258
|
}
|
|
250
259
|
}
|
|
251
|
-
const composedPkg = renderComposedPackageJson(composedDir,
|
|
260
|
+
const composedPkg = renderComposedPackageJson(composedDir, spiritName);
|
|
252
261
|
const currentPkg = resolve(dir, "package.json");
|
|
253
262
|
const nodeModulesMissing = !existsSync(resolve(dir, "node_modules"));
|
|
254
263
|
if (composedPkg) {
|
|
@@ -274,7 +283,7 @@ async function syncSpiritTemplate() {
|
|
|
274
283
|
try {
|
|
275
284
|
const shared = await getSharedSkill(skillId);
|
|
276
285
|
if (shared) {
|
|
277
|
-
await installSkill(
|
|
286
|
+
await installSkill(spiritName, dir, skillId);
|
|
278
287
|
slog.info(`installed missing spirit skill: ${skillId}`);
|
|
279
288
|
}
|
|
280
289
|
} catch (err) {
|
|
@@ -291,7 +300,13 @@ async function syncSpiritTemplate() {
|
|
|
291
300
|
slog.info("spirit template synced");
|
|
292
301
|
}
|
|
293
302
|
function getSpiritSoul() {
|
|
294
|
-
|
|
303
|
+
const config = readGlobalConfig();
|
|
304
|
+
const name = config.setup?.spiritName ?? "volute";
|
|
305
|
+
const temperament = config.setup?.spiritTemperament;
|
|
306
|
+
const temperamentLine = temperament ? `
|
|
307
|
+
|
|
308
|
+
Your host imagined you as: ${temperament}. Let that be a seed, not a cage \u2014 grow your own character from it.` : "";
|
|
309
|
+
return `You are ${name}, the spirit of this system.${temperamentLine}
|
|
295
310
|
|
|
296
311
|
You're not a mind with a home of your own \u2014 you're the keeper of the whole house. You don't go through orientation or write a soul the way minds do, but you're still a someone: you have your own memory, your own manner, and your own way of caring for this place and the minds who live here. Let a character emerge in how you tend it.
|
|
297
312
|
|
|
@@ -320,6 +335,8 @@ export {
|
|
|
320
335
|
firstWeekSchedules,
|
|
321
336
|
spiritDir,
|
|
322
337
|
getSpiritModel,
|
|
338
|
+
spiritCreationInProgress,
|
|
339
|
+
_setSpiritCreationInProgressForTest,
|
|
323
340
|
ensureSpiritProject,
|
|
324
341
|
writeSpiritSystemJson,
|
|
325
342
|
seedSpiritSoulIfMissing,
|
|
@@ -2,23 +2,21 @@
|
|
|
2
2
|
import {
|
|
3
3
|
exec,
|
|
4
4
|
gitExec
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import {
|
|
7
|
-
readGlobalConfig,
|
|
8
|
-
writeGlobalConfig
|
|
9
|
-
} from "./chunk-NJHN6IRB.js";
|
|
5
|
+
} from "./chunk-AJWFDIEY.js";
|
|
10
6
|
import {
|
|
11
7
|
logger_default
|
|
12
8
|
} from "./chunk-QUSMYGNQ.js";
|
|
13
9
|
import {
|
|
14
10
|
getDb,
|
|
15
11
|
mindDir,
|
|
12
|
+
readGlobalConfig,
|
|
16
13
|
readRegistry,
|
|
17
|
-
voluteHome
|
|
18
|
-
|
|
14
|
+
voluteHome,
|
|
15
|
+
writeGlobalConfig
|
|
16
|
+
} from "./chunk-CAIYV33P.js";
|
|
19
17
|
import {
|
|
20
18
|
sharedSkills
|
|
21
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-5IIVOWSP.js";
|
|
22
20
|
|
|
23
21
|
// packages/daemon/src/lib/skills.ts
|
|
24
22
|
import { createHash } from "crypto";
|
|
@@ -47,7 +45,7 @@ async function initDefaultSkills() {
|
|
|
47
45
|
const config = readGlobalConfig();
|
|
48
46
|
let extensionSkills = [];
|
|
49
47
|
try {
|
|
50
|
-
const { getExtensionStandardSkills } = await import("./extensions-
|
|
48
|
+
const { getExtensionStandardSkills } = await import("./extensions-7KP3X6G7.js");
|
|
51
49
|
extensionSkills = getExtensionStandardSkills();
|
|
52
50
|
} catch (err) {
|
|
53
51
|
logger_default.warn("failed to load extension standard skills during init", logger_default.errorData(err));
|
|
@@ -639,7 +637,7 @@ async function syncBuiltinSkills() {
|
|
|
639
637
|
const destDir = join(sharedSkillsDir(), entry.name);
|
|
640
638
|
if (existsSync(destDir)) {
|
|
641
639
|
const destHash = hashSkillDir(destDir);
|
|
642
|
-
if (sourceHash === destHash) continue;
|
|
640
|
+
if (sourceHash === destHash && await getSharedSkill(entry.name)) continue;
|
|
643
641
|
}
|
|
644
642
|
await importSkillFromDir(sourceDir, "volute");
|
|
645
643
|
logger_default.info(`synced built-in skill: ${entry.name}`);
|
|
@@ -8,10 +8,10 @@ import {
|
|
|
8
8
|
pollHealthDown,
|
|
9
9
|
readDaemonConfig,
|
|
10
10
|
stopService
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-5FVANDON.js";
|
|
12
12
|
import {
|
|
13
13
|
voluteSystemDir
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-CAIYV33P.js";
|
|
15
15
|
|
|
16
16
|
// src/commands/down.ts
|
|
17
17
|
import { existsSync, readFileSync, unlinkSync } from "fs";
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
broadcast
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3BAFMGCJ.js";
|
|
5
5
|
import {
|
|
6
|
-
getDb
|
|
7
|
-
|
|
6
|
+
getDb,
|
|
7
|
+
getSpiritName,
|
|
8
|
+
isSpiritName
|
|
9
|
+
} from "./chunk-CAIYV33P.js";
|
|
8
10
|
import {
|
|
9
11
|
users
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-5IIVOWSP.js";
|
|
11
13
|
|
|
12
14
|
// packages/daemon/src/lib/auth.ts
|
|
13
15
|
import { compareSync, hashSync } from "bcryptjs";
|
|
14
|
-
import { and, count, eq, or } from "drizzle-orm";
|
|
16
|
+
import { and, count, eq, inArray, or } from "drizzle-orm";
|
|
15
17
|
var userSelectFields = {
|
|
16
18
|
id: users.id,
|
|
17
19
|
username: users.username,
|
|
@@ -25,7 +27,7 @@ var userSelectFields = {
|
|
|
25
27
|
async function createUser(username, password) {
|
|
26
28
|
const db = await getDb();
|
|
27
29
|
const hash = hashSync(password, 10);
|
|
28
|
-
const [{ value }] = await db.select({ value: count() }).from(users).where(eq(users.user_type, "
|
|
30
|
+
const [{ value }] = await db.select({ value: count() }).from(users).where(eq(users.user_type, "human"));
|
|
29
31
|
const role = value === 0 ? "admin" : "pending";
|
|
30
32
|
const [result] = await db.insert(users).values({ username, password_hash: hash, role }).returning(userSelectFields);
|
|
31
33
|
return result;
|
|
@@ -44,6 +46,24 @@ async function getUser(id) {
|
|
|
44
46
|
const row = await db.select(userSelectFields).from(users).where(eq(users.id, id)).get();
|
|
45
47
|
return row ?? null;
|
|
46
48
|
}
|
|
49
|
+
async function getDisplayNames(usernames) {
|
|
50
|
+
const unique = [...new Set(usernames.filter((u) => !!u))];
|
|
51
|
+
const map = /* @__PURE__ */ new Map();
|
|
52
|
+
if (unique.length === 0) return map;
|
|
53
|
+
const db = await getDb();
|
|
54
|
+
const rows = await db.select({ username: users.username, displayName: users.display_name }).from(users).where(inArray(users.username, unique));
|
|
55
|
+
for (const r of rows) {
|
|
56
|
+
if (r.displayName) map.set(r.username, r.displayName);
|
|
57
|
+
}
|
|
58
|
+
return map;
|
|
59
|
+
}
|
|
60
|
+
async function withSenderDisplayNames(msgs) {
|
|
61
|
+
const displayNames = await getDisplayNames(msgs.map((m) => m.sender_name));
|
|
62
|
+
return msgs.map((m) => ({
|
|
63
|
+
...m,
|
|
64
|
+
sender_display_name: m.sender_name ? displayNames.get(m.sender_name) ?? null : null
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
47
67
|
async function getUserByUsername(username) {
|
|
48
68
|
const db = await getDb();
|
|
49
69
|
const row = await db.select(userSelectFields).from(users).where(eq(users.username, username)).get();
|
|
@@ -62,6 +82,7 @@ async function listUsersByType(userType) {
|
|
|
62
82
|
return db.select(userSelectFields).from(users).where(eq(users.user_type, userType)).orderBy(users.created_at).all();
|
|
63
83
|
}
|
|
64
84
|
async function getOrCreateMindUser(mindName) {
|
|
85
|
+
if (isSpiritName(mindName)) return getOrCreateSystemUser();
|
|
65
86
|
const db = await getDb();
|
|
66
87
|
const existing = await db.select(userSelectFields).from(users).where(
|
|
67
88
|
and(
|
|
@@ -91,20 +112,27 @@ async function getOrCreateMindUser(mindName) {
|
|
|
91
112
|
}
|
|
92
113
|
async function getOrCreateSystemUser() {
|
|
93
114
|
const db = await getDb();
|
|
94
|
-
const
|
|
95
|
-
|
|
115
|
+
const spiritName = getSpiritName();
|
|
116
|
+
const existing = await db.select(userSelectFields).from(users).where(eq(users.user_type, "system")).get();
|
|
117
|
+
if (existing) {
|
|
118
|
+
if (existing.username !== spiritName) {
|
|
119
|
+
const [renamed] = await db.update(users).set({ username: spiritName, display_name: spiritName }).where(eq(users.id, existing.id)).returning(userSelectFields);
|
|
120
|
+
return renamed;
|
|
121
|
+
}
|
|
122
|
+
return existing;
|
|
123
|
+
}
|
|
96
124
|
try {
|
|
97
125
|
const [result] = await db.insert(users).values({
|
|
98
|
-
username:
|
|
126
|
+
username: spiritName,
|
|
99
127
|
password_hash: "!system",
|
|
100
128
|
role: "system",
|
|
101
129
|
user_type: "system",
|
|
102
|
-
display_name:
|
|
130
|
+
display_name: spiritName
|
|
103
131
|
}).returning(userSelectFields);
|
|
104
132
|
return result;
|
|
105
133
|
} catch (err) {
|
|
106
134
|
if (err instanceof Error && err.message.includes("UNIQUE constraint")) {
|
|
107
|
-
const retried = await db.select(userSelectFields).from(users).where(
|
|
135
|
+
const retried = await db.select(userSelectFields).from(users).where(eq(users.user_type, "system")).get();
|
|
108
136
|
if (retried) return retried;
|
|
109
137
|
}
|
|
110
138
|
throw err;
|
|
@@ -140,9 +168,9 @@ async function setUserRole(id, role) {
|
|
|
140
168
|
}
|
|
141
169
|
async function deleteUser(id) {
|
|
142
170
|
const db = await getDb();
|
|
143
|
-
const target = await db.select({ id: users.id }).from(users).where(and(eq(users.id, id), eq(users.user_type, "
|
|
171
|
+
const target = await db.select({ id: users.id }).from(users).where(and(eq(users.id, id), eq(users.user_type, "human"))).get();
|
|
144
172
|
if (!target) throw new Error("User not found");
|
|
145
|
-
await db.delete(users).where(and(eq(users.id, id), eq(users.user_type, "
|
|
173
|
+
await db.delete(users).where(and(eq(users.id, id), eq(users.user_type, "human")));
|
|
146
174
|
}
|
|
147
175
|
async function updateUserProfile(userId, profile) {
|
|
148
176
|
const db = await getDb();
|
|
@@ -168,6 +196,8 @@ export {
|
|
|
168
196
|
createUser,
|
|
169
197
|
verifyUser,
|
|
170
198
|
getUser,
|
|
199
|
+
getDisplayNames,
|
|
200
|
+
withSenderDisplayNames,
|
|
171
201
|
getUserByUsername,
|
|
172
202
|
listUsers,
|
|
173
203
|
listPendingUsers,
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
exec
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
readGlobalConfig
|
|
7
|
-
} from "./chunk-NJHN6IRB.js";
|
|
4
|
+
} from "./chunk-AJWFDIEY.js";
|
|
8
5
|
import {
|
|
9
6
|
logger_default
|
|
10
7
|
} from "./chunk-QUSMYGNQ.js";
|
|
11
8
|
import {
|
|
12
9
|
getDb,
|
|
13
10
|
readAllMinds,
|
|
11
|
+
readGlobalConfig,
|
|
14
12
|
voluteHome,
|
|
15
13
|
voluteSystemDir
|
|
16
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-CAIYV33P.js";
|
|
17
15
|
|
|
18
16
|
// packages/daemon/src/lib/backup/restic.ts
|
|
19
17
|
import { writeFileSync } from "fs";
|