volute 0.49.0 → 0.51.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-LQII6PZS.js} +3 -3
- package/dist/{ai-service-A7FS7EC3.js → ai-service-YW5SWCSB.js} +9 -4
- package/dist/{archive-7E3YE6VF.js → archive-FOHGXHPT.js} +3 -3
- package/dist/{auth-ABYLOEZ7.js → auth-X6EMNEGB.js} +10 -6
- package/dist/{avatar-image-6ATV2IOZ.js → avatar-image-52WGXLHV.js} +3 -3
- package/dist/{backup-XYAMT4CU.js → backup-YVGV2ZNM.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-VAZ25KVT.js} +9 -9
- package/dist/{chunk-P4LHVRNE.js → chunk-2RNMBXD2.js} +43 -19
- package/dist/{chunk-6HGEZJDH.js → chunk-5N32EN4O.js} +2 -2
- package/dist/{chunk-JCWB2ITW.js → chunk-5Y54AE3L.js} +35 -5
- package/dist/{chunk-HCYQRME2.js → chunk-6NLW72HP.js} +2 -2
- package/dist/chunk-7HN63Q7J.js +1317 -0
- package/dist/chunk-7YJY3F2R.js +38 -0
- package/dist/{chunk-EADX54RG.js → chunk-AI47FDGL.js} +6 -7
- package/dist/{chunk-IH5TKXX6.js → chunk-BSHZ23MS.js} +12 -11
- package/dist/{chunk-K3JOLGWF.js → chunk-CDKQJWGK.js} +76 -63
- package/dist/{chunk-L27YYONJ.js → chunk-CV6BNGFK.js} +3 -3
- package/dist/{chunk-NOIAHMJB.js → chunk-DMK5ASKV.js} +1 -1
- package/dist/chunk-DN3LKLYR.js +109 -0
- package/dist/{chunk-JBIFXB6I.js → chunk-EDR47UE2.js} +3 -5
- package/dist/{chunk-SHKM5RGD.js → chunk-EEOMA4DX.js} +1 -1
- package/dist/{chunk-YIJGKHIS.js → chunk-EGV6R6UF.js} +43 -20
- package/dist/{chunk-KHCKZ36O.js → chunk-FLIEXG2T.js} +1 -1
- package/dist/chunk-FNJCBRD3.js +31 -0
- package/dist/{chunk-JPGHSXSV.js → chunk-FXWBFDQR.js} +23 -9
- package/dist/{chunk-JCBPU57A.js → chunk-G7A5LEVI.js} +6 -6
- package/dist/{chunk-PY24ZL62.js → chunk-GLM7TVWP.js} +1 -1
- package/dist/{chunk-RSBL3FAD.js → chunk-H6X6CKDN.js} +235 -24
- package/dist/{chunk-4DSGN4FL.js → chunk-HKP6OAJP.js} +43 -13
- package/dist/{chunk-C3KLHJDB.js → chunk-HTRSSOHY.js} +1 -1
- package/dist/{chunk-EG5LSKHU.js → chunk-I7U5EEZC.js} +2 -2
- package/dist/chunk-ICL6T4SN.js +562 -0
- package/dist/{chunk-FBBS4BVR.js → chunk-ICXY54ZC.js} +1 -1
- package/dist/{chunk-DAIIMBLB.js → chunk-IWAVIJO2.js} +3 -5
- package/dist/{chunk-TXJL36ZQ.js → chunk-JHKBALS2.js} +2 -2
- package/dist/{chunk-MG3Z34YE.js → chunk-L7BKTZ5U.js} +1 -1
- package/dist/{chunk-SX72DOO3.js → chunk-LAUCO2HC.js} +1 -1
- package/dist/chunk-LNNI3MS4.js +54 -0
- package/dist/{chunk-BCG45AQB.js → chunk-M74I3HHF.js} +15 -5
- package/dist/{chunk-DVN6DNMI.js → chunk-M77B73VV.js} +17 -2
- package/dist/{chunk-4B62E4CG.js → chunk-OXWUEU5V.js} +2 -2
- package/dist/chunk-Q7XQLKZB.js +289 -0
- package/dist/{chunk-GWVFDUNB.js → chunk-QT4D5XCI.js} +8 -10
- package/dist/{chunk-VNRSXEBF.js → chunk-TPX6E6PL.js} +38 -5
- package/dist/{chunk-3B427GUK.js → chunk-U54PJPTB.js} +2 -2
- package/dist/{chunk-EFT2OALG.js → chunk-UDZLPR34.js} +20 -5
- package/dist/{chunk-ZX46PGCC.js → chunk-UFTDRTCP.js} +1 -1
- package/dist/chunk-VAEZCIJC.js +1058 -0
- package/dist/chunk-VP5PFNZO.js +2905 -0
- package/dist/{chunk-VIUH5CHQ.js → chunk-VSBMLB2W.js} +51 -34
- package/dist/{chunk-RRZ4RQQU.js → chunk-X67BDDZR.js} +5 -7
- package/dist/cli.js +34 -27
- package/dist/{clock-6JZL2FS6.js → clock-ZT5YT6HA.js} +4 -3
- package/dist/{cloud-sync-VFDTNNCA.js → cloud-sync-GPXYPTIC.js} +23 -20
- package/dist/{config-RPSLA2HX.js → config-UGJS57VT.js} +3 -3
- package/dist/{conversations-TUM5PJJ4.js → conversations-ZL6PHROD.js} +8 -4
- package/dist/{create-Z5FSDNVZ.js → create-G2RIKQYK.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-2EWBRTN5.js} +6 -7
- package/dist/daemon.js +2005 -762
- package/dist/{db-F6UMFRYD.js → db-BONH4SUG.js} +2 -2
- package/dist/{delete-ESEP7NGQ.js → delete-O7PEFQDF.js} +1 -1
- package/dist/delivery-manager-HGVZSEES.js +35 -0
- package/dist/{delivery-router-VUOL5YSA.js → delivery-router-RHANNTAC.js} +7 -5
- package/dist/{down-6X7KX7BZ.js → down-QSNEMTTX.js} +5 -5
- package/dist/echo-text-6ANI5HHN.js +39 -0
- package/dist/{env-ZYMSCB7B.js → env-IBW2QI6K.js} +3 -2
- package/dist/{env-KUL4XKN2.js → env-SQFCWW52.js} +3 -3
- package/dist/{exec-FBXA3CM4.js → exec-ABD3DYA2.js} +3 -3
- package/dist/{export-TNBPDH77.js → export-VBNWM7I4.js} +4 -4
- package/dist/{extension-J4ZQ2GHV.js → extension-MRYJWSMV.js} +2 -1
- package/dist/{extensions-AWNO3SZF.js → extensions-NY6WST33.js} +23 -20
- package/dist/{files-BVBRJJ2P.js → files-BRY5RRIM.js} +5 -4
- package/dist/{import-ZUNKMCKC.js → import-DB2KULRO.js} +8 -8
- package/dist/{isolation-OPCZQRTH.js → isolation-GVV2IBAU.js} +5 -3
- package/dist/{join-34TR2GXQ.js → join-PYA36HEC.js} +1 -1
- package/dist/{list-PMUXZNAM.js → list-UQGIW7OF.js} +8 -3
- package/dist/{login-LKNLCJPA.js → login-RJJTCVR3.js} +2 -1
- package/dist/{login-KAKNFCW5.js → login-SB5OENMV.js} +4 -3
- package/dist/{logout-YZRMZ3O2.js → logout-BYV433X6.js} +2 -1
- package/dist/{logout-RLT62RQP.js → logout-YFZAJRPY.js} +4 -3
- package/dist/message-delivery-JHMAJ2GU.js +43 -0
- package/dist/migrate-thread-config-EQSEP2XG.js +90 -0
- package/dist/{mind-IF6CGMFW.js → mind-WF6QIXWV.js} +19 -19
- package/dist/{mind-activity-tracker-YMMERB6B.js → mind-activity-tracker-QF6DCX2X.js} +4 -4
- package/dist/{mind-contacts-BKUFPUCU.js → mind-contacts-QYU4TPEA.js} +3 -2
- package/dist/{mind-history-WI5OI3BW.js → mind-history-OGNR4L7W.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-DZCUUC7J.js +47 -0
- package/dist/{mind-sleep-VBV7YRSU.js → mind-sleep-LZAFBDZD.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-B6O5APCZ.js} +23 -23
- package/dist/{prompts-MDHDLWEX.js → prompts-NBO3HRK3.js} +3 -3
- package/dist/{read-YSWUXYL7.js → read-RJ5NAW5J.js} +5 -14
- package/dist/{register-TWQDKQRT.js → register-OX4HRSGC.js} +2 -1
- package/dist/{registry-3ELJPUGJ.js → registry-TRC2HJXR.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-NNWCTHRI.js} +7 -4
- package/dist/scheduler-TNBN54ZK.js +25 -0
- package/dist/{schema-6YONVTKZ.js → schema-ZZQVM4GR.js} +5 -3
- package/dist/{seed-NQED7PSX.js → seed-K2LYODIH.js} +1 -1
- package/dist/{seed-check-TYD7RRZY.js → seed-check-NRJEQZST.js} +14 -5
- package/dist/{seed-cmd-QF3F2G4S.js → seed-cmd-2EWBTR6P.js} +3 -3
- package/dist/{seed-create-XOO4N2OE.js → seed-create-VGTLU5FD.js} +4 -4
- package/dist/{seed-readiness-3LRYASA4.js → seed-readiness-DYOVCYHN.js} +4 -5
- package/dist/{seed-sprout-HSBBGSS2.js → seed-sprout-PILHJ3YS.js} +9 -9
- package/dist/{send-IHRJYNXA.js → send-2YKOZJJ5.js} +108 -54
- package/dist/{service-YCOPCTSZ.js → service-XQPMZAGI.js} +4 -4
- package/dist/{service-install-Y46OTF55.js → service-install-2EWD7KXD.js} +5 -5
- package/dist/{setup-F4TE64YI.js → setup-MDPSK2XG.js} +6 -7
- package/dist/{setup-TCN7VH5U.js → setup-WZSXHHRJ.js} +10 -3
- package/dist/{skill-4CYJLYVY.js → skill-B5OJEQUA.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-NH2GQKAF.js} +4 -5
- package/dist/sleep-manager-7JXEQQ2P.js +41 -0
- package/dist/{spirit-SSJMYC6A.js → spirit-25JVAL3M.js} +11 -8
- package/dist/spirit-availability-PJDWZJ3J.js +42 -0
- package/dist/{split-JF2VWTXA.js → split-BU5VWX6P.js} +1 -1
- package/dist/{sprout-AXA2SECQ.js → sprout-EXUZMIOR.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-MWLE3RVC.js} +7 -6
- package/dist/{stop-YORESK4U.js → stop-EKERNYTX.js} +2 -1
- package/dist/system-events-ZPSH63QX.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-KHNZFC7L.js} +2 -2
- package/dist/{template-hash-GSOUARW4.js → template-hash-YKWMVYMM.js} +2 -2
- package/dist/{template-staleness-HKGCTS3H.js → template-staleness-PY2CULH6.js} +5 -5
- package/dist/{turn-tracker-JQ2YUUY2.js → turn-tracker-TAT2HGK6.js} +6 -6
- package/dist/{up-SDLTLPAO.js → up-J7XCAH7P.js} +5 -6
- package/dist/{update-WEA4N2TR.js → update-CIWI2JYA.js} +5 -5
- package/dist/{update-check-DZOTONII.js → update-check-SZ7B5IFI.js} +3 -3
- package/dist/{upgrade-K5FIQPQD.js → upgrade-LIE46UBB.js} +1 -1
- package/dist/variant-cleanup-YXN25ZVW.js +22 -0
- package/dist/{version-notify-WFA5XB5A.js → version-notify-EN3KJ7HH.js} +11 -28
- package/dist/web-assets/assets/index-BOyJ4Gqs.css +1 -0
- package/dist/web-assets/assets/index-CrxBwnzp.js +95 -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/0018_api_tokens.sql +20 -0
- package/drizzle/meta/_journal.json +35 -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/{biome.json.tmpl → biome.json} +2 -1
- package/templates/_base/gitignore +44 -0
- package/templates/_base/home/.config/routes.json +2 -2
- package/templates/_base/home/VOLUTE.md +18 -5
- package/templates/_base/home/public/.gitkeep +0 -0
- 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 +36 -10
- package/templates/_base/src/lib/router.ts +19 -10
- 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 → package.json} +4 -4
- package/templates/claude/src/agent.ts +4 -1
- package/templates/claude/src/lib/hooks/reply-instructions.ts +26 -1
- package/templates/claude/volute-template.json +1 -3
- package/templates/codex/.init/.config/routes.json +3 -3
- package/templates/codex/.init/AGENTS.md +1 -1
- package/templates/codex/{package.json.tmpl → package.json} +4 -4
- package/templates/codex/src/agent.ts +11 -11
- package/templates/codex/src/lib/turn-context.ts +51 -0
- package/templates/codex/volute-template.json +1 -3
- package/templates/pi/.init/.config/routes.json +3 -3
- package/templates/pi/.init/MINDS.md +1 -1
- package/templates/pi/{package.json.tmpl → package.json} +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/templates/pi/volute-template.json +1 -3
- package/dist/chunk-5T5YMX6S.js +0 -23
- 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
- /package/templates/_base/home/.config/{config.json.tmpl → config.json} +0 -0
- /package/templates/codex/home/.config/{config.json.tmpl → config.json} +0 -0
- /package/templates/pi/home/.config/{config.json.tmpl → config.json} +0 -0
|
@@ -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}`, {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
getBaseName,
|
|
4
|
+
isSpiritName,
|
|
4
5
|
validateMindName
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-H6X6CKDN.js";
|
|
6
7
|
|
|
7
8
|
// packages/daemon/src/lib/mind/isolation.ts
|
|
8
9
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
@@ -63,7 +64,7 @@ function isIsolationEnabled() {
|
|
|
63
64
|
}
|
|
64
65
|
function mindUserName(mindName) {
|
|
65
66
|
const err = validateMindName(mindName);
|
|
66
|
-
if (err && mindName
|
|
67
|
+
if (err && !isSpiritName(mindName)) {
|
|
67
68
|
throw new Error(`Invalid mind name for isolation: ${err}`);
|
|
68
69
|
}
|
|
69
70
|
const prefix = process.env.VOLUTE_USER_PREFIX ?? "mind-";
|
|
@@ -255,6 +256,19 @@ async function chownMindDir(dir, name) {
|
|
|
255
256
|
throw new Error(`Failed to chmod ${dir}${stderr ? `: ${stderr}` : ""}`);
|
|
256
257
|
}
|
|
257
258
|
}
|
|
259
|
+
async function chownMindFile(filePath, name) {
|
|
260
|
+
if (!isIsolationEnabled()) return;
|
|
261
|
+
const user = mindUserName(name);
|
|
262
|
+
const group = process.platform === "darwin" ? "volute" : user;
|
|
263
|
+
try {
|
|
264
|
+
await exec("chown", [`${user}:${group}`, filePath]);
|
|
265
|
+
} catch (err) {
|
|
266
|
+
const stderr = String(err?.stderr ?? "").trim();
|
|
267
|
+
throw new Error(
|
|
268
|
+
`Failed to chown ${filePath} to ${user}:${group}${stderr ? `: ${stderr}` : ""}`
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
258
272
|
|
|
259
273
|
export {
|
|
260
274
|
isIsolationEnabled,
|
|
@@ -265,6 +279,7 @@ export {
|
|
|
265
279
|
wrapForIsolation,
|
|
266
280
|
chownTargets,
|
|
267
281
|
chownMindDir,
|
|
282
|
+
chownMindFile,
|
|
268
283
|
exec,
|
|
269
284
|
gitExec,
|
|
270
285
|
resolveVoluteBin,
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
LAUNCHD_PLIST_LABEL,
|
|
4
4
|
LAUNCHD_PLIST_PATH,
|
|
5
5
|
USER_SYSTEMD_UNIT
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-6NLW72HP.js";
|
|
7
7
|
import {
|
|
8
8
|
resolveVoluteBin
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-M77B73VV.js";
|
|
10
10
|
|
|
11
11
|
// packages/daemon/src/lib/config/service-install.ts
|
|
12
12
|
import { execFile } from "child_process";
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
buildMindBaseEnv,
|
|
4
|
+
clearJsonMap,
|
|
5
|
+
generateMindToken,
|
|
6
|
+
getMindToken,
|
|
7
|
+
loadJsonMap,
|
|
8
|
+
saveJsonMapAsync
|
|
9
|
+
} from "./chunk-VAEZCIJC.js";
|
|
10
|
+
import {
|
|
11
|
+
deliverEvent
|
|
12
|
+
} from "./chunk-ICL6T4SN.js";
|
|
13
|
+
import {
|
|
14
|
+
isSandboxEnabled,
|
|
15
|
+
wrapForSandbox
|
|
16
|
+
} from "./chunk-5Y54AE3L.js";
|
|
17
|
+
import {
|
|
18
|
+
readVoluteConfig,
|
|
19
|
+
writeVoluteConfig
|
|
20
|
+
} from "./chunk-WCFSBH33.js";
|
|
21
|
+
import {
|
|
22
|
+
exec
|
|
23
|
+
} from "./chunk-M77B73VV.js";
|
|
24
|
+
import {
|
|
25
|
+
loadMergedEnv
|
|
26
|
+
} from "./chunk-GLM7TVWP.js";
|
|
27
|
+
import {
|
|
28
|
+
logger_default
|
|
29
|
+
} from "./chunk-QUSMYGNQ.js";
|
|
30
|
+
import {
|
|
31
|
+
findMind,
|
|
32
|
+
mindDir,
|
|
33
|
+
mindTmpDir,
|
|
34
|
+
mindTmpEnv,
|
|
35
|
+
stateDir,
|
|
36
|
+
voluteSystemDir
|
|
37
|
+
} from "./chunk-H6X6CKDN.js";
|
|
38
|
+
|
|
39
|
+
// packages/daemon/src/lib/daemon/scheduler.ts
|
|
40
|
+
import { resolve } from "path";
|
|
41
|
+
import { CronExpressionParser } from "cron-parser";
|
|
42
|
+
var slog = logger_default.child("scheduler");
|
|
43
|
+
var CATCHUP_STALE_MINUTES = 10;
|
|
44
|
+
var Scheduler = class {
|
|
45
|
+
schedules = /* @__PURE__ */ new Map();
|
|
46
|
+
mindDirs = /* @__PURE__ */ new Map();
|
|
47
|
+
// mindName → dir override
|
|
48
|
+
interval = null;
|
|
49
|
+
lastFired = /* @__PURE__ */ new Map();
|
|
50
|
+
// "mind:scheduleId" → epoch minute
|
|
51
|
+
get statePath() {
|
|
52
|
+
return resolve(voluteSystemDir(), "scheduler-state.json");
|
|
53
|
+
}
|
|
54
|
+
start() {
|
|
55
|
+
this.loadState();
|
|
56
|
+
this.interval = setInterval(() => {
|
|
57
|
+
this.tick().catch((err) => slog.error("scheduler tick failed", logger_default.errorData(err)));
|
|
58
|
+
}, 6e4);
|
|
59
|
+
}
|
|
60
|
+
stop() {
|
|
61
|
+
if (this.interval) clearInterval(this.interval);
|
|
62
|
+
}
|
|
63
|
+
loadState() {
|
|
64
|
+
this.lastFired = loadJsonMap(this.statePath);
|
|
65
|
+
}
|
|
66
|
+
async saveState() {
|
|
67
|
+
await saveJsonMapAsync(this.statePath, this.lastFired);
|
|
68
|
+
}
|
|
69
|
+
clearState() {
|
|
70
|
+
clearJsonMap(this.statePath, this.lastFired);
|
|
71
|
+
}
|
|
72
|
+
loadSchedules(mindName, dir) {
|
|
73
|
+
if (dir) this.mindDirs.set(mindName, dir);
|
|
74
|
+
const resolvedDir = this.mindDirs.get(mindName) ?? mindDir(mindName);
|
|
75
|
+
const config = readVoluteConfig(resolvedDir);
|
|
76
|
+
if (!config) return;
|
|
77
|
+
const schedules = config.schedules ?? [];
|
|
78
|
+
if (schedules.length > 0) {
|
|
79
|
+
this.schedules.set(mindName, schedules);
|
|
80
|
+
} else {
|
|
81
|
+
this.schedules.delete(mindName);
|
|
82
|
+
}
|
|
83
|
+
const epochMinute = Math.floor(Date.now() / 6e4);
|
|
84
|
+
const validKeys = new Set(schedules.map((s) => `${mindName}:${s.id}`));
|
|
85
|
+
let changed = false;
|
|
86
|
+
for (const key of this.lastFired.keys()) {
|
|
87
|
+
if (key.startsWith(`${mindName}:`) && !validKeys.has(key)) {
|
|
88
|
+
this.lastFired.delete(key);
|
|
89
|
+
changed = true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const key of validKeys) {
|
|
93
|
+
if (!this.lastFired.has(key)) {
|
|
94
|
+
this.lastFired.set(key, epochMinute);
|
|
95
|
+
changed = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (changed) {
|
|
99
|
+
this.saveState().catch(
|
|
100
|
+
(err) => slog.warn(`failed to persist scheduler state for ${mindName}`, logger_default.errorData(err))
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
unloadSchedules(mindName) {
|
|
105
|
+
this.schedules.delete(mindName);
|
|
106
|
+
this.mindDirs.delete(mindName);
|
|
107
|
+
}
|
|
108
|
+
async tick() {
|
|
109
|
+
const now = /* @__PURE__ */ new Date();
|
|
110
|
+
const epochMinute = Math.floor(now.getTime() / 6e4);
|
|
111
|
+
const cronCache = /* @__PURE__ */ new Map();
|
|
112
|
+
let anyFired = false;
|
|
113
|
+
for (const [mind, schedules] of this.schedules) {
|
|
114
|
+
for (const schedule of schedules) {
|
|
115
|
+
if (!schedule.enabled) continue;
|
|
116
|
+
if (this.shouldFire(schedule, epochMinute, mind, cronCache)) {
|
|
117
|
+
anyFired = true;
|
|
118
|
+
this.fire(mind, schedule);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (anyFired) await this.saveState();
|
|
123
|
+
}
|
|
124
|
+
shouldFire(schedule, epochMinute, mind, cronCache) {
|
|
125
|
+
const key = `${mind}:${schedule.id}`;
|
|
126
|
+
if (this.lastFired.get(key) === epochMinute) return false;
|
|
127
|
+
if (schedule.fireAt) {
|
|
128
|
+
const fireTime = Math.floor(new Date(schedule.fireAt).getTime() / 6e4);
|
|
129
|
+
if (epochMinute >= fireTime) {
|
|
130
|
+
this.lastFired.set(key, epochMinute);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
if (!schedule.cron) return false;
|
|
136
|
+
let prevMinute = cronCache.get(schedule.cron);
|
|
137
|
+
if (prevMinute === void 0) {
|
|
138
|
+
try {
|
|
139
|
+
const interval = CronExpressionParser.parse(schedule.cron);
|
|
140
|
+
const prev = interval.prev().toDate();
|
|
141
|
+
prevMinute = Math.floor(prev.getTime() / 6e4);
|
|
142
|
+
cronCache.set(schedule.cron, prevMinute);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
slog.warn(`invalid cron "${schedule.cron}" for ${mind}:${schedule.id}`, logger_default.errorData(err));
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const lastFired = this.lastFired.get(key) ?? epochMinute;
|
|
149
|
+
if (prevMinute <= lastFired) return false;
|
|
150
|
+
this.lastFired.set(key, prevMinute);
|
|
151
|
+
if (epochMinute - prevMinute > CATCHUP_STALE_MINUTES) {
|
|
152
|
+
slog.info(`skipping stale catch-up fire for ${key} (${epochMinute - prevMinute}min late)`);
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
async fire(mindName, schedule) {
|
|
158
|
+
try {
|
|
159
|
+
let text;
|
|
160
|
+
if (schedule.script) {
|
|
161
|
+
const homeDir = resolve(this.mindDirs.get(mindName) ?? mindDir(mindName), "home");
|
|
162
|
+
try {
|
|
163
|
+
const output = await this.runScript(schedule.script, homeDir, mindName);
|
|
164
|
+
if (!output.trim()) {
|
|
165
|
+
slog.info(`fired script "${schedule.id}" for ${mindName} (no output)`);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
text = output;
|
|
169
|
+
} catch (err) {
|
|
170
|
+
const stderr = err.stderr ?? "";
|
|
171
|
+
text = `[script error] ${err.message}${stderr ? `
|
|
172
|
+
${stderr}` : ""}`;
|
|
173
|
+
slog.warn(`script "${schedule.id}" failed for ${mindName}`, logger_default.errorData(err));
|
|
174
|
+
}
|
|
175
|
+
} else if (Array.isArray(schedule.messages) && schedule.messages.length > 0) {
|
|
176
|
+
const pick = schedule.messages[Math.floor(Math.random() * schedule.messages.length)];
|
|
177
|
+
if (typeof pick !== "string" || !pick.trim()) {
|
|
178
|
+
slog.warn(`schedule "${schedule.id}" for ${mindName} has a malformed messages pool`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
text = pick;
|
|
182
|
+
} else if (schedule.message) {
|
|
183
|
+
text = schedule.message;
|
|
184
|
+
} else {
|
|
185
|
+
slog.warn(`schedule "${schedule.id}" for ${mindName} has no message, messages, or script`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const { id, delivered } = await this.deliverSystem(mindName, schedule.id, text, {
|
|
189
|
+
// Default schedule fires to "queue" while asleep so an unadorned cron
|
|
190
|
+
// schedule doesn't inherit the DM wake-trigger fallback and wake the mind.
|
|
191
|
+
whileSleeping: schedule.whileSleeping ?? "queue",
|
|
192
|
+
thread: schedule.thread
|
|
193
|
+
});
|
|
194
|
+
slog.info(`fired "${schedule.id}" for ${mindName}${delivered ? "" : " (event pending)"}`);
|
|
195
|
+
if (schedule.fireAt && id != null) {
|
|
196
|
+
this.removeSchedule(mindName, schedule.id);
|
|
197
|
+
}
|
|
198
|
+
} catch (err) {
|
|
199
|
+
slog.warn(`failed to fire "${schedule.id}" for ${mindName}`, logger_default.errorData(err));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
removeSchedule(mindName, scheduleId) {
|
|
203
|
+
const memSchedules = this.schedules.get(mindName);
|
|
204
|
+
if (memSchedules) {
|
|
205
|
+
const filtered = memSchedules.filter((s) => s.id !== scheduleId);
|
|
206
|
+
if (filtered.length > 0) {
|
|
207
|
+
this.schedules.set(mindName, filtered);
|
|
208
|
+
} else {
|
|
209
|
+
this.schedules.delete(mindName);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const dir = this.mindDirs.get(mindName) ?? mindDir(mindName);
|
|
214
|
+
const config = readVoluteConfig(dir);
|
|
215
|
+
if (!config?.schedules) return;
|
|
216
|
+
config.schedules = config.schedules.filter((s) => s.id !== scheduleId);
|
|
217
|
+
if (config.schedules.length === 0) config.schedules = void 0;
|
|
218
|
+
writeVoluteConfig(dir, config);
|
|
219
|
+
slog.info(`removed one-time schedule "${scheduleId}" for ${mindName}`);
|
|
220
|
+
} catch (err) {
|
|
221
|
+
slog.error(
|
|
222
|
+
`failed to persist removal of schedule "${scheduleId}" for ${mindName} (removed from memory)`,
|
|
223
|
+
logger_default.errorData(err)
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
async runScript(script, cwd, mindName) {
|
|
228
|
+
const env = await this.buildScriptEnv(mindName);
|
|
229
|
+
if (isSandboxEnabled()) {
|
|
230
|
+
const dir = this.mindDirs.get(mindName) ?? mindDir(mindName);
|
|
231
|
+
const [cmd, args] = await wrapForSandbox("bash", ["-c", script], dir, mindName, [
|
|
232
|
+
dir,
|
|
233
|
+
mindTmpDir(dir)
|
|
234
|
+
]);
|
|
235
|
+
return exec(cmd, args, { cwd, env });
|
|
236
|
+
}
|
|
237
|
+
return exec("bash", ["-c", script], { cwd, mindName, env });
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Build the environment for a scheduled script — mirrors the mind process env
|
|
241
|
+
* (allowlisted base + merged mind env + VOLUTE_* runtime vars), authenticated
|
|
242
|
+
* with the mind's own per-mind, non-admin token. Reuses the running mind's
|
|
243
|
+
* token when present; otherwise mints one (stable across fires, regenerated on
|
|
244
|
+
* next mind start). The daemon admin token is never included.
|
|
245
|
+
*/
|
|
246
|
+
async buildScriptEnv(mindName) {
|
|
247
|
+
const dir = this.mindDirs.get(mindName) ?? mindDir(mindName);
|
|
248
|
+
const entry = await findMind(mindName);
|
|
249
|
+
const token = getMindToken(mindName) ?? generateMindToken(mindName);
|
|
250
|
+
const mindLocalBin = resolve(dir, "home", ".local", "bin");
|
|
251
|
+
const currentPath = process.env.PATH ?? "";
|
|
252
|
+
return {
|
|
253
|
+
...buildMindBaseEnv(),
|
|
254
|
+
...loadMergedEnv(mindName),
|
|
255
|
+
VOLUTE_MIND: mindName,
|
|
256
|
+
VOLUTE_STATE_DIR: stateDir(mindName),
|
|
257
|
+
VOLUTE_MIND_DIR: dir,
|
|
258
|
+
VOLUTE_MIND_PORT: entry ? String(entry.port) : void 0,
|
|
259
|
+
VOLUTE_MIND_TOKEN: token,
|
|
260
|
+
...mindTmpEnv(dir),
|
|
261
|
+
PATH: `${mindLocalBin}:${currentPath}`
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
async deliverSystem(mindName, scheduleId, text, opts) {
|
|
265
|
+
return deliverEvent(mindName, {
|
|
266
|
+
type: "schedule",
|
|
267
|
+
body: text,
|
|
268
|
+
meta: { scheduleId },
|
|
269
|
+
thread: opts?.thread,
|
|
270
|
+
whileSleeping: opts?.whileSleeping
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
var instance = null;
|
|
275
|
+
function initScheduler() {
|
|
276
|
+
if (instance) throw new Error("Scheduler already initialized");
|
|
277
|
+
instance = new Scheduler();
|
|
278
|
+
return instance;
|
|
279
|
+
}
|
|
280
|
+
function getScheduler() {
|
|
281
|
+
if (!instance) throw new Error("Scheduler not initialized \u2014 call initScheduler() first");
|
|
282
|
+
return instance;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export {
|
|
286
|
+
Scheduler,
|
|
287
|
+
initScheduler,
|
|
288
|
+
getScheduler
|
|
289
|
+
};
|
|
@@ -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-M77B73VV.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-H6X6CKDN.js";
|
|
19
17
|
import {
|
|
20
18
|
sharedSkills
|
|
21
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-2RNMBXD2.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-NY6WST33.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}`);
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import {
|
|
3
3
|
bufferEvent,
|
|
4
4
|
subscribe
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-U54PJPTB.js";
|
|
6
6
|
import {
|
|
7
7
|
logger_default
|
|
8
8
|
} from "./chunk-QUSMYGNQ.js";
|
|
9
9
|
import {
|
|
10
10
|
getDb
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-H6X6CKDN.js";
|
|
12
12
|
import {
|
|
13
13
|
channels,
|
|
14
14
|
conversationParticipants,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
conversations,
|
|
17
17
|
messages,
|
|
18
18
|
users
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-2RNMBXD2.js";
|
|
20
20
|
|
|
21
21
|
// packages/daemon/src/lib/events/conversations.ts
|
|
22
22
|
import { randomUUID } from "crypto";
|
|
@@ -99,6 +99,21 @@ function subscribe2(conversationId, callback) {
|
|
|
99
99
|
if (set.size === 0) subscribers.delete(conversationId);
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
|
+
var participantSubscribers = /* @__PURE__ */ new Set();
|
|
103
|
+
function subscribeParticipantAdded(callback) {
|
|
104
|
+
participantSubscribers.add(callback);
|
|
105
|
+
return () => participantSubscribers.delete(callback);
|
|
106
|
+
}
|
|
107
|
+
function publishParticipantAdded(conversationId, userId) {
|
|
108
|
+
for (const cb of participantSubscribers) {
|
|
109
|
+
try {
|
|
110
|
+
cb({ conversationId, userId });
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.error("[conversation-events] participant subscriber threw:", err);
|
|
113
|
+
participantSubscribers.delete(cb);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
102
117
|
function publish(conversationId, event) {
|
|
103
118
|
const set = subscribers.get(conversationId);
|
|
104
119
|
if (!set) return;
|
|
@@ -134,6 +149,9 @@ async function createConversation(opts) {
|
|
|
134
149
|
role: i === 0 ? "owner" : "member"
|
|
135
150
|
}))
|
|
136
151
|
);
|
|
152
|
+
for (const uid of opts.participantIds) {
|
|
153
|
+
publishParticipantAdded(id, uid);
|
|
154
|
+
}
|
|
137
155
|
}
|
|
138
156
|
fireWebhook({
|
|
139
157
|
event: "conversation_created",
|
|
@@ -161,6 +179,7 @@ async function addParticipant(conversationId, userId, role = "member") {
|
|
|
161
179
|
user_id: userId,
|
|
162
180
|
role
|
|
163
181
|
});
|
|
182
|
+
publishParticipantAdded(conversationId, userId);
|
|
164
183
|
}
|
|
165
184
|
async function removeParticipant(conversationId, userId) {
|
|
166
185
|
const db = await getDb();
|
|
@@ -251,6 +270,11 @@ async function addMessage(conversationId, role, senderName, content, opts) {
|
|
|
251
270
|
});
|
|
252
271
|
return msg;
|
|
253
272
|
}
|
|
273
|
+
async function getLastMessageBySender(conversationId, sender) {
|
|
274
|
+
const db = await getDb();
|
|
275
|
+
const row = await db.select().from(messages).where(and(eq(messages.conversation_id, conversationId), eq(messages.sender_name, sender))).orderBy(desc(messages.id)).limit(1).get();
|
|
276
|
+
return row ? parseMessageRow(row) : null;
|
|
277
|
+
}
|
|
254
278
|
async function getMessages(conversationId, limit = 200) {
|
|
255
279
|
const db = await getDb();
|
|
256
280
|
const rows = await db.select().from(messages).where(eq(messages.conversation_id, conversationId)).orderBy(desc(messages.id)).limit(limit).all();
|
|
@@ -351,6 +375,12 @@ async function listConversationsWithParticipants(userId) {
|
|
|
351
375
|
const convs = await listConversationsForUser(userId);
|
|
352
376
|
return enrichConversations(convs);
|
|
353
377
|
}
|
|
378
|
+
async function getConversationWithParticipants(conversationId) {
|
|
379
|
+
const conv = await getConversation(conversationId);
|
|
380
|
+
if (!conv) return null;
|
|
381
|
+
const [enriched] = await enrichConversations([conv]);
|
|
382
|
+
return enriched ?? null;
|
|
383
|
+
}
|
|
354
384
|
async function findDMConversation(participantIds) {
|
|
355
385
|
const db = await getDb();
|
|
356
386
|
const [id1, id2] = participantIds;
|
|
@@ -513,12 +543,13 @@ async function markConversationRead(userId, conversationId) {
|
|
|
513
543
|
}
|
|
514
544
|
|
|
515
545
|
export {
|
|
546
|
+
subscribe2 as subscribe,
|
|
547
|
+
subscribeParticipantAdded,
|
|
548
|
+
publish,
|
|
516
549
|
getWebhookUrl,
|
|
517
550
|
getAuthHeaders,
|
|
518
551
|
fireWebhook,
|
|
519
552
|
initWebhook,
|
|
520
|
-
subscribe2 as subscribe,
|
|
521
|
-
publish,
|
|
522
553
|
createConversation,
|
|
523
554
|
getConversation,
|
|
524
555
|
addParticipant,
|
|
@@ -529,9 +560,11 @@ export {
|
|
|
529
560
|
isParticipantOrOwner,
|
|
530
561
|
deleteConversationForUser,
|
|
531
562
|
addMessage,
|
|
563
|
+
getLastMessageBySender,
|
|
532
564
|
getMessages,
|
|
533
565
|
getMessagesPaginated,
|
|
534
566
|
listConversationsWithParticipants,
|
|
567
|
+
getConversationWithParticipants,
|
|
535
568
|
findDMConversation,
|
|
536
569
|
listConversationsForMind,
|
|
537
570
|
isConversationForMind,
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-QUSMYGNQ.js";
|
|
5
5
|
import {
|
|
6
6
|
getDb
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-H6X6CKDN.js";
|
|
8
8
|
import {
|
|
9
9
|
activity
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2RNMBXD2.js";
|
|
11
11
|
|
|
12
12
|
// packages/daemon/src/lib/events/event-sequencer.ts
|
|
13
13
|
var BUFFER_SIZE = 1e3;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-QUSMYGNQ.js";
|
|
5
5
|
import {
|
|
6
6
|
mindDir
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-H6X6CKDN.js";
|
|
8
8
|
|
|
9
9
|
// packages/daemon/src/lib/delivery/delivery-router.ts
|
|
10
10
|
import { readFileSync, statSync } from "fs";
|
|
@@ -63,6 +63,7 @@ function getRoutingConfig(mindName) {
|
|
|
63
63
|
try {
|
|
64
64
|
const config = JSON.parse(readFileSync(path, "utf-8"));
|
|
65
65
|
const changed = cached != null && cached.mtime !== mtime;
|
|
66
|
+
warnUnknownRuleKeys(mindName, config);
|
|
66
67
|
configCache.set(mindName, { config, mtime });
|
|
67
68
|
if (changed) notifyRoutesChanged(mindName);
|
|
68
69
|
return config;
|
|
@@ -94,7 +95,20 @@ function globMatch(pattern, value) {
|
|
|
94
95
|
return regex.test(value);
|
|
95
96
|
}
|
|
96
97
|
var GLOB_MATCH_KEYS = /* @__PURE__ */ new Set(["channel", "sender"]);
|
|
97
|
-
var NON_MATCH_KEYS = /* @__PURE__ */ new Set(["
|
|
98
|
+
var NON_MATCH_KEYS = /* @__PURE__ */ new Set(["thread", "destination", "path", "mode", "batch"]);
|
|
99
|
+
var KNOWN_RULE_KEYS = /* @__PURE__ */ new Set([...GLOB_MATCH_KEYS, ...NON_MATCH_KEYS, "isDM", "participants"]);
|
|
100
|
+
function warnUnknownRuleKeys(mindName, config) {
|
|
101
|
+
if (!Array.isArray(config.rules)) return;
|
|
102
|
+
for (const rule of config.rules) {
|
|
103
|
+
if (rule == null || typeof rule !== "object") continue;
|
|
104
|
+
const unknown = Object.keys(rule).filter((k) => !KNOWN_RULE_KEYS.has(k));
|
|
105
|
+
if (unknown.length > 0) {
|
|
106
|
+
dlog.warn(
|
|
107
|
+
`routes.json for ${mindName} has a rule with unrecognized key(s) ${unknown.map((k) => `"${k}"`).join(", ")} \u2014 the rule will never match (known keys: ${[...KNOWN_RULE_KEYS].join(", ")})`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
98
112
|
function ruleMatches(rule, meta) {
|
|
99
113
|
for (const [key, pattern] of Object.entries(rule)) {
|
|
100
114
|
if (NON_MATCH_KEYS.has(key)) continue;
|
|
@@ -137,7 +151,7 @@ function resolveRoute(config, meta) {
|
|
|
137
151
|
}
|
|
138
152
|
return {
|
|
139
153
|
destination: "mind",
|
|
140
|
-
session: sanitizeSessionName(expandTemplate(rule.
|
|
154
|
+
session: sanitizeSessionName(expandTemplate(rule.thread ?? fallback, meta)),
|
|
141
155
|
matched: true,
|
|
142
156
|
mode: rule.mode,
|
|
143
157
|
rule
|
|
@@ -160,7 +174,7 @@ function resolveDeliveryMode(config, sessionName, rule) {
|
|
|
160
174
|
const defaults = {
|
|
161
175
|
delivery: { mode: "immediate" }
|
|
162
176
|
};
|
|
163
|
-
if (!config.
|
|
177
|
+
if (!config.threads) {
|
|
164
178
|
if (ruleBatch != null) {
|
|
165
179
|
const batch = normalizeBatchConfig(ruleBatch);
|
|
166
180
|
return {
|
|
@@ -174,7 +188,7 @@ function resolveDeliveryMode(config, sessionName, rule) {
|
|
|
174
188
|
}
|
|
175
189
|
return defaults;
|
|
176
190
|
}
|
|
177
|
-
for (const [pattern, sessionConfig] of Object.entries(config.
|
|
191
|
+
for (const [pattern, sessionConfig] of Object.entries(config.threads)) {
|
|
178
192
|
if (globMatch(pattern, sessionName)) {
|
|
179
193
|
let delivery;
|
|
180
194
|
if (sessionConfig.delivery == null || sessionConfig.delivery === "immediate") {
|
|
@@ -219,6 +233,7 @@ export {
|
|
|
219
233
|
registerMindDir,
|
|
220
234
|
getRoutingConfig,
|
|
221
235
|
clearConfigCache,
|
|
236
|
+
warnUnknownRuleKeys,
|
|
222
237
|
resolveRoute,
|
|
223
238
|
shouldGate,
|
|
224
239
|
resolveDeliveryMode
|