volute 0.48.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 +79 -328
- package/dist/{accept-KYNC5X3U.js → accept-5NK5XJB5.js} +2 -1
- package/dist/{activity-events-MIOK3IOU.js → activity-events-H7YI3BTF.js} +4 -4
- package/dist/{ai-service-643TNFPH.js → ai-service-V4CTNGI3.js} +6 -5
- package/dist/{archive-6Z4GFQPH.js → archive-ORM3ENHI.js} +3 -3
- package/dist/{auth-A4VGHADI.js → auth-DT7GY7EZ.js} +11 -7
- package/dist/{avatar-image-Y45R7LW5.js → avatar-image-QEPAP3A5.js} +4 -4
- package/dist/{backup-UDH4GMSW.js → backup-IE6PMXJO.js} +17 -18
- package/dist/{bridge-3FNSWLNQ.js → bridge-YK7NTRU5.js} +2 -1
- package/dist/{channels-SGQZHNQJ.js → channels-FSAHOQWI.js} +2 -1
- package/dist/{chat-X43VYHH2.js → chat-W5K6HCBE.js} +9 -9
- package/dist/{chunk-LTLFOSA4.js → chunk-3BAFMGCJ.js} +3 -3
- package/dist/{chunk-XVBSFLM7.js → chunk-4CN7OCJE.js} +2 -2
- package/dist/{chunk-HPGN6XRT.js → chunk-574M6I7F.js} +39 -6
- package/dist/{chunk-FJ2MZ5PH.js → chunk-5FVANDON.js} +2 -2
- package/dist/{chunk-2MJ7EOMT.js → chunk-5IIVOWSP.js} +28 -19
- package/dist/{chunk-4FCL4DVZ.js → chunk-5PKFJHCR.js} +2 -2
- package/dist/{chunk-MOERAQXH.js → chunk-5TPC4KCV.js} +38 -31
- package/dist/{chunk-YNBXEQAP.js → chunk-632FJ23O.js} +24 -20
- package/dist/{chunk-T4VS7UDW.js → chunk-636GFQNE.js} +12 -12
- package/dist/{chunk-EIQDZC43.js → chunk-6BM2I736.js} +25 -6
- package/dist/{chunk-WARH6GIV.js → chunk-74T3CEXK.js} +17 -15
- package/dist/{chunk-OQJMTHEH.js → chunk-77IZUVBB.js} +2 -2
- package/dist/{chunk-USD45JKR.js → chunk-7DXLIYPY.js} +77 -64
- package/dist/chunk-7FDWPQCU.js +289 -0
- package/dist/chunk-7OZWKHA3.js +548 -0
- package/dist/{chunk-IJPMIEVE.js → chunk-7UWXAJMK.js} +1 -1
- package/dist/{chunk-SZJCJVXV.js → chunk-7XDOTN4R.js} +2 -2
- package/dist/{chunk-YKA7DCVW.js → chunk-AFSLNUTT.js} +1 -1
- package/dist/{chunk-DGGZVZTM.js → chunk-AJWFDIEY.js} +17 -2
- package/dist/chunk-ALIVXDM4.js +1014 -0
- package/dist/chunk-CAIYV33P.js +523 -0
- package/dist/{chunk-MTRMQFCQ.js → chunk-E5S3ILVA.js} +2 -2
- 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-HW6Q7AMB.js +113 -0
- package/dist/chunk-JI67D7O2.js +1222 -0
- package/dist/{chunk-3YUBFTDN.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-2OIYNHWO.js → chunk-QFVGPKJI.js} +1 -1
- package/dist/{chunk-T2TP6ZC6.js → chunk-QUSMYGNQ.js} +6 -0
- package/dist/{chunk-HNGFKPNS.js → chunk-SFRYRW37.js} +85 -36
- package/dist/{chunk-7KRIHYLR.js → chunk-SSNZ6ZNN.js} +2 -2
- package/dist/{chunk-HUNDXZBZ.js → chunk-TGJHGVBZ.js} +48 -19
- package/dist/{chunk-PJVPDY2Z.js → chunk-U3EJJ7JN.js} +2 -2
- package/dist/{chunk-ODDGGLM6.js → chunk-UC6BNMGT.js} +43 -13
- package/dist/{chunk-Q7HOAVFR.js → chunk-WBBKYUGF.js} +4 -6
- package/dist/{chunk-WQ46E33M.js → chunk-X67VT4QO.js} +2 -2
- package/dist/{chunk-MJRXFUMS.js → chunk-YQOYZ6G7.js} +3 -5
- package/dist/{chunk-VZRA5TYO.js → chunk-ZUG76D3P.js} +36 -6
- package/dist/cli.js +34 -27
- package/dist/{clock-CNRF6F7T.js → clock-LH7UFNLJ.js} +5 -4
- package/dist/{cloud-sync-WHKCB4CD.js → cloud-sync-IDJFVDEP.js} +23 -20
- package/dist/{config-RPSLA2HX.js → config-UGJS57VT.js} +3 -3
- package/dist/{conversations-C7IKYSHD.js → conversations-S2232Y5I.js} +9 -5
- package/dist/{create-GJKHABJB.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-7KUHVZIN.js → daemon-restart-2AAGYFHE.js} +6 -7
- package/dist/daemon.js +2166 -833
- package/dist/{db-FO6LXYCW.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-3QFG2ZEX.js → delivery-router-JE7SHYNU.js} +10 -6
- package/dist/{down-G6IADJXV.js → down-D4IRNEMJ.js} +5 -5
- package/dist/echo-text-WYAAODBV.js +39 -0
- package/dist/{env-C7Z55QCJ.js → env-ABM5IMA7.js} +8 -7
- package/dist/{env-6TGPO5WG.js → env-AZK5X4W7.js} +3 -3
- package/dist/{exec-QIFYZG4C.js → exec-2H65LMTA.js} +3 -3
- package/dist/{export-C2K3NIRD.js → export-3E3EL6W3.js} +4 -4
- package/dist/{extension-J4ZQ2GHV.js → extension-MRYJWSMV.js} +2 -1
- package/dist/{extensions-GEKF47A4.js → extensions-7KP3X6G7.js} +23 -20
- package/dist/{files-LXQSQOFG.js → files-6BMKVG5G.js} +5 -4
- package/dist/{import-SX3ZXHB4.js → import-UPNTEBBT.js} +9 -9
- package/dist/{isolation-MCT4ZYLT.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-CL4IT2ED.js → login-MOXVLULE.js} +7 -6
- package/dist/{login-ARRZ4ORJ.js → login-RJJTCVR3.js} +4 -3
- package/dist/{logout-YZRMZ3O2.js → logout-BYV433X6.js} +2 -1
- package/dist/{logout-HZYJCYCA.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-46AOK373.js → mind-NYRALSV2.js} +19 -19
- package/dist/{mind-activity-tracker-YVZPC4A5.js → mind-activity-tracker-L7GCYXQR.js} +5 -5
- package/dist/{mind-contacts-GV7XYL5D.js → mind-contacts-QYU4TPEA.js} +8 -7
- package/dist/{mind-history-TTGA5BHZ.js → mind-history-NXXOOTX6.js} +34 -11
- 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-DV7KP255.js → mind-sleep-TH6BRQ5X.js} +5 -4
- 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-RTN2PS7O.js → package-XYSV7NUT.js} +27 -26
- package/dist/prompts-QKFPX6DQ.js +24 -0
- package/dist/{read-YSWUXYL7.js → read-ZXGUT4QC.js} +5 -3
- package/dist/{register-42VBJKTP.js → register-OX4HRSGC.js} +4 -3
- package/dist/{registry-UMMDRPRM.js → registry-4UF6OCOE.js} +10 -4
- package/dist/{reject-SXGCYN4A.js → reject-TWB4QJHG.js} +2 -1
- package/dist/{restart-YYEGZJDD.js → restart-AGEGNSYQ.js} +6 -5
- package/dist/{sandbox-5VQ454XP.js → sandbox-EGEU5GGE.js} +8 -5
- package/dist/scheduler-UV6RUJ7P.js +25 -0
- package/dist/{schema-VEVO7HG6.js → schema-C2GIPD4V.js} +3 -3
- package/dist/{seed-F2HXZQU4.js → seed-3IMBOAGK.js} +1 -1
- package/dist/{seed-check-TYD7RRZY.js → seed-check-NRJEQZST.js} +14 -5
- package/dist/{seed-cmd-MLCTGSX5.js → seed-cmd-U73XVQMI.js} +3 -3
- package/dist/{seed-create-KQ7OILWB.js → seed-create-FBLNVSUP.js} +4 -4
- package/dist/{seed-readiness-RBPGOLSZ.js → seed-readiness-QRA46ZJQ.js} +4 -5
- package/dist/{seed-sprout-HVYCFJLA.js → seed-sprout-3B4SZX7J.js} +12 -12
- package/dist/{send-TD2X5U3K.js → send-NBRZJXKX.js} +34 -12
- package/dist/{service-CVZMQYK6.js → service-XMXAXGJD.js} +4 -4
- package/dist/{service-install-VCRMFWX5.js → service-install-MOKTEG7B.js} +5 -5
- package/dist/{setup-5ECWTYKG.js → setup-CAJFOR2N.js} +12 -3
- package/dist/{setup-AE4CVUC4.js → setup-JGYAXXW7.js} +6 -7
- package/dist/{skill-UUM4JZRF.js → skill-NXIHDQCG.js} +7 -6
- 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 +6 -6
- package/dist/skills/volute-mind/references/integrations.md +2 -2
- package/dist/skills/volute-mind/references/routing.md +19 -18
- package/dist/skills/volute-mind/references/variants.md +48 -14
- package/dist/{skills-B3SVDCEB.js → skills-5MSMT7PT.js} +7 -6
- package/dist/sleep-manager-LIEPO6WG.js +41 -0
- package/dist/spirit-IL5EMWYZ.js +34 -0
- package/dist/spirit-availability-YFEGJNJ2.js +42 -0
- package/dist/{split-SKZ4Y2D6.js → split-BU5VWX6P.js} +5 -2
- package/dist/{sprout-KQ43BWZJ.js → sprout-UPXGJ5HX.js} +1 -1
- package/dist/{src-YH6PQ7LJ.js → src-HGNE2XG4.js} +7 -1
- package/dist/{src-WLJE73NP.js → src-LCSOQY6Z.js} +60 -54
- package/dist/{src-JAOVXO5W.js → src-UDMJZ6MH.js} +8 -8
- package/dist/{start-O6UKK7BG.js → start-MUMNFR52.js} +4 -3
- package/dist/{status-F4PGREUU.js → status-IL67CYM4.js} +7 -6
- package/dist/{stop-UBX6X5RA.js → stop-EKERNYTX.js} +6 -5
- package/dist/system-events-A6IGCEC3.js +46 -0
- package/dist/system-install-YZSWCPDK.js +8 -0
- package/dist/{systems-JJNGQHAO.js → systems-VDRUZXNF.js} +5 -4
- package/dist/{tailscale-MCLY5GYE.js → tailscale-SJUW2ETR.js} +3 -3
- package/dist/{template-staleness-EMQORSGG.js → template-staleness-T27VCGYA.js} +4 -4
- package/dist/{turn-tracker-KLPV3PAU.js → turn-tracker-6EI2EL7G.js} +7 -7
- package/dist/{up-RVGDE6CQ.js → up-CLL4665A.js} +5 -6
- package/dist/{update-OXQEGGXD.js → update-HVAUCQPN.js} +5 -5
- package/dist/{update-check-266R4ZSY.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-73YURTFR.js → version-notify-7BUHWZNT.js} +11 -28
- 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/0013_variant_purpose.sql +3 -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 +35 -0
- package/package.json +27 -26
- 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 +34 -2
- package/templates/_base/home/.config/routes.json +2 -2
- package/templates/_base/home/VOLUTE.md +30 -5
- package/templates/_base/src/lib/daemon-client.ts +28 -8
- 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 +5 -2
- package/templates/claude/src/lib/hooks/identity-reload.ts +12 -3
- 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 +47 -6
- package/templates/pi/src/lib/reply-instructions-extension.ts +28 -1
- package/dist/chunk-5KXCM5AW.js +0 -169
- package/dist/chunk-IYCV34IU.js +0 -158
- package/dist/chunk-VB2QXUJQ.js +0 -5260
- package/dist/chunk-WW6C3PLV.js +0 -280
- package/dist/delivery-manager-HZTT5SJR.js +0 -36
- package/dist/echo-text-H3SH337Q.js +0 -36
- package/dist/message-delivery-GPQ5SE5N.js +0 -40
- package/dist/mind-service-2ARGJNKP.js +0 -44
- package/dist/notices-2KU5NTRY.js +0 -25
- package/dist/scheduler-I7JZCT47.js +0 -34
- package/dist/sleep-manager-Z27R3WTW.js +0 -38
- package/dist/spirit-WXS3HCLN.js +0 -25
- package/dist/system-chat-63ABFF6V.js +0 -40
- package/dist/web-assets/assets/index-WdZ60R6c.css +0 -1
- package/dist/web-assets/assets/index-taX6Ezfa.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
|
};
|
|
@@ -63,6 +63,12 @@ function child(cat) {
|
|
|
63
63
|
}
|
|
64
64
|
function errorData(err) {
|
|
65
65
|
if (err instanceof Error) return { error: err.stack ?? err.message };
|
|
66
|
+
if (err && typeof err === "object") {
|
|
67
|
+
const e = err;
|
|
68
|
+
if (e.error instanceof Error) return { error: e.error.stack ?? e.error.message };
|
|
69
|
+
if (typeof e.error === "string" && e.error) return { error: e.error };
|
|
70
|
+
if (typeof e.message === "string" && e.message) return { error: e.message };
|
|
71
|
+
}
|
|
66
72
|
return { error: String(err) };
|
|
67
73
|
}
|
|
68
74
|
var log = {
|
|
@@ -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-5KXCM5AW.js";
|
|
25
|
+
} from "./chunk-632FJ23O.js";
|
|
29
26
|
import {
|
|
30
27
|
logger_default
|
|
31
|
-
} from "./chunk-
|
|
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,17 +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
|
-
|
|
108
|
-
|
|
109
|
-
const systemName = globalConfig.name ?? "Volute";
|
|
110
|
-
const soulContent = getSpiritSoul(systemName, globalConfig.description);
|
|
111
|
-
writeFileSync(soulPath, soulContent);
|
|
115
|
+
writeFileSync(resolve(dir, "home/SOUL.md"), getSpiritSoul());
|
|
116
|
+
writeSpiritSystemJson(dir);
|
|
112
117
|
const routesPath = resolve(dir, "home/.config/routes.json");
|
|
113
118
|
mkdirSync(resolve(dir, "home/.config"), { recursive: true });
|
|
114
|
-
const routesContent = { rules: [{ channel: "*",
|
|
119
|
+
const routesContent = { rules: [{ channel: "*", thread: "${channel}" }], default: "main" };
|
|
115
120
|
writeFileSync(routesPath, `${JSON.stringify(routesContent, null, 2)}
|
|
116
121
|
`);
|
|
117
122
|
if (spiritModel) {
|
|
@@ -134,7 +139,7 @@ async function ensureSpiritProject() {
|
|
|
134
139
|
try {
|
|
135
140
|
const shared = await getSharedSkill(skillId);
|
|
136
141
|
if (shared) {
|
|
137
|
-
await installSkill(
|
|
142
|
+
await installSkill(spiritName, dir, skillId);
|
|
138
143
|
}
|
|
139
144
|
} catch (err) {
|
|
140
145
|
slog.warn(`failed to install skill ${skillId} for spirit`, logger_default.errorData(err));
|
|
@@ -145,22 +150,59 @@ async function ensureSpiritProject() {
|
|
|
145
150
|
} catch (err) {
|
|
146
151
|
slog.warn("failed to add tending schedule to spirit config", logger_default.errorData(err));
|
|
147
152
|
}
|
|
148
|
-
const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-
|
|
153
|
+
const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-OKDFM6WA.js");
|
|
149
154
|
ensureVoluteGroup();
|
|
150
|
-
createMindUser(
|
|
151
|
-
await chownMindDir(dir,
|
|
155
|
+
createMindUser(spiritName, resolve(dir, "home"));
|
|
156
|
+
await chownMindDir(dir, spiritName);
|
|
152
157
|
const port = await nextPort();
|
|
153
|
-
await addSpirit(
|
|
158
|
+
await addSpirit(spiritName, port, template, dir);
|
|
154
159
|
slog.info("spirit project created");
|
|
155
160
|
} catch (err) {
|
|
156
161
|
slog.error("failed to create spirit project", logger_default.errorData(err));
|
|
157
162
|
rmSync(dir, { recursive: true, force: true });
|
|
158
163
|
throw err;
|
|
164
|
+
} finally {
|
|
165
|
+
creationInProgress = false;
|
|
159
166
|
}
|
|
160
167
|
}
|
|
168
|
+
function spiritSystemJsonPath(dir) {
|
|
169
|
+
return resolve(dir, "home/.config/system.json");
|
|
170
|
+
}
|
|
171
|
+
function writeSpiritSystemJson(dir) {
|
|
172
|
+
const config = readGlobalConfig();
|
|
173
|
+
const path = spiritSystemJsonPath(dir);
|
|
174
|
+
mkdirSync(resolve(path, ".."), { recursive: true });
|
|
175
|
+
const data = { name: config.name ?? "Volute", description: config.description };
|
|
176
|
+
writeFileSync(path, `${JSON.stringify(data, null, 2)}
|
|
177
|
+
`);
|
|
178
|
+
}
|
|
179
|
+
function seedSpiritSoulIfMissing(dir) {
|
|
180
|
+
const soulPath = resolve(dir, "home/SOUL.md");
|
|
181
|
+
if (existsSync(soulPath)) return false;
|
|
182
|
+
writeFileSync(soulPath, getSpiritSoul());
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
async function notifySpiritSystemChange() {
|
|
186
|
+
const spiritName = getSpiritName();
|
|
187
|
+
const entry = await findMind(spiritName);
|
|
188
|
+
if (entry?.mindType !== "spirit") return;
|
|
189
|
+
const dir = spiritDir();
|
|
190
|
+
if (!existsSync(dir)) return;
|
|
191
|
+
writeSpiritSystemJson(dir);
|
|
192
|
+
const config = readGlobalConfig();
|
|
193
|
+
const name = config.name ?? "Volute";
|
|
194
|
+
const desc = config.description ? ` \u2014 ${config.description}` : "";
|
|
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
|
+
});
|
|
201
|
+
}
|
|
161
202
|
async function syncSpiritTemplate() {
|
|
162
|
-
const
|
|
163
|
-
|
|
203
|
+
const spiritName = getSpiritName();
|
|
204
|
+
const entry = await findMind(spiritName);
|
|
205
|
+
if (entry?.mindType !== "spirit") return;
|
|
164
206
|
const dir = spiritDir();
|
|
165
207
|
if (!existsSync(dir)) return;
|
|
166
208
|
const templatesRoot = findTemplatesRoot();
|
|
@@ -174,15 +216,15 @@ async function syncSpiritTemplate() {
|
|
|
174
216
|
if (existsSync(newSrc)) {
|
|
175
217
|
cpSync(newSrc, resolve(dir, "src"), { recursive: true });
|
|
176
218
|
}
|
|
177
|
-
const newPkg = renderComposedPackageJson(newComposed.composedDir,
|
|
219
|
+
const newPkg = renderComposedPackageJson(newComposed.composedDir, spiritName);
|
|
178
220
|
if (newPkg) {
|
|
179
221
|
cpSync(newPkg, resolve(dir, "package.json"));
|
|
180
222
|
await exec("npm", ["install"], { cwd: dir, env: npmEnv() });
|
|
181
223
|
}
|
|
182
|
-
const db = await (await import("./db-
|
|
183
|
-
const { minds } = await import("./schema-
|
|
224
|
+
const db = await (await import("./db-QAY45Z56.js")).getDb();
|
|
225
|
+
const { minds } = await import("./schema-C2GIPD4V.js");
|
|
184
226
|
const { eq } = await import("drizzle-orm");
|
|
185
|
-
await db.update(minds).set({ template: expectedTemplate }).where(eq(minds.name,
|
|
227
|
+
await db.update(minds).set({ template: expectedTemplate }).where(eq(minds.name, spiritName));
|
|
186
228
|
}
|
|
187
229
|
const template = expectedTemplate;
|
|
188
230
|
const { composedDir } = composeTemplate(templatesRoot, template);
|
|
@@ -201,9 +243,9 @@ async function syncSpiritTemplate() {
|
|
|
201
243
|
cpSync(composedSrc, srcDir, { recursive: true });
|
|
202
244
|
}
|
|
203
245
|
}
|
|
246
|
+
seedSpiritSoulIfMissing(dir);
|
|
247
|
+
writeSpiritSystemJson(dir);
|
|
204
248
|
const config = readGlobalConfig();
|
|
205
|
-
const systemName = config.name ?? "Volute";
|
|
206
|
-
writeFileSync(resolve(dir, "home/SOUL.md"), getSpiritSoul(systemName, config.description));
|
|
207
249
|
const spiritModel = config.spiritModel;
|
|
208
250
|
if (spiritModel) {
|
|
209
251
|
const modelForConfig = template === "pi" ? qualifyModelId(spiritModel) : unqualifyModelId(spiritModel);
|
|
@@ -215,7 +257,7 @@ async function syncSpiritTemplate() {
|
|
|
215
257
|
`);
|
|
216
258
|
}
|
|
217
259
|
}
|
|
218
|
-
const composedPkg = renderComposedPackageJson(composedDir,
|
|
260
|
+
const composedPkg = renderComposedPackageJson(composedDir, spiritName);
|
|
219
261
|
const currentPkg = resolve(dir, "package.json");
|
|
220
262
|
const nodeModulesMissing = !existsSync(resolve(dir, "node_modules"));
|
|
221
263
|
if (composedPkg) {
|
|
@@ -241,7 +283,7 @@ async function syncSpiritTemplate() {
|
|
|
241
283
|
try {
|
|
242
284
|
const shared = await getSharedSkill(skillId);
|
|
243
285
|
if (shared) {
|
|
244
|
-
await installSkill(
|
|
286
|
+
await installSkill(spiritName, dir, skillId);
|
|
245
287
|
slog.info(`installed missing spirit skill: ${skillId}`);
|
|
246
288
|
}
|
|
247
289
|
} catch (err) {
|
|
@@ -257,12 +299,14 @@ async function syncSpiritTemplate() {
|
|
|
257
299
|
}
|
|
258
300
|
slog.info("spirit template synced");
|
|
259
301
|
}
|
|
260
|
-
function getSpiritSoul(
|
|
261
|
-
const
|
|
302
|
+
function getSpiritSoul() {
|
|
303
|
+
const config = readGlobalConfig();
|
|
304
|
+
const name = config.setup?.spiritName ?? "volute";
|
|
305
|
+
const temperament = config.setup?.spiritTemperament;
|
|
306
|
+
const temperamentLine = temperament ? `
|
|
262
307
|
|
|
263
|
-
${
|
|
264
|
-
`
|
|
265
|
-
return `You are Volute, the spirit of the ${systemName} system.${descLine}
|
|
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}
|
|
266
310
|
|
|
267
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.
|
|
268
312
|
|
|
@@ -291,6 +335,11 @@ export {
|
|
|
291
335
|
firstWeekSchedules,
|
|
292
336
|
spiritDir,
|
|
293
337
|
getSpiritModel,
|
|
338
|
+
spiritCreationInProgress,
|
|
339
|
+
_setSpiritCreationInProgressForTest,
|
|
294
340
|
ensureSpiritProject,
|
|
341
|
+
writeSpiritSystemJson,
|
|
342
|
+
seedSpiritSoulIfMissing,
|
|
343
|
+
notifySpiritSystemChange,
|
|
295
344
|
syncSpiritTemplate
|
|
296
345
|
};
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
} from "./chunk-RRZ4RQQU.js";
|
|
10
10
|
import {
|
|
11
11
|
logger_default
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QUSMYGNQ.js";
|
|
13
13
|
import {
|
|
14
14
|
mindDir
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-CAIYV33P.js";
|
|
16
16
|
|
|
17
17
|
// packages/daemon/src/lib/mind/template-staleness.ts
|
|
18
18
|
import { createHash } from "crypto";
|
|
@@ -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-5KXCM5AW.js";
|
|
5
|
+
} from "./chunk-AJWFDIEY.js";
|
|
10
6
|
import {
|
|
11
7
|
logger_default
|
|
12
|
-
} from "./chunk-
|
|
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";
|
|
@@ -28,6 +26,7 @@ import {
|
|
|
28
26
|
mkdirSync,
|
|
29
27
|
readdirSync,
|
|
30
28
|
readFileSync,
|
|
29
|
+
renameSync,
|
|
31
30
|
rmSync,
|
|
32
31
|
writeFileSync
|
|
33
32
|
} from "fs";
|
|
@@ -46,7 +45,7 @@ async function initDefaultSkills() {
|
|
|
46
45
|
const config = readGlobalConfig();
|
|
47
46
|
let extensionSkills = [];
|
|
48
47
|
try {
|
|
49
|
-
const { getExtensionStandardSkills } = await import("./extensions-
|
|
48
|
+
const { getExtensionStandardSkills } = await import("./extensions-7KP3X6G7.js");
|
|
50
49
|
extensionSkills = getExtensionStandardSkills();
|
|
51
50
|
} catch (err) {
|
|
52
51
|
logger_default.warn("failed to load extension standard skills during init", logger_default.errorData(err));
|
|
@@ -185,9 +184,12 @@ function mindSkillsDir(dir) {
|
|
|
185
184
|
}
|
|
186
185
|
return resolve(home, subdir);
|
|
187
186
|
}
|
|
188
|
-
function
|
|
187
|
+
function mindSkillsSubdir(dir) {
|
|
189
188
|
const home = resolve(dir, "home");
|
|
190
|
-
return
|
|
189
|
+
return mindSkillsDir(dir).slice(home.length + 1);
|
|
190
|
+
}
|
|
191
|
+
function relSkillsPath(dir) {
|
|
192
|
+
return join("home", mindSkillsSubdir(dir));
|
|
191
193
|
}
|
|
192
194
|
function readUpstream(skillDir) {
|
|
193
195
|
const upstreamPath = join(skillDir, ".upstream.json");
|
|
@@ -453,9 +455,7 @@ exec node ${skillScriptPath} "$@"
|
|
|
453
455
|
exec bash ${skillScriptPath} "$@"
|
|
454
456
|
`;
|
|
455
457
|
}
|
|
456
|
-
function installHookShims(dir, skillId, hooks) {
|
|
457
|
-
const home = resolve(dir, "home");
|
|
458
|
-
const skillsSubdir = mindSkillsDir(dir).slice(home.length + 1);
|
|
458
|
+
function installHookShims(dir, skillId, hooks, skillsSubdir = mindSkillsSubdir(dir)) {
|
|
459
459
|
for (const [event, scriptPath] of Object.entries(hooks)) {
|
|
460
460
|
const eventDir = join(dir, "home", ".local", "hooks", event);
|
|
461
461
|
mkdirSync(eventDir, { recursive: true });
|
|
@@ -498,9 +498,7 @@ function binShimOwner(shimPath) {
|
|
|
498
498
|
const line = readFileSync(shimPath, "utf-8").split("\n").find((l) => l.startsWith(BIN_SHIM_MARKER));
|
|
499
499
|
return line?.slice(BIN_SHIM_MARKER.length).trim() || void 0;
|
|
500
500
|
}
|
|
501
|
-
function installBinShim(dir, skillId, scriptPath) {
|
|
502
|
-
const home = resolve(dir, "home");
|
|
503
|
-
const skillsSubdir = mindSkillsDir(dir).slice(home.length + 1);
|
|
501
|
+
function installBinShim(dir, skillId, scriptPath, skillsSubdir = mindSkillsSubdir(dir)) {
|
|
504
502
|
const binDir = join(dir, "home", ".local", "bin");
|
|
505
503
|
mkdirSync(binDir, { recursive: true });
|
|
506
504
|
const cmdName = binCommandName(scriptPath);
|
|
@@ -520,6 +518,36 @@ function removeBinShim(dir, scriptPath) {
|
|
|
520
518
|
const shimPath = join(dir, "home", ".local", "bin", cmdName);
|
|
521
519
|
if (existsSync(shimPath)) rmSync(shimPath);
|
|
522
520
|
}
|
|
521
|
+
function migrateSkillsToTemplate(dir, oldTemplate, newTemplate) {
|
|
522
|
+
const home = resolve(dir, "home");
|
|
523
|
+
const oldSubdir = TEMPLATE_SKILLS_DIR[oldTemplate] ?? TEMPLATE_SKILLS_DIR.claude;
|
|
524
|
+
const newSubdir = TEMPLATE_SKILLS_DIR[newTemplate] ?? TEMPLATE_SKILLS_DIR.claude;
|
|
525
|
+
if (oldSubdir === newSubdir) return [];
|
|
526
|
+
const oldDir = resolve(home, oldSubdir);
|
|
527
|
+
const newDir = resolve(home, newSubdir);
|
|
528
|
+
if (!existsSync(oldDir)) return [];
|
|
529
|
+
const skillIds = readdirSync(oldDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
530
|
+
const migrated = [];
|
|
531
|
+
if (skillIds.length > 0) {
|
|
532
|
+
mkdirSync(newDir, { recursive: true });
|
|
533
|
+
for (const skillId of skillIds) {
|
|
534
|
+
const from = join(oldDir, skillId);
|
|
535
|
+
const to = join(newDir, skillId);
|
|
536
|
+
if (existsSync(to)) rmSync(to, { recursive: true, force: true });
|
|
537
|
+
renameSync(from, to);
|
|
538
|
+
removeHookShims(dir, skillId);
|
|
539
|
+
const skillMdPath = join(to, "SKILL.md");
|
|
540
|
+
if (existsSync(skillMdPath)) {
|
|
541
|
+
const { hooks, bin } = parseSkillMd(readFileSync(skillMdPath, "utf-8"));
|
|
542
|
+
installHookShims(dir, skillId, hooks, newSubdir);
|
|
543
|
+
if (bin) installBinShim(dir, skillId, bin, newSubdir);
|
|
544
|
+
}
|
|
545
|
+
migrated.push(skillId);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
rmSync(oldDir, { recursive: true, force: true });
|
|
549
|
+
return migrated;
|
|
550
|
+
}
|
|
523
551
|
function listFilesRecursive(dir, prefix = "") {
|
|
524
552
|
const results = [];
|
|
525
553
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
@@ -609,7 +637,7 @@ async function syncBuiltinSkills() {
|
|
|
609
637
|
const destDir = join(sharedSkillsDir(), entry.name);
|
|
610
638
|
if (existsSync(destDir)) {
|
|
611
639
|
const destHash = hashSkillDir(destDir);
|
|
612
|
-
if (sourceHash === destHash) continue;
|
|
640
|
+
if (sourceHash === destHash && await getSharedSkill(entry.name)) continue;
|
|
613
641
|
}
|
|
614
642
|
await importSkillFromDir(sourceDir, "volute");
|
|
615
643
|
logger_default.info(`synced built-in skill: ${entry.name}`);
|
|
@@ -641,6 +669,7 @@ export {
|
|
|
641
669
|
removeHookShims,
|
|
642
670
|
installBinShim,
|
|
643
671
|
removeBinShim,
|
|
672
|
+
migrateSkillsToTemplate,
|
|
644
673
|
listFilesRecursive,
|
|
645
674
|
findSkillsRoot,
|
|
646
675
|
hashSkillDir,
|
|
@@ -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";
|