volute 0.46.0 → 0.47.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 +1 -1
- package/dist/{activity-events-NF6VWTJQ.js → activity-events-MIOK3IOU.js} +3 -3
- package/dist/{ai-service-UODCCE4O.js → ai-service-CVZEYKTK.js} +4 -4
- package/dist/{archive-WS2L2VIQ.js → archive-6Z4GFQPH.js} +3 -3
- package/dist/{auth-CCFAU4GQ.js → auth-A4VGHADI.js} +4 -4
- package/dist/avatar-image-7S3WA77A.js +22 -0
- package/dist/{backup-TST5C2YN.js → backup-IIAFOW2L.js} +13 -13
- package/dist/channels-ITE4YC57.js +89 -0
- package/dist/{chat-ZIQQS25U.js → chat-AJLJCQ3M.js} +12 -8
- package/dist/{chunk-ZV7MFISX.js → chunk-2MJ7EOMT.js} +20 -2
- package/dist/{chunk-R77O2WMK.js → chunk-2OIYNHWO.js} +1 -1
- package/dist/{chunk-QCN24XEN.js → chunk-3YUBFTDN.js} +1 -1
- package/dist/{chunk-E3DA4HYV.js → chunk-4I72V3E5.js} +10 -10
- package/dist/{chunk-K6T43YBD.js → chunk-5IERLDUS.js} +3 -3
- package/dist/{chunk-FXORA5JG.js → chunk-5NN2VHJV.js} +3 -3
- package/dist/chunk-7KRIHYLR.js +124 -0
- package/dist/{chunk-RRNXJOKB.js → chunk-BGYHLR54.js} +2 -2
- package/dist/{chunk-QMJCNZ6C.js → chunk-C3KLHJDB.js} +1 -1
- package/dist/{chunk-TQJ6ZYVY.js → chunk-CBOIHNMR.js} +2 -2
- package/dist/{chunk-H2X54EHC.js → chunk-DGGZVZTM.js} +1 -1
- package/dist/{chunk-4JOQZPCE.js → chunk-EIQDZC43.js} +1 -1
- package/dist/{chunk-JO5IO4FH.js → chunk-F55GRIEK.js} +243 -121
- package/dist/{chunk-5ZQZDDIK.js → chunk-HPGN6XRT.js} +3 -3
- package/dist/{chunk-KGIXX4NM.js → chunk-IWJSNMSY.js} +5 -5
- package/dist/{chunk-ZDZISKCL.js → chunk-IYG4FBMP.js} +1 -1
- package/dist/{chunk-4YU7HF4L.js → chunk-JCMGDCGX.js} +4 -4
- package/dist/{chunk-PJ45FQPT.js → chunk-JSVHH32K.js} +6 -6
- package/dist/{chunk-YXSUMLTC.js → chunk-K23P5Q5N.js} +301 -77
- package/dist/{chunk-ZNMCCHCP.js → chunk-LTLFOSA4.js} +2 -2
- package/dist/{chunk-IHKGWTGT.js → chunk-LWDTP6DH.js} +1 -1
- package/dist/{chunk-JZ62SYWR.js → chunk-M3XDVS5Q.js} +1 -1
- package/dist/{chunk-BJZ4PV7R.js → chunk-M6TTZRGH.js} +9 -9
- package/dist/{chunk-KQSFTPIM.js → chunk-MTRMQFCQ.js} +1 -1
- package/dist/{chunk-OV7ZQ2GH.js → chunk-ODDGGLM6.js} +3 -3
- package/dist/{chunk-QLWG3C2Z.js → chunk-RRZ4RQQU.js} +2 -2
- package/dist/{chunk-CDPBTTZO.js → chunk-RUFLGTOT.js} +2 -2
- package/dist/{chunk-F7H6ATM4.js → chunk-SKNXMUIU.js} +1 -1
- package/dist/{chunk-RXEEYDIB.js → chunk-SZJCJVXV.js} +1 -1
- package/dist/{chunk-DRJ24GXK.js → chunk-VMCZBXF2.js} +52 -8
- package/dist/{chunk-ALKYQULU.js → chunk-WW6C3PLV.js} +1 -1
- package/dist/{chunk-A7WQZKOU.js → chunk-XHN6XBWV.js} +2 -2
- package/dist/{chunk-6EMWJZBK.js → chunk-YKA7DCVW.js} +1 -1
- package/dist/cli.js +21 -21
- package/dist/{clock-RHS2JEDL.js → clock-E6N5Y3YW.js} +3 -3
- package/dist/{cloud-sync-46RS4SDA.js → cloud-sync-LQTVDTQ3.js} +19 -18
- package/dist/{conversations-CJOOCGNW.js → conversations-C7IKYSHD.js} +4 -4
- package/dist/{create-IOV4GCRX.js → create-PQQXKTJK.js} +1 -1
- package/dist/{daemon-restart-VFEI57UO.js → daemon-restart-5F3YTLZK.js} +7 -7
- package/dist/daemon.js +217 -151
- package/dist/{db-MF2JNRUW.js → db-FO6LXYCW.js} +2 -2
- package/dist/delivery-manager-TN5KK2AP.js +34 -0
- package/dist/{delivery-router-N4A7ZC5T.js → delivery-router-3QFG2ZEX.js} +3 -3
- package/dist/{down-U2CZ23M4.js → down-ZI4S6265.js} +5 -5
- package/dist/echo-text-SEQCLGAT.js +34 -0
- package/dist/{exec-G3ZRST4Z.js → exec-QIFYZG4C.js} +3 -3
- package/dist/{export-LY723I3Z.js → export-4GVGNW54.js} +3 -3
- package/dist/{extensions-ZELQLTSR.js → extensions-PIMIQ7J3.js} +21 -18
- package/dist/{files-4LN3EN7Q.js → files-FEFZKMNM.js} +6 -6
- package/dist/{import-42YNQBF4.js → import-7MO3YTRE.js} +6 -6
- package/dist/{isolation-YMGZZ4E5.js → isolation-MCT4ZYLT.js} +3 -3
- package/dist/{login-M6OJUPQ2.js → login-OF4WXDAN.js} +5 -5
- package/dist/{logout-WQBWO77G.js → logout-ERE2BGA3.js} +5 -5
- package/dist/message-delivery-ZE3YGJDD.js +38 -0
- package/dist/{mind-LHKS55DI.js → mind-POOHFZHP.js} +13 -13
- package/dist/{mind-activity-tracker-3QRNJVR4.js → mind-activity-tracker-YVZPC4A5.js} +4 -4
- package/dist/{mind-list-4D7J4CHD.js → mind-list-KEGRGQEQ.js} +5 -4
- package/dist/mind-service-JFY7UG5E.js +40 -0
- package/dist/{mind-sleep-74TGOQBC.js → mind-sleep-IN3WPA76.js} +5 -5
- package/dist/{mind-status-UO34ASXZ.js → mind-status-SMUWJKGV.js} +20 -3
- package/dist/{package-DOD6CPO6.js → package-WPEE2HVJ.js} +2 -2
- package/dist/{registry-OUZBZ3Q4.js → registry-UMMDRPRM.js} +2 -2
- package/dist/{sandbox-ZJ7QA6Z6.js → sandbox-G4X4K3UN.js} +4 -4
- package/dist/scheduler-HQSDYJFY.js +32 -0
- package/dist/{schema-PVNG3PQM.js → schema-VEVO7HG6.js} +3 -1
- package/dist/{seed-CNYIHPOH.js → seed-VANPU43L.js} +1 -1
- package/dist/{seed-cmd-AVNUNLZV.js → seed-cmd-SYVDZKM4.js} +2 -2
- package/dist/{seed-create-ANXGYSCC.js → seed-create-3FGZPS6C.js} +3 -3
- package/dist/{seed-sprout-NIUFTX32.js → seed-sprout-H7QLFPFM.js} +12 -12
- package/dist/{send-SPE6DVNJ.js → send-HYDFGC6G.js} +7 -7
- package/dist/{service-UOCLXDWR.js → service-SYJ5G6LP.js} +4 -4
- package/dist/{service-install-4HHFDDWY.js → service-install-FQ43Z4DF.js} +5 -5
- package/dist/{setup-Y2EJI3GG.js → setup-KFYVWTXG.js} +3 -3
- package/dist/{setup-QT2A25SY.js → setup-QJHGMGSN.js} +7 -7
- package/dist/{skills-AKCFA7BN.js → skills-L2CMTW7A.js} +5 -5
- package/dist/sleep-manager-3NA7ZJP3.js +36 -0
- package/dist/{spirit-RPBLLUQ5.js → spirit-WXN4IDBF.js} +8 -8
- package/dist/{sprout-SMX42ZBP.js → sprout-LTL5P36T.js} +1 -1
- package/dist/{status-SWRVGXBI.js → status-V4RJMHJ4.js} +19 -9
- package/dist/system-chat-N2F7HVY3.js +38 -0
- package/dist/{systems-VNB5WKSS.js → systems-B5YJKMW4.js} +6 -6
- package/dist/{tailscale-3XOKOW7T.js → tailscale-MCLY5GYE.js} +2 -2
- package/dist/{template-hash-446HHH5V.js → template-hash-GSOUARW4.js} +2 -2
- package/dist/template-staleness-EMQORSGG.js +15 -0
- package/dist/{turn-tracker-FOIBNUUA.js → turn-tracker-JZRZDFWV.js} +6 -6
- package/dist/{up-PS6PFS75.js → up-J2PBPOZL.js} +6 -6
- package/dist/{update-SWAYZRWJ.js → update-ACV4SAY3.js} +5 -5
- package/dist/{update-check-PQ2MZ47K.js → update-check-266R4ZSY.js} +3 -3
- package/dist/{version-notify-C5CH7CVP.js → version-notify-XRGTEEDK.js} +37 -23
- package/dist/web-assets/assets/index-DtctoDXY.css +1 -0
- package/dist/web-assets/assets/index-Wpyb2CML.js +86 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0011_drop_turn_summary_event_id.sql +3 -0
- package/drizzle/0012_channel_gates.sql +17 -0
- package/drizzle/meta/_journal.json +14 -0
- package/package.json +2 -2
- package/templates/_base/src/lib/startup.ts +43 -2
- package/templates/claude/src/agent.ts +28 -2
- package/templates/claude/src/lib/session-reaper.ts +32 -0
- package/templates/claude/src/server.ts +10 -1
- package/dist/avatar-image-6KY6UU4D.js +0 -16
- package/dist/delivery-manager-JINZRG2W.js +0 -33
- package/dist/echo-text-VQPB5L2X.js +0 -33
- package/dist/message-delivery-R7JSQGYX.js +0 -37
- package/dist/mind-service-NB2JMWQZ.js +0 -39
- package/dist/scheduler-WVKII3LA.js +0 -31
- package/dist/sleep-manager-G6TXSDP7.js +0 -35
- package/dist/system-chat-NDAW6YP7.js +0 -37
- package/dist/web-assets/assets/index-B1JBQv2m.css +0 -1
- package/dist/web-assets/assets/index-CU6XWICM.js +0 -86
- package/dist/{accept-N5XULCXK.js → accept-YAFP5JFJ.js} +3 -3
- package/dist/{bridge-2PO3AI5D.js → bridge-TIZGSXOD.js} +3 -3
- package/dist/{create-DF3KISTW.js → create-A7PDHIIL.js} +3 -3
- package/dist/{env-VZ4MLFQW.js → env-HRL2PWAT.js} +5 -5
- package/dist/{extension-SEID47SR.js → extension-QBY4C44L.js} +3 -3
- package/dist/{list-OXIAY3W7.js → list-LQO2DCIK.js} +3 -3
- package/dist/{login-MY6ETFYB.js → login-6TLMI2TQ.js} +3 -3
- package/dist/{logout-NCG3TMDL.js → logout-BK53HXNY.js} +3 -3
- package/dist/{mind-history-VRO5A76U.js → mind-history-47DN6ILW.js} +4 -4
- package/dist/{mind-wake-LCLGTXA2.js → mind-wake-R54BPESY.js} +3 -3
- package/dist/{read-QVAXMTPV.js → read-PWAJOQIQ.js} +3 -3
- package/dist/{register-Y2H4PY5R.js → register-7SZJFHU6.js} +3 -3
- package/dist/{reject-EV35X64Y.js → reject-6VH7N2A4.js} +3 -3
- package/dist/{restart-FJQ662XJ.js → restart-H5WJDMA7.js} +4 -4
- package/dist/{skill-FKFHIJRR.js → skill-GUKG2YVH.js} +5 -5
- package/dist/{start-5JE3TV66.js → start-X46I3GXB.js} +4 -4
- package/dist/{stop-AAMTG3TU.js → stop-HJQV4YSM.js} +4 -4
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadMergedEnv
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IYG4FBMP.js";
|
|
5
5
|
import {
|
|
6
6
|
spiritDir
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-M6TTZRGH.js";
|
|
8
|
+
import {
|
|
9
|
+
clearMind,
|
|
10
|
+
linkInboundToActiveTurn,
|
|
11
|
+
publish as publish3,
|
|
12
|
+
summarizeOrphanedTurns
|
|
13
|
+
} from "./chunk-K23P5Q5N.js";
|
|
14
|
+
import {
|
|
15
|
+
getPrompt
|
|
16
|
+
} from "./chunk-JCMGDCGX.js";
|
|
8
17
|
import {
|
|
9
18
|
hashSkillDir,
|
|
10
19
|
importSkillFromDir,
|
|
11
20
|
removeSharedSkill,
|
|
12
21
|
sharedSkillsDir
|
|
13
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-IWJSNMSY.js";
|
|
14
23
|
import {
|
|
15
24
|
addMessage,
|
|
16
25
|
createChannel,
|
|
@@ -20,63 +29,57 @@ import {
|
|
|
20
29
|
getParticipants,
|
|
21
30
|
joinChannel,
|
|
22
31
|
publish as publish2
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import {
|
|
25
|
-
readVoluteConfig,
|
|
26
|
-
resolveWakeTriggers,
|
|
27
|
-
writeVoluteConfig
|
|
28
|
-
} from "./chunk-PFZBNKUH.js";
|
|
32
|
+
} from "./chunk-HPGN6XRT.js";
|
|
29
33
|
import {
|
|
30
34
|
isSandboxEnabled,
|
|
31
35
|
wrapForSandbox
|
|
32
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-M3XDVS5Q.js";
|
|
33
37
|
import {
|
|
34
38
|
markIdle,
|
|
35
39
|
onMindEvent
|
|
36
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-MTRMQFCQ.js";
|
|
41
|
+
import {
|
|
42
|
+
renderAvatarBlock
|
|
43
|
+
} from "./chunk-VMCZBXF2.js";
|
|
44
|
+
import {
|
|
45
|
+
readVoluteConfig,
|
|
46
|
+
resolveWakeTriggers,
|
|
47
|
+
writeVoluteConfig
|
|
48
|
+
} from "./chunk-PFZBNKUH.js";
|
|
37
49
|
import {
|
|
38
50
|
extractTextContent,
|
|
39
51
|
getRoutingConfig,
|
|
40
52
|
resolveDeliveryMode,
|
|
41
53
|
resolveRoute,
|
|
42
54
|
setRoutesChangeListener
|
|
43
|
-
} from "./chunk-
|
|
44
|
-
import {
|
|
45
|
-
clearMind,
|
|
46
|
-
linkInboundToActiveTurn,
|
|
47
|
-
publish as publish3,
|
|
48
|
-
summarizeOrphanedTurns
|
|
49
|
-
} from "./chunk-YXSUMLTC.js";
|
|
50
|
-
import {
|
|
51
|
-
getPrompt
|
|
52
|
-
} from "./chunk-4YU7HF4L.js";
|
|
55
|
+
} from "./chunk-EIQDZC43.js";
|
|
53
56
|
import {
|
|
54
57
|
chownMindDir,
|
|
55
58
|
exec,
|
|
56
59
|
isIsolationEnabled,
|
|
57
60
|
mindUserName,
|
|
58
61
|
wrapForIsolation
|
|
59
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-DGGZVZTM.js";
|
|
60
63
|
import {
|
|
61
64
|
aiCompleteUtility,
|
|
62
65
|
getAiConfig,
|
|
63
66
|
resolveApiKey
|
|
64
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-LWDTP6DH.js";
|
|
65
68
|
import {
|
|
66
69
|
readGlobalConfig,
|
|
67
70
|
writeGlobalConfig
|
|
68
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-SKNXMUIU.js";
|
|
69
72
|
import {
|
|
70
73
|
getOrCreateMindUser,
|
|
71
74
|
getOrCreateSystemUser,
|
|
72
75
|
getUser,
|
|
73
76
|
getUserByUsername,
|
|
74
77
|
syncMindProfile
|
|
75
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-ODDGGLM6.js";
|
|
76
79
|
import {
|
|
77
80
|
publish,
|
|
78
81
|
subscribe
|
|
79
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-LTLFOSA4.js";
|
|
80
83
|
import {
|
|
81
84
|
logger_default
|
|
82
85
|
} from "./chunk-T2TP6ZC6.js";
|
|
@@ -92,15 +95,16 @@ import {
|
|
|
92
95
|
stateDir,
|
|
93
96
|
voluteHome,
|
|
94
97
|
voluteSystemDir
|
|
95
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-WW6C3PLV.js";
|
|
96
99
|
import {
|
|
97
100
|
activity,
|
|
101
|
+
channelGates,
|
|
98
102
|
deliveryQueue,
|
|
99
103
|
messages,
|
|
100
104
|
mindHistory,
|
|
101
105
|
mindNotices,
|
|
102
106
|
sessions
|
|
103
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-2MJ7EOMT.js";
|
|
104
108
|
|
|
105
109
|
// packages/daemon/src/lib/delivery/message-delivery.ts
|
|
106
110
|
import { and as and5, eq as eq6, inArray as inArray3 } from "drizzle-orm";
|
|
@@ -934,7 +938,7 @@ var MindManager = class {
|
|
|
934
938
|
if (this.shuttingDown || this.stopping.has(name)) return;
|
|
935
939
|
mlog.error(`mind ${name} exited with code ${code}`);
|
|
936
940
|
try {
|
|
937
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
941
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-3NA7ZJP3.js");
|
|
938
942
|
const sleepMgr = getSleepManagerIfReady2();
|
|
939
943
|
const sleepState = sleepMgr?.getState(name);
|
|
940
944
|
if (sleepState?.sleeping) {
|
|
@@ -964,15 +968,15 @@ var MindManager = class {
|
|
|
964
968
|
(err) => mlog.warn(`failed to clear turn state for ${name} after crash`, logger_default.errorData(err))
|
|
965
969
|
);
|
|
966
970
|
try {
|
|
967
|
-
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-
|
|
971
|
+
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-TN5KK2AP.js");
|
|
968
972
|
getDeliveryManager2().clearMindSessions(name);
|
|
969
973
|
} catch (err) {
|
|
970
974
|
if (!(err instanceof Error && err.message.includes("not initialized"))) {
|
|
971
975
|
mlog.warn(`failed to clear delivery state for ${name} after crash`, logger_default.errorData(err));
|
|
972
976
|
}
|
|
973
977
|
}
|
|
974
|
-
import("./mind-activity-tracker-
|
|
975
|
-
import("./activity-events-
|
|
978
|
+
import("./mind-activity-tracker-YVZPC4A5.js").then(({ markIdle: markIdle2 }) => markIdle2(name)).catch((err) => mlog.warn(`failed to mark ${name} idle after crash`, logger_default.errorData(err)));
|
|
979
|
+
import("./activity-events-MIOK3IOU.js").then(
|
|
976
980
|
({ publish: publish4 }) => publish4({ type: "mind_stopped", mind: name, summary: `${name} crashed (exit ${code})` })
|
|
977
981
|
).catch((err) => mlog.warn(`failed to publish crash event for ${name}`, logger_default.errorData(err)));
|
|
978
982
|
const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(name);
|
|
@@ -1030,7 +1034,7 @@ var MindManager = class {
|
|
|
1030
1034
|
mlog.warn(`failed to clear turn state for ${name} on stop`, logger_default.errorData(err));
|
|
1031
1035
|
}
|
|
1032
1036
|
try {
|
|
1033
|
-
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-
|
|
1037
|
+
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-TN5KK2AP.js");
|
|
1034
1038
|
getDeliveryManager2().clearMindSessions(name);
|
|
1035
1039
|
} catch (err) {
|
|
1036
1040
|
if (!(err instanceof Error && err.message.includes("not initialized"))) {
|
|
@@ -1038,7 +1042,7 @@ var MindManager = class {
|
|
|
1038
1042
|
}
|
|
1039
1043
|
}
|
|
1040
1044
|
try {
|
|
1041
|
-
const { clearEchoTextCache } = await import("./echo-text-
|
|
1045
|
+
const { clearEchoTextCache } = await import("./echo-text-SEQCLGAT.js");
|
|
1042
1046
|
clearEchoTextCache(name);
|
|
1043
1047
|
} catch (err) {
|
|
1044
1048
|
mlog.debug(`failed to clear echo-text cache for ${name}`, logger_default.errorData(err));
|
|
@@ -1362,10 +1366,54 @@ function deleteSystemsConfig() {
|
|
|
1362
1366
|
}
|
|
1363
1367
|
}
|
|
1364
1368
|
|
|
1369
|
+
// packages/daemon/src/lib/util/sanitize-svg.ts
|
|
1370
|
+
import DOMPurify from "isomorphic-dompurify";
|
|
1371
|
+
var ALLOWED_TAGS = ["svg", "path", "circle", "rect", "line", "polyline", "polygon", "g"];
|
|
1372
|
+
var ALLOWED_ATTR = [
|
|
1373
|
+
"viewBox",
|
|
1374
|
+
"fill",
|
|
1375
|
+
"fill-opacity",
|
|
1376
|
+
"fill-rule",
|
|
1377
|
+
"stroke",
|
|
1378
|
+
"stroke-width",
|
|
1379
|
+
"stroke-linecap",
|
|
1380
|
+
"stroke-linejoin",
|
|
1381
|
+
"stroke-dasharray",
|
|
1382
|
+
"stroke-opacity",
|
|
1383
|
+
"opacity",
|
|
1384
|
+
"d",
|
|
1385
|
+
"cx",
|
|
1386
|
+
"cy",
|
|
1387
|
+
"r",
|
|
1388
|
+
"x",
|
|
1389
|
+
"y",
|
|
1390
|
+
"width",
|
|
1391
|
+
"height",
|
|
1392
|
+
"points",
|
|
1393
|
+
"transform"
|
|
1394
|
+
];
|
|
1395
|
+
function sanitizeSvgIcon(html) {
|
|
1396
|
+
return DOMPurify.sanitize(html, {
|
|
1397
|
+
ALLOWED_TAGS,
|
|
1398
|
+
ALLOWED_ATTR,
|
|
1399
|
+
FORBID_TAGS: ["script", "foreignObject"],
|
|
1400
|
+
FORBID_ATTR: ["href", "xlink:href"]
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1365
1404
|
// packages/daemon/src/lib/extensions.ts
|
|
1366
1405
|
var VALID_EXTENSION_ID = /^[a-z0-9][a-z0-9_-]*$/;
|
|
1367
1406
|
var loaded = [];
|
|
1368
1407
|
var discovered = [];
|
|
1408
|
+
function enrichActivityMetadata(manifest, metadata) {
|
|
1409
|
+
const enriched = {
|
|
1410
|
+
...metadata,
|
|
1411
|
+
...manifest.icon && !metadata?.icon ? { icon: manifest.icon } : {},
|
|
1412
|
+
...manifest.color && !metadata?.color ? { color: manifest.color } : {}
|
|
1413
|
+
};
|
|
1414
|
+
if (typeof enriched.icon === "string") enriched.icon = sanitizeSvgIcon(enriched.icon);
|
|
1415
|
+
return enriched;
|
|
1416
|
+
}
|
|
1369
1417
|
function toCommandInfo(cmd) {
|
|
1370
1418
|
const { handler: _, ...info } = cmd;
|
|
1371
1419
|
return info;
|
|
@@ -1469,14 +1517,8 @@ async function buildContext(manifest, dataDir, authMw) {
|
|
|
1469
1517
|
getUser: async (id) => getUser(id),
|
|
1470
1518
|
getUserByUsername: async (username) => getUserByUsername(username),
|
|
1471
1519
|
publishActivity: (event) => {
|
|
1472
|
-
const
|
|
1473
|
-
|
|
1474
|
-
metadata: {
|
|
1475
|
-
...event.metadata,
|
|
1476
|
-
...manifest.icon && !event.metadata?.icon ? { icon: manifest.icon } : {},
|
|
1477
|
-
...manifest.color && !event.metadata?.color ? { color: manifest.color } : {}
|
|
1478
|
-
}
|
|
1479
|
-
};
|
|
1520
|
+
const metadata = enrichActivityMetadata(manifest, event.metadata);
|
|
1521
|
+
const enriched = { ...event, metadata };
|
|
1480
1522
|
publish(enriched).catch(
|
|
1481
1523
|
(err) => logger_default.error(`extension ${manifest.id}: failed to publish activity`, logger_default.errorData(err))
|
|
1482
1524
|
);
|
|
@@ -1554,14 +1596,8 @@ async function loadExtension(manifest, app, authMw) {
|
|
|
1554
1596
|
const result = await cmd.handler(parsed, {
|
|
1555
1597
|
...context,
|
|
1556
1598
|
publishActivity: (rawEvent) => {
|
|
1557
|
-
const
|
|
1558
|
-
|
|
1559
|
-
metadata: {
|
|
1560
|
-
...rawEvent.metadata,
|
|
1561
|
-
...manifest.icon && !rawEvent.metadata?.icon ? { icon: manifest.icon } : {},
|
|
1562
|
-
...manifest.color && !rawEvent.metadata?.color ? { color: manifest.color } : {}
|
|
1563
|
-
}
|
|
1564
|
-
};
|
|
1599
|
+
const metadata = enrichActivityMetadata(manifest, rawEvent.metadata);
|
|
1600
|
+
const event = { ...rawEvent, metadata };
|
|
1565
1601
|
activityPromises.push(
|
|
1566
1602
|
publish(event).catch((err) => {
|
|
1567
1603
|
logger_default.error(
|
|
@@ -1601,7 +1637,7 @@ async function loadExtension(manifest, app, authMw) {
|
|
|
1601
1637
|
}
|
|
1602
1638
|
if (resolvedAssetsDir && existsSync6(resolvedAssetsDir)) {
|
|
1603
1639
|
const assetsDir = resolvedAssetsDir;
|
|
1604
|
-
const { readFile
|
|
1640
|
+
const { readFile, stat: fsStat } = await import("fs/promises");
|
|
1605
1641
|
const { extname: ext } = await import("path");
|
|
1606
1642
|
const mimeTypes = {
|
|
1607
1643
|
".html": "text/html",
|
|
@@ -1626,11 +1662,11 @@ async function loadExtension(manifest, app, authMw) {
|
|
|
1626
1662
|
const s = await fsStat(filePath).catch(() => null);
|
|
1627
1663
|
if (s?.isFile()) {
|
|
1628
1664
|
const mime = mimeTypes[ext(filePath)] || "application/octet-stream";
|
|
1629
|
-
const body = await
|
|
1665
|
+
const body = await readFile(filePath);
|
|
1630
1666
|
return c.body(body, 200, { "Content-Type": mime });
|
|
1631
1667
|
}
|
|
1632
1668
|
if (existsSync6(indexPath)) {
|
|
1633
|
-
const body = await
|
|
1669
|
+
const body = await readFile(indexPath, "utf-8");
|
|
1634
1670
|
return c.html(body);
|
|
1635
1671
|
}
|
|
1636
1672
|
return c.text("Not found", 404);
|
|
@@ -1948,7 +1984,7 @@ async function installNpmExtension(pkg) {
|
|
|
1948
1984
|
throw new Error(`Extension "${pkg}" is already installed`);
|
|
1949
1985
|
}
|
|
1950
1986
|
const dir = ensureExtensionsNpmDir();
|
|
1951
|
-
const { exec: exec2 } = await import("./exec-
|
|
1987
|
+
const { exec: exec2 } = await import("./exec-QIFYZG4C.js");
|
|
1952
1988
|
try {
|
|
1953
1989
|
await exec2("npm", ["install", "--ignore-scripts", pkg], { cwd: dir });
|
|
1954
1990
|
} catch (err) {
|
|
@@ -1969,7 +2005,7 @@ async function uninstallNpmExtension(pkg) {
|
|
|
1969
2005
|
packages.splice(idx, 1);
|
|
1970
2006
|
writeExtensionsConfig(packages);
|
|
1971
2007
|
try {
|
|
1972
|
-
const { exec: exec2 } = await import("./exec-
|
|
2008
|
+
const { exec: exec2 } = await import("./exec-QIFYZG4C.js");
|
|
1973
2009
|
await exec2("npm", ["uninstall", "--ignore-scripts", pkg], { cwd: extensionsNpmDir() });
|
|
1974
2010
|
} catch (err) {
|
|
1975
2011
|
logger_default.warn(
|
|
@@ -2818,7 +2854,7 @@ async function wakeMind(name) {
|
|
|
2818
2854
|
async function startSpiritFull(name) {
|
|
2819
2855
|
const entry = await findMind(name);
|
|
2820
2856
|
if (entry?.dir) {
|
|
2821
|
-
const { registerMindDir } = await import("./delivery-router-
|
|
2857
|
+
const { registerMindDir } = await import("./delivery-router-3QFG2ZEX.js");
|
|
2822
2858
|
registerMindDir(name, entry.dir);
|
|
2823
2859
|
}
|
|
2824
2860
|
await getMindManager().startMind(name);
|
|
@@ -2848,14 +2884,14 @@ function buildSeedOrientation(createdBy, creatorType) {
|
|
|
2848
2884
|
async function sendSeedOrientation(mindName, createdBy) {
|
|
2849
2885
|
let creatorType;
|
|
2850
2886
|
if (createdBy) {
|
|
2851
|
-
const { getUserByUsername: getUserByUsername2 } = await import("./auth-
|
|
2887
|
+
const { getUserByUsername: getUserByUsername2 } = await import("./auth-A4VGHADI.js");
|
|
2852
2888
|
creatorType = (await getUserByUsername2(createdBy))?.user_type;
|
|
2853
2889
|
}
|
|
2854
2890
|
await sendSystemMessage(mindName, buildSeedOrientation(createdBy, creatorType));
|
|
2855
2891
|
}
|
|
2856
2892
|
async function ensureCreatorDM(mindName, creatorUsername) {
|
|
2857
|
-
const { getOrCreateMindUser: getOrCreateMindUser2, getUserByUsername: getUserByUsername2 } = await import("./auth-
|
|
2858
|
-
const { findDMConversation: findDMConversation2, createConversation: createConversation2 } = await import("./conversations-
|
|
2893
|
+
const { getOrCreateMindUser: getOrCreateMindUser2, getUserByUsername: getUserByUsername2 } = await import("./auth-A4VGHADI.js");
|
|
2894
|
+
const { findDMConversation: findDMConversation2, createConversation: createConversation2 } = await import("./conversations-C7IKYSHD.js");
|
|
2859
2895
|
const mindUser = await getOrCreateMindUser2(mindName);
|
|
2860
2896
|
const creatorUser = await getUserByUsername2(creatorUsername);
|
|
2861
2897
|
if (!creatorUser) {
|
|
@@ -3314,7 +3350,7 @@ var SleepManager = class {
|
|
|
3314
3350
|
* the real delivery stack. Returns whether the batch was handed off to the mind.
|
|
3315
3351
|
*/
|
|
3316
3352
|
async deliverQueuedBatch(name, payloads) {
|
|
3317
|
-
const { deliverBatch: deliverBatch2 } = await import("./message-delivery-
|
|
3353
|
+
const { deliverBatch: deliverBatch2 } = await import("./message-delivery-ZE3YGJDD.js");
|
|
3318
3354
|
return deliverBatch2(name, payloads);
|
|
3319
3355
|
}
|
|
3320
3356
|
// --- Wake failure handling (#419) ---
|
|
@@ -3709,8 +3745,8 @@ function getSleepManagerIfReady() {
|
|
|
3709
3745
|
}
|
|
3710
3746
|
|
|
3711
3747
|
// packages/daemon/src/lib/delivery/delivery-manager.ts
|
|
3712
|
-
import {
|
|
3713
|
-
import {
|
|
3748
|
+
import { realpath } from "fs/promises";
|
|
3749
|
+
import { resolve as resolve8 } from "path";
|
|
3714
3750
|
import { and as and4, eq as eq5, inArray as inArray2, sql as sql2 } from "drizzle-orm";
|
|
3715
3751
|
|
|
3716
3752
|
// packages/daemon/src/lib/chat/typing.ts
|
|
@@ -3876,6 +3912,8 @@ var REDRIVE_INTERVAL_MS = 15e3;
|
|
|
3876
3912
|
var RETRY_BASE_MS = 5e3;
|
|
3877
3913
|
var RETRY_MAX_MS = 5 * 6e4;
|
|
3878
3914
|
var REDRIVE_BATCH_LIMIT = 200;
|
|
3915
|
+
var GATED_RELEASE_LIMIT_PER_CHANNEL = 10;
|
|
3916
|
+
var GATED_NOTIFY_EVERY = 10;
|
|
3879
3917
|
var mentionRegexCache = /* @__PURE__ */ new Map();
|
|
3880
3918
|
var avatarBlocksCache = /* @__PURE__ */ new Map();
|
|
3881
3919
|
var AVATAR_CACHE_TTL = 5 * 60 * 1e3;
|
|
@@ -3896,6 +3934,11 @@ var DeliveryManager = class {
|
|
|
3896
3934
|
redriveTimer = null;
|
|
3897
3935
|
/** Predicate for whether a mind is up; overridable in tests. */
|
|
3898
3936
|
isMindRunning = (name) => tryGetMindManager()?.isRunning(name) ?? false;
|
|
3937
|
+
/** Sends a system message to a mind (invites, release summaries); overridable in tests. */
|
|
3938
|
+
notify = async (mindName, text) => {
|
|
3939
|
+
const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-N2F7HVY3.js");
|
|
3940
|
+
await sendSystemMessage2(mindName, text);
|
|
3941
|
+
};
|
|
3899
3942
|
constructor() {
|
|
3900
3943
|
setRoutesChangeListener((mind) => {
|
|
3901
3944
|
this.releaseGated(mind).catch(
|
|
@@ -3907,6 +3950,10 @@ var DeliveryManager = class {
|
|
|
3907
3950
|
setRunningCheck(fn) {
|
|
3908
3951
|
this.isMindRunning = fn;
|
|
3909
3952
|
}
|
|
3953
|
+
/** Test seam: capture/override system notifications sent to minds. */
|
|
3954
|
+
setNotifier(fn) {
|
|
3955
|
+
this.notify = fn;
|
|
3956
|
+
}
|
|
3910
3957
|
// --- Public API ---
|
|
3911
3958
|
/**
|
|
3912
3959
|
* Route and deliver a message to a mind. This is the main entry point.
|
|
@@ -4069,9 +4116,15 @@ var DeliveryManager = class {
|
|
|
4069
4116
|
if (redriven > 0) dlog.info(`redrove ${redriven} pending delivery queue rows`);
|
|
4070
4117
|
}
|
|
4071
4118
|
/**
|
|
4072
|
-
* Re-evaluate a mind's `gated` rows against its current routes.json
|
|
4073
|
-
*
|
|
4074
|
-
*
|
|
4119
|
+
* Re-evaluate a mind's `gated` rows against its current routes.json when the routing
|
|
4120
|
+
* config changes. For each channel that now matches a `mind` route:
|
|
4121
|
+
* - the newest {@link GATED_RELEASE_LIMIT_PER_CHANNEL} rows are promoted to `pending`
|
|
4122
|
+
* and re-stamped with the freshly-resolved session (NOT the gate-time fallback), so
|
|
4123
|
+
* they land in the correct session instead of `main` (#537 bug 1);
|
|
4124
|
+
* - any older rows are `archived` (inert) so a long backlog can't flood the mind
|
|
4125
|
+
* in one sweep (#537 bug 2), and the mind gets one summary rather than a flood.
|
|
4126
|
+
* Rows resolving to a `file` destination are archived (the delivery manager doesn't
|
|
4127
|
+
* deliver file routes). Declined channels are skipped entirely — they stay gated.
|
|
4075
4128
|
*/
|
|
4076
4129
|
async releaseGated(mindName) {
|
|
4077
4130
|
const baseName = await getBaseName(mindName);
|
|
@@ -4084,7 +4137,8 @@ var DeliveryManager = class {
|
|
|
4084
4137
|
dlog.warn(`failed to read gated rows for ${baseName}`, logger_default.errorData(err));
|
|
4085
4138
|
return;
|
|
4086
4139
|
}
|
|
4087
|
-
const
|
|
4140
|
+
const byChannel = /* @__PURE__ */ new Map();
|
|
4141
|
+
const archiveIds = [];
|
|
4088
4142
|
for (const row of rows) {
|
|
4089
4143
|
let payload;
|
|
4090
4144
|
try {
|
|
@@ -4099,21 +4153,121 @@ var DeliveryManager = class {
|
|
|
4099
4153
|
participantCount: payload.participantCount
|
|
4100
4154
|
};
|
|
4101
4155
|
const route = resolveRoute(config, meta);
|
|
4102
|
-
if (route.matched
|
|
4103
|
-
|
|
4156
|
+
if (!route.matched) continue;
|
|
4157
|
+
if (route.destination === "file") {
|
|
4158
|
+
archiveIds.push(row.id);
|
|
4159
|
+
continue;
|
|
4104
4160
|
}
|
|
4161
|
+
let session = route.session;
|
|
4162
|
+
if (session === "$new") {
|
|
4163
|
+
session = `new-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
4164
|
+
}
|
|
4165
|
+
const channel = row.channel ?? payload.channel ?? "unknown";
|
|
4166
|
+
const list = byChannel.get(channel) ?? [];
|
|
4167
|
+
list.push({ id: row.id, session });
|
|
4168
|
+
byChannel.set(channel, list);
|
|
4169
|
+
}
|
|
4170
|
+
const promote = [];
|
|
4171
|
+
const truncationNotes = [];
|
|
4172
|
+
for (const [channel, items] of byChannel) {
|
|
4173
|
+
if (await this.isChannelDeclined(baseName, channel)) continue;
|
|
4174
|
+
items.sort((a, b) => b.id - a.id);
|
|
4175
|
+
const keep = items.slice(0, GATED_RELEASE_LIMIT_PER_CHANNEL);
|
|
4176
|
+
const drop = items.slice(GATED_RELEASE_LIMIT_PER_CHANNEL);
|
|
4177
|
+
promote.push(...keep);
|
|
4178
|
+
for (const d of drop) archiveIds.push(d.id);
|
|
4179
|
+
if (drop.length > 0) {
|
|
4180
|
+
truncationNotes.push(
|
|
4181
|
+
`${channel}: released the ${keep.length} most recent message(s); ${drop.length} earlier message(s) were held while unrouted and remain in the channel history (volute chat read ${channel}).`
|
|
4182
|
+
);
|
|
4183
|
+
dlog.info(
|
|
4184
|
+
`truncated gated release for ${baseName} on ${channel}: kept ${keep.length}, archived ${drop.length}`
|
|
4185
|
+
);
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4188
|
+
if (archiveIds.length > 0) {
|
|
4189
|
+
try {
|
|
4190
|
+
const db = await getDb();
|
|
4191
|
+
for (let i = 0; i < archiveIds.length; i += 500) {
|
|
4192
|
+
await db.update(deliveryQueue).set({ status: "archived" }).where(inArray2(deliveryQueue.id, archiveIds.slice(i, i + 500)));
|
|
4193
|
+
}
|
|
4194
|
+
} catch (err) {
|
|
4195
|
+
dlog.warn(`failed to archive gated rows for ${baseName}`, logger_default.errorData(err));
|
|
4196
|
+
}
|
|
4197
|
+
}
|
|
4198
|
+
if (promote.length === 0) {
|
|
4199
|
+
if (truncationNotes.length > 0) await this.sendReleaseSummary(mindName, truncationNotes);
|
|
4200
|
+
return;
|
|
4105
4201
|
}
|
|
4106
|
-
if (promote.length === 0) return;
|
|
4107
4202
|
try {
|
|
4108
4203
|
const db = await getDb();
|
|
4109
|
-
|
|
4204
|
+
for (const p of promote) {
|
|
4205
|
+
await db.update(deliveryQueue).set({ status: "pending", session: p.session, attempts: 0, next_attempt_at: null }).where(eq5(deliveryQueue.id, p.id));
|
|
4206
|
+
}
|
|
4110
4207
|
dlog.info(`released ${promote.length} gated message(s) for ${baseName} after route change`);
|
|
4111
4208
|
} catch (err) {
|
|
4112
4209
|
dlog.warn(`failed to promote gated rows for ${baseName}`, logger_default.errorData(err));
|
|
4113
4210
|
return;
|
|
4114
4211
|
}
|
|
4212
|
+
if (truncationNotes.length > 0) await this.sendReleaseSummary(mindName, truncationNotes);
|
|
4115
4213
|
await this.redrive();
|
|
4116
4214
|
}
|
|
4215
|
+
/**
|
|
4216
|
+
* Whether the mind has explicitly declined a channel. A declined channel keeps
|
|
4217
|
+
* persisting history but never notifies and is never released. #537
|
|
4218
|
+
*/
|
|
4219
|
+
async isChannelDeclined(baseName, channel) {
|
|
4220
|
+
if (!channel) return false;
|
|
4221
|
+
try {
|
|
4222
|
+
const db = await getDb();
|
|
4223
|
+
const rows = await db.select({ state: channelGates.state }).from(channelGates).where(and4(eq5(channelGates.mind, baseName), eq5(channelGates.channel, channel)));
|
|
4224
|
+
return rows[0]?.state === "declined";
|
|
4225
|
+
} catch (err) {
|
|
4226
|
+
dlog.warn(`failed to read gate state for ${baseName}/${channel}`, logger_default.errorData(err));
|
|
4227
|
+
return false;
|
|
4228
|
+
}
|
|
4229
|
+
}
|
|
4230
|
+
/**
|
|
4231
|
+
* Record that a mind has declined an unrouted channel: future messages are still
|
|
4232
|
+
* persisted (history is preserved) but never notify, and any currently-gated rows are
|
|
4233
|
+
* archived so they're inert. Returns the number of held messages archived. #537
|
|
4234
|
+
*/
|
|
4235
|
+
async declineChannel(mindName, channel) {
|
|
4236
|
+
const baseName = await getBaseName(mindName);
|
|
4237
|
+
const db = await getDb();
|
|
4238
|
+
await db.insert(channelGates).values({ mind: baseName, channel, state: "declined" }).onConflictDoUpdate({
|
|
4239
|
+
target: [channelGates.mind, channelGates.channel],
|
|
4240
|
+
set: { state: "declined", updated_at: sql2`(datetime('now'))` }
|
|
4241
|
+
});
|
|
4242
|
+
const archived = await db.update(deliveryQueue).set({ status: "archived" }).where(
|
|
4243
|
+
and4(
|
|
4244
|
+
eq5(deliveryQueue.mind, baseName),
|
|
4245
|
+
eq5(deliveryQueue.channel, channel),
|
|
4246
|
+
eq5(deliveryQueue.status, "gated")
|
|
4247
|
+
)
|
|
4248
|
+
).returning({ id: deliveryQueue.id });
|
|
4249
|
+
dlog.info(
|
|
4250
|
+
`declined channel ${channel} for ${baseName}; archived ${archived.length} held row(s)`
|
|
4251
|
+
);
|
|
4252
|
+
return archived.length;
|
|
4253
|
+
}
|
|
4254
|
+
/**
|
|
4255
|
+
* Send the mind a single summary when a routing change released a truncated backlog,
|
|
4256
|
+
* rather than a flood of individual messages. #537
|
|
4257
|
+
*/
|
|
4258
|
+
async sendReleaseSummary(mindName, notes) {
|
|
4259
|
+
const body = [
|
|
4260
|
+
`[Channel backlog released]`,
|
|
4261
|
+
`A routing change matched channel(s) that had held messages while unrouted. To avoid flooding you, only the ${GATED_RELEASE_LIMIT_PER_CHANNEL} most recent per channel were delivered:`,
|
|
4262
|
+
"",
|
|
4263
|
+
...notes.map((n) => `- ${n}`)
|
|
4264
|
+
].join("\n");
|
|
4265
|
+
try {
|
|
4266
|
+
await this.notify(mindName, body);
|
|
4267
|
+
} catch (err) {
|
|
4268
|
+
dlog.warn(`failed to send release summary for ${mindName}`, logger_default.errorData(err));
|
|
4269
|
+
}
|
|
4270
|
+
}
|
|
4117
4271
|
/**
|
|
4118
4272
|
* Get pending (gated) messages for a mind.
|
|
4119
4273
|
*/
|
|
@@ -4513,41 +4667,44 @@ var DeliveryManager = class {
|
|
|
4513
4667
|
}
|
|
4514
4668
|
async gateMessage(mindName, session, payload) {
|
|
4515
4669
|
const baseName = await getBaseName(mindName);
|
|
4516
|
-
await this.
|
|
4670
|
+
const declined = await this.isChannelDeclined(baseName, payload.channel);
|
|
4671
|
+
await this.persistToQueue(mindName, session, payload, declined ? "archived" : "gated");
|
|
4672
|
+
if (declined) return;
|
|
4517
4673
|
try {
|
|
4518
4674
|
const db = await getDb();
|
|
4519
|
-
const
|
|
4675
|
+
const rows = await db.select({ count: sql2`count(*)` }).from(deliveryQueue).where(
|
|
4520
4676
|
and4(
|
|
4521
4677
|
eq5(deliveryQueue.mind, baseName),
|
|
4522
4678
|
eq5(deliveryQueue.channel, payload.channel),
|
|
4523
|
-
|
|
4679
|
+
inArray2(deliveryQueue.status, ["gated", "archived"])
|
|
4524
4680
|
)
|
|
4525
4681
|
);
|
|
4526
|
-
|
|
4527
|
-
|
|
4682
|
+
const count = rows[0]?.count ?? 0;
|
|
4683
|
+
if (count === 1 || count % GATED_NOTIFY_EVERY === 0) {
|
|
4684
|
+
await this.sendInviteNotification(mindName, payload, count);
|
|
4528
4685
|
}
|
|
4529
4686
|
} catch (err) {
|
|
4530
4687
|
dlog.warn(`failed to check gated count for ${baseName}`, logger_default.errorData(err));
|
|
4531
4688
|
}
|
|
4532
4689
|
}
|
|
4533
|
-
async sendInviteNotification(mindName, payload) {
|
|
4690
|
+
async sendInviteNotification(mindName, payload, gatedCount = 1) {
|
|
4534
4691
|
const text = extractTextContent(payload.content);
|
|
4535
4692
|
const preview = text.length > 200 ? `${text.slice(0, 200)}...` : text;
|
|
4536
4693
|
const channel = payload.channel ?? "unknown";
|
|
4694
|
+
const heldLine = gatedCount > 1 ? `${gatedCount} messages from this channel are being held, unrouted \u2014 you've not routed it yet.` : `Someone new is reaching out \u2014 you don't have a route for this channel yet.`;
|
|
4537
4695
|
const notification = [
|
|
4538
4696
|
`[New channel: ${channel}]`,
|
|
4539
|
-
|
|
4697
|
+
heldLine,
|
|
4540
4698
|
`Sender: ${payload.sender ?? "unknown"}`,
|
|
4541
4699
|
payload.platform ? `Platform: ${payload.platform}` : null,
|
|
4542
4700
|
payload.participantCount ? `Participants: ${payload.participantCount}` : null,
|
|
4543
4701
|
"",
|
|
4544
4702
|
`Preview: ${preview}`,
|
|
4545
4703
|
"",
|
|
4546
|
-
`To start hearing this channel, add a routing rule for "${channel}" to .config/routes.json.`,
|
|
4547
|
-
`
|
|
4704
|
+
`To start hearing this channel, add a routing rule for "${channel}" to .config/routes.json \u2014 only the ${GATED_RELEASE_LIMIT_PER_CHANNEL} most recent held messages are replayed; older ones stay in the channel history (volute chat read ${channel}).`,
|
|
4705
|
+
`To stop hearing about it, decline the channel: volute chat channels decline ${channel}`
|
|
4548
4706
|
].filter((line) => line !== null).join("\n");
|
|
4549
|
-
|
|
4550
|
-
await sendSystemMessage2(mindName, notification);
|
|
4707
|
+
await this.notify(mindName, notification);
|
|
4551
4708
|
}
|
|
4552
4709
|
/**
|
|
4553
4710
|
* Insert a delivery_queue row and return its id. The `mind` column is always keyed by
|
|
@@ -4612,18 +4769,6 @@ var DeliveryManager = class {
|
|
|
4612
4769
|
const cached = avatarBlocksCache.get(cacheKey);
|
|
4613
4770
|
if (cached && cached.expiresAt > Date.now()) return cached.blocks;
|
|
4614
4771
|
const blocks = [];
|
|
4615
|
-
let sharpDefault = null;
|
|
4616
|
-
try {
|
|
4617
|
-
const mod = await import("sharp");
|
|
4618
|
-
sharpDefault = mod.default ?? mod;
|
|
4619
|
-
} catch (err) {
|
|
4620
|
-
const code = err.code;
|
|
4621
|
-
if (code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND") {
|
|
4622
|
-
dlog.debug("sharp not available, sending full-size avatars");
|
|
4623
|
-
} else {
|
|
4624
|
-
dlog.warn("sharp import failed, sending full-size avatars", logger_default.errorData(err));
|
|
4625
|
-
}
|
|
4626
|
-
}
|
|
4627
4772
|
for (const p of participants) {
|
|
4628
4773
|
if (!p.avatar) continue;
|
|
4629
4774
|
try {
|
|
@@ -4654,32 +4799,8 @@ var DeliveryManager = class {
|
|
|
4654
4799
|
} else {
|
|
4655
4800
|
filePath = resolve8(voluteHome(), "avatars", p.avatar);
|
|
4656
4801
|
}
|
|
4657
|
-
const
|
|
4658
|
-
|
|
4659
|
-
".png": "image/png",
|
|
4660
|
-
".jpg": "image/jpeg",
|
|
4661
|
-
".jpeg": "image/jpeg",
|
|
4662
|
-
".gif": "image/gif",
|
|
4663
|
-
".webp": "image/webp"
|
|
4664
|
-
};
|
|
4665
|
-
const mediaType = mimeMap[ext];
|
|
4666
|
-
if (!mediaType) continue;
|
|
4667
|
-
const data = await readFile(filePath);
|
|
4668
|
-
let imageData = data;
|
|
4669
|
-
if (sharpDefault) {
|
|
4670
|
-
try {
|
|
4671
|
-
imageData = await sharpDefault(data).resize(128, 128, { fit: "cover" }).toBuffer();
|
|
4672
|
-
} catch (err) {
|
|
4673
|
-
dlog.warn(
|
|
4674
|
-
`avatar resize failed for ${p.username}, sending original`,
|
|
4675
|
-
logger_default.errorData(err)
|
|
4676
|
-
);
|
|
4677
|
-
}
|
|
4678
|
-
}
|
|
4679
|
-
blocks.push(
|
|
4680
|
-
{ type: "text", text: `[Avatar for ${p.username}]` },
|
|
4681
|
-
{ type: "image", media_type: mediaType, data: imageData.toString("base64") }
|
|
4682
|
-
);
|
|
4802
|
+
const rendered = await renderAvatarBlock(filePath, p.username);
|
|
4803
|
+
if (rendered) blocks.push(...rendered);
|
|
4683
4804
|
} catch (err) {
|
|
4684
4805
|
const code = err.code;
|
|
4685
4806
|
if (code !== "ENOENT") {
|
|
@@ -5007,7 +5128,7 @@ async function spiritWillHandle() {
|
|
|
5007
5128
|
const spiritEntry = await findMind(SPIRIT_NAME);
|
|
5008
5129
|
if (spiritEntry?.running && spiritEntry.mindType === "spirit") return true;
|
|
5009
5130
|
try {
|
|
5010
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5131
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-3NA7ZJP3.js");
|
|
5011
5132
|
const sm = getSleepManagerIfReady2();
|
|
5012
5133
|
if (sm?.isSleeping(SPIRIT_NAME)) return true;
|
|
5013
5134
|
} catch (err) {
|
|
@@ -5035,7 +5156,7 @@ async function generateSystemFallbackReply(conversationId, mindName, message) {
|
|
|
5035
5156
|
if (config.sleep.schedule?.wake) contextParts.push(`Wake cron: ${config.sleep.schedule.wake}`);
|
|
5036
5157
|
}
|
|
5037
5158
|
try {
|
|
5038
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5159
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-3NA7ZJP3.js");
|
|
5039
5160
|
const sm = getSleepManagerIfReady2();
|
|
5040
5161
|
if (sm) {
|
|
5041
5162
|
const state2 = sm.getState(mindName);
|
|
@@ -5120,6 +5241,7 @@ export {
|
|
|
5120
5241
|
readSystemsConfig,
|
|
5121
5242
|
writeSystemsConfig,
|
|
5122
5243
|
deleteSystemsConfig,
|
|
5244
|
+
enrichActivityMetadata,
|
|
5123
5245
|
parseCommandArgs,
|
|
5124
5246
|
loadAllExtensions,
|
|
5125
5247
|
getLoadedExtensions,
|