volute 0.33.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{accept-D5VBM7JW.js → accept-TW6V4WI4.js} +6 -6
- package/dist/{activity-events-XJO3P4RR.js → activity-events-BN7V6KCC.js} +4 -4
- package/dist/{ai-service-SBY2WG7O.js → ai-service-PSILB5WD.js} +5 -5
- package/dist/{api-client-YPKOZP2O.js → api-client-XUXOB7LI.js} +1 -1
- package/dist/api.d.ts +426 -3
- package/dist/{archive-INXYFVCW.js → archive-C2VEMQOR.js} +4 -4
- package/dist/{auth-GKCDSO4T.js → auth-ZFZXJZDQ.js} +5 -5
- package/dist/{bridge-TXWWPPOJ.js → bridge-O753D5F4.js} +6 -6
- package/dist/{chat-U5ZOME3O.js → chat-BHYX7DJ4.js} +9 -9
- package/dist/{chunk-M7UL5S3Q.js → chunk-2IOP6PHB.js} +1 -1
- package/dist/{chunk-NPKSDYA2.js → chunk-47XDEWWV.js} +5 -5
- package/dist/{chunk-RSX4OPZY.js → chunk-47ZPNLF4.js} +7 -7
- package/dist/{chunk-RPZZSXV3.js → chunk-4JSR7YO7.js} +20 -1
- package/dist/{chunk-N432I7QH.js → chunk-6OWJXUAR.js} +1 -1
- package/dist/{chunk-I5KY25PQ.js → chunk-6WAWMWR5.js} +1 -1
- package/dist/{chunk-NNB4WIG7.js → chunk-7F2SW2KD.js} +2 -2
- package/dist/chunk-7KJOFUNN.js +22 -0
- package/dist/{chunk-7J3HEVR7.js → chunk-B2BVAIZ4.js} +15 -9
- package/dist/{chunk-VH33ZWMW.js → chunk-BDK73LK6.js} +1 -1
- package/dist/{chunk-QTUVYI7W.js → chunk-BFWHBQK4.js} +1 -1
- package/dist/{chunk-JYVGHWEJ.js → chunk-BM474GX6.js} +3 -3
- package/dist/{chunk-LOEJ4HPQ.js → chunk-BTWAGDV5.js} +1 -1
- package/dist/{chunk-A2A4KLFE.js → chunk-CVL5IGIR.js} +596 -40
- package/dist/{chunk-RVGLDGMI.js → chunk-E5C7OWZ2.js} +20 -22
- package/dist/chunk-FYCALD4Q.js +23 -0
- package/dist/{chunk-SKLSMHXO.js → chunk-IS7WJ56Q.js} +1 -1
- package/dist/{chunk-2NGTS5UU.js → chunk-M3K5AARV.js} +1 -1
- package/dist/{chunk-ALEF47VT.js → chunk-MLOQKQNB.js} +1 -1
- package/dist/{chunk-C7I35G4R.js → chunk-N3DNFPVA.js} +41 -5
- package/dist/{chunk-LRCG2JLP.js → chunk-N7BLAHNE.js} +5 -1
- package/dist/{chunk-UKVWJRKN.js → chunk-PLDWHR4D.js} +1 -1
- package/dist/{chunk-3Z2DPESO.js → chunk-TAHX36HZ.js} +126 -81
- package/dist/{chunk-KIEPMIM5.js → chunk-U5BTYSAL.js} +1 -1
- package/dist/{chunk-GY5HBI7A.js → chunk-V45JXOWY.js} +2 -2
- package/dist/{chunk-JUKK7FPS.js → chunk-V6ZCNULL.js} +2 -2
- package/dist/{chunk-KVK2DLWI.js → chunk-XWXBJQBE.js} +2 -2
- package/dist/cli.js +23 -23
- package/dist/{clock-BVH3V6E3.js → clock-3X4DSC2N.js} +40 -25
- package/dist/{cloud-sync-4NWLMFVH.js → cloud-sync-TG3TIX5H.js} +21 -21
- package/dist/{config-H2H4UIF7.js → config-OROA5DUA.js} +4 -4
- package/dist/connectors/discord-bridge.js +1 -1
- package/dist/connectors/slack-bridge.js +1 -1
- package/dist/connectors/telegram-bridge.js +1 -1
- package/dist/{conversations-AWI5SZW2.js → conversations-HL2JP5GI.js} +5 -5
- package/dist/{create-YWD2TIP4.js → create-3SEKKI6P.js} +6 -6
- package/dist/{create-2FK7Z46Y.js → create-UOSOQ2HN.js} +4 -4
- package/dist/daemon-client-WOAQXXBM.js +12 -0
- package/dist/{daemon-restart-GOBUKLX7.js → daemon-restart-5ABHNXJZ.js} +9 -9
- package/dist/daemon.js +1747 -688
- package/dist/{db-RA45JBFG.js → db-PLEDCBHZ.js} +1 -1
- package/dist/db-RYX3SS2W.js +9 -0
- package/dist/{delete-QTGWEDBI.js → delete-KYOVWR23.js} +3 -3
- package/dist/delivery-manager-2BR5NZKF.js +32 -0
- package/dist/{delivery-router-FL45JL7N.js → delivery-router-D5ELDMS2.js} +4 -4
- package/dist/down-QVFN4UPK.js +15 -0
- package/dist/{env-JCOF2222.js → env-R34DT7XL.js} +12 -8
- package/dist/exec-DVLXKRIO.js +17 -0
- package/dist/{export-SUYRLI5Q.js → export-6ZXAXATG.js} +6 -6
- package/dist/extension-PM42QCID.js +97 -0
- package/dist/extensions-BBGVL5JC.js +38 -0
- package/dist/{files-65PMW5IK.js → files-VQV2VZQO.js} +7 -7
- package/dist/{import-DDUFE7AY.js → import-MK2I2T6F.js} +5 -5
- package/dist/{isolation-LLAYQYDY.js → isolation-62MKDZN3.js} +4 -4
- package/dist/{join-I5QEE3LG.js → join-DGYHTJUH.js} +3 -3
- package/dist/lib-DYEZMGW7.js +6588 -0
- package/dist/{list-JQ463EDA.js → list-C644WTHV.js} +18 -10
- package/dist/{login-D7ETSU4R.js → login-IIGEQPHL.js} +6 -6
- package/dist/{login-RIJF2F4G.js → login-KZQLMAWE.js} +4 -4
- package/dist/{logout-5MLHZALK.js → logout-AGTZVRGP.js} +4 -4
- package/dist/{logout-UZJRGY4Z.js → logout-KD6GXIJJ.js} +4 -4
- package/dist/message-delivery-V3R6NXJP.js +42 -0
- package/dist/{mind-IOJFLEM5.js → mind-BI4EPBVZ.js} +19 -19
- package/dist/{mind-activity-tracker-F6O4Q2SL.js → mind-activity-tracker-2ACNHA7B.js} +5 -5
- package/dist/mind-history-WOYFLQAI.js +264 -0
- package/dist/{mind-list-WUPMQDYQ.js → mind-list-6VPM7GUQ.js} +4 -4
- package/dist/mind-manager-MWW3BTS4.js +32 -0
- package/dist/{mind-profile-P67FEHOY.js → mind-profile-WPG42U5Y.js} +2 -2
- package/dist/mind-service-VIKZJK2M.js +38 -0
- package/dist/{mind-sleep-WW2IX7JT.js → mind-sleep-XDISJY74.js} +6 -6
- package/dist/{mind-status-L3EFFRPR.js → mind-status-7FTZWPZF.js} +4 -4
- package/dist/{mind-wake-VSSGW465.js → mind-wake-KIIKEI3A.js} +6 -6
- package/dist/{package-U3VFO273.js → package-V2WHWVG6.js} +8 -5
- package/dist/{read-EBY56C33.js → read-H5C26YO7.js} +20 -10
- package/dist/{read-stdin-HQJ7774D.js → read-stdin-PIRM6A2Y.js} +1 -1
- package/dist/{register-HD74C4TT.js → register-J27WP33N.js} +6 -6
- package/dist/{registry-PJ4S5PHQ.js → registry-UYV5S6QT.js} +3 -3
- package/dist/{reject-UJKFBHRO.js → reject-OEANJYIA.js} +6 -6
- package/dist/{restart-3UCMRUVC.js → restart-V5EGYBJG.js} +4 -4
- package/dist/{sandbox-GJOK4QLQ.js → sandbox-SI5HMBP3.js} +5 -5
- package/dist/scheduler-AGG3L2FO.js +32 -0
- package/dist/{schema-PA3M5ZKH.js → schema-ETMABTW4.js} +4 -2
- package/dist/{seed-QDYVLG74.js → seed-WNGI6PNW.js} +2 -2
- package/dist/{seed-check-S2IX25RL.js → seed-check-PXTH7YXS.js} +2 -2
- package/dist/{seed-cmd-DKOUFEAU.js → seed-cmd-VENFTGS3.js} +4 -4
- package/dist/{seed-create-4XBBOLRH.js → seed-create-663ALOKH.js} +6 -6
- package/dist/{seed-sprout-GQEIIQRT.js → seed-sprout-EH3AGKAI.js} +12 -12
- package/dist/{send-QIV2INHB.js → send-7FUUUZZH.js} +23 -10
- package/dist/{setup-TISPCO22.js → setup-GGMKENLN.js} +4 -4
- package/dist/{setup-XMCBE3LF.js → setup-Z3DEVWV7.js} +11 -11
- package/dist/{skill-PSQGRRJX.js → skill-DKNYJS4P.js} +14 -10
- package/dist/skills/plan-coordinator/SKILL.md +60 -0
- package/dist/skills/volute-mind/SKILL.md +7 -221
- package/dist/skills/volute-mind/references/extensions.md +37 -0
- package/dist/skills/volute-mind/references/integrations.md +48 -0
- package/dist/skills/volute-mind/references/routing.md +86 -0
- package/dist/skills/volute-mind/references/sleep.md +33 -0
- package/dist/skills/volute-mind/references/variants.md +31 -0
- package/dist/{skills-7FV7EJTE.js → skills-Q6VZ2UGD.js} +11 -7
- package/dist/sleep-manager-BJK2ROPX.js +36 -0
- package/dist/spirit-4JP4TY4C.js +23 -0
- package/dist/{split-STOROBYJ.js → split-3YPMS2CL.js} +3 -3
- package/dist/{sprout-WKLZXUIQ.js → sprout-E3HJIV2Z.js} +2 -2
- package/dist/{start-K2NCUUCG.js → start-W3TPKX4D.js} +4 -4
- package/dist/{status-3JBTFSMI.js → status-4OVFXFEJ.js} +7 -7
- package/dist/{stop-H26JZDXF.js → stop-GTT6YWYO.js} +4 -4
- package/dist/system-channel-DXD2JBOU.js +36 -0
- package/dist/system-chat-TYLOL7SX.js +36 -0
- package/dist/{systems-XRI52VCH.js → systems-AYLO727G.js} +7 -7
- package/dist/{tailscale-XHQBZROW.js → tailscale-ZEUK7GKZ.js} +3 -3
- package/dist/{template-hash-A6VVKOXJ.js → template-hash-EJRTKE36.js} +1 -1
- package/dist/up-PA7F2CXE.js +18 -0
- package/dist/{update-UD543CXX.js → update-HG4LCUSG.js} +7 -7
- package/dist/{update-check-ZD6OOIYQ.js → update-check-X3YG4WVP.js} +4 -4
- package/dist/{upgrade-O4Q7WJM3.js → upgrade-YGNIDICG.js} +3 -3
- package/dist/{variant-7TGZHOU3.js → variant-MZUMRTQO.js} +1 -1
- package/dist/{version-notify-NBI2MTJO.js → version-notify-YCH4UVQ2.js} +19 -19
- package/dist/{volute-config-HD7WWUQC.js → volute-config-WBKYJGYQ.js} +1 -1
- package/dist/web-assets/assets/index-DiiwC-CZ.css +1 -0
- package/dist/web-assets/assets/index-d6y5b9Ij.js +75 -0
- package/dist/web-assets/ext-theme.css +48 -9
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0005_meta_summaries.sql +15 -0
- package/drizzle/meta/0005_snapshot.json +7 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +7 -4
- package/packages/extensions/plan/dist/ui/assets/index-CJj2gZnZ.css +1 -0
- package/packages/extensions/plan/dist/ui/assets/index-FMEJmvQz.js +61 -0
- package/packages/extensions/plan/dist/ui/index.html +14 -0
- package/packages/extensions/plan/skills/plan/SKILL.md +43 -0
- package/packages/extensions/plan/skills/plan/scripts/plan-hook.sh +37 -0
- package/templates/_base/home/VOLUTE.md +12 -19
- package/templates/_base/src/lib/context-breakdown.ts +450 -0
- package/templates/_base/src/lib/format-prefix.ts +17 -0
- package/templates/_base/src/lib/hook-loader.ts +8 -2
- package/templates/_base/src/lib/router.ts +75 -33
- package/templates/_base/src/lib/routing.ts +4 -1
- package/templates/_base/src/lib/startup.ts +16 -8
- package/templates/_base/src/lib/types.ts +2 -1
- package/templates/_base/src/lib/volute-server.ts +69 -8
- package/templates/claude/.init/CLAUDE.md +4 -10
- package/templates/claude/package.json.tmpl +1 -0
- package/templates/claude/src/agent.ts +100 -32
- package/templates/claude/src/lib/hooks/reply-instructions.ts +27 -7
- package/templates/claude/src/lib/stream-consumer.ts +2 -2
- package/templates/claude/src/server.ts +1 -0
- package/templates/codex/package.json.tmpl +1 -0
- package/templates/codex/src/agent.ts +80 -8
- package/templates/codex/src/server.ts +1 -4
- package/templates/pi/package.json.tmpl +1 -0
- package/templates/pi/src/agent.ts +115 -36
- package/templates/pi/src/lib/event-handler.ts +22 -7
- package/templates/pi/src/lib/reply-instructions-extension.ts +23 -4
- package/templates/pi/src/lib/subagents.ts +20 -17
- package/templates/pi/src/server.ts +2 -5
- package/dist/chunk-K3NQKI34.js +0 -10
- package/dist/daemon-client-6QXHZ7US.js +0 -12
- package/dist/db-F34YLV7D.js +0 -9
- package/dist/delivery-manager-PFAKEJTC.js +0 -32
- package/dist/down-FWWTEKXM.js +0 -15
- package/dist/extension-OBTGKQQD.js +0 -175
- package/dist/extensions-KYNTVTMO.js +0 -30
- package/dist/history-DKCDI3JO.js +0 -128
- package/dist/message-delivery-DFF5SJRM.js +0 -42
- package/dist/mind-manager-NBJF5D26.js +0 -32
- package/dist/mind-service-2MQ6UK5N.js +0 -38
- package/dist/scheduler-ZZ7XGQG6.js +0 -32
- package/dist/sleep-manager-JTXSN7NV.js +0 -36
- package/dist/spirit-VRONKFMF.js +0 -23
- package/dist/system-chat-JAPOJ3KE.js +0 -36
- package/dist/up-M5AS6SBV.js +0 -18
- package/dist/web-assets/assets/index-CWJrVveV.css +0 -1
- package/dist/web-assets/assets/index-DJt14FRI.js +0 -75
package/dist/daemon.js
CHANGED
|
@@ -3,10 +3,18 @@ import {
|
|
|
3
3
|
checkForUpdate,
|
|
4
4
|
checkForUpdateCached,
|
|
5
5
|
getCurrentVersion
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-2IOP6PHB.js";
|
|
7
7
|
import {
|
|
8
8
|
computeTemplateHash
|
|
9
9
|
} from "./chunk-PVY5W6QN.js";
|
|
10
|
+
import {
|
|
11
|
+
acceptPending,
|
|
12
|
+
formatFileSize,
|
|
13
|
+
listPending,
|
|
14
|
+
rejectPending,
|
|
15
|
+
stageFile,
|
|
16
|
+
validateFilePath
|
|
17
|
+
} from "./chunk-MLOQKQNB.js";
|
|
10
18
|
import {
|
|
11
19
|
PROMPT_DEFAULTS,
|
|
12
20
|
PROMPT_KEYS,
|
|
@@ -45,7 +53,6 @@ import {
|
|
|
45
53
|
recordInbound,
|
|
46
54
|
recordOutbound,
|
|
47
55
|
resolveMindToken,
|
|
48
|
-
setSummaryEventId,
|
|
49
56
|
startMindFull,
|
|
50
57
|
stopMindFull,
|
|
51
58
|
subscribe as subscribe3,
|
|
@@ -54,53 +61,22 @@ import {
|
|
|
54
61
|
tagUntaggedInbound,
|
|
55
62
|
tagUntaggedOutbound,
|
|
56
63
|
trackToolUse
|
|
57
|
-
} from "./chunk-
|
|
58
|
-
import {
|
|
59
|
-
extractTextContent
|
|
60
|
-
} from "./chunk-SKLSMHXO.js";
|
|
61
|
-
import {
|
|
62
|
-
getActiveMinds,
|
|
63
|
-
onMindEvent,
|
|
64
|
-
stopAll
|
|
65
|
-
} from "./chunk-LOEJ4HPQ.js";
|
|
64
|
+
} from "./chunk-TAHX36HZ.js";
|
|
66
65
|
import {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
isParticipant,
|
|
82
|
-
isParticipantOrOwner,
|
|
83
|
-
joinChannel,
|
|
84
|
-
leaveChannel,
|
|
85
|
-
listChannels,
|
|
86
|
-
listConversationsForMind,
|
|
87
|
-
listConversationsForUser,
|
|
88
|
-
listConversationsWithParticipants,
|
|
89
|
-
markConversationRead,
|
|
90
|
-
publish,
|
|
91
|
-
setConversationPrivate,
|
|
92
|
-
subscribe as subscribe2
|
|
93
|
-
} from "./chunk-RVGLDGMI.js";
|
|
94
|
-
import "./chunk-GY5HBI7A.js";
|
|
95
|
-
import {
|
|
96
|
-
acceptPending,
|
|
97
|
-
formatFileSize,
|
|
98
|
-
listPending,
|
|
99
|
-
rejectPending,
|
|
100
|
-
stageFile,
|
|
101
|
-
validateFilePath
|
|
102
|
-
} from "./chunk-ALEF47VT.js";
|
|
103
|
-
import "./chunk-7J3HEVR7.js";
|
|
66
|
+
deleteSystemsConfig,
|
|
67
|
+
getAllDiscoveredExtensions,
|
|
68
|
+
getExtensionStandardSkills,
|
|
69
|
+
getLoadedExtensions,
|
|
70
|
+
installNpmExtension,
|
|
71
|
+
loadAllExtensions,
|
|
72
|
+
notifyExtensionsDaemonStart,
|
|
73
|
+
notifyExtensionsDaemonStop,
|
|
74
|
+
readSystemsConfig,
|
|
75
|
+
setExtensionEnabled,
|
|
76
|
+
uninstallNpmExtension,
|
|
77
|
+
writeSystemsConfig
|
|
78
|
+
} from "./chunk-CVL5IGIR.js";
|
|
79
|
+
import "./chunk-B2BVAIZ4.js";
|
|
104
80
|
import {
|
|
105
81
|
applyInitFiles,
|
|
106
82
|
composeTemplate,
|
|
@@ -108,10 +84,39 @@ import {
|
|
|
108
84
|
findTemplatesRoot,
|
|
109
85
|
listFiles
|
|
110
86
|
} from "./chunk-G53F3JA4.js";
|
|
87
|
+
import {
|
|
88
|
+
SEED_SKILLS,
|
|
89
|
+
STANDARD_SKILLS,
|
|
90
|
+
autoUpdateMindSkills,
|
|
91
|
+
getSharedSkill,
|
|
92
|
+
getStandardSkillsWithExtensions,
|
|
93
|
+
importSkillFromDir,
|
|
94
|
+
initDefaultSkills,
|
|
95
|
+
installSkill,
|
|
96
|
+
isAutoUpdateSkillsEnabled,
|
|
97
|
+
listFilesRecursive,
|
|
98
|
+
listMindSkills,
|
|
99
|
+
listSharedSkills,
|
|
100
|
+
publishSkill,
|
|
101
|
+
removeSharedSkill,
|
|
102
|
+
sharedSkillsDir,
|
|
103
|
+
syncBuiltinSkills,
|
|
104
|
+
uninstallSkill,
|
|
105
|
+
updateSkill
|
|
106
|
+
} from "./chunk-N3DNFPVA.js";
|
|
111
107
|
import {
|
|
112
108
|
readVoluteConfig,
|
|
113
109
|
writeVoluteConfig
|
|
114
110
|
} from "./chunk-OYAKCAVY.js";
|
|
111
|
+
import "./chunk-V45JXOWY.js";
|
|
112
|
+
import {
|
|
113
|
+
extractTextContent
|
|
114
|
+
} from "./chunk-IS7WJ56Q.js";
|
|
115
|
+
import {
|
|
116
|
+
getActiveMinds,
|
|
117
|
+
onMindEvent,
|
|
118
|
+
stopAll
|
|
119
|
+
} from "./chunk-BTWAGDV5.js";
|
|
115
120
|
import {
|
|
116
121
|
findBridgeForChannel,
|
|
117
122
|
findOpenClawSession,
|
|
@@ -125,27 +130,17 @@ import {
|
|
|
125
130
|
resolveChannelMapping,
|
|
126
131
|
setBridgeConfig,
|
|
127
132
|
setChannelMapping
|
|
128
|
-
} from "./chunk-
|
|
133
|
+
} from "./chunk-47ZPNLF4.js";
|
|
129
134
|
import {
|
|
130
135
|
loadMergedEnv,
|
|
131
136
|
mindEnvPath,
|
|
132
137
|
readEnv,
|
|
133
138
|
sharedEnvPath,
|
|
134
139
|
writeEnv
|
|
135
|
-
} from "./chunk-
|
|
140
|
+
} from "./chunk-M3K5AARV.js";
|
|
136
141
|
import {
|
|
137
142
|
isHomeOnlyArchive
|
|
138
|
-
} from "./chunk-
|
|
139
|
-
import {
|
|
140
|
-
deleteSystemsConfig,
|
|
141
|
-
getExtensionStandardSkills,
|
|
142
|
-
getLoadedExtensions,
|
|
143
|
-
loadAllExtensions,
|
|
144
|
-
notifyExtensionsDaemonStart,
|
|
145
|
-
notifyExtensionsDaemonStop,
|
|
146
|
-
readSystemsConfig,
|
|
147
|
-
writeSystemsConfig
|
|
148
|
-
} from "./chunk-A2A4KLFE.js";
|
|
143
|
+
} from "./chunk-6WAWMWR5.js";
|
|
149
144
|
import "./chunk-PB65JZK2.js";
|
|
150
145
|
import {
|
|
151
146
|
approveUser,
|
|
@@ -162,31 +157,42 @@ import {
|
|
|
162
157
|
listUsers,
|
|
163
158
|
listUsersByType,
|
|
164
159
|
setUserRole,
|
|
160
|
+
syncMindProfile,
|
|
165
161
|
updateUserProfile,
|
|
166
162
|
verifyUser
|
|
167
|
-
} from "./chunk-
|
|
163
|
+
} from "./chunk-BM474GX6.js";
|
|
164
|
+
import {
|
|
165
|
+
addMessage,
|
|
166
|
+
createChannel,
|
|
167
|
+
createConversation,
|
|
168
|
+
deleteConversationForUser,
|
|
169
|
+
findDMConversation,
|
|
170
|
+
fireWebhook,
|
|
171
|
+
getChannelByName,
|
|
172
|
+
getConversation,
|
|
173
|
+
getMessages,
|
|
174
|
+
getMessagesPaginated,
|
|
175
|
+
getParticipants,
|
|
176
|
+
getUnreadCounts,
|
|
177
|
+
initWebhook,
|
|
178
|
+
isConversationForMind,
|
|
179
|
+
isParticipant,
|
|
180
|
+
isParticipantOrOwner,
|
|
181
|
+
joinChannel,
|
|
182
|
+
leaveChannel,
|
|
183
|
+
listChannels,
|
|
184
|
+
listConversationsForMind,
|
|
185
|
+
listConversationsForUser,
|
|
186
|
+
listConversationsWithParticipants,
|
|
187
|
+
markConversationRead,
|
|
188
|
+
publish,
|
|
189
|
+
setConversationPrivate,
|
|
190
|
+
subscribe as subscribe2
|
|
191
|
+
} from "./chunk-E5C7OWZ2.js";
|
|
168
192
|
import {
|
|
169
193
|
broadcast,
|
|
170
194
|
subscribe
|
|
171
|
-
} from "./chunk-
|
|
172
|
-
import {
|
|
173
|
-
SEED_SKILLS,
|
|
174
|
-
STANDARD_SKILLS,
|
|
175
|
-
getSharedSkill,
|
|
176
|
-
getStandardSkillsWithExtensions,
|
|
177
|
-
importSkillFromDir,
|
|
178
|
-
initDefaultSkills,
|
|
179
|
-
installSkill,
|
|
180
|
-
listFilesRecursive,
|
|
181
|
-
listMindSkills,
|
|
182
|
-
listSharedSkills,
|
|
183
|
-
publishSkill,
|
|
184
|
-
removeSharedSkill,
|
|
185
|
-
sharedSkillsDir,
|
|
186
|
-
syncBuiltinSkills,
|
|
187
|
-
uninstallSkill,
|
|
188
|
-
updateSkill
|
|
189
|
-
} from "./chunk-C7I35G4R.js";
|
|
195
|
+
} from "./chunk-XWXBJQBE.js";
|
|
190
196
|
import {
|
|
191
197
|
aiCompleteUtility,
|
|
192
198
|
getAiConfig,
|
|
@@ -203,16 +209,17 @@ import {
|
|
|
203
209
|
setEnabledModels,
|
|
204
210
|
setUtilityModel,
|
|
205
211
|
unqualifyModelId
|
|
206
|
-
} from "./chunk-
|
|
212
|
+
} from "./chunk-BFWHBQK4.js";
|
|
207
213
|
import {
|
|
208
214
|
logBuffer,
|
|
209
215
|
logger_default
|
|
210
216
|
} from "./chunk-YUIHSKR6.js";
|
|
217
|
+
import "./chunk-D424ZQGI.js";
|
|
211
218
|
import {
|
|
212
219
|
exec,
|
|
213
220
|
gitExec,
|
|
214
221
|
resolveVoluteBin
|
|
215
|
-
} from "./chunk-
|
|
222
|
+
} from "./chunk-U5BTYSAL.js";
|
|
216
223
|
import {
|
|
217
224
|
chownMindDir,
|
|
218
225
|
createMindUser,
|
|
@@ -221,16 +228,15 @@ import {
|
|
|
221
228
|
isIsolationEnabled,
|
|
222
229
|
mindUserName,
|
|
223
230
|
wrapForIsolation
|
|
224
|
-
} from "./chunk-
|
|
231
|
+
} from "./chunk-BDK73LK6.js";
|
|
225
232
|
import {
|
|
226
233
|
isSetupComplete,
|
|
227
234
|
readGlobalConfig,
|
|
228
235
|
writeGlobalConfig
|
|
229
|
-
} from "./chunk-
|
|
236
|
+
} from "./chunk-6OWJXUAR.js";
|
|
230
237
|
import {
|
|
231
238
|
readSessionFile
|
|
232
|
-
} from "./chunk-
|
|
233
|
-
import "./chunk-D424ZQGI.js";
|
|
239
|
+
} from "./chunk-PLDWHR4D.js";
|
|
234
240
|
import {
|
|
235
241
|
buildVoluteSlug,
|
|
236
242
|
slugify
|
|
@@ -257,24 +263,26 @@ import {
|
|
|
257
263
|
validateMindName,
|
|
258
264
|
voluteHome,
|
|
259
265
|
voluteSystemDir
|
|
260
|
-
} from "./chunk-
|
|
266
|
+
} from "./chunk-N7BLAHNE.js";
|
|
261
267
|
import {
|
|
262
268
|
activity,
|
|
269
|
+
conversationParticipants,
|
|
263
270
|
conversations,
|
|
264
271
|
messages,
|
|
265
272
|
mindHistory,
|
|
266
273
|
sessions,
|
|
274
|
+
summaries,
|
|
267
275
|
systemPrompts,
|
|
268
276
|
turns,
|
|
269
277
|
users
|
|
270
|
-
} from "./chunk-
|
|
278
|
+
} from "./chunk-4JSR7YO7.js";
|
|
271
279
|
import {
|
|
272
280
|
__export
|
|
273
|
-
} from "./chunk-
|
|
281
|
+
} from "./chunk-7KJOFUNN.js";
|
|
274
282
|
|
|
275
283
|
// src/daemon.ts
|
|
276
284
|
import { randomBytes } from "crypto";
|
|
277
|
-
import { mkdirSync as
|
|
285
|
+
import { mkdirSync as mkdirSync11, readFileSync as readFileSync12, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
|
|
278
286
|
import { homedir as homedir3 } from "os";
|
|
279
287
|
import { resolve as resolve19 } from "path";
|
|
280
288
|
import { format } from "util";
|
|
@@ -450,160 +458,923 @@ var BridgeManager = class {
|
|
|
450
458
|
logStream.write(chunk);
|
|
451
459
|
lastStderr = chunk.toString().trim();
|
|
452
460
|
});
|
|
453
|
-
if (child.pid) {
|
|
454
|
-
this.saveBridgePid(platform, child.pid);
|
|
455
|
-
}
|
|
456
|
-
this.bridges.set(platform, { child, platform });
|
|
457
|
-
this.restartTracker.reset(platform);
|
|
458
|
-
child.on("exit", (code) => {
|
|
459
|
-
const tracked = this.bridges.get(platform);
|
|
460
|
-
if (tracked?.child === child) {
|
|
461
|
-
this.bridges.delete(platform);
|
|
462
|
-
}
|
|
463
|
-
if (this.shuttingDown) return;
|
|
464
|
-
if (this.stopping.has(platform)) return;
|
|
465
|
-
blog.error(`bridge ${platform} exited with code ${code}`);
|
|
466
|
-
if (lastStderr) blog.warn(`bridge ${platform} last output: ${lastStderr}`);
|
|
467
|
-
const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(platform);
|
|
468
|
-
if (!shouldRestart) {
|
|
469
|
-
blog.error(`bridge ${platform} crashed ${attempt} times \u2014 giving up`);
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
blog.info(
|
|
473
|
-
`restarting bridge ${platform} \u2014 attempt ${attempt}/${this.restartTracker.maxRestartAttempts}, in ${delay}ms`
|
|
461
|
+
if (child.pid) {
|
|
462
|
+
this.saveBridgePid(platform, child.pid);
|
|
463
|
+
}
|
|
464
|
+
this.bridges.set(platform, { child, platform });
|
|
465
|
+
this.restartTracker.reset(platform);
|
|
466
|
+
child.on("exit", (code) => {
|
|
467
|
+
const tracked = this.bridges.get(platform);
|
|
468
|
+
if (tracked?.child === child) {
|
|
469
|
+
this.bridges.delete(platform);
|
|
470
|
+
}
|
|
471
|
+
if (this.shuttingDown) return;
|
|
472
|
+
if (this.stopping.has(platform)) return;
|
|
473
|
+
blog.error(`bridge ${platform} exited with code ${code}`);
|
|
474
|
+
if (lastStderr) blog.warn(`bridge ${platform} last output: ${lastStderr}`);
|
|
475
|
+
const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(platform);
|
|
476
|
+
if (!shouldRestart) {
|
|
477
|
+
blog.error(`bridge ${platform} crashed ${attempt} times \u2014 giving up`);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
blog.info(
|
|
481
|
+
`restarting bridge ${platform} \u2014 attempt ${attempt}/${this.restartTracker.maxRestartAttempts}, in ${delay}ms`
|
|
482
|
+
);
|
|
483
|
+
setTimeout(() => {
|
|
484
|
+
if (this.shuttingDown || this.stopping.has(platform)) return;
|
|
485
|
+
this.startBridge(platform, daemonPort).catch((err) => {
|
|
486
|
+
blog.error(`failed to restart bridge ${platform}`, logger_default.errorData(err));
|
|
487
|
+
});
|
|
488
|
+
}, delay);
|
|
489
|
+
});
|
|
490
|
+
blog.info(`started bridge ${platform}`);
|
|
491
|
+
}
|
|
492
|
+
async stopBridge(platform) {
|
|
493
|
+
const tracked = this.bridges.get(platform);
|
|
494
|
+
if (!tracked) return;
|
|
495
|
+
this.stopping.add(platform);
|
|
496
|
+
this.bridges.delete(platform);
|
|
497
|
+
await new Promise((resolve20) => {
|
|
498
|
+
tracked.child.on("exit", () => resolve20());
|
|
499
|
+
try {
|
|
500
|
+
if (tracked.child.pid) {
|
|
501
|
+
process.kill(-tracked.child.pid, "SIGTERM");
|
|
502
|
+
} else {
|
|
503
|
+
tracked.child.kill("SIGTERM");
|
|
504
|
+
}
|
|
505
|
+
} catch (err) {
|
|
506
|
+
if (err instanceof Error && err.code !== "ESRCH") {
|
|
507
|
+
blog.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
|
|
508
|
+
}
|
|
509
|
+
resolve20();
|
|
510
|
+
}
|
|
511
|
+
setTimeout(() => {
|
|
512
|
+
try {
|
|
513
|
+
if (tracked.child.pid) {
|
|
514
|
+
process.kill(-tracked.child.pid, "SIGKILL");
|
|
515
|
+
} else {
|
|
516
|
+
tracked.child.kill("SIGKILL");
|
|
517
|
+
}
|
|
518
|
+
} catch {
|
|
519
|
+
}
|
|
520
|
+
resolve20();
|
|
521
|
+
}, 5e3);
|
|
522
|
+
});
|
|
523
|
+
this.stopping.delete(platform);
|
|
524
|
+
this.restartTracker.reset(platform);
|
|
525
|
+
try {
|
|
526
|
+
this.removeBridgePid(platform);
|
|
527
|
+
} catch (err) {
|
|
528
|
+
blog.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
|
|
529
|
+
}
|
|
530
|
+
blog.info(`stopped bridge ${platform}`);
|
|
531
|
+
}
|
|
532
|
+
async stopAll() {
|
|
533
|
+
this.shuttingDown = true;
|
|
534
|
+
const platforms = [...this.bridges.keys()];
|
|
535
|
+
await Promise.all(platforms.map((p) => this.stopBridge(p)));
|
|
536
|
+
}
|
|
537
|
+
getBridgeStatus() {
|
|
538
|
+
return [...this.bridges.entries()].map(([platform, tracked]) => ({
|
|
539
|
+
platform,
|
|
540
|
+
running: !tracked.child.killed
|
|
541
|
+
}));
|
|
542
|
+
}
|
|
543
|
+
isRunning(platform) {
|
|
544
|
+
const tracked = this.bridges.get(platform);
|
|
545
|
+
return tracked != null && !tracked.child.killed;
|
|
546
|
+
}
|
|
547
|
+
bridgePidPath(platform) {
|
|
548
|
+
return resolve2(voluteSystemDir(), "bridges", `${platform}.pid`);
|
|
549
|
+
}
|
|
550
|
+
saveBridgePid(platform, pid) {
|
|
551
|
+
const pidPath = this.bridgePidPath(platform);
|
|
552
|
+
mkdirSync(dirname(pidPath), { recursive: true });
|
|
553
|
+
writeFileSync(pidPath, String(pid));
|
|
554
|
+
}
|
|
555
|
+
removeBridgePid(platform) {
|
|
556
|
+
try {
|
|
557
|
+
unlinkSync(this.bridgePidPath(platform));
|
|
558
|
+
} catch (err) {
|
|
559
|
+
if (err instanceof Error && err.code !== "ENOENT") {
|
|
560
|
+
blog.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
killOrphanBridge(platform) {
|
|
565
|
+
const pidPath = this.bridgePidPath(platform);
|
|
566
|
+
if (!existsSync2(pidPath)) return;
|
|
567
|
+
try {
|
|
568
|
+
const pid = parseInt(readFileSync2(pidPath, "utf-8").trim(), 10);
|
|
569
|
+
if (pid > 0) {
|
|
570
|
+
try {
|
|
571
|
+
process.kill(-pid, "SIGTERM");
|
|
572
|
+
} catch {
|
|
573
|
+
try {
|
|
574
|
+
process.kill(pid, "SIGTERM");
|
|
575
|
+
} catch {
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
blog.warn(`killed orphan bridge ${platform} (pid ${pid})`);
|
|
579
|
+
}
|
|
580
|
+
} catch (err) {
|
|
581
|
+
if (err instanceof Error && err.code !== "ESRCH") {
|
|
582
|
+
blog.debug(`orphan bridge ${platform} cleanup: ${err}`);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
try {
|
|
586
|
+
unlinkSync(pidPath);
|
|
587
|
+
} catch (err) {
|
|
588
|
+
if (err instanceof Error && err.code !== "ENOENT") {
|
|
589
|
+
blog.warn(`failed to clean up PID file for orphan bridge ${platform}`, logger_default.errorData(err));
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
resolveBuiltinBridge(platform) {
|
|
594
|
+
return searchUpwards("connectors", `${platform}-bridge.js`);
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
var instance = null;
|
|
598
|
+
function initBridgeManager() {
|
|
599
|
+
if (instance) throw new Error("BridgeManager already initialized");
|
|
600
|
+
instance = new BridgeManager();
|
|
601
|
+
return instance;
|
|
602
|
+
}
|
|
603
|
+
function getBridgeManager() {
|
|
604
|
+
if (!instance) throw new Error("BridgeManager not initialized \u2014 call initBridgeManager() first");
|
|
605
|
+
return instance;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// src/lib/daemon/summarizer.ts
|
|
609
|
+
import { and, desc, eq, gte, like, lt, sql } from "drizzle-orm";
|
|
610
|
+
|
|
611
|
+
// src/lib/format-tool.ts
|
|
612
|
+
function summarizeTool(name, input) {
|
|
613
|
+
if (input && typeof input === "object") {
|
|
614
|
+
const args = input;
|
|
615
|
+
const val = args.path ?? args.command ?? args.query ?? args.url;
|
|
616
|
+
if (typeof val === "string") {
|
|
617
|
+
const brief = val.length > 60 ? `${val.slice(0, 57)}...` : val;
|
|
618
|
+
return `[${name} ${brief}]`;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return `[${name}]`;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// src/lib/daemon/summarizer.ts
|
|
625
|
+
var sLog = logger_default.child("summarizer");
|
|
626
|
+
var SYSTEM_MIND = "_system";
|
|
627
|
+
function getPeriodKey(date, period) {
|
|
628
|
+
switch (period) {
|
|
629
|
+
case "hour": {
|
|
630
|
+
const y = date.getFullYear();
|
|
631
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
632
|
+
const d = String(date.getDate()).padStart(2, "0");
|
|
633
|
+
const h = String(date.getHours()).padStart(2, "0");
|
|
634
|
+
return `${y}-${m}-${d}T${h}`;
|
|
635
|
+
}
|
|
636
|
+
case "day": {
|
|
637
|
+
const y = date.getFullYear();
|
|
638
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
639
|
+
const d = String(date.getDate()).padStart(2, "0");
|
|
640
|
+
return `${y}-${m}-${d}`;
|
|
641
|
+
}
|
|
642
|
+
case "week":
|
|
643
|
+
return getISOWeekKey(date);
|
|
644
|
+
case "month": {
|
|
645
|
+
const y = date.getFullYear();
|
|
646
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
647
|
+
return `${y}-${m}`;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
function getISOWeekKey(date) {
|
|
652
|
+
const d = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
653
|
+
d.setDate(d.getDate() + 4 - (d.getDay() || 7));
|
|
654
|
+
const yearStart = new Date(d.getFullYear(), 0, 1);
|
|
655
|
+
const weekNum = Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
|
|
656
|
+
return `${d.getFullYear()}-W${String(weekNum).padStart(2, "0")}`;
|
|
657
|
+
}
|
|
658
|
+
function getPreviousPeriodKey(key, period) {
|
|
659
|
+
switch (period) {
|
|
660
|
+
case "hour": {
|
|
661
|
+
const d = /* @__PURE__ */ new Date(`${key.slice(0, 10)}T${key.slice(11)}:00:00`);
|
|
662
|
+
d.setHours(d.getHours() - 1);
|
|
663
|
+
return getPeriodKey(d, "hour");
|
|
664
|
+
}
|
|
665
|
+
case "day": {
|
|
666
|
+
const d = /* @__PURE__ */ new Date(`${key}T00:00:00`);
|
|
667
|
+
d.setDate(d.getDate() - 1);
|
|
668
|
+
return getPeriodKey(d, "day");
|
|
669
|
+
}
|
|
670
|
+
case "week": {
|
|
671
|
+
const d = isoWeekToDate(key);
|
|
672
|
+
d.setDate(d.getDate() - 7);
|
|
673
|
+
return getPeriodKey(d, "week");
|
|
674
|
+
}
|
|
675
|
+
case "month": {
|
|
676
|
+
const [y, m] = key.split("-").map(Number);
|
|
677
|
+
const d = new Date(y, m - 2, 1);
|
|
678
|
+
return getPeriodKey(d, "month");
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
function isoWeekToDate(weekKey) {
|
|
683
|
+
const [yearStr, weekStr] = weekKey.split("-W");
|
|
684
|
+
const year = parseInt(yearStr, 10);
|
|
685
|
+
const week = parseInt(weekStr, 10);
|
|
686
|
+
const jan4 = new Date(year, 0, 4);
|
|
687
|
+
const dayOfWeek = jan4.getDay() || 7;
|
|
688
|
+
const monday = new Date(jan4);
|
|
689
|
+
monday.setDate(jan4.getDate() - dayOfWeek + 1 + (week - 1) * 7);
|
|
690
|
+
return monday;
|
|
691
|
+
}
|
|
692
|
+
function localDateStr(d) {
|
|
693
|
+
const y = d.getFullYear();
|
|
694
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
695
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
696
|
+
return `${y}-${m}-${day}`;
|
|
697
|
+
}
|
|
698
|
+
function utcDateTimeStr(d) {
|
|
699
|
+
return d.toISOString().replace("T", " ").slice(0, 19);
|
|
700
|
+
}
|
|
701
|
+
function getTimeRange(periodKey, period) {
|
|
702
|
+
switch (period) {
|
|
703
|
+
case "hour": {
|
|
704
|
+
const d = /* @__PURE__ */ new Date(`${periodKey.slice(0, 10)}T${periodKey.slice(11)}:00:00`);
|
|
705
|
+
const dEnd = new Date(d.getTime() + 36e5);
|
|
706
|
+
return { start: utcDateTimeStr(d), end: utcDateTimeStr(dEnd) };
|
|
707
|
+
}
|
|
708
|
+
case "day":
|
|
709
|
+
return { start: `${periodKey} 00:00:00`, end: `${periodKey} 23:59:59` };
|
|
710
|
+
case "week": {
|
|
711
|
+
const monday = isoWeekToDate(periodKey);
|
|
712
|
+
const sunday = new Date(monday);
|
|
713
|
+
sunday.setDate(monday.getDate() + 6);
|
|
714
|
+
return {
|
|
715
|
+
start: `${localDateStr(monday)} 00:00:00`,
|
|
716
|
+
end: `${localDateStr(sunday)} 23:59:59`
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
case "month": {
|
|
720
|
+
const [y, m] = periodKey.split("-").map(Number);
|
|
721
|
+
const lastDay = new Date(y, m, 0).getDate();
|
|
722
|
+
return {
|
|
723
|
+
start: `${periodKey}-01 00:00:00`,
|
|
724
|
+
end: `${periodKey}-${String(lastDay).padStart(2, "0")} 23:59:59`
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
async function gatherTurnEvents(mind, session, doneId) {
|
|
730
|
+
const db = await getDb();
|
|
731
|
+
const conditions = [
|
|
732
|
+
eq(mindHistory.mind, mind),
|
|
733
|
+
eq(mindHistory.type, "done"),
|
|
734
|
+
lt(mindHistory.id, doneId)
|
|
735
|
+
];
|
|
736
|
+
if (session) {
|
|
737
|
+
conditions.push(eq(mindHistory.session, session));
|
|
738
|
+
}
|
|
739
|
+
const prevDone = await db.select({ id: mindHistory.id }).from(mindHistory).where(and(...conditions)).orderBy(desc(mindHistory.id)).limit(1);
|
|
740
|
+
const prevDoneId = prevDone.length > 0 ? prevDone[0].id : 0;
|
|
741
|
+
const turnConditions = [
|
|
742
|
+
eq(mindHistory.mind, mind),
|
|
743
|
+
sql`${mindHistory.id} > ${prevDoneId}`,
|
|
744
|
+
sql`${mindHistory.id} <= ${doneId}`
|
|
745
|
+
];
|
|
746
|
+
if (session) {
|
|
747
|
+
turnConditions.push(eq(mindHistory.session, session));
|
|
748
|
+
}
|
|
749
|
+
const events = await db.select({
|
|
750
|
+
id: mindHistory.id,
|
|
751
|
+
type: mindHistory.type,
|
|
752
|
+
channel: mindHistory.channel,
|
|
753
|
+
session: mindHistory.session,
|
|
754
|
+
content: mindHistory.content,
|
|
755
|
+
metadata: mindHistory.metadata,
|
|
756
|
+
created_at: mindHistory.created_at
|
|
757
|
+
}).from(mindHistory).where(and(...turnConditions)).orderBy(mindHistory.id);
|
|
758
|
+
return {
|
|
759
|
+
events,
|
|
760
|
+
fromId: events.length > 0 ? events[0].id : doneId,
|
|
761
|
+
toId: doneId
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
async function gatherTurnEventsByTurnId(turnId) {
|
|
765
|
+
const db = await getDb();
|
|
766
|
+
const events = await db.select({
|
|
767
|
+
id: mindHistory.id,
|
|
768
|
+
type: mindHistory.type,
|
|
769
|
+
channel: mindHistory.channel,
|
|
770
|
+
session: mindHistory.session,
|
|
771
|
+
content: mindHistory.content,
|
|
772
|
+
metadata: mindHistory.metadata,
|
|
773
|
+
created_at: mindHistory.created_at
|
|
774
|
+
}).from(mindHistory).where(eq(mindHistory.turn_id, turnId)).orderBy(mindHistory.id);
|
|
775
|
+
return {
|
|
776
|
+
events,
|
|
777
|
+
fromId: events.length > 0 ? events[0].id : 0,
|
|
778
|
+
toId: events.length > 0 ? events[events.length - 1].id : 0
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
function buildTurnDeterministicSummary(events) {
|
|
782
|
+
const channels = /* @__PURE__ */ new Set();
|
|
783
|
+
const tools = [];
|
|
784
|
+
let hasInbound = false;
|
|
785
|
+
let hasOutbound = false;
|
|
786
|
+
for (const ev of events) {
|
|
787
|
+
if (ev.type === "inbound") {
|
|
788
|
+
hasInbound = true;
|
|
789
|
+
if (ev.channel) channels.add(ev.channel);
|
|
790
|
+
}
|
|
791
|
+
if (ev.type === "outbound" || ev.type === "text") {
|
|
792
|
+
hasOutbound = true;
|
|
793
|
+
}
|
|
794
|
+
if (ev.type === "tool_use" && ev.metadata) {
|
|
795
|
+
try {
|
|
796
|
+
const meta = JSON.parse(ev.metadata);
|
|
797
|
+
if (meta.name) tools.push(meta.name);
|
|
798
|
+
} catch (err) {
|
|
799
|
+
sLog.debug(`failed to parse tool_use metadata for event ${ev.id}`, logger_default.errorData(err));
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const parts = [];
|
|
804
|
+
if (hasInbound) {
|
|
805
|
+
const channelList = [...channels];
|
|
806
|
+
parts.push(
|
|
807
|
+
channelList.length > 0 ? `Received message on ${channelList.join(", ")}` : "Received message"
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
if (tools.length > 0) {
|
|
811
|
+
const unique = [...new Set(tools)];
|
|
812
|
+
parts.push(`Used ${unique.join(", ")}`);
|
|
813
|
+
}
|
|
814
|
+
if (hasOutbound) {
|
|
815
|
+
parts.push("Sent response");
|
|
816
|
+
}
|
|
817
|
+
return parts.length > 0 ? `${parts.join(". ")}.` : "Turn completed.";
|
|
818
|
+
}
|
|
819
|
+
function buildTranscript(events) {
|
|
820
|
+
const lines = [];
|
|
821
|
+
for (const ev of events) {
|
|
822
|
+
switch (ev.type) {
|
|
823
|
+
case "inbound":
|
|
824
|
+
lines.push(`[inbound${ev.channel ? ` ${ev.channel}` : ""}] ${ev.content ?? ""}`);
|
|
825
|
+
break;
|
|
826
|
+
case "outbound":
|
|
827
|
+
case "text":
|
|
828
|
+
lines.push(`[response] ${(ev.content ?? "").slice(0, 500)}`);
|
|
829
|
+
break;
|
|
830
|
+
case "tool_use": {
|
|
831
|
+
let toolInfo = "tool";
|
|
832
|
+
if (ev.metadata) {
|
|
833
|
+
try {
|
|
834
|
+
const meta = JSON.parse(ev.metadata);
|
|
835
|
+
toolInfo = summarizeTool(meta.name ?? "tool", meta.input ?? {});
|
|
836
|
+
} catch (err) {
|
|
837
|
+
sLog.debug(`failed to parse tool_use metadata for event ${ev.id}`, logger_default.errorData(err));
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
lines.push(toolInfo);
|
|
841
|
+
break;
|
|
842
|
+
}
|
|
843
|
+
case "tool_result": {
|
|
844
|
+
const content = ev.content ?? "";
|
|
845
|
+
let isError = false;
|
|
846
|
+
if (ev.metadata) {
|
|
847
|
+
try {
|
|
848
|
+
const meta = JSON.parse(ev.metadata);
|
|
849
|
+
isError = !!meta.is_error;
|
|
850
|
+
} catch (err) {
|
|
851
|
+
sLog.debug(
|
|
852
|
+
`failed to parse tool_result metadata for event ${ev.id}`,
|
|
853
|
+
logger_default.errorData(err)
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
lines.push(isError ? "[result error]" : `[result] ${content.slice(0, 200)}`);
|
|
858
|
+
break;
|
|
859
|
+
}
|
|
860
|
+
case "thinking":
|
|
861
|
+
lines.push(`[thinking] ${(ev.content ?? "").slice(0, 300)}`);
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
return lines.join("\n");
|
|
866
|
+
}
|
|
867
|
+
async function summarizeTurn(mind, session, channel, doneId, turnId) {
|
|
868
|
+
const { events, fromId, toId } = turnId ? await gatherTurnEventsByTurnId(turnId) : await gatherTurnEvents(mind, session, doneId);
|
|
869
|
+
if (events.length === 0) return;
|
|
870
|
+
const substantiveTypes = /* @__PURE__ */ new Set(["text", "outbound", "tool_use", "tool_result", "thinking"]);
|
|
871
|
+
const hasSubstantiveOutput = events.some((ev) => substantiveTypes.has(ev.type));
|
|
872
|
+
if (!hasSubstantiveOutput) {
|
|
873
|
+
sLog.info(
|
|
874
|
+
`skipping summary for interrupted turn ${turnId ?? "(no turn)"} (no substantive output)`
|
|
875
|
+
);
|
|
876
|
+
if (turnId) {
|
|
877
|
+
try {
|
|
878
|
+
const db2 = await getDb();
|
|
879
|
+
await db2.update(mindHistory).set({ turn_id: null }).where(and(eq(mindHistory.turn_id, turnId), eq(mindHistory.type, "inbound")));
|
|
880
|
+
await db2.update(messages).set({ turn_id: null }).where(eq(messages.turn_id, turnId));
|
|
881
|
+
} catch (err) {
|
|
882
|
+
sLog.error(`failed to un-tag events for interrupted turn ${turnId}`, logger_default.errorData(err));
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const tools = [];
|
|
888
|
+
for (const ev of events) {
|
|
889
|
+
if (ev.type === "tool_use" && ev.metadata) {
|
|
890
|
+
try {
|
|
891
|
+
const meta = JSON.parse(ev.metadata);
|
|
892
|
+
if (meta.name) tools.push(meta.name);
|
|
893
|
+
} catch (err) {
|
|
894
|
+
sLog.debug(`failed to parse tool_use metadata for event ${ev.id}`, logger_default.errorData(err));
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
const fromTime = events[0].created_at;
|
|
899
|
+
const toTime = events[events.length - 1].created_at;
|
|
900
|
+
let summaryText;
|
|
901
|
+
let deterministic;
|
|
902
|
+
const transcript = buildTranscript(events);
|
|
903
|
+
if (transcript.trim()) {
|
|
904
|
+
const summaryPrompt = await getPrompt("turn_summary");
|
|
905
|
+
const aiResult = await aiCompleteUtility(summaryPrompt, transcript);
|
|
906
|
+
if (aiResult) {
|
|
907
|
+
summaryText = aiResult;
|
|
908
|
+
deterministic = false;
|
|
909
|
+
} else {
|
|
910
|
+
summaryText = buildTurnDeterministicSummary(events);
|
|
911
|
+
deterministic = true;
|
|
912
|
+
}
|
|
913
|
+
} else {
|
|
914
|
+
summaryText = buildTurnDeterministicSummary(events);
|
|
915
|
+
deterministic = true;
|
|
916
|
+
}
|
|
917
|
+
const metadata = {
|
|
918
|
+
deterministic,
|
|
919
|
+
tool_count: tools.length,
|
|
920
|
+
tools: [...new Set(tools)],
|
|
921
|
+
from_id: fromId,
|
|
922
|
+
to_id: toId,
|
|
923
|
+
from_time: fromTime,
|
|
924
|
+
to_time: toTime
|
|
925
|
+
};
|
|
926
|
+
const periodKey = turnId ?? `${mind}-${doneId}`;
|
|
927
|
+
const db = await getDb();
|
|
928
|
+
let summaryId;
|
|
929
|
+
try {
|
|
930
|
+
const result = await db.insert(summaries).values({
|
|
931
|
+
mind,
|
|
932
|
+
period: "turn",
|
|
933
|
+
period_key: periodKey,
|
|
934
|
+
content: summaryText,
|
|
935
|
+
metadata: JSON.stringify(metadata)
|
|
936
|
+
}).onConflictDoNothing().returning({ id: summaries.id });
|
|
937
|
+
summaryId = result[0]?.id;
|
|
938
|
+
if (summaryId == null) {
|
|
939
|
+
const existing = await db.select({ id: summaries.id }).from(summaries).where(
|
|
940
|
+
and(
|
|
941
|
+
eq(summaries.mind, mind),
|
|
942
|
+
eq(summaries.period, "turn"),
|
|
943
|
+
eq(summaries.period_key, periodKey)
|
|
944
|
+
)
|
|
945
|
+
).get();
|
|
946
|
+
summaryId = existing?.id;
|
|
947
|
+
}
|
|
948
|
+
} catch (err) {
|
|
949
|
+
sLog.error(
|
|
950
|
+
`failed to persist turn summary for ${mind} (events ${fromId}-${toId})`,
|
|
951
|
+
logger_default.errorData(err)
|
|
952
|
+
);
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
if (turnId && summaryId != null) {
|
|
956
|
+
setSummaryId(turnId, summaryId).catch((err) => {
|
|
957
|
+
sLog.error(`failed to link summary to turn ${turnId}`, logger_default.errorData(err));
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
publish2(mind, {
|
|
961
|
+
mind,
|
|
962
|
+
type: "summary",
|
|
963
|
+
session,
|
|
964
|
+
channel,
|
|
965
|
+
content: summaryText,
|
|
966
|
+
metadata,
|
|
967
|
+
turnId
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
async function setSummaryId(turnId, summaryId) {
|
|
971
|
+
const db = await getDb();
|
|
972
|
+
await db.update(turns).set({ summary_id: summaryId }).where(eq(turns.id, turnId));
|
|
973
|
+
}
|
|
974
|
+
function getChildPeriod(period) {
|
|
975
|
+
switch (period) {
|
|
976
|
+
case "hour":
|
|
977
|
+
return "turn";
|
|
978
|
+
case "day":
|
|
979
|
+
return "hour";
|
|
980
|
+
case "week":
|
|
981
|
+
case "month":
|
|
982
|
+
return "day";
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
function getScopeInstruction(mind) {
|
|
986
|
+
if (mind === SYSTEM_MIND) {
|
|
987
|
+
return 'Write in third person, describing what the minds in the system did (e.g. "Alice explored...", "The system saw activity in..."). Reference minds by name.';
|
|
988
|
+
}
|
|
989
|
+
return 'Write in first person as the mind who performed the actions (e.g. "I explored...", "I worked on...").';
|
|
990
|
+
}
|
|
991
|
+
function buildPeriodicDeterministicSummary(sources, period, periodKey) {
|
|
992
|
+
if (sources.length === 0) return "";
|
|
993
|
+
switch (period) {
|
|
994
|
+
case "hour":
|
|
995
|
+
return `Activity during ${periodKey.slice(11)}:00: ${sources.join(" ")}`;
|
|
996
|
+
case "day":
|
|
997
|
+
return `Activity on ${periodKey}:
|
|
998
|
+
|
|
999
|
+
${sources.join("\n\n")}`;
|
|
1000
|
+
case "week":
|
|
1001
|
+
return `Week ${periodKey} summary:
|
|
1002
|
+
|
|
1003
|
+
${sources.join("\n\n")}`;
|
|
1004
|
+
case "month":
|
|
1005
|
+
return `${periodKey} summary:
|
|
1006
|
+
|
|
1007
|
+
${sources.join("\n\n")}`;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
async function gatherChildSummaries(mind, period, periodKey) {
|
|
1011
|
+
const db = await getDb();
|
|
1012
|
+
const childPeriod = getChildPeriod(period);
|
|
1013
|
+
if (period === "hour") {
|
|
1014
|
+
const { start: start2, end: end2 } = getTimeRange(periodKey, "hour");
|
|
1015
|
+
const rows2 = await db.select({ id: summaries.id, content: summaries.content }).from(summaries).where(
|
|
1016
|
+
and(
|
|
1017
|
+
eq(summaries.mind, mind),
|
|
1018
|
+
eq(summaries.period, childPeriod),
|
|
1019
|
+
gte(summaries.created_at, start2),
|
|
1020
|
+
lt(summaries.created_at, end2)
|
|
1021
|
+
)
|
|
1022
|
+
).orderBy(summaries.created_at);
|
|
1023
|
+
return {
|
|
1024
|
+
texts: rows2.map((r) => r.content),
|
|
1025
|
+
sourceIds: rows2.map((r) => r.id)
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
if (period === "day") {
|
|
1029
|
+
const rows2 = await db.select({ id: summaries.id, content: summaries.content }).from(summaries).where(
|
|
1030
|
+
and(
|
|
1031
|
+
eq(summaries.mind, mind),
|
|
1032
|
+
eq(summaries.period, childPeriod),
|
|
1033
|
+
like(summaries.period_key, `${periodKey}%`)
|
|
1034
|
+
)
|
|
1035
|
+
).orderBy(summaries.period_key);
|
|
1036
|
+
return {
|
|
1037
|
+
texts: rows2.map((r) => r.content),
|
|
1038
|
+
sourceIds: rows2.map((r) => r.id)
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
const { start, end } = getTimeRange(periodKey, period);
|
|
1042
|
+
const startKey = start.slice(0, 10);
|
|
1043
|
+
const endKey = end.slice(0, 10);
|
|
1044
|
+
const rows = await db.select({ id: summaries.id, content: summaries.content }).from(summaries).where(
|
|
1045
|
+
and(
|
|
1046
|
+
eq(summaries.mind, mind),
|
|
1047
|
+
eq(summaries.period, childPeriod),
|
|
1048
|
+
gte(summaries.period_key, startKey),
|
|
1049
|
+
sql`${summaries.period_key} <= ${endKey}`
|
|
1050
|
+
)
|
|
1051
|
+
).orderBy(summaries.period_key);
|
|
1052
|
+
return {
|
|
1053
|
+
texts: rows.map((r) => r.content),
|
|
1054
|
+
sourceIds: rows.map((r) => r.id)
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
async function summarizePeriod(mind, period, periodKey) {
|
|
1058
|
+
if (await summaryExists(mind, period, periodKey)) return false;
|
|
1059
|
+
const db = await getDb();
|
|
1060
|
+
const sources = await gatherChildSummaries(mind, period, periodKey);
|
|
1061
|
+
if (sources.texts.length === 0) return false;
|
|
1062
|
+
if (sources.texts.length === 1) {
|
|
1063
|
+
try {
|
|
1064
|
+
await db.insert(summaries).values({
|
|
1065
|
+
mind,
|
|
1066
|
+
period,
|
|
1067
|
+
period_key: periodKey,
|
|
1068
|
+
content: sources.texts[0],
|
|
1069
|
+
metadata: JSON.stringify({
|
|
1070
|
+
deterministic: false,
|
|
1071
|
+
promoted: true,
|
|
1072
|
+
source_count: 1,
|
|
1073
|
+
source_ids: sources.sourceIds
|
|
1074
|
+
})
|
|
1075
|
+
}).onConflictDoNothing();
|
|
1076
|
+
} catch (err) {
|
|
1077
|
+
sLog.error(
|
|
1078
|
+
`failed to persist promoted ${period} summary for ${mind} (${periodKey})`,
|
|
1079
|
+
logger_default.errorData(err)
|
|
474
1080
|
);
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
});
|
|
480
|
-
}, delay);
|
|
481
|
-
});
|
|
482
|
-
blog.info(`started bridge ${platform}`);
|
|
1081
|
+
return false;
|
|
1082
|
+
}
|
|
1083
|
+
sLog.info(`promoted single-child ${period} summary for ${mind} (${periodKey})`);
|
|
1084
|
+
return true;
|
|
483
1085
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
1086
|
+
const promptKey = `meta_summary_${period}`;
|
|
1087
|
+
const scopeInstruction = getScopeInstruction(mind);
|
|
1088
|
+
const systemPrompt = await getPrompt(promptKey, { scope_instruction: scopeInstruction });
|
|
1089
|
+
const userMessage = sources.texts.join("\n\n---\n\n");
|
|
1090
|
+
let content;
|
|
1091
|
+
let deterministic;
|
|
1092
|
+
const aiResult = await aiCompleteUtility(systemPrompt, userMessage);
|
|
1093
|
+
if (aiResult) {
|
|
1094
|
+
content = aiResult;
|
|
1095
|
+
deterministic = false;
|
|
1096
|
+
} else {
|
|
1097
|
+
content = buildPeriodicDeterministicSummary(sources.texts, period, periodKey);
|
|
1098
|
+
deterministic = true;
|
|
1099
|
+
}
|
|
1100
|
+
const metadata = {
|
|
1101
|
+
deterministic,
|
|
1102
|
+
source_count: sources.texts.length,
|
|
1103
|
+
source_ids: sources.sourceIds
|
|
1104
|
+
};
|
|
1105
|
+
try {
|
|
1106
|
+
await db.insert(summaries).values({
|
|
1107
|
+
mind,
|
|
1108
|
+
period,
|
|
1109
|
+
period_key: periodKey,
|
|
1110
|
+
content,
|
|
1111
|
+
metadata: JSON.stringify(metadata)
|
|
1112
|
+
}).onConflictDoNothing();
|
|
1113
|
+
} catch (err) {
|
|
1114
|
+
sLog.error(
|
|
1115
|
+
`failed to persist ${period} summary for ${mind} (${periodKey})`,
|
|
1116
|
+
logger_default.errorData(err)
|
|
1117
|
+
);
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
sLog.info(
|
|
1121
|
+
`generated ${period} summary for ${mind} (${periodKey})${deterministic ? " [deterministic]" : ""}`
|
|
1122
|
+
);
|
|
1123
|
+
return true;
|
|
1124
|
+
}
|
|
1125
|
+
async function summarizeSystem(period, periodKey) {
|
|
1126
|
+
if (await summaryExists(SYSTEM_MIND, period, periodKey)) return;
|
|
1127
|
+
const db = await getDb();
|
|
1128
|
+
const rows = await db.select({ mind: summaries.mind, content: summaries.content }).from(summaries).where(
|
|
1129
|
+
and(
|
|
1130
|
+
eq(summaries.period, period),
|
|
1131
|
+
eq(summaries.period_key, periodKey),
|
|
1132
|
+
sql`${summaries.mind} != ${SYSTEM_MIND}`
|
|
1133
|
+
)
|
|
1134
|
+
).orderBy(summaries.mind);
|
|
1135
|
+
if (rows.length === 0) return;
|
|
1136
|
+
const minds = [...new Set(rows.map((r) => r.mind))];
|
|
1137
|
+
const texts = rows.map((r) => `[${r.mind}] ${r.content}`);
|
|
1138
|
+
const promptKey = `meta_summary_${period}`;
|
|
1139
|
+
const scopeInstruction = getScopeInstruction(SYSTEM_MIND);
|
|
1140
|
+
const systemPrompt = await getPrompt(promptKey, { scope_instruction: scopeInstruction });
|
|
1141
|
+
const userMessage = texts.join("\n\n---\n\n");
|
|
1142
|
+
let content;
|
|
1143
|
+
let deterministic;
|
|
1144
|
+
const aiResult = await aiCompleteUtility(systemPrompt, userMessage);
|
|
1145
|
+
if (aiResult) {
|
|
1146
|
+
content = aiResult;
|
|
1147
|
+
deterministic = false;
|
|
1148
|
+
} else {
|
|
1149
|
+
content = buildPeriodicDeterministicSummary(texts, period, periodKey);
|
|
1150
|
+
deterministic = true;
|
|
1151
|
+
}
|
|
1152
|
+
try {
|
|
1153
|
+
await db.insert(summaries).values({
|
|
1154
|
+
mind: SYSTEM_MIND,
|
|
1155
|
+
period,
|
|
1156
|
+
period_key: periodKey,
|
|
1157
|
+
content,
|
|
1158
|
+
metadata: JSON.stringify({ deterministic, minds, source_count: rows.length })
|
|
1159
|
+
}).onConflictDoNothing();
|
|
1160
|
+
} catch (err) {
|
|
1161
|
+
sLog.error(`failed to persist system ${period} summary (${periodKey})`, logger_default.errorData(err));
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
async function mindsWithTurnSummaries(start, end) {
|
|
1165
|
+
const db = await getDb();
|
|
1166
|
+
const rows = await db.select({ mind: summaries.mind }).from(summaries).where(
|
|
1167
|
+
and(
|
|
1168
|
+
eq(summaries.period, "turn"),
|
|
1169
|
+
gte(summaries.created_at, start),
|
|
1170
|
+
lt(summaries.created_at, end),
|
|
1171
|
+
sql`${summaries.mind} != ${SYSTEM_MIND}`
|
|
1172
|
+
)
|
|
1173
|
+
).groupBy(summaries.mind);
|
|
1174
|
+
return rows.map((r) => r.mind);
|
|
1175
|
+
}
|
|
1176
|
+
async function mindsWithSummaries(period, keyPattern) {
|
|
1177
|
+
const db = await getDb();
|
|
1178
|
+
const rows = await db.select({ mind: summaries.mind }).from(summaries).where(
|
|
1179
|
+
and(
|
|
1180
|
+
eq(summaries.period, period),
|
|
1181
|
+
like(summaries.period_key, keyPattern),
|
|
1182
|
+
sql`${summaries.mind} != ${SYSTEM_MIND}`
|
|
1183
|
+
)
|
|
1184
|
+
).groupBy(summaries.mind);
|
|
1185
|
+
return rows.map((r) => r.mind);
|
|
1186
|
+
}
|
|
1187
|
+
async function mindsWithDailySummariesInRange(startKey, endKey) {
|
|
1188
|
+
const db = await getDb();
|
|
1189
|
+
const rows = await db.select({ mind: summaries.mind }).from(summaries).where(
|
|
1190
|
+
and(
|
|
1191
|
+
eq(summaries.period, "day"),
|
|
1192
|
+
gte(summaries.period_key, startKey),
|
|
1193
|
+
sql`${summaries.period_key} <= ${endKey}`,
|
|
1194
|
+
sql`${summaries.mind} != ${SYSTEM_MIND}`
|
|
1195
|
+
)
|
|
1196
|
+
).groupBy(summaries.mind);
|
|
1197
|
+
return rows.map((r) => r.mind);
|
|
1198
|
+
}
|
|
1199
|
+
async function processHour(periodKey) {
|
|
1200
|
+
const { start, end } = getTimeRange(periodKey, "hour");
|
|
1201
|
+
const minds = await mindsWithTurnSummaries(start, end);
|
|
1202
|
+
for (const mind of minds) {
|
|
517
1203
|
try {
|
|
518
|
-
|
|
1204
|
+
await summarizePeriod(mind, "hour", periodKey);
|
|
519
1205
|
} catch (err) {
|
|
520
|
-
|
|
1206
|
+
sLog.error(`failed to summarize hour for ${mind} (${periodKey})`, logger_default.errorData(err));
|
|
521
1207
|
}
|
|
522
|
-
blog.info(`stopped bridge ${platform}`);
|
|
523
1208
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const platforms = [...this.bridges.keys()];
|
|
527
|
-
await Promise.all(platforms.map((p) => this.stopBridge(p)));
|
|
1209
|
+
if (minds.length > 0) {
|
|
1210
|
+
await summarizeSystem("hour", periodKey);
|
|
528
1211
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
1212
|
+
}
|
|
1213
|
+
async function processDay(periodKey) {
|
|
1214
|
+
const minds = await mindsWithSummaries("hour", `${periodKey}%`);
|
|
1215
|
+
for (const mind of minds) {
|
|
1216
|
+
try {
|
|
1217
|
+
await summarizePeriod(mind, "day", periodKey);
|
|
1218
|
+
} catch (err) {
|
|
1219
|
+
sLog.error(`failed to summarize day for ${mind} (${periodKey})`, logger_default.errorData(err));
|
|
1220
|
+
}
|
|
534
1221
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
return tracked != null && !tracked.child.killed;
|
|
1222
|
+
if (minds.length > 0) {
|
|
1223
|
+
await summarizeSystem("day", periodKey);
|
|
538
1224
|
}
|
|
539
|
-
|
|
540
|
-
|
|
1225
|
+
}
|
|
1226
|
+
async function processWeek(periodKey) {
|
|
1227
|
+
const { start, end } = getTimeRange(periodKey, "week");
|
|
1228
|
+
const startKey = start.slice(0, 10);
|
|
1229
|
+
const endKey = end.slice(0, 10);
|
|
1230
|
+
const minds = await mindsWithDailySummariesInRange(startKey, endKey);
|
|
1231
|
+
for (const mind of minds) {
|
|
1232
|
+
try {
|
|
1233
|
+
await summarizePeriod(mind, "week", periodKey);
|
|
1234
|
+
} catch (err) {
|
|
1235
|
+
sLog.error(`failed to summarize week for ${mind} (${periodKey})`, logger_default.errorData(err));
|
|
1236
|
+
}
|
|
541
1237
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
mkdirSync(dirname(pidPath), { recursive: true });
|
|
545
|
-
writeFileSync(pidPath, String(pid));
|
|
1238
|
+
if (minds.length > 0) {
|
|
1239
|
+
await summarizeSystem("week", periodKey);
|
|
546
1240
|
}
|
|
547
|
-
|
|
1241
|
+
}
|
|
1242
|
+
async function processMonth(periodKey) {
|
|
1243
|
+
const minds = await mindsWithSummaries("day", `${periodKey}%`);
|
|
1244
|
+
for (const mind of minds) {
|
|
548
1245
|
try {
|
|
549
|
-
|
|
1246
|
+
await summarizePeriod(mind, "month", periodKey);
|
|
550
1247
|
} catch (err) {
|
|
551
|
-
|
|
552
|
-
blog.warn(`failed to remove PID file for bridge ${platform}`, logger_default.errorData(err));
|
|
553
|
-
}
|
|
1248
|
+
sLog.error(`failed to summarize month for ${mind} (${periodKey})`, logger_default.errorData(err));
|
|
554
1249
|
}
|
|
555
1250
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
1251
|
+
if (minds.length > 0) {
|
|
1252
|
+
await summarizeSystem("month", periodKey);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
async function summaryExists(mind, period, periodKey) {
|
|
1256
|
+
const db = await getDb();
|
|
1257
|
+
const row = await db.select({ id: summaries.id }).from(summaries).where(
|
|
1258
|
+
and(
|
|
1259
|
+
eq(summaries.mind, mind),
|
|
1260
|
+
eq(summaries.period, period),
|
|
1261
|
+
eq(summaries.period_key, periodKey)
|
|
1262
|
+
)
|
|
1263
|
+
).get();
|
|
1264
|
+
return !!row;
|
|
1265
|
+
}
|
|
1266
|
+
async function backfill() {
|
|
1267
|
+
const now = /* @__PURE__ */ new Date();
|
|
1268
|
+
for (let i = 1; i <= 48; i++) {
|
|
559
1269
|
try {
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
try {
|
|
566
|
-
process.kill(pid, "SIGTERM");
|
|
567
|
-
} catch {
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
blog.warn(`killed orphan bridge ${platform} (pid ${pid})`);
|
|
1270
|
+
const d = new Date(now);
|
|
1271
|
+
d.setHours(d.getHours() - i);
|
|
1272
|
+
const key = getPeriodKey(d, "hour");
|
|
1273
|
+
if (!await summaryExists(SYSTEM_MIND, "hour", key)) {
|
|
1274
|
+
await processHour(key);
|
|
571
1275
|
}
|
|
572
1276
|
} catch (err) {
|
|
573
|
-
|
|
574
|
-
|
|
1277
|
+
sLog.error(`backfill failed for hour -${i}`, logger_default.errorData(err));
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
for (let i = 1; i <= 7; i++) {
|
|
1281
|
+
try {
|
|
1282
|
+
const d = new Date(now);
|
|
1283
|
+
d.setDate(d.getDate() - i);
|
|
1284
|
+
const key = getPeriodKey(d, "day");
|
|
1285
|
+
if (!await summaryExists(SYSTEM_MIND, "day", key)) {
|
|
1286
|
+
await processDay(key);
|
|
575
1287
|
}
|
|
1288
|
+
} catch (err) {
|
|
1289
|
+
sLog.error(`backfill failed for day -${i}`, logger_default.errorData(err));
|
|
576
1290
|
}
|
|
1291
|
+
}
|
|
1292
|
+
for (let i = 1; i <= 4; i++) {
|
|
577
1293
|
try {
|
|
578
|
-
|
|
1294
|
+
const d = new Date(now);
|
|
1295
|
+
d.setDate(d.getDate() - i * 7);
|
|
1296
|
+
const key = getPeriodKey(d, "week");
|
|
1297
|
+
if (!await summaryExists(SYSTEM_MIND, "week", key)) {
|
|
1298
|
+
await processWeek(key);
|
|
1299
|
+
}
|
|
579
1300
|
} catch (err) {
|
|
580
|
-
|
|
581
|
-
|
|
1301
|
+
sLog.error(`backfill failed for week -${i}`, logger_default.errorData(err));
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
for (let i = 1; i <= 3; i++) {
|
|
1305
|
+
try {
|
|
1306
|
+
const d = new Date(now);
|
|
1307
|
+
d.setMonth(d.getMonth() - i);
|
|
1308
|
+
const key = getPeriodKey(d, "month");
|
|
1309
|
+
if (!await summaryExists(SYSTEM_MIND, "month", key)) {
|
|
1310
|
+
await processMonth(key);
|
|
582
1311
|
}
|
|
1312
|
+
} catch (err) {
|
|
1313
|
+
sLog.error(`backfill failed for month -${i}`, logger_default.errorData(err));
|
|
583
1314
|
}
|
|
584
1315
|
}
|
|
585
|
-
|
|
586
|
-
|
|
1316
|
+
}
|
|
1317
|
+
var Summarizer = class {
|
|
1318
|
+
interval = null;
|
|
1319
|
+
lastHourKey = null;
|
|
1320
|
+
hasBackfilled = false;
|
|
1321
|
+
start() {
|
|
1322
|
+
this.interval = setInterval(() => this.tick(), 5 * 6e4);
|
|
1323
|
+
this.tick();
|
|
1324
|
+
}
|
|
1325
|
+
stop() {
|
|
1326
|
+
if (this.interval) {
|
|
1327
|
+
clearInterval(this.interval);
|
|
1328
|
+
this.interval = null;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
async tick() {
|
|
1332
|
+
try {
|
|
1333
|
+
if (!this.hasBackfilled) {
|
|
1334
|
+
await backfill();
|
|
1335
|
+
this.hasBackfilled = true;
|
|
1336
|
+
}
|
|
1337
|
+
const now = /* @__PURE__ */ new Date();
|
|
1338
|
+
const currentHourKey = getPeriodKey(now, "hour");
|
|
1339
|
+
if (this.lastHourKey && this.lastHourKey !== currentHourKey) {
|
|
1340
|
+
await processHour(this.lastHourKey);
|
|
1341
|
+
}
|
|
1342
|
+
this.lastHourKey = currentHourKey;
|
|
1343
|
+
const yesterday = new Date(now);
|
|
1344
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
1345
|
+
const yesterdayKey = getPeriodKey(yesterday, "day");
|
|
1346
|
+
if (!await summaryExists(SYSTEM_MIND, "day", yesterdayKey)) {
|
|
1347
|
+
await processDay(yesterdayKey);
|
|
1348
|
+
}
|
|
1349
|
+
const currentWeekKey = getPeriodKey(now, "week");
|
|
1350
|
+
const prevWeekKey = getPreviousPeriodKey(currentWeekKey, "week");
|
|
1351
|
+
if (!await summaryExists(SYSTEM_MIND, "week", prevWeekKey)) {
|
|
1352
|
+
await processWeek(prevWeekKey);
|
|
1353
|
+
}
|
|
1354
|
+
const currentMonthKey = getPeriodKey(now, "month");
|
|
1355
|
+
const prevMonthKey = getPreviousPeriodKey(currentMonthKey, "month");
|
|
1356
|
+
if (!await summaryExists(SYSTEM_MIND, "month", prevMonthKey)) {
|
|
1357
|
+
await processMonth(prevMonthKey);
|
|
1358
|
+
}
|
|
1359
|
+
} catch (err) {
|
|
1360
|
+
sLog.error("tick failed", logger_default.errorData(err));
|
|
1361
|
+
}
|
|
587
1362
|
}
|
|
588
1363
|
};
|
|
589
|
-
var
|
|
590
|
-
function
|
|
591
|
-
if (
|
|
592
|
-
|
|
593
|
-
return
|
|
594
|
-
}
|
|
595
|
-
function getBridgeManager() {
|
|
596
|
-
if (!instance) throw new Error("BridgeManager not initialized \u2014 call initBridgeManager() first");
|
|
597
|
-
return instance;
|
|
1364
|
+
var instance2 = null;
|
|
1365
|
+
function initSummarizer() {
|
|
1366
|
+
if (instance2) throw new Error("Summarizer already initialized");
|
|
1367
|
+
instance2 = new Summarizer();
|
|
1368
|
+
return instance2;
|
|
598
1369
|
}
|
|
599
1370
|
|
|
600
1371
|
// src/lib/history-cleanup.ts
|
|
601
|
-
import { and, eq, lt } from "drizzle-orm";
|
|
1372
|
+
import { and as and2, eq as eq2, lt as lt2 } from "drizzle-orm";
|
|
602
1373
|
var LOG_RETENTION_MS = 24 * 60 * 60 * 1e3;
|
|
603
1374
|
async function cleanExpiredLogs() {
|
|
604
1375
|
const db = await getDb();
|
|
605
1376
|
const cutoff = new Date(Date.now() - LOG_RETENTION_MS).toISOString().replace("T", " ").slice(0, 19);
|
|
606
|
-
await db.delete(mindHistory).where(
|
|
1377
|
+
await db.delete(mindHistory).where(and2(eq2(mindHistory.type, "log"), lt2(mindHistory.created_at, cutoff)));
|
|
607
1378
|
}
|
|
608
1379
|
|
|
609
1380
|
// src/lib/shared.ts
|
|
@@ -977,7 +1748,7 @@ async function generateImage(model, prompt) {
|
|
|
977
1748
|
|
|
978
1749
|
// src/web/middleware/auth.ts
|
|
979
1750
|
import { timingSafeEqual } from "crypto";
|
|
980
|
-
import { eq as
|
|
1751
|
+
import { eq as eq3, lt as lt3 } from "drizzle-orm";
|
|
981
1752
|
import { getCookie } from "hono/cookie";
|
|
982
1753
|
import { createMiddleware } from "hono/factory";
|
|
983
1754
|
function isValidDaemonToken(token) {
|
|
@@ -1000,14 +1771,14 @@ async function createSession(userId) {
|
|
|
1000
1771
|
async function deleteSession(sessionId) {
|
|
1001
1772
|
sessionCache.delete(sessionId);
|
|
1002
1773
|
const db = await getDb();
|
|
1003
|
-
await db.delete(sessions).where(
|
|
1774
|
+
await db.delete(sessions).where(eq3(sessions.id, sessionId));
|
|
1004
1775
|
}
|
|
1005
1776
|
async function getSessionUserId(sessionId) {
|
|
1006
1777
|
const db = await getDb();
|
|
1007
|
-
const row = await db.select().from(sessions).where(
|
|
1778
|
+
const row = await db.select().from(sessions).where(eq3(sessions.id, sessionId)).get();
|
|
1008
1779
|
if (!row) return void 0;
|
|
1009
1780
|
if (Date.now() - row.createdAt > SESSION_MAX_AGE) {
|
|
1010
|
-
await db.delete(sessions).where(
|
|
1781
|
+
await db.delete(sessions).where(eq3(sessions.id, sessionId));
|
|
1011
1782
|
return void 0;
|
|
1012
1783
|
}
|
|
1013
1784
|
return row.userId;
|
|
@@ -1015,7 +1786,7 @@ async function getSessionUserId(sessionId) {
|
|
|
1015
1786
|
async function cleanExpiredSessions() {
|
|
1016
1787
|
const db = await getDb();
|
|
1017
1788
|
const cutoff = Date.now() - SESSION_MAX_AGE;
|
|
1018
|
-
await db.delete(sessions).where(
|
|
1789
|
+
await db.delete(sessions).where(lt3(sessions.createdAt, cutoff));
|
|
1019
1790
|
}
|
|
1020
1791
|
var requireAdmin = createMiddleware(async (c, next) => {
|
|
1021
1792
|
const user = c.get("user");
|
|
@@ -1136,7 +1907,14 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1136
1907
|
});
|
|
1137
1908
|
}).get("/info", (c) => {
|
|
1138
1909
|
const config2 = readSystemsConfig();
|
|
1139
|
-
|
|
1910
|
+
const globalConfig = readGlobalConfig();
|
|
1911
|
+
return c.json({ system: config2?.system ?? null, name: globalConfig.name ?? null });
|
|
1912
|
+
}).put("/info", requireAdmin, zValidator("json", z.object({ name: z.string() })), (c) => {
|
|
1913
|
+
const { name } = c.req.valid("json");
|
|
1914
|
+
const config2 = readGlobalConfig();
|
|
1915
|
+
config2.name = name.trim() || void 0;
|
|
1916
|
+
writeGlobalConfig(config2);
|
|
1917
|
+
return c.json({ name: config2.name ?? null });
|
|
1140
1918
|
}).post(
|
|
1141
1919
|
"/register",
|
|
1142
1920
|
requireAdmin,
|
|
@@ -1382,15 +2160,17 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1382
2160
|
zValidator(
|
|
1383
2161
|
"json",
|
|
1384
2162
|
z.object({
|
|
1385
|
-
spiritModel: z.string().nullable(),
|
|
2163
|
+
spiritModel: z.string().nullable().optional(),
|
|
1386
2164
|
utilityModel: z.string().nullable()
|
|
1387
2165
|
})
|
|
1388
2166
|
),
|
|
1389
2167
|
(c) => {
|
|
1390
2168
|
const { spiritModel, utilityModel } = c.req.valid("json");
|
|
1391
2169
|
const config2 = readGlobalConfig();
|
|
1392
|
-
|
|
1393
|
-
|
|
2170
|
+
if (spiritModel !== void 0) {
|
|
2171
|
+
config2.spiritModel = spiritModel ?? void 0;
|
|
2172
|
+
writeGlobalConfig(config2);
|
|
2173
|
+
}
|
|
1394
2174
|
setUtilityModel(utilityModel ?? void 0);
|
|
1395
2175
|
return c.json({ ok: true });
|
|
1396
2176
|
}
|
|
@@ -1505,7 +2285,54 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1505
2285
|
setTimeout(() => oauthFlows.delete(flowId), 3e4);
|
|
1506
2286
|
}
|
|
1507
2287
|
return c.json(result);
|
|
1508
|
-
})
|
|
2288
|
+
}).get("/mind-defaults", requireAdmin, (c) => {
|
|
2289
|
+
const config2 = readGlobalConfig();
|
|
2290
|
+
return c.json(config2.mindDefaults ?? {});
|
|
2291
|
+
}).put(
|
|
2292
|
+
"/mind-defaults",
|
|
2293
|
+
requireAdmin,
|
|
2294
|
+
zValidator(
|
|
2295
|
+
"json",
|
|
2296
|
+
z.object({
|
|
2297
|
+
cognition: z.object({
|
|
2298
|
+
model: z.string().optional(),
|
|
2299
|
+
thinkingLevel: z.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional(),
|
|
2300
|
+
maxThinkingTokens: z.number().nonnegative().optional(),
|
|
2301
|
+
tokenBudget: z.number().nonnegative().optional(),
|
|
2302
|
+
tokenBudgetPeriodMinutes: z.number().positive().optional(),
|
|
2303
|
+
compaction: z.object({ maxContextTokens: z.number().positive().optional() }).optional()
|
|
2304
|
+
}).optional(),
|
|
2305
|
+
sleep: z.object({
|
|
2306
|
+
enabled: z.boolean().optional(),
|
|
2307
|
+
schedule: z.object({ sleep: z.string(), wake: z.string() }).optional(),
|
|
2308
|
+
wakeTriggers: z.object({
|
|
2309
|
+
mentions: z.boolean().optional(),
|
|
2310
|
+
dms: z.boolean().optional(),
|
|
2311
|
+
channels: z.array(z.string()).optional(),
|
|
2312
|
+
senders: z.array(z.string()).optional()
|
|
2313
|
+
}).optional()
|
|
2314
|
+
}).optional(),
|
|
2315
|
+
schedules: z.array(
|
|
2316
|
+
z.object({
|
|
2317
|
+
id: z.string().min(1),
|
|
2318
|
+
cron: z.string().optional(),
|
|
2319
|
+
message: z.string().optional(),
|
|
2320
|
+
script: z.string().optional(),
|
|
2321
|
+
session: z.string().optional(),
|
|
2322
|
+
enabled: z.boolean(),
|
|
2323
|
+
whileSleeping: z.enum(["skip", "queue", "trigger-wake"]).optional()
|
|
2324
|
+
})
|
|
2325
|
+
).optional()
|
|
2326
|
+
})
|
|
2327
|
+
),
|
|
2328
|
+
(c) => {
|
|
2329
|
+
const mindDefaults = c.req.valid("json");
|
|
2330
|
+
const config2 = readGlobalConfig();
|
|
2331
|
+
config2.mindDefaults = mindDefaults;
|
|
2332
|
+
writeGlobalConfig(config2);
|
|
2333
|
+
return c.json({ ok: true });
|
|
2334
|
+
}
|
|
2335
|
+
);
|
|
1509
2336
|
var oauthFlows = /* @__PURE__ */ new Map();
|
|
1510
2337
|
var OAUTH_FLOW_TTL_MS = 10 * 60 * 1e3;
|
|
1511
2338
|
function cleanupOAuthFlows() {
|
|
@@ -1563,7 +2390,7 @@ import { csrf } from "hono/csrf";
|
|
|
1563
2390
|
import { HTTPException } from "hono/http-exception";
|
|
1564
2391
|
|
|
1565
2392
|
// src/web/api/activity.ts
|
|
1566
|
-
import { desc } from "drizzle-orm";
|
|
2393
|
+
import { desc as desc2 } from "drizzle-orm";
|
|
1567
2394
|
import { Hono as Hono2 } from "hono";
|
|
1568
2395
|
import { streamSSE as streamSSE2 } from "hono/streaming";
|
|
1569
2396
|
var app2 = new Hono2().get("/events", async (c) => {
|
|
@@ -1574,7 +2401,7 @@ var app2 = new Hono2().get("/events", async (c) => {
|
|
|
1574
2401
|
let recentActivity = [];
|
|
1575
2402
|
try {
|
|
1576
2403
|
const db = await getDb();
|
|
1577
|
-
recentActivity = await db.select().from(activity).orderBy(
|
|
2404
|
+
recentActivity = await db.select().from(activity).orderBy(desc2(activity.created_at)).limit(50);
|
|
1578
2405
|
recentActivity = recentActivity.map((row) => ({
|
|
1579
2406
|
...row,
|
|
1580
2407
|
metadata: row.metadata ? JSON.parse(row.metadata) : null
|
|
@@ -1900,7 +2727,7 @@ import { Hono as Hono4 } from "hono";
|
|
|
1900
2727
|
import { z as z3 } from "zod";
|
|
1901
2728
|
|
|
1902
2729
|
// src/lib/puppets.ts
|
|
1903
|
-
import { and as
|
|
2730
|
+
import { and as and3, eq as eq4 } from "drizzle-orm";
|
|
1904
2731
|
async function findOrCreatePuppet(platform, platformId, displayName) {
|
|
1905
2732
|
const username = `${platform}:${platformId}`;
|
|
1906
2733
|
const db = await getDb();
|
|
@@ -1909,10 +2736,10 @@ async function findOrCreatePuppet(platform, platformId, displayName) {
|
|
|
1909
2736
|
username: users.username,
|
|
1910
2737
|
display_name: users.display_name,
|
|
1911
2738
|
avatar: users.avatar
|
|
1912
|
-
}).from(users).where(
|
|
2739
|
+
}).from(users).where(and3(eq4(users.username, username), eq4(users.user_type, "puppet"))).get();
|
|
1913
2740
|
if (existing) {
|
|
1914
2741
|
if (existing.display_name !== displayName) {
|
|
1915
|
-
await db.update(users).set({ display_name: displayName }).where(
|
|
2742
|
+
await db.update(users).set({ display_name: displayName }).where(eq4(users.id, existing.id));
|
|
1916
2743
|
existing.display_name = displayName;
|
|
1917
2744
|
}
|
|
1918
2745
|
return existing;
|
|
@@ -1938,7 +2765,7 @@ async function findOrCreatePuppet(platform, platformId, displayName) {
|
|
|
1938
2765
|
username: users.username,
|
|
1939
2766
|
display_name: users.display_name,
|
|
1940
2767
|
avatar: users.avatar
|
|
1941
|
-
}).from(users).where(
|
|
2768
|
+
}).from(users).where(and3(eq4(users.username, username), eq4(users.user_type, "puppet"))).get();
|
|
1942
2769
|
if (retried) return retried;
|
|
1943
2770
|
}
|
|
1944
2771
|
throw err;
|
|
@@ -2020,7 +2847,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
|
|
|
2020
2847
|
}
|
|
2021
2848
|
const participants = await getParticipants(channel.id);
|
|
2022
2849
|
if (!participants.some((p) => p.userId === puppet.id)) {
|
|
2023
|
-
const { addParticipant } = await import("./conversations-
|
|
2850
|
+
const { addParticipant } = await import("./conversations-HL2JP5GI.js");
|
|
2024
2851
|
await addParticipant(channel.id, puppet.id);
|
|
2025
2852
|
}
|
|
2026
2853
|
const contentBlocks = body.content;
|
|
@@ -2113,8 +2940,8 @@ async function fanOutToBridgedMinds(opts) {
|
|
|
2113
2940
|
const participants = await getParticipants(opts.conversationId);
|
|
2114
2941
|
const mindParticipants = participants.filter((p) => p.userType === "mind");
|
|
2115
2942
|
const participantNames = participants.map((p) => p.username);
|
|
2116
|
-
const { getMindManager: getMindManager2 } = await import("./mind-manager-
|
|
2117
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
2943
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-MWW3BTS4.js");
|
|
2944
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-BJK2ROPX.js");
|
|
2118
2945
|
const manager = getMindManager2();
|
|
2119
2946
|
const sm = getSleepManagerIfReady2();
|
|
2120
2947
|
const targetMinds = mindParticipants.filter((ap) => {
|
|
@@ -2916,6 +3743,44 @@ var env_default = app6;
|
|
|
2916
3743
|
import { Hono as Hono8 } from "hono";
|
|
2917
3744
|
var app7 = new Hono8().get("/", (c) => {
|
|
2918
3745
|
return c.json(getLoadedExtensions());
|
|
3746
|
+
}).get("/all", (c) => {
|
|
3747
|
+
return c.json(getAllDiscoveredExtensions());
|
|
3748
|
+
}).put("/:id/enabled", async (c) => {
|
|
3749
|
+
const { id } = c.req.param();
|
|
3750
|
+
const body = await c.req.json().catch(() => null);
|
|
3751
|
+
if (!body || typeof body.enabled !== "boolean") {
|
|
3752
|
+
return c.json({ error: "enabled must be a boolean" }, 400);
|
|
3753
|
+
}
|
|
3754
|
+
try {
|
|
3755
|
+
setExtensionEnabled(id, body.enabled);
|
|
3756
|
+
} catch (err) {
|
|
3757
|
+
return c.json({ error: err.message }, 404);
|
|
3758
|
+
}
|
|
3759
|
+
return c.json({ ok: true, requiresRestart: true });
|
|
3760
|
+
}).post("/install", async (c) => {
|
|
3761
|
+
const body = await c.req.json();
|
|
3762
|
+
const pkg = body.package?.trim();
|
|
3763
|
+
if (!pkg) {
|
|
3764
|
+
return c.json({ error: "package is required" }, 400);
|
|
3765
|
+
}
|
|
3766
|
+
try {
|
|
3767
|
+
await installNpmExtension(pkg);
|
|
3768
|
+
return c.json({ ok: true, requiresRestart: true });
|
|
3769
|
+
} catch (err) {
|
|
3770
|
+
const message = err.message;
|
|
3771
|
+
const isValidation = message.includes("already installed") || message.includes("Invalid package");
|
|
3772
|
+
return c.json({ error: message }, isValidation ? 400 : 500);
|
|
3773
|
+
}
|
|
3774
|
+
}).delete("/uninstall/:package", async (c) => {
|
|
3775
|
+
const pkg = c.req.param("package");
|
|
3776
|
+
try {
|
|
3777
|
+
await uninstallNpmExtension(pkg);
|
|
3778
|
+
return c.json({ ok: true, requiresRestart: true });
|
|
3779
|
+
} catch (err) {
|
|
3780
|
+
const message = err.message;
|
|
3781
|
+
const isValidation = message.includes("not installed");
|
|
3782
|
+
return c.json({ error: message }, isValidation ? 400 : 500);
|
|
3783
|
+
}
|
|
2919
3784
|
});
|
|
2920
3785
|
var extensions_default = app7;
|
|
2921
3786
|
|
|
@@ -2927,7 +3792,7 @@ async function notifyMind(mindName, message) {
|
|
|
2927
3792
|
const entry = await findMind(mindName);
|
|
2928
3793
|
if (!entry) return;
|
|
2929
3794
|
try {
|
|
2930
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
3795
|
+
const { sendSystemMessage } = await import("./system-chat-TYLOL7SX.js");
|
|
2931
3796
|
await sendSystemMessage(mindName, message);
|
|
2932
3797
|
} catch (err) {
|
|
2933
3798
|
logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
|
|
@@ -3050,6 +3915,7 @@ var app8 = new Hono9().post("/:name/files/send", requireSelf(), async (c) => {
|
|
|
3050
3915
|
var file_sharing_default = app8;
|
|
3051
3916
|
|
|
3052
3917
|
// src/web/api/files.ts
|
|
3918
|
+
import { mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
3053
3919
|
import { readFile, realpath, stat } from "fs/promises";
|
|
3054
3920
|
import { extname as extname2, resolve as resolve7 } from "path";
|
|
3055
3921
|
import { Hono as Hono10 } from "hono";
|
|
@@ -3061,11 +3927,46 @@ var AVATAR_MIME2 = {
|
|
|
3061
3927
|
".webp": "image/webp"
|
|
3062
3928
|
};
|
|
3063
3929
|
var MAX_AVATAR_SIZE2 = 2 * 1024 * 1024;
|
|
3064
|
-
var app9 = new Hono10().
|
|
3930
|
+
var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
|
|
3065
3931
|
const name = c.req.param("name");
|
|
3066
3932
|
const entry = await findMind(name);
|
|
3067
3933
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3068
|
-
const
|
|
3934
|
+
const body = await c.req.parseBody();
|
|
3935
|
+
const file = body.file;
|
|
3936
|
+
if (!(file instanceof File)) {
|
|
3937
|
+
return c.json({ error: "No file uploaded" }, 400);
|
|
3938
|
+
}
|
|
3939
|
+
if (file.size > MAX_AVATAR_SIZE2) {
|
|
3940
|
+
return c.json({ error: "File too large (max 2MB)" }, 400);
|
|
3941
|
+
}
|
|
3942
|
+
const ext = extname2(file.name).toLowerCase();
|
|
3943
|
+
if (!AVATAR_MIME2[ext]) {
|
|
3944
|
+
return c.json({ error: "Invalid file type (png, jpg, gif, webp only)" }, 400);
|
|
3945
|
+
}
|
|
3946
|
+
const dir = entry.dir ?? mindDir(name);
|
|
3947
|
+
const homeDir = resolve7(dir, "home");
|
|
3948
|
+
const filename = `avatar${ext}`;
|
|
3949
|
+
const avatarPath = resolve7(homeDir, filename);
|
|
3950
|
+
const config2 = readVoluteConfig(dir) ?? {};
|
|
3951
|
+
const oldAvatar = config2.profile?.avatar;
|
|
3952
|
+
if (oldAvatar && oldAvatar !== filename) {
|
|
3953
|
+
rmSync3(resolve7(homeDir, oldAvatar), { force: true });
|
|
3954
|
+
}
|
|
3955
|
+
const buffer2 = Buffer.from(await file.arrayBuffer());
|
|
3956
|
+
mkdirSync4(homeDir, { recursive: true });
|
|
3957
|
+
writeFileSync4(avatarPath, buffer2);
|
|
3958
|
+
const profile = config2.profile ?? {};
|
|
3959
|
+
profile.avatar = filename;
|
|
3960
|
+
config2.profile = profile;
|
|
3961
|
+
writeVoluteConfig(dir, config2);
|
|
3962
|
+
await syncMindProfile(name, profile);
|
|
3963
|
+
broadcast({ type: "profile_updated", mind: name, summary: `${name} avatar updated` });
|
|
3964
|
+
return c.json({ ok: true, avatar: filename });
|
|
3965
|
+
}).get("/:name/avatar", async (c) => {
|
|
3966
|
+
const name = c.req.param("name");
|
|
3967
|
+
const entry = await findMind(name);
|
|
3968
|
+
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3969
|
+
const dir = entry.dir ?? mindDir(name);
|
|
3069
3970
|
const config2 = readVoluteConfig(dir);
|
|
3070
3971
|
if (!config2?.profile?.avatar) return c.json({ error: "No avatar configured" }, 404);
|
|
3071
3972
|
const ext = extname2(config2.profile.avatar).toLowerCase();
|
|
@@ -3100,25 +4001,29 @@ var app9 = new Hono10().get("/:name/avatar", async (c) => {
|
|
|
3100
4001
|
var files_default = app9;
|
|
3101
4002
|
|
|
3102
4003
|
// src/web/api/history.ts
|
|
3103
|
-
import { and as
|
|
4004
|
+
import { and as and4, desc as desc3, eq as eq5, gte as gte2, inArray, sql as sql2 } from "drizzle-orm";
|
|
3104
4005
|
import { Hono as Hono11 } from "hono";
|
|
3105
4006
|
var history = new Hono11().get("/turns", async (c) => {
|
|
3106
4007
|
const mindFilter = c.req.query("mind");
|
|
3107
4008
|
const turnIdFilter = c.req.query("turnId");
|
|
4009
|
+
const turnIdsFilter = c.req.query("turnIds");
|
|
3108
4010
|
const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 200);
|
|
3109
4011
|
const offset = Math.max(parseInt(c.req.query("offset") ?? "0", 10) || 0, 0);
|
|
3110
4012
|
const db = await getDb();
|
|
3111
4013
|
const conditions = [];
|
|
3112
|
-
if (mindFilter) conditions.push(
|
|
3113
|
-
if (turnIdFilter) conditions.push(
|
|
3114
|
-
|
|
4014
|
+
if (mindFilter) conditions.push(eq5(turns.mind, mindFilter));
|
|
4015
|
+
if (turnIdFilter) conditions.push(eq5(turns.id, turnIdFilter));
|
|
4016
|
+
if (turnIdsFilter) {
|
|
4017
|
+
const ids = turnIdsFilter.split(",").filter(Boolean);
|
|
4018
|
+
if (ids.length > 0) conditions.push(inArray(turns.id, ids));
|
|
4019
|
+
}
|
|
4020
|
+
const turnRows = await db.select().from(turns).where(conditions.length > 0 ? and4(...conditions) : void 0).orderBy(desc3(turns.created_at)).limit(limit).offset(offset);
|
|
3115
4021
|
if (turnRows.length === 0) return c.json([]);
|
|
3116
4022
|
const turnIds = turnRows.map((t) => t.id);
|
|
3117
|
-
const summaryRows = await db.select().from(
|
|
4023
|
+
const summaryRows = await db.select().from(summaries).where(and4(eq5(summaries.period, "turn"), inArray(summaries.period_key, turnIds)));
|
|
3118
4024
|
const summaryByTurn = /* @__PURE__ */ new Map();
|
|
3119
4025
|
for (const s of summaryRows) {
|
|
3120
|
-
|
|
3121
|
-
summaryByTurn.set(s.turn_id, { content: s.content ?? "", metadata: s.metadata });
|
|
4026
|
+
summaryByTurn.set(s.period_key, { content: s.content, metadata: s.metadata });
|
|
3122
4027
|
}
|
|
3123
4028
|
const historyMsgRows = await db.select({
|
|
3124
4029
|
id: mindHistory.id,
|
|
@@ -3130,9 +4035,9 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3130
4035
|
turn_id: mindHistory.turn_id,
|
|
3131
4036
|
created_at: mindHistory.created_at
|
|
3132
4037
|
}).from(mindHistory).where(
|
|
3133
|
-
|
|
4038
|
+
and4(
|
|
3134
4039
|
inArray(mindHistory.turn_id, turnIds),
|
|
3135
|
-
|
|
4040
|
+
sql2`${mindHistory.type} IN ('inbound', 'outbound')`
|
|
3136
4041
|
)
|
|
3137
4042
|
).orderBy(mindHistory.created_at);
|
|
3138
4043
|
const msgsByTurnChannel = /* @__PURE__ */ new Map();
|
|
@@ -3191,13 +4096,92 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3191
4096
|
}).from(mindHistory).where(inArray(mindHistory.id, triggerIds));
|
|
3192
4097
|
for (const r of triggerRows) triggerMap.set(r.id, r);
|
|
3193
4098
|
}
|
|
4099
|
+
const allChannelSlugs = /* @__PURE__ */ new Set();
|
|
4100
|
+
for (const [, channels] of msgsByTurnChannel) {
|
|
4101
|
+
for (const ch of channels.keys()) allChannelSlugs.add(ch);
|
|
4102
|
+
}
|
|
4103
|
+
const dmSlugMinds = /* @__PURE__ */ new Map();
|
|
4104
|
+
for (const [turnId, channels] of msgsByTurnChannel) {
|
|
4105
|
+
const mindName = turnMindMap.get(turnId);
|
|
4106
|
+
if (!mindName) continue;
|
|
4107
|
+
for (const ch of channels.keys()) {
|
|
4108
|
+
if (ch.startsWith("@")) {
|
|
4109
|
+
let minds = dmSlugMinds.get(ch);
|
|
4110
|
+
if (!minds) {
|
|
4111
|
+
minds = /* @__PURE__ */ new Set();
|
|
4112
|
+
dmSlugMinds.set(ch, minds);
|
|
4113
|
+
}
|
|
4114
|
+
minds.add(mindName);
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
}
|
|
4118
|
+
const channelIdMap = /* @__PURE__ */ new Map();
|
|
4119
|
+
try {
|
|
4120
|
+
if (allChannelSlugs.size > 0) {
|
|
4121
|
+
const channelNames = [...allChannelSlugs].filter((s) => !s.startsWith("@")).map((s) => {
|
|
4122
|
+
let name = s;
|
|
4123
|
+
if (name.startsWith("#")) name = name.slice(1);
|
|
4124
|
+
const colonIdx = name.indexOf(":");
|
|
4125
|
+
if (colonIdx >= 0) name = name.substring(colonIdx + 1);
|
|
4126
|
+
return { slug: s, name };
|
|
4127
|
+
});
|
|
4128
|
+
if (channelNames.length > 0) {
|
|
4129
|
+
const channelRows = await db.select({ id: conversations.id, name: conversations.name }).from(conversations).where(
|
|
4130
|
+
and4(
|
|
4131
|
+
eq5(conversations.type, "channel"),
|
|
4132
|
+
inArray(
|
|
4133
|
+
conversations.name,
|
|
4134
|
+
channelNames.map((c2) => c2.name)
|
|
4135
|
+
)
|
|
4136
|
+
)
|
|
4137
|
+
);
|
|
4138
|
+
const nameToId = new Map(channelRows.map((r) => [r.name, r.id]));
|
|
4139
|
+
for (const { slug, name } of channelNames) {
|
|
4140
|
+
const id = nameToId.get(name);
|
|
4141
|
+
if (id) channelIdMap.set(slug, id);
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
const dmSlugs = [...dmSlugMinds.keys()];
|
|
4145
|
+
if (dmSlugs.length > 0) {
|
|
4146
|
+
const targetNames = dmSlugs.map((s) => s.slice(1));
|
|
4147
|
+
const cp2 = db.$with("cp2").as(
|
|
4148
|
+
db.select({
|
|
4149
|
+
conversation_id: conversationParticipants.conversation_id,
|
|
4150
|
+
username: users.username
|
|
4151
|
+
}).from(conversationParticipants).innerJoin(users, eq5(conversationParticipants.user_id, users.id))
|
|
4152
|
+
);
|
|
4153
|
+
const dmRows = await db.with(cp2).select({
|
|
4154
|
+
id: conversations.id,
|
|
4155
|
+
targetUsername: users.username
|
|
4156
|
+
}).from(conversations).innerJoin(
|
|
4157
|
+
conversationParticipants,
|
|
4158
|
+
eq5(conversations.id, conversationParticipants.conversation_id)
|
|
4159
|
+
).innerJoin(users, eq5(conversationParticipants.user_id, users.id)).where(and4(eq5(conversations.type, "dm"), inArray(users.username, targetNames)));
|
|
4160
|
+
for (const row of dmRows) {
|
|
4161
|
+
const slug = `@${row.targetUsername}`;
|
|
4162
|
+
const mindNames = dmSlugMinds.get(slug);
|
|
4163
|
+
if (mindNames && !channelIdMap.has(slug)) {
|
|
4164
|
+
const mindCheck = await db.select({ id: conversationParticipants.user_id }).from(conversationParticipants).innerJoin(users, eq5(conversationParticipants.user_id, users.id)).where(
|
|
4165
|
+
and4(
|
|
4166
|
+
eq5(conversationParticipants.conversation_id, row.id),
|
|
4167
|
+
inArray(users.username, [...mindNames])
|
|
4168
|
+
)
|
|
4169
|
+
).get();
|
|
4170
|
+
if (mindCheck) channelIdMap.set(slug, row.id);
|
|
4171
|
+
}
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
}
|
|
4175
|
+
} catch (err) {
|
|
4176
|
+
logger_default.warn("Failed to resolve channel slugs to conversation IDs", logger_default.errorData(err));
|
|
4177
|
+
}
|
|
3194
4178
|
const result = turnRows.map((t) => {
|
|
3195
4179
|
const summary = summaryByTurn.get(t.id);
|
|
3196
4180
|
const turnChannels = msgsByTurnChannel.get(t.id) ?? /* @__PURE__ */ new Map();
|
|
3197
4181
|
const convEntries = [...turnChannels.entries()].map(([channel, evts]) => {
|
|
3198
4182
|
const { label, type } = getChannelLabel(channel);
|
|
3199
4183
|
return {
|
|
3200
|
-
id: channel,
|
|
4184
|
+
id: channelIdMap.get(channel) ?? channel,
|
|
3201
4185
|
label,
|
|
3202
4186
|
type,
|
|
3203
4187
|
messages: evts.map((m) => ({
|
|
@@ -3305,6 +4289,59 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3305
4289
|
Connection: "keep-alive"
|
|
3306
4290
|
}
|
|
3307
4291
|
});
|
|
4292
|
+
}).get("/summaries", async (c) => {
|
|
4293
|
+
const mind = c.req.query("mind") ?? "_system";
|
|
4294
|
+
const period = c.req.query("period");
|
|
4295
|
+
const ids = c.req.query("ids");
|
|
4296
|
+
const from = c.req.query("from");
|
|
4297
|
+
const to = c.req.query("to");
|
|
4298
|
+
const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 200);
|
|
4299
|
+
if (ids) {
|
|
4300
|
+
const db2 = await getDb();
|
|
4301
|
+
const idList = ids.split(",").map((s) => parseInt(s, 10)).filter((n) => !isNaN(n));
|
|
4302
|
+
if (idList.length === 0) return c.json([]);
|
|
4303
|
+
const rows2 = await db2.select().from(summaries).where(inArray(summaries.id, idList));
|
|
4304
|
+
const result2 = rows2.map((r) => {
|
|
4305
|
+
let metadata = null;
|
|
4306
|
+
if (r.metadata) {
|
|
4307
|
+
try {
|
|
4308
|
+
metadata = JSON.parse(r.metadata);
|
|
4309
|
+
} catch (err) {
|
|
4310
|
+
logger_default.debug(`malformed summary metadata for id ${r.id}`, logger_default.errorData(err));
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
return { ...r, metadata };
|
|
4314
|
+
});
|
|
4315
|
+
return c.json(result2);
|
|
4316
|
+
}
|
|
4317
|
+
if (!period || !["turn", "hour", "day", "week", "month"].includes(period)) {
|
|
4318
|
+
return c.json({ error: "period is required (turn, hour, day, week, month)" }, 400);
|
|
4319
|
+
}
|
|
4320
|
+
const db = await getDb();
|
|
4321
|
+
const conditions = [eq5(summaries.mind, mind), eq5(summaries.period, period)];
|
|
4322
|
+
if (from) conditions.push(gte2(summaries.period_key, from));
|
|
4323
|
+
if (to) conditions.push(sql2`${summaries.period_key} <= ${to}`);
|
|
4324
|
+
const rows = await db.select({
|
|
4325
|
+
id: summaries.id,
|
|
4326
|
+
mind: summaries.mind,
|
|
4327
|
+
period: summaries.period,
|
|
4328
|
+
period_key: summaries.period_key,
|
|
4329
|
+
content: summaries.content,
|
|
4330
|
+
metadata: summaries.metadata,
|
|
4331
|
+
created_at: summaries.created_at
|
|
4332
|
+
}).from(summaries).where(and4(...conditions)).orderBy(desc3(summaries.period_key)).limit(limit);
|
|
4333
|
+
const result = rows.map((r) => {
|
|
4334
|
+
let metadata = null;
|
|
4335
|
+
if (r.metadata) {
|
|
4336
|
+
try {
|
|
4337
|
+
metadata = JSON.parse(r.metadata);
|
|
4338
|
+
} catch (err) {
|
|
4339
|
+
logger_default.debug(`malformed meta_summary metadata for id ${r.id}`, logger_default.errorData(err));
|
|
4340
|
+
}
|
|
4341
|
+
}
|
|
4342
|
+
return { ...r, metadata };
|
|
4343
|
+
});
|
|
4344
|
+
return c.json(result);
|
|
3308
4345
|
});
|
|
3309
4346
|
var history_default = history;
|
|
3310
4347
|
|
|
@@ -3313,19 +4350,19 @@ import { Hono as Hono12 } from "hono";
|
|
|
3313
4350
|
|
|
3314
4351
|
// src/lib/identity.ts
|
|
3315
4352
|
import { createHash, generateKeyPairSync, sign, verify } from "crypto";
|
|
3316
|
-
import { existsSync as existsSync6, mkdirSync as
|
|
4353
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
3317
4354
|
import { resolve as resolve8 } from "path";
|
|
3318
4355
|
function generateIdentity(mindDir2) {
|
|
3319
4356
|
const identityDir = resolve8(mindDir2, ".mind/identity");
|
|
3320
|
-
|
|
4357
|
+
mkdirSync5(identityDir, { recursive: true });
|
|
3321
4358
|
const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
|
|
3322
4359
|
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
3323
4360
|
privateKeyEncoding: { type: "pkcs8", format: "pem" }
|
|
3324
4361
|
});
|
|
3325
4362
|
const privatePath = resolve8(identityDir, "private.pem");
|
|
3326
4363
|
const publicPath = resolve8(identityDir, "public.pem");
|
|
3327
|
-
|
|
3328
|
-
|
|
4364
|
+
writeFileSync5(privatePath, privateKey, { mode: 384 });
|
|
4365
|
+
writeFileSync5(publicPath, publicKey, { mode: 420 });
|
|
3329
4366
|
const config2 = readVoluteConfig(mindDir2) ?? {};
|
|
3330
4367
|
config2.identity = {
|
|
3331
4368
|
privateKey: ".mind/identity/private.pem",
|
|
@@ -3449,7 +4486,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
|
|
|
3449
4486
|
const name = c.req.param("name");
|
|
3450
4487
|
const entry = await findMind(name);
|
|
3451
4488
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3452
|
-
const dir = mindDir(name);
|
|
4489
|
+
const dir = entry.dir ?? mindDir(name);
|
|
3453
4490
|
const skills = await listMindSkills(dir);
|
|
3454
4491
|
return c.json(skills);
|
|
3455
4492
|
}).post(
|
|
@@ -3461,7 +4498,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
|
|
|
3461
4498
|
const entry = await findMind(name);
|
|
3462
4499
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3463
4500
|
const { skillId } = c.req.valid("json");
|
|
3464
|
-
const dir = mindDir(name);
|
|
4501
|
+
const dir = entry.dir ?? mindDir(name);
|
|
3465
4502
|
try {
|
|
3466
4503
|
const result = await installSkill(name, dir, skillId);
|
|
3467
4504
|
return c.json({ ok: true, ...result });
|
|
@@ -3479,7 +4516,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
|
|
|
3479
4516
|
const entry = await findMind(name);
|
|
3480
4517
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3481
4518
|
const { skillId } = c.req.valid("json");
|
|
3482
|
-
const dir = mindDir(name);
|
|
4519
|
+
const dir = entry.dir ?? mindDir(name);
|
|
3483
4520
|
try {
|
|
3484
4521
|
const result = await updateSkill(name, dir, skillId);
|
|
3485
4522
|
return c.json(result);
|
|
@@ -3497,7 +4534,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
|
|
|
3497
4534
|
const entry = await findMind(name);
|
|
3498
4535
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3499
4536
|
const { skillId } = c.req.valid("json");
|
|
3500
|
-
const dir = mindDir(name);
|
|
4537
|
+
const dir = entry.dir ?? mindDir(name);
|
|
3501
4538
|
try {
|
|
3502
4539
|
const skill = await publishSkill(name, dir, skillId);
|
|
3503
4540
|
return c.json(skill);
|
|
@@ -3511,7 +4548,7 @@ var app12 = new Hono14().get("/:name/skills", async (c) => {
|
|
|
3511
4548
|
const skillName = c.req.param("skill");
|
|
3512
4549
|
const entry = await findMind(name);
|
|
3513
4550
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3514
|
-
const dir = mindDir(name);
|
|
4551
|
+
const dir = entry.dir ?? mindDir(name);
|
|
3515
4552
|
try {
|
|
3516
4553
|
await uninstallSkill(name, dir, skillName);
|
|
3517
4554
|
} catch (e) {
|
|
@@ -3526,11 +4563,11 @@ var mind_skills_default = app12;
|
|
|
3526
4563
|
import {
|
|
3527
4564
|
cpSync,
|
|
3528
4565
|
existsSync as existsSync9,
|
|
3529
|
-
mkdirSync as
|
|
4566
|
+
mkdirSync as mkdirSync7,
|
|
3530
4567
|
readdirSync as readdirSync2,
|
|
3531
4568
|
readFileSync as readFileSync10,
|
|
3532
|
-
rmSync as
|
|
3533
|
-
writeFileSync as
|
|
4569
|
+
rmSync as rmSync5,
|
|
4570
|
+
writeFileSync as writeFileSync8
|
|
3534
4571
|
} from "fs";
|
|
3535
4572
|
import { resolve as resolve12 } from "path";
|
|
3536
4573
|
import { zValidator as zValidator5 } from "@hono/zod-validator";
|
|
@@ -3539,7 +4576,7 @@ import { Hono as Hono15 } from "hono";
|
|
|
3539
4576
|
import { z as z5 } from "zod";
|
|
3540
4577
|
|
|
3541
4578
|
// src/lib/consolidate.ts
|
|
3542
|
-
import { readdirSync, readFileSync as readFileSync8, writeFileSync as
|
|
4579
|
+
import { readdirSync, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
3543
4580
|
import { resolve as resolve10 } from "path";
|
|
3544
4581
|
async function consolidateMemory(mindDir2) {
|
|
3545
4582
|
const soulPath = resolve10(mindDir2, "home/SOUL.md");
|
|
@@ -3601,7 +4638,7 @@ ${content2}`);
|
|
|
3601
4638
|
const data = await res.json();
|
|
3602
4639
|
const content = data.content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join("").trim();
|
|
3603
4640
|
if (content) {
|
|
3604
|
-
|
|
4641
|
+
writeFileSync6(memoryPath, `${content}
|
|
3605
4642
|
`);
|
|
3606
4643
|
console.log("MEMORY.md created successfully.");
|
|
3607
4644
|
} else {
|
|
@@ -3611,7 +4648,7 @@ ${content2}`);
|
|
|
3611
4648
|
|
|
3612
4649
|
// src/lib/convert-session.ts
|
|
3613
4650
|
import { randomUUID } from "crypto";
|
|
3614
|
-
import { mkdirSync as
|
|
4651
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
3615
4652
|
import { homedir } from "os";
|
|
3616
4653
|
import { resolve as resolve11 } from "path";
|
|
3617
4654
|
function convertSession(opts) {
|
|
@@ -3717,321 +4754,70 @@ function convertSession(opts) {
|
|
|
3717
4754
|
isSidechain: false,
|
|
3718
4755
|
userType: "external",
|
|
3719
4756
|
type: "user",
|
|
3720
|
-
sourceToolAssistantUUID: lastSdkUuid ?? void 0,
|
|
3721
|
-
toolUseResult: "imported",
|
|
3722
|
-
message: {
|
|
3723
|
-
role: "user",
|
|
3724
|
-
content: toolResults
|
|
3725
|
-
}
|
|
3726
|
-
};
|
|
3727
|
-
sdkEvents.push(JSON.stringify(sdkEvent));
|
|
3728
|
-
lastSdkUuid = uuid;
|
|
3729
|
-
}
|
|
3730
|
-
}
|
|
3731
|
-
const projectId = opts.projectDir.replace(/\//g, "-");
|
|
3732
|
-
const sdkDir = resolve11(homedir(), ".claude", "projects", projectId);
|
|
3733
|
-
mkdirSync5(sdkDir, { recursive: true });
|
|
3734
|
-
const sdkPath = resolve11(sdkDir, `${sessionId}.jsonl`);
|
|
3735
|
-
writeFileSync6(sdkPath, `${sdkEvents.join("\n")}
|
|
3736
|
-
`);
|
|
3737
|
-
console.log(`Converted ${sdkEvents.length} messages \u2192 ${sdkPath}`);
|
|
3738
|
-
return sessionId;
|
|
3739
|
-
}
|
|
3740
|
-
var MODEL_MAP = {
|
|
3741
|
-
"claude-opus-4-5": "claude-opus-4-5-20251101",
|
|
3742
|
-
"claude-sonnet-4": "claude-sonnet-4-20250514"
|
|
3743
|
-
};
|
|
3744
|
-
function mapModel(model) {
|
|
3745
|
-
if (!model) return "claude-opus-4-5-20251101";
|
|
3746
|
-
return MODEL_MAP[model] ?? model;
|
|
3747
|
-
}
|
|
3748
|
-
function mapStopReason(stopReason) {
|
|
3749
|
-
if (!stopReason) return "end_turn";
|
|
3750
|
-
const map = {
|
|
3751
|
-
toolUse: "tool_use",
|
|
3752
|
-
endTurn: "end_turn",
|
|
3753
|
-
stop: "end_turn",
|
|
3754
|
-
maxTokens: "max_tokens"
|
|
3755
|
-
};
|
|
3756
|
-
return map[stopReason] ?? stopReason;
|
|
3757
|
-
}
|
|
3758
|
-
function mapUsage(usage) {
|
|
3759
|
-
if (!usage) return { input_tokens: 0, output_tokens: 0 };
|
|
3760
|
-
return {
|
|
3761
|
-
input_tokens: usage.input ?? usage.input_tokens ?? 0,
|
|
3762
|
-
output_tokens: usage.output ?? usage.output_tokens ?? 0,
|
|
3763
|
-
cache_read_input_tokens: usage.cacheRead ?? usage.cache_read_input_tokens ?? 0,
|
|
3764
|
-
cache_creation_input_tokens: usage.cacheWrite ?? usage.cache_creation_input_tokens ?? 0
|
|
3765
|
-
};
|
|
3766
|
-
}
|
|
3767
|
-
function convertAssistantContent(content) {
|
|
3768
|
-
const result = [];
|
|
3769
|
-
for (const block of content) {
|
|
3770
|
-
if (block.type === "thinking") {
|
|
3771
|
-
} else if (block.type === "toolCall") {
|
|
3772
|
-
result.push({
|
|
3773
|
-
type: "tool_use",
|
|
3774
|
-
id: block.id,
|
|
3775
|
-
name: block.name,
|
|
3776
|
-
input: block.arguments ?? block.input ?? {},
|
|
3777
|
-
caller: { type: "direct" }
|
|
3778
|
-
});
|
|
3779
|
-
} else {
|
|
3780
|
-
result.push(block);
|
|
3781
|
-
}
|
|
3782
|
-
}
|
|
3783
|
-
return result;
|
|
3784
|
-
}
|
|
3785
|
-
|
|
3786
|
-
// src/lib/daemon/turn-summarizer.ts
|
|
3787
|
-
import { and as and4, desc as desc3, eq as eq5, gt, lt as lt3, sql as sql2 } from "drizzle-orm";
|
|
3788
|
-
|
|
3789
|
-
// src/lib/format-tool.ts
|
|
3790
|
-
function summarizeTool(name, input) {
|
|
3791
|
-
if (input && typeof input === "object") {
|
|
3792
|
-
const args = input;
|
|
3793
|
-
const val = args.path ?? args.command ?? args.query ?? args.url;
|
|
3794
|
-
if (typeof val === "string") {
|
|
3795
|
-
const brief = val.length > 60 ? `${val.slice(0, 57)}...` : val;
|
|
3796
|
-
return `[${name} ${brief}]`;
|
|
3797
|
-
}
|
|
3798
|
-
}
|
|
3799
|
-
return `[${name}]`;
|
|
3800
|
-
}
|
|
3801
|
-
|
|
3802
|
-
// src/lib/daemon/turn-summarizer.ts
|
|
3803
|
-
var sLog = logger_default.child("turn-summarizer");
|
|
3804
|
-
async function gatherTurnEvents(mind, session, doneId) {
|
|
3805
|
-
const db = await getDb();
|
|
3806
|
-
const conditions = [
|
|
3807
|
-
eq5(mindHistory.mind, mind),
|
|
3808
|
-
eq5(mindHistory.type, "done"),
|
|
3809
|
-
lt3(mindHistory.id, doneId)
|
|
3810
|
-
];
|
|
3811
|
-
if (session) {
|
|
3812
|
-
conditions.push(eq5(mindHistory.session, session));
|
|
3813
|
-
}
|
|
3814
|
-
const prevDone = await db.select({ id: mindHistory.id }).from(mindHistory).where(and4(...conditions)).orderBy(desc3(mindHistory.id)).limit(1);
|
|
3815
|
-
const prevDoneId = prevDone.length > 0 ? prevDone[0].id : 0;
|
|
3816
|
-
const turnConditions = [
|
|
3817
|
-
eq5(mindHistory.mind, mind),
|
|
3818
|
-
gt(mindHistory.id, prevDoneId),
|
|
3819
|
-
sql2`${mindHistory.id} <= ${doneId}`
|
|
3820
|
-
];
|
|
3821
|
-
if (session) {
|
|
3822
|
-
turnConditions.push(eq5(mindHistory.session, session));
|
|
3823
|
-
}
|
|
3824
|
-
const events = await db.select({
|
|
3825
|
-
id: mindHistory.id,
|
|
3826
|
-
type: mindHistory.type,
|
|
3827
|
-
channel: mindHistory.channel,
|
|
3828
|
-
session: mindHistory.session,
|
|
3829
|
-
content: mindHistory.content,
|
|
3830
|
-
metadata: mindHistory.metadata,
|
|
3831
|
-
created_at: mindHistory.created_at
|
|
3832
|
-
}).from(mindHistory).where(and4(...turnConditions)).orderBy(mindHistory.id);
|
|
3833
|
-
return {
|
|
3834
|
-
events,
|
|
3835
|
-
fromId: events.length > 0 ? events[0].id : doneId,
|
|
3836
|
-
toId: doneId
|
|
3837
|
-
};
|
|
3838
|
-
}
|
|
3839
|
-
function buildDeterministicSummary(events) {
|
|
3840
|
-
const channels = /* @__PURE__ */ new Set();
|
|
3841
|
-
const tools = [];
|
|
3842
|
-
let hasInbound = false;
|
|
3843
|
-
let hasOutbound = false;
|
|
3844
|
-
for (const ev of events) {
|
|
3845
|
-
if (ev.type === "inbound") {
|
|
3846
|
-
hasInbound = true;
|
|
3847
|
-
if (ev.channel) channels.add(ev.channel);
|
|
3848
|
-
}
|
|
3849
|
-
if (ev.type === "outbound" || ev.type === "text") {
|
|
3850
|
-
hasOutbound = true;
|
|
3851
|
-
}
|
|
3852
|
-
if (ev.type === "tool_use" && ev.metadata) {
|
|
3853
|
-
try {
|
|
3854
|
-
const meta = JSON.parse(ev.metadata);
|
|
3855
|
-
if (meta.name) tools.push(meta.name);
|
|
3856
|
-
} catch (err) {
|
|
3857
|
-
sLog.debug(`failed to parse tool_use metadata for event ${ev.id}`, logger_default.errorData(err));
|
|
3858
|
-
}
|
|
3859
|
-
}
|
|
3860
|
-
}
|
|
3861
|
-
const parts = [];
|
|
3862
|
-
if (hasInbound) {
|
|
3863
|
-
const channelList = [...channels];
|
|
3864
|
-
parts.push(
|
|
3865
|
-
channelList.length > 0 ? `Received message on ${channelList.join(", ")}` : "Received message"
|
|
3866
|
-
);
|
|
3867
|
-
}
|
|
3868
|
-
if (tools.length > 0) {
|
|
3869
|
-
const unique = [...new Set(tools)];
|
|
3870
|
-
parts.push(`Used ${unique.join(", ")}`);
|
|
3871
|
-
}
|
|
3872
|
-
if (hasOutbound) {
|
|
3873
|
-
parts.push("Sent response");
|
|
3874
|
-
}
|
|
3875
|
-
return parts.length > 0 ? `${parts.join(". ")}.` : "Turn completed.";
|
|
3876
|
-
}
|
|
3877
|
-
function buildTranscript(events) {
|
|
3878
|
-
const lines = [];
|
|
3879
|
-
for (const ev of events) {
|
|
3880
|
-
switch (ev.type) {
|
|
3881
|
-
case "inbound":
|
|
3882
|
-
lines.push(`[inbound${ev.channel ? ` ${ev.channel}` : ""}] ${ev.content ?? ""}`);
|
|
3883
|
-
break;
|
|
3884
|
-
case "outbound":
|
|
3885
|
-
case "text":
|
|
3886
|
-
lines.push(`[response] ${(ev.content ?? "").slice(0, 500)}`);
|
|
3887
|
-
break;
|
|
3888
|
-
case "tool_use": {
|
|
3889
|
-
let toolInfo = "tool";
|
|
3890
|
-
if (ev.metadata) {
|
|
3891
|
-
try {
|
|
3892
|
-
const meta = JSON.parse(ev.metadata);
|
|
3893
|
-
toolInfo = summarizeTool(meta.name ?? "tool", meta.input ?? {});
|
|
3894
|
-
} catch (err) {
|
|
3895
|
-
sLog.debug(`failed to parse tool_use metadata for event ${ev.id}`, logger_default.errorData(err));
|
|
3896
|
-
}
|
|
3897
|
-
}
|
|
3898
|
-
lines.push(toolInfo);
|
|
3899
|
-
break;
|
|
3900
|
-
}
|
|
3901
|
-
case "tool_result": {
|
|
3902
|
-
const content = ev.content ?? "";
|
|
3903
|
-
let isError = false;
|
|
3904
|
-
if (ev.metadata) {
|
|
3905
|
-
try {
|
|
3906
|
-
const meta = JSON.parse(ev.metadata);
|
|
3907
|
-
isError = !!meta.is_error;
|
|
3908
|
-
} catch (err) {
|
|
3909
|
-
sLog.debug(
|
|
3910
|
-
`failed to parse tool_result metadata for event ${ev.id}`,
|
|
3911
|
-
logger_default.errorData(err)
|
|
3912
|
-
);
|
|
3913
|
-
}
|
|
4757
|
+
sourceToolAssistantUUID: lastSdkUuid ?? void 0,
|
|
4758
|
+
toolUseResult: "imported",
|
|
4759
|
+
message: {
|
|
4760
|
+
role: "user",
|
|
4761
|
+
content: toolResults
|
|
3914
4762
|
}
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
case "thinking":
|
|
3919
|
-
lines.push(`[thinking] ${(ev.content ?? "").slice(0, 300)}`);
|
|
3920
|
-
break;
|
|
4763
|
+
};
|
|
4764
|
+
sdkEvents.push(JSON.stringify(sdkEvent));
|
|
4765
|
+
lastSdkUuid = uuid;
|
|
3921
4766
|
}
|
|
3922
4767
|
}
|
|
3923
|
-
|
|
4768
|
+
const projectId = opts.projectDir.replace(/\//g, "-");
|
|
4769
|
+
const sdkDir = resolve11(homedir(), ".claude", "projects", projectId);
|
|
4770
|
+
mkdirSync6(sdkDir, { recursive: true });
|
|
4771
|
+
const sdkPath = resolve11(sdkDir, `${sessionId}.jsonl`);
|
|
4772
|
+
writeFileSync7(sdkPath, `${sdkEvents.join("\n")}
|
|
4773
|
+
`);
|
|
4774
|
+
console.log(`Converted ${sdkEvents.length} messages \u2192 ${sdkPath}`);
|
|
4775
|
+
return sessionId;
|
|
3924
4776
|
}
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
4777
|
+
var MODEL_MAP = {
|
|
4778
|
+
"claude-opus-4-5": "claude-opus-4-5-20251101",
|
|
4779
|
+
"claude-sonnet-4": "claude-sonnet-4-20250514"
|
|
4780
|
+
};
|
|
4781
|
+
function mapModel(model) {
|
|
4782
|
+
if (!model) return "claude-opus-4-5-20251101";
|
|
4783
|
+
return MODEL_MAP[model] ?? model;
|
|
4784
|
+
}
|
|
4785
|
+
function mapStopReason(stopReason) {
|
|
4786
|
+
if (!stopReason) return "end_turn";
|
|
4787
|
+
const map = {
|
|
4788
|
+
toolUse: "tool_use",
|
|
4789
|
+
endTurn: "end_turn",
|
|
4790
|
+
stop: "end_turn",
|
|
4791
|
+
maxTokens: "max_tokens"
|
|
4792
|
+
};
|
|
4793
|
+
return map[stopReason] ?? stopReason;
|
|
4794
|
+
}
|
|
4795
|
+
function mapUsage(usage) {
|
|
4796
|
+
if (!usage) return { input_tokens: 0, output_tokens: 0 };
|
|
3936
4797
|
return {
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
4798
|
+
input_tokens: usage.input ?? usage.input_tokens ?? 0,
|
|
4799
|
+
output_tokens: usage.output ?? usage.output_tokens ?? 0,
|
|
4800
|
+
cache_read_input_tokens: usage.cacheRead ?? usage.cache_read_input_tokens ?? 0,
|
|
4801
|
+
cache_creation_input_tokens: usage.cacheWrite ?? usage.cache_creation_input_tokens ?? 0
|
|
3940
4802
|
};
|
|
3941
4803
|
}
|
|
3942
|
-
|
|
3943
|
-
const
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
await db2.update(mindHistory).set({ turn_id: null }).where(and4(eq5(mindHistory.turn_id, turnId), eq5(mindHistory.type, "inbound")));
|
|
3955
|
-
await db2.update(messages).set({ turn_id: null }).where(eq5(messages.turn_id, turnId));
|
|
3956
|
-
} catch (err) {
|
|
3957
|
-
sLog.error(`failed to un-tag events for interrupted turn ${turnId}`, logger_default.errorData(err));
|
|
3958
|
-
}
|
|
3959
|
-
}
|
|
3960
|
-
return;
|
|
3961
|
-
}
|
|
3962
|
-
const tools = [];
|
|
3963
|
-
for (const ev of events) {
|
|
3964
|
-
if (ev.type === "tool_use" && ev.metadata) {
|
|
3965
|
-
try {
|
|
3966
|
-
const meta = JSON.parse(ev.metadata);
|
|
3967
|
-
if (meta.name) tools.push(meta.name);
|
|
3968
|
-
} catch (err) {
|
|
3969
|
-
sLog.debug(`failed to parse tool_use metadata for event ${ev.id}`, logger_default.errorData(err));
|
|
3970
|
-
}
|
|
3971
|
-
}
|
|
3972
|
-
}
|
|
3973
|
-
const fromTime = events[0].created_at;
|
|
3974
|
-
const toTime = events[events.length - 1].created_at;
|
|
3975
|
-
let summaryText;
|
|
3976
|
-
let deterministic;
|
|
3977
|
-
const transcript = buildTranscript(events);
|
|
3978
|
-
if (transcript.trim()) {
|
|
3979
|
-
const summaryPrompt = await getPrompt("turn_summary");
|
|
3980
|
-
const aiResult = await aiCompleteUtility(summaryPrompt, transcript);
|
|
3981
|
-
if (aiResult) {
|
|
3982
|
-
summaryText = aiResult;
|
|
3983
|
-
deterministic = false;
|
|
4804
|
+
function convertAssistantContent(content) {
|
|
4805
|
+
const result = [];
|
|
4806
|
+
for (const block of content) {
|
|
4807
|
+
if (block.type === "thinking") {
|
|
4808
|
+
} else if (block.type === "toolCall") {
|
|
4809
|
+
result.push({
|
|
4810
|
+
type: "tool_use",
|
|
4811
|
+
id: block.id,
|
|
4812
|
+
name: block.name,
|
|
4813
|
+
input: block.arguments ?? block.input ?? {},
|
|
4814
|
+
caller: { type: "direct" }
|
|
4815
|
+
});
|
|
3984
4816
|
} else {
|
|
3985
|
-
|
|
3986
|
-
deterministic = true;
|
|
4817
|
+
result.push(block);
|
|
3987
4818
|
}
|
|
3988
|
-
} else {
|
|
3989
|
-
summaryText = buildDeterministicSummary(events);
|
|
3990
|
-
deterministic = true;
|
|
3991
|
-
}
|
|
3992
|
-
const metadata = {
|
|
3993
|
-
deterministic,
|
|
3994
|
-
tool_count: tools.length,
|
|
3995
|
-
tools: [...new Set(tools)],
|
|
3996
|
-
from_id: fromId,
|
|
3997
|
-
to_id: toId,
|
|
3998
|
-
from_time: fromTime,
|
|
3999
|
-
to_time: toTime
|
|
4000
|
-
};
|
|
4001
|
-
const db = await getDb();
|
|
4002
|
-
let summaryId;
|
|
4003
|
-
try {
|
|
4004
|
-
const result = await db.insert(mindHistory).values({
|
|
4005
|
-
mind,
|
|
4006
|
-
type: "summary",
|
|
4007
|
-
session: session ?? null,
|
|
4008
|
-
channel: channel ?? null,
|
|
4009
|
-
content: summaryText,
|
|
4010
|
-
metadata: JSON.stringify(metadata),
|
|
4011
|
-
turn_id: turnId ?? null
|
|
4012
|
-
}).returning({ id: mindHistory.id });
|
|
4013
|
-
summaryId = result[0]?.id;
|
|
4014
|
-
} catch (err) {
|
|
4015
|
-
sLog.error(
|
|
4016
|
-
`failed to persist summary for ${mind} (events ${fromId}-${toId})`,
|
|
4017
|
-
logger_default.errorData(err)
|
|
4018
|
-
);
|
|
4019
|
-
return;
|
|
4020
|
-
}
|
|
4021
|
-
if (turnId && summaryId != null) {
|
|
4022
|
-
setSummaryEventId(turnId, summaryId).catch((err) => {
|
|
4023
|
-
sLog.error(`failed to link summary to turn ${turnId}`, logger_default.errorData(err));
|
|
4024
|
-
});
|
|
4025
4819
|
}
|
|
4026
|
-
|
|
4027
|
-
mind,
|
|
4028
|
-
type: "summary",
|
|
4029
|
-
session,
|
|
4030
|
-
channel,
|
|
4031
|
-
content: summaryText,
|
|
4032
|
-
metadata,
|
|
4033
|
-
turnId
|
|
4034
|
-
});
|
|
4820
|
+
return result;
|
|
4035
4821
|
}
|
|
4036
4822
|
|
|
4037
4823
|
// src/lib/health.ts
|
|
@@ -4049,7 +4835,7 @@ async function checkHealth(port) {
|
|
|
4049
4835
|
}
|
|
4050
4836
|
|
|
4051
4837
|
// src/lib/variant-cleanup.ts
|
|
4052
|
-
import { existsSync as existsSync8, rmSync as
|
|
4838
|
+
import { existsSync as existsSync8, rmSync as rmSync4 } from "fs";
|
|
4053
4839
|
async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
|
|
4054
4840
|
if (opts?.stop) {
|
|
4055
4841
|
try {
|
|
@@ -4058,14 +4844,14 @@ async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
|
|
|
4058
4844
|
logger_default.warn(`failed to stop variant ${variantName}`, logger_default.errorData(err));
|
|
4059
4845
|
}
|
|
4060
4846
|
}
|
|
4061
|
-
const { findMind: findMind2 } = await import("./registry-
|
|
4847
|
+
const { findMind: findMind2 } = await import("./registry-UYV5S6QT.js");
|
|
4062
4848
|
const variantEntry = await findMind2(variantName);
|
|
4063
4849
|
const branchName = variantEntry?.branch ?? variantName;
|
|
4064
4850
|
if (existsSync8(variantPath)) {
|
|
4065
4851
|
try {
|
|
4066
4852
|
await gitExec(["worktree", "remove", "--force", variantPath], { cwd: projectRoot });
|
|
4067
4853
|
} catch {
|
|
4068
|
-
|
|
4854
|
+
rmSync4(variantPath, { recursive: true, force: true });
|
|
4069
4855
|
try {
|
|
4070
4856
|
await gitExec(["worktree", "prune"], { cwd: projectRoot });
|
|
4071
4857
|
} catch (err) {
|
|
@@ -4112,7 +4898,7 @@ async function getMindStatus(name, port) {
|
|
|
4112
4898
|
const manager = getMindManager();
|
|
4113
4899
|
let status = "stopped";
|
|
4114
4900
|
try {
|
|
4115
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4901
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-BJK2ROPX.js");
|
|
4116
4902
|
if (getSleepManagerIfReady2()?.isSleeping(name)) {
|
|
4117
4903
|
status = "sleeping";
|
|
4118
4904
|
}
|
|
@@ -4170,7 +4956,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4170
4956
|
} catch {
|
|
4171
4957
|
}
|
|
4172
4958
|
if (existsSync9(tempWorktree)) {
|
|
4173
|
-
|
|
4959
|
+
rmSync5(tempWorktree, { recursive: true, force: true });
|
|
4174
4960
|
}
|
|
4175
4961
|
const templatesRoot = findTemplatesRoot();
|
|
4176
4962
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
@@ -4192,13 +4978,13 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4192
4978
|
copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
|
|
4193
4979
|
const initDir = resolve12(tempWorktree, ".init");
|
|
4194
4980
|
if (existsSync9(initDir)) {
|
|
4195
|
-
|
|
4981
|
+
rmSync5(initDir, { recursive: true, force: true });
|
|
4196
4982
|
}
|
|
4197
4983
|
const homeDir = resolve12(tempWorktree, "home");
|
|
4198
4984
|
if (existsSync9(homeDir)) {
|
|
4199
4985
|
for (const entry of readdirSync2(homeDir)) {
|
|
4200
4986
|
if (entry !== "VOLUTE.md") {
|
|
4201
|
-
|
|
4987
|
+
rmSync5(resolve12(homeDir, entry), { recursive: true, force: true });
|
|
4202
4988
|
}
|
|
4203
4989
|
}
|
|
4204
4990
|
}
|
|
@@ -4214,9 +5000,9 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4214
5000
|
} catch {
|
|
4215
5001
|
}
|
|
4216
5002
|
if (existsSync9(tempWorktree)) {
|
|
4217
|
-
|
|
5003
|
+
rmSync5(tempWorktree, { recursive: true, force: true });
|
|
4218
5004
|
}
|
|
4219
|
-
|
|
5005
|
+
rmSync5(composedDir, { recursive: true, force: true });
|
|
4220
5006
|
}
|
|
4221
5007
|
}
|
|
4222
5008
|
async function mergeTemplateBranch(worktreeDir) {
|
|
@@ -4316,7 +5102,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4316
5102
|
generateIdentity(dest);
|
|
4317
5103
|
}
|
|
4318
5104
|
const state = stateDir(name);
|
|
4319
|
-
|
|
5105
|
+
mkdirSync7(state, { recursive: true });
|
|
4320
5106
|
const envJson = resolve12(tempDir, "state/env.json");
|
|
4321
5107
|
if (existsSync9(envJson)) {
|
|
4322
5108
|
cpSync(envJson, resolve12(state, "env.json"));
|
|
@@ -4344,20 +5130,20 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4344
5130
|
await gitExec(["commit", "-m", "import from archive"], { cwd: dest, mindName: name, env });
|
|
4345
5131
|
} catch (err) {
|
|
4346
5132
|
logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
|
|
4347
|
-
|
|
5133
|
+
rmSync5(resolve12(dest, ".git"), { recursive: true, force: true });
|
|
4348
5134
|
}
|
|
4349
5135
|
}
|
|
4350
5136
|
chownMindDir(dest, name);
|
|
4351
|
-
|
|
5137
|
+
rmSync5(tempDir, { recursive: true, force: true });
|
|
4352
5138
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
4353
5139
|
} catch (err) {
|
|
4354
|
-
if (existsSync9(dest))
|
|
5140
|
+
if (existsSync9(dest)) rmSync5(dest, { recursive: true, force: true });
|
|
4355
5141
|
try {
|
|
4356
5142
|
await removeMind(name);
|
|
4357
5143
|
} catch (cleanupErr) {
|
|
4358
5144
|
logger_default.error(`Failed to clean up registry for ${name}`, logger_default.errorData(cleanupErr));
|
|
4359
5145
|
}
|
|
4360
|
-
|
|
5146
|
+
rmSync5(tempDir, { recursive: true, force: true });
|
|
4361
5147
|
return c.json({ error: err instanceof Error ? err.message : "Failed to import mind" }, 500);
|
|
4362
5148
|
}
|
|
4363
5149
|
}
|
|
@@ -4395,11 +5181,11 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4395
5181
|
const promptsPath = resolve12(dest, "home/.config/prompts.json");
|
|
4396
5182
|
if (!existsSync9(promptsPath)) {
|
|
4397
5183
|
const mindPrompts = await getMindPromptDefaults();
|
|
4398
|
-
|
|
5184
|
+
writeFileSync8(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
|
|
4399
5185
|
`);
|
|
4400
5186
|
}
|
|
4401
5187
|
const state = stateDir(name);
|
|
4402
|
-
|
|
5188
|
+
mkdirSync7(state, { recursive: true });
|
|
4403
5189
|
const envJson = resolve12(tempDir, "state/env.json");
|
|
4404
5190
|
if (existsSync9(envJson)) {
|
|
4405
5191
|
cpSync(envJson, resolve12(state, "env.json"));
|
|
@@ -4419,7 +5205,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4419
5205
|
await initTemplateBranch(dest, composedDir, templateManifest, name, env);
|
|
4420
5206
|
} catch (err) {
|
|
4421
5207
|
logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
|
|
4422
|
-
|
|
5208
|
+
rmSync5(resolve12(dest, ".git"), { recursive: true, force: true });
|
|
4423
5209
|
gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
|
|
4424
5210
|
}
|
|
4425
5211
|
try {
|
|
@@ -4443,7 +5229,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4443
5229
|
publishPublicKey(name, publicKeyPem).catch(
|
|
4444
5230
|
(err) => logger_default.warn(`failed to publish key for ${name}`, { error: err.message })
|
|
4445
5231
|
);
|
|
4446
|
-
|
|
5232
|
+
rmSync5(tempDir, { recursive: true, force: true });
|
|
4447
5233
|
return c.json({
|
|
4448
5234
|
ok: true,
|
|
4449
5235
|
name,
|
|
@@ -4454,16 +5240,16 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4454
5240
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
4455
5241
|
});
|
|
4456
5242
|
} catch (err) {
|
|
4457
|
-
if (existsSync9(dest))
|
|
5243
|
+
if (existsSync9(dest)) rmSync5(dest, { recursive: true, force: true });
|
|
4458
5244
|
try {
|
|
4459
5245
|
await removeMind(name);
|
|
4460
5246
|
} catch (cleanupErr) {
|
|
4461
5247
|
logger_default.error(`Failed to clean up registry for ${name}`, logger_default.errorData(cleanupErr));
|
|
4462
5248
|
}
|
|
4463
|
-
|
|
5249
|
+
rmSync5(tempDir, { recursive: true, force: true });
|
|
4464
5250
|
return c.json({ error: err instanceof Error ? err.message : "Failed to import mind" }, 500);
|
|
4465
5251
|
} finally {
|
|
4466
|
-
|
|
5252
|
+
rmSync5(composedDir, { recursive: true, force: true });
|
|
4467
5253
|
}
|
|
4468
5254
|
}
|
|
4469
5255
|
async function importHistoryFromArchive(name, tempDir) {
|
|
@@ -4511,7 +5297,7 @@ function importSessionsFromArchive(dest, tempDir) {
|
|
|
4511
5297
|
if (!existsSync9(sessionsDir)) return;
|
|
4512
5298
|
try {
|
|
4513
5299
|
const destSessions = resolve12(dest, ".mind/sessions");
|
|
4514
|
-
|
|
5300
|
+
mkdirSync7(destSessions, { recursive: true });
|
|
4515
5301
|
for (const file of readdirSync2(sessionsDir)) {
|
|
4516
5302
|
cpSync(resolve12(sessionsDir, file), resolve12(destSessions, file));
|
|
4517
5303
|
}
|
|
@@ -4556,19 +5342,21 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
|
|
|
4556
5342
|
applyInitFiles(dest);
|
|
4557
5343
|
const { publicKeyPem } = generateIdentity(dest);
|
|
4558
5344
|
{
|
|
5345
|
+
const { readGlobalConfig: readGlobal } = await import("./setup-GGMKENLN.js");
|
|
5346
|
+
const mindDefaults = readGlobal().mindDefaults;
|
|
4559
5347
|
const config2 = readVoluteConfig(dest);
|
|
4560
5348
|
if (!config2) throw new Error("Failed to read volute.json after identity generation");
|
|
4561
5349
|
if (body.description) {
|
|
4562
5350
|
config2.profile = { ...config2.profile, description: body.description };
|
|
4563
5351
|
}
|
|
4564
5352
|
if (!config2.sleep) {
|
|
4565
|
-
config2.sleep = {
|
|
5353
|
+
config2.sleep = mindDefaults?.sleep ?? {
|
|
4566
5354
|
enabled: true,
|
|
4567
5355
|
schedule: { sleep: "0 0 * * *", wake: "0 8 * * *" }
|
|
4568
5356
|
};
|
|
4569
5357
|
}
|
|
4570
5358
|
if (!config2.schedules || config2.schedules.length === 0) {
|
|
4571
|
-
config2.schedules = [
|
|
5359
|
+
config2.schedules = mindDefaults?.schedules ?? [
|
|
4572
5360
|
{
|
|
4573
5361
|
id: "heartbeat",
|
|
4574
5362
|
cron: "0 12,16,20 * * *",
|
|
@@ -4578,17 +5366,34 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
|
|
|
4578
5366
|
}
|
|
4579
5367
|
];
|
|
4580
5368
|
}
|
|
5369
|
+
const cog = mindDefaults?.cognition;
|
|
5370
|
+
if (cog) {
|
|
5371
|
+
if (cog.thinkingLevel != null && !config2.thinkingLevel)
|
|
5372
|
+
config2.thinkingLevel = cog.thinkingLevel;
|
|
5373
|
+
if (cog.maxThinkingTokens != null && config2.maxThinkingTokens == null)
|
|
5374
|
+
config2.maxThinkingTokens = cog.maxThinkingTokens;
|
|
5375
|
+
if (cog.tokenBudget != null && config2.tokenBudget == null)
|
|
5376
|
+
config2.tokenBudget = cog.tokenBudget;
|
|
5377
|
+
if (cog.tokenBudgetPeriodMinutes != null && config2.tokenBudgetPeriodMinutes == null)
|
|
5378
|
+
config2.tokenBudgetPeriodMinutes = cog.tokenBudgetPeriodMinutes;
|
|
5379
|
+
}
|
|
4581
5380
|
writeVoluteConfig(dest, config2);
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
5381
|
+
const modelId = body.model ?? cog?.model;
|
|
5382
|
+
const sdkConfigPath = resolve12(dest, "home/.config/config.json");
|
|
5383
|
+
if (modelId || cog?.compaction) {
|
|
5384
|
+
const existing = existsSync9(sdkConfigPath) ? JSON.parse(readFileSync10(sdkConfigPath, "utf-8")) : {};
|
|
5385
|
+
if (modelId) {
|
|
5386
|
+
existing.model = template === "pi" ? qualifyModelId(modelId) : unqualifyModelId(modelId);
|
|
5387
|
+
}
|
|
5388
|
+
if (cog?.compaction && !existing.compaction) {
|
|
5389
|
+
existing.compaction = cog.compaction;
|
|
5390
|
+
}
|
|
5391
|
+
writeFileSync8(sdkConfigPath, `${JSON.stringify(existing, null, 2)}
|
|
4588
5392
|
`);
|
|
5393
|
+
}
|
|
4589
5394
|
}
|
|
4590
5395
|
const mindPrompts = await getMindPromptDefaults();
|
|
4591
|
-
|
|
5396
|
+
writeFileSync8(
|
|
4592
5397
|
resolve12(dest, "home/.config/prompts.json"),
|
|
4593
5398
|
`${JSON.stringify(mindPrompts, null, 2)}
|
|
4594
5399
|
`
|
|
@@ -4614,7 +5419,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
|
|
|
4614
5419
|
await initTemplateBranch(dest, composedDir, manifest, name, env);
|
|
4615
5420
|
} catch (err) {
|
|
4616
5421
|
logger_default.error(`git setup failed for ${name}`, logger_default.errorData(err));
|
|
4617
|
-
|
|
5422
|
+
rmSync5(resolve12(dest, ".git"), { recursive: true, force: true });
|
|
4618
5423
|
gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
|
|
4619
5424
|
}
|
|
4620
5425
|
try {
|
|
@@ -4629,11 +5434,11 @@ The human who planted you described you as: "${body.description}"
|
|
|
4629
5434
|
` : "";
|
|
4630
5435
|
const seedSoulRaw = body.seedSoul ?? await getPrompt("seed_soul", { name, description: descLine });
|
|
4631
5436
|
const seedSoul = body.seedSoul ? substitute(seedSoulRaw, { name, description: descLine }) : seedSoulRaw;
|
|
4632
|
-
|
|
5437
|
+
writeFileSync8(resolve12(dest, "home/SOUL.md"), seedSoul);
|
|
4633
5438
|
}
|
|
4634
5439
|
let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
|
|
4635
5440
|
if (body.stage === "seed" && !body.skills) {
|
|
4636
|
-
const { isImagegenEnabled } = await import("./setup-
|
|
5441
|
+
const { isImagegenEnabled } = await import("./setup-GGMKENLN.js");
|
|
4637
5442
|
if (isImagegenEnabled()) {
|
|
4638
5443
|
skillSet = [...skillSet, "imagegen"];
|
|
4639
5444
|
}
|
|
@@ -4651,7 +5456,7 @@ The human who planted you described you as: "${body.description}"
|
|
|
4651
5456
|
try {
|
|
4652
5457
|
const spiritEntry = await findMind("volute");
|
|
4653
5458
|
if (spiritEntry) {
|
|
4654
|
-
const { spiritDir } = await import("./spirit-
|
|
5459
|
+
const { spiritDir } = await import("./spirit-4JP4TY4C.js");
|
|
4655
5460
|
const sDir = spiritEntry.dir ?? spiritDir();
|
|
4656
5461
|
const spiritConfig = readVoluteConfig(sDir) ?? {};
|
|
4657
5462
|
const schedules = spiritConfig.schedules ?? [];
|
|
@@ -4666,7 +5471,7 @@ The human who planted you described you as: "${body.description}"
|
|
|
4666
5471
|
});
|
|
4667
5472
|
spiritConfig.schedules = schedules;
|
|
4668
5473
|
writeVoluteConfig(sDir, spiritConfig);
|
|
4669
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
5474
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-AGG3L2FO.js");
|
|
4670
5475
|
getScheduler2().loadSchedules("volute", sDir);
|
|
4671
5476
|
}
|
|
4672
5477
|
}
|
|
@@ -4677,11 +5482,11 @@ The human who planted you described you as: "${body.description}"
|
|
|
4677
5482
|
if (body.stage !== "seed") {
|
|
4678
5483
|
const customSoul = await getPromptIfCustom("default_soul");
|
|
4679
5484
|
if (customSoul) {
|
|
4680
|
-
|
|
5485
|
+
writeFileSync8(resolve12(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
|
|
4681
5486
|
}
|
|
4682
5487
|
const customMemory = await getPromptIfCustom("default_memory");
|
|
4683
5488
|
if (customMemory) {
|
|
4684
|
-
|
|
5489
|
+
writeFileSync8(resolve12(dest, "home/MEMORY.md"), customMemory);
|
|
4685
5490
|
}
|
|
4686
5491
|
}
|
|
4687
5492
|
publishPublicKey(name, publicKeyPem).catch(
|
|
@@ -4710,14 +5515,14 @@ The human who planted you described you as: "${body.description}"
|
|
|
4710
5515
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
4711
5516
|
});
|
|
4712
5517
|
} catch (err) {
|
|
4713
|
-
if (existsSync9(dest))
|
|
5518
|
+
if (existsSync9(dest)) rmSync5(dest, { recursive: true, force: true });
|
|
4714
5519
|
try {
|
|
4715
5520
|
await removeMind(name);
|
|
4716
5521
|
} catch {
|
|
4717
5522
|
}
|
|
4718
5523
|
return c.json({ error: err instanceof Error ? err.message : "Failed to create mind" }, 500);
|
|
4719
5524
|
} finally {
|
|
4720
|
-
|
|
5525
|
+
rmSync5(composedDir, { recursive: true, force: true });
|
|
4721
5526
|
}
|
|
4722
5527
|
}).post("/import", requireAdmin, async (c) => {
|
|
4723
5528
|
let body;
|
|
@@ -4763,17 +5568,17 @@ ${user.trimEnd()}
|
|
|
4763
5568
|
copyTemplateToDir(composedDir, dest, name, manifest);
|
|
4764
5569
|
applyInitFiles(dest);
|
|
4765
5570
|
const { publicKeyPem: importPublicKey } = generateIdentity(dest);
|
|
4766
|
-
|
|
5571
|
+
writeFileSync8(resolve12(dest, "home/SOUL.md"), mergedSoul);
|
|
4767
5572
|
const wsMemoryPath = resolve12(wsDir, "MEMORY.md");
|
|
4768
5573
|
const hasMemory = existsSync9(wsMemoryPath);
|
|
4769
5574
|
if (hasMemory) {
|
|
4770
5575
|
const existingMemory = readFileSync10(wsMemoryPath, "utf-8");
|
|
4771
|
-
|
|
5576
|
+
writeFileSync8(
|
|
4772
5577
|
resolve12(dest, "home/MEMORY.md"),
|
|
4773
5578
|
`${existingMemory.trimEnd()}${mergedMemoryExtra}`
|
|
4774
5579
|
);
|
|
4775
5580
|
} else if (user) {
|
|
4776
|
-
|
|
5581
|
+
writeFileSync8(resolve12(dest, "home/MEMORY.md"), `${user.trimEnd()}
|
|
4777
5582
|
`);
|
|
4778
5583
|
}
|
|
4779
5584
|
const wsMemoryDir = resolve12(wsDir, "memory");
|
|
@@ -4813,8 +5618,8 @@ ${user.trimEnd()}
|
|
|
4813
5618
|
} else if (template === "claude") {
|
|
4814
5619
|
const sessionId = convertSession({ sessionPath: sessionFile, projectDir: dest });
|
|
4815
5620
|
const mindRuntimeDir = resolve12(dest, ".mind");
|
|
4816
|
-
|
|
4817
|
-
|
|
5621
|
+
mkdirSync7(mindRuntimeDir, { recursive: true });
|
|
5622
|
+
writeFileSync8(resolve12(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
|
|
4818
5623
|
}
|
|
4819
5624
|
}
|
|
4820
5625
|
importOpenClawConnectors(name, dest);
|
|
@@ -4829,14 +5634,14 @@ ${user.trimEnd()}
|
|
|
4829
5634
|
);
|
|
4830
5635
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
4831
5636
|
} catch (err) {
|
|
4832
|
-
if (existsSync9(dest))
|
|
5637
|
+
if (existsSync9(dest)) rmSync5(dest, { recursive: true, force: true });
|
|
4833
5638
|
try {
|
|
4834
5639
|
await removeMind(name);
|
|
4835
5640
|
} catch {
|
|
4836
5641
|
}
|
|
4837
5642
|
return c.json({ error: err instanceof Error ? err.message : "Failed to import mind" }, 500);
|
|
4838
5643
|
} finally {
|
|
4839
|
-
|
|
5644
|
+
rmSync5(composedDir, { recursive: true, force: true });
|
|
4840
5645
|
}
|
|
4841
5646
|
}).get("/", async (c) => {
|
|
4842
5647
|
const entries = await readRegistry();
|
|
@@ -4884,6 +5689,32 @@ ${user.trimEnd()}
|
|
|
4884
5689
|
);
|
|
4885
5690
|
const hasPages = existsSync9(resolve12(mindDir(name), "home", "public", "pages"));
|
|
4886
5691
|
return c.json({ ...entry, ...mindStatus, variants: variantStatuses, hasPages });
|
|
5692
|
+
}).get("/:name/context", async (c) => {
|
|
5693
|
+
const name = c.req.param("name");
|
|
5694
|
+
const entry = await findMind(name);
|
|
5695
|
+
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5696
|
+
if (!getMindManager().isRunning(name)) {
|
|
5697
|
+
return c.json({ error: "Mind is not running" }, 503);
|
|
5698
|
+
}
|
|
5699
|
+
try {
|
|
5700
|
+
const res = await fetch(`http://127.0.0.1:${entry.port}/context`, {
|
|
5701
|
+
signal: AbortSignal.timeout(3e3)
|
|
5702
|
+
});
|
|
5703
|
+
if (!res.ok) {
|
|
5704
|
+
const status = res.status >= 500 ? 502 : 404;
|
|
5705
|
+
return c.json(
|
|
5706
|
+
{
|
|
5707
|
+
error: res.status >= 500 ? "Mind context handler errored" : "Context endpoint not available"
|
|
5708
|
+
},
|
|
5709
|
+
status
|
|
5710
|
+
);
|
|
5711
|
+
}
|
|
5712
|
+
const data = await res.json();
|
|
5713
|
+
return c.json(data);
|
|
5714
|
+
} catch (err) {
|
|
5715
|
+
console.error(`context proxy for ${name}:`, err);
|
|
5716
|
+
return c.json({ error: "Failed to reach mind" }, 503);
|
|
5717
|
+
}
|
|
4887
5718
|
}).post("/:name/start", requireSelf(), async (c) => {
|
|
4888
5719
|
const name = c.req.param("name");
|
|
4889
5720
|
const entry = await findMind(name);
|
|
@@ -4929,7 +5760,7 @@ ${user.trimEnd()}
|
|
|
4929
5760
|
const manager = getMindManager();
|
|
4930
5761
|
try {
|
|
4931
5762
|
if (context?.type === "reload") {
|
|
4932
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5763
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-BJK2ROPX.js");
|
|
4933
5764
|
const sleepState = getSleepManagerIfReady2()?.getState(name);
|
|
4934
5765
|
if (sleepState?.sleeping) {
|
|
4935
5766
|
logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
|
|
@@ -5025,7 +5856,7 @@ ${user.trimEnd()}
|
|
|
5025
5856
|
const name = c.req.param("name");
|
|
5026
5857
|
const entry = await findMind(name);
|
|
5027
5858
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5028
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5859
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-BJK2ROPX.js");
|
|
5029
5860
|
const sm = getSleepManagerIfReady2();
|
|
5030
5861
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5031
5862
|
return c.json(sm.getState(name));
|
|
@@ -5033,7 +5864,7 @@ ${user.trimEnd()}
|
|
|
5033
5864
|
const name = c.req.param("name");
|
|
5034
5865
|
const entry = await findMind(name);
|
|
5035
5866
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5036
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5867
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-BJK2ROPX.js");
|
|
5037
5868
|
const sm = getSleepManagerIfReady2();
|
|
5038
5869
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5039
5870
|
if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
|
|
@@ -5053,7 +5884,7 @@ ${user.trimEnd()}
|
|
|
5053
5884
|
const name = c.req.param("name");
|
|
5054
5885
|
const entry = await findMind(name);
|
|
5055
5886
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5056
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5887
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-BJK2ROPX.js");
|
|
5057
5888
|
const sm = getSleepManagerIfReady2();
|
|
5058
5889
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5059
5890
|
const sleepState = sm.getState(name);
|
|
@@ -5068,7 +5899,7 @@ ${user.trimEnd()}
|
|
|
5068
5899
|
const name = c.req.param("name");
|
|
5069
5900
|
const entry = await findMind(name);
|
|
5070
5901
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5071
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5902
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-BJK2ROPX.js");
|
|
5072
5903
|
const sm = getSleepManagerIfReady2();
|
|
5073
5904
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5074
5905
|
const flushed = await sm.flushQueuedMessages(name);
|
|
@@ -5086,8 +5917,8 @@ ${user.trimEnd()}
|
|
|
5086
5917
|
if (body.avatar !== void 0) profile.avatar = body.avatar;
|
|
5087
5918
|
config2.profile = profile;
|
|
5088
5919
|
writeVoluteConfig(dir, config2);
|
|
5089
|
-
const { syncMindProfile } = await import("./auth-
|
|
5090
|
-
await
|
|
5920
|
+
const { syncMindProfile: syncMindProfile2 } = await import("./auth-ZFZXJZDQ.js");
|
|
5921
|
+
await syncMindProfile2(name, profile);
|
|
5091
5922
|
broadcast({ type: "profile_updated", mind: name, summary: `${name} profile updated` });
|
|
5092
5923
|
return c.json({ ok: true });
|
|
5093
5924
|
}).get("/:name/seed-check", requireSelf(), async (c) => {
|
|
@@ -5133,7 +5964,7 @@ ${user.trimEnd()}
|
|
|
5133
5964
|
const config2 = readVoluteConfig(dir);
|
|
5134
5965
|
const displayNameSet = !!config2?.profile?.displayName;
|
|
5135
5966
|
const avatarSet = !!config2?.profile?.avatar;
|
|
5136
|
-
const { isImagegenEnabled } = await import("./setup-
|
|
5967
|
+
const { isImagegenEnabled } = await import("./setup-GGMKENLN.js");
|
|
5137
5968
|
const imagegenEnabled = isImagegenEnabled();
|
|
5138
5969
|
const done = [];
|
|
5139
5970
|
const remaining = [];
|
|
@@ -5171,7 +6002,7 @@ ${user.trimEnd()}
|
|
|
5171
6002
|
try {
|
|
5172
6003
|
const spiritEntry = await findMind("volute");
|
|
5173
6004
|
if (spiritEntry) {
|
|
5174
|
-
const { spiritDir } = await import("./spirit-
|
|
6005
|
+
const { spiritDir } = await import("./spirit-4JP4TY4C.js");
|
|
5175
6006
|
const sDir = spiritEntry.dir ?? spiritDir();
|
|
5176
6007
|
const spiritConfig = readVoluteConfig(sDir);
|
|
5177
6008
|
if (spiritConfig?.schedules) {
|
|
@@ -5179,7 +6010,7 @@ ${user.trimEnd()}
|
|
|
5179
6010
|
spiritConfig.schedules = spiritConfig.schedules.filter((s) => s.id !== nurtureId);
|
|
5180
6011
|
if (spiritConfig.schedules.length === 0) spiritConfig.schedules = void 0;
|
|
5181
6012
|
writeVoluteConfig(sDir, spiritConfig);
|
|
5182
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
6013
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-AGG3L2FO.js");
|
|
5183
6014
|
getScheduler2().loadSchedules("volute", sDir);
|
|
5184
6015
|
}
|
|
5185
6016
|
}
|
|
@@ -5212,10 +6043,10 @@ ${user.trimEnd()}
|
|
|
5212
6043
|
await deleteMindUser2(name);
|
|
5213
6044
|
const state = stateDir(name);
|
|
5214
6045
|
if (existsSync9(state)) {
|
|
5215
|
-
|
|
6046
|
+
rmSync5(state, { recursive: true, force: true });
|
|
5216
6047
|
}
|
|
5217
6048
|
if (force && existsSync9(dir)) {
|
|
5218
|
-
|
|
6049
|
+
rmSync5(dir, { recursive: true, force: true });
|
|
5219
6050
|
deleteMindUser(name);
|
|
5220
6051
|
}
|
|
5221
6052
|
fireWebhook({
|
|
@@ -5363,7 +6194,7 @@ ${user.trimEnd()}
|
|
|
5363
6194
|
await gitExec(["commit", "-m", "initial commit"], { cwd: dir, mindName, env });
|
|
5364
6195
|
chownMindDir(dir, mindName);
|
|
5365
6196
|
} catch (err) {
|
|
5366
|
-
|
|
6197
|
+
rmSync5(resolve12(dir, ".git"), { recursive: true, force: true });
|
|
5367
6198
|
return c.json(
|
|
5368
6199
|
{
|
|
5369
6200
|
error: `Git initialization failed: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -5390,7 +6221,7 @@ ${user.trimEnd()}
|
|
|
5390
6221
|
await updateTemplateBranch(dir, template, mindName);
|
|
5391
6222
|
const parentDir = resolve12(dir, ".variants");
|
|
5392
6223
|
if (!existsSync9(parentDir)) {
|
|
5393
|
-
|
|
6224
|
+
mkdirSync7(parentDir, { recursive: true });
|
|
5394
6225
|
}
|
|
5395
6226
|
await gitExec(["worktree", "add", "-b", UPGRADE_BRANCH, worktreeDir], { cwd: dir });
|
|
5396
6227
|
await gitExec(["rm", "-r", "--cached", "--ignore-unmatch", "home/"], {
|
|
@@ -5517,7 +6348,7 @@ ${user.trimEnd()}
|
|
|
5517
6348
|
const name = c.req.param("name");
|
|
5518
6349
|
const entry = await findMind(name);
|
|
5519
6350
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5520
|
-
const dir = mindDir(name);
|
|
6351
|
+
const dir = entry.dir ?? mindDir(name);
|
|
5521
6352
|
if (!existsSync9(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5522
6353
|
let config2 = readVoluteConfig(dir);
|
|
5523
6354
|
if (!config2 && entry.template === "pi") {
|
|
@@ -5529,6 +6360,14 @@ ${user.trimEnd()}
|
|
|
5529
6360
|
}
|
|
5530
6361
|
}
|
|
5531
6362
|
}
|
|
6363
|
+
let templateConfig = {};
|
|
6364
|
+
const configJsonPath = resolve12(dir, "home/.config/config.json");
|
|
6365
|
+
if (existsSync9(configJsonPath)) {
|
|
6366
|
+
try {
|
|
6367
|
+
templateConfig = JSON.parse(readFileSync10(configJsonPath, "utf-8"));
|
|
6368
|
+
} catch {
|
|
6369
|
+
}
|
|
6370
|
+
}
|
|
5532
6371
|
return c.json({
|
|
5533
6372
|
registry: {
|
|
5534
6373
|
name: entry.name,
|
|
@@ -5538,10 +6377,26 @@ ${user.trimEnd()}
|
|
|
5538
6377
|
template: entry.template
|
|
5539
6378
|
},
|
|
5540
6379
|
config: {
|
|
5541
|
-
model: config2?.model ?? null,
|
|
5542
|
-
thinkingLevel:
|
|
6380
|
+
model: config2?.model ?? templateConfig.model ?? null,
|
|
6381
|
+
thinkingLevel: (() => {
|
|
6382
|
+
if (config2?.thinkingLevel) return config2.thinkingLevel;
|
|
6383
|
+
const tc = templateConfig;
|
|
6384
|
+
if (tc.thinkingLevel) return tc.thinkingLevel;
|
|
6385
|
+
if (tc.reasoningEffort) return tc.reasoningEffort;
|
|
6386
|
+
const mtt = tc.maxThinkingTokens;
|
|
6387
|
+
if (mtt) {
|
|
6388
|
+
if (mtt <= 1024) return "minimal";
|
|
6389
|
+
if (mtt <= 4096) return "low";
|
|
6390
|
+
if (mtt <= 1e4) return "medium";
|
|
6391
|
+
if (mtt <= 32e3) return "high";
|
|
6392
|
+
return "xhigh";
|
|
6393
|
+
}
|
|
6394
|
+
return null;
|
|
6395
|
+
})(),
|
|
6396
|
+
maxThinkingTokens: config2?.maxThinkingTokens ?? templateConfig.maxThinkingTokens ?? null,
|
|
5543
6397
|
tokenBudget: config2?.tokenBudget ?? null,
|
|
5544
|
-
tokenBudgetPeriodMinutes: config2?.tokenBudgetPeriodMinutes ?? null
|
|
6398
|
+
tokenBudgetPeriodMinutes: config2?.tokenBudgetPeriodMinutes ?? null,
|
|
6399
|
+
compaction: templateConfig.compaction ?? null
|
|
5545
6400
|
}
|
|
5546
6401
|
});
|
|
5547
6402
|
}).put(
|
|
@@ -5552,15 +6407,17 @@ ${user.trimEnd()}
|
|
|
5552
6407
|
z5.object({
|
|
5553
6408
|
model: z5.string().optional(),
|
|
5554
6409
|
thinkingLevel: z5.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional(),
|
|
6410
|
+
maxThinkingTokens: z5.number().int().positive().nullable().optional(),
|
|
5555
6411
|
tokenBudget: z5.number().int().positive().nullable().optional(),
|
|
5556
|
-
tokenBudgetPeriodMinutes: z5.number().int().positive().nullable().optional()
|
|
6412
|
+
tokenBudgetPeriodMinutes: z5.number().int().positive().nullable().optional(),
|
|
6413
|
+
compaction: z5.object({ maxContextTokens: z5.number().int().positive().nullable().optional() }).nullable().optional()
|
|
5557
6414
|
})
|
|
5558
6415
|
),
|
|
5559
6416
|
async (c) => {
|
|
5560
6417
|
const name = c.req.param("name");
|
|
5561
6418
|
const entry = await findMind(name);
|
|
5562
6419
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5563
|
-
const dir = mindDir(name);
|
|
6420
|
+
const dir = entry.dir ?? mindDir(name);
|
|
5564
6421
|
if (!existsSync9(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5565
6422
|
const body = c.req.valid("json");
|
|
5566
6423
|
const existing = readVoluteConfig(dir) ?? {};
|
|
@@ -5582,7 +6439,96 @@ ${user.trimEnd()}
|
|
|
5582
6439
|
existing.tokenBudgetPeriodMinutes = body.tokenBudgetPeriodMinutes;
|
|
5583
6440
|
}
|
|
5584
6441
|
}
|
|
6442
|
+
if (body.maxThinkingTokens !== void 0) {
|
|
6443
|
+
if (body.maxThinkingTokens === null) {
|
|
6444
|
+
delete existing.maxThinkingTokens;
|
|
6445
|
+
} else {
|
|
6446
|
+
existing.maxThinkingTokens = body.maxThinkingTokens;
|
|
6447
|
+
}
|
|
6448
|
+
}
|
|
5585
6449
|
writeVoluteConfig(dir, existing);
|
|
6450
|
+
const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.maxThinkingTokens !== void 0 || body.compaction !== void 0;
|
|
6451
|
+
if (needsConfigJson) {
|
|
6452
|
+
const configJsonPath = resolve12(dir, "home/.config/config.json");
|
|
6453
|
+
let templateConfig = {};
|
|
6454
|
+
if (existsSync9(configJsonPath)) {
|
|
6455
|
+
try {
|
|
6456
|
+
templateConfig = JSON.parse(readFileSync10(configJsonPath, "utf-8"));
|
|
6457
|
+
} catch {
|
|
6458
|
+
}
|
|
6459
|
+
}
|
|
6460
|
+
if (body.model !== void 0) {
|
|
6461
|
+
templateConfig.model = body.model;
|
|
6462
|
+
}
|
|
6463
|
+
const tmpl = entry.template ?? "claude";
|
|
6464
|
+
if (body.thinkingLevel !== void 0) {
|
|
6465
|
+
if (tmpl === "claude") {
|
|
6466
|
+
const claudeThinkingTokens = {
|
|
6467
|
+
off: null,
|
|
6468
|
+
minimal: 1024,
|
|
6469
|
+
low: 4096,
|
|
6470
|
+
medium: 1e4,
|
|
6471
|
+
high: 32e3,
|
|
6472
|
+
xhigh: 128e3
|
|
6473
|
+
};
|
|
6474
|
+
const tokens = claudeThinkingTokens[body.thinkingLevel] ?? null;
|
|
6475
|
+
if (tokens === null) {
|
|
6476
|
+
delete templateConfig.maxThinkingTokens;
|
|
6477
|
+
} else {
|
|
6478
|
+
templateConfig.maxThinkingTokens = tokens;
|
|
6479
|
+
}
|
|
6480
|
+
} else if (tmpl === "codex") {
|
|
6481
|
+
const codexMap = {
|
|
6482
|
+
off: null,
|
|
6483
|
+
minimal: "minimal",
|
|
6484
|
+
low: "low",
|
|
6485
|
+
medium: "medium",
|
|
6486
|
+
high: "high",
|
|
6487
|
+
xhigh: "xhigh"
|
|
6488
|
+
};
|
|
6489
|
+
const effort = codexMap[body.thinkingLevel] ?? null;
|
|
6490
|
+
if (effort === null) {
|
|
6491
|
+
delete templateConfig.reasoningEffort;
|
|
6492
|
+
} else {
|
|
6493
|
+
templateConfig.reasoningEffort = effort;
|
|
6494
|
+
}
|
|
6495
|
+
} else {
|
|
6496
|
+
templateConfig.thinkingLevel = body.thinkingLevel;
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6499
|
+
if (body.maxThinkingTokens !== void 0) {
|
|
6500
|
+
if (body.maxThinkingTokens === null) {
|
|
6501
|
+
delete templateConfig.maxThinkingTokens;
|
|
6502
|
+
} else {
|
|
6503
|
+
templateConfig.maxThinkingTokens = body.maxThinkingTokens;
|
|
6504
|
+
}
|
|
6505
|
+
}
|
|
6506
|
+
if (body.compaction !== void 0) {
|
|
6507
|
+
if (body.compaction === null) {
|
|
6508
|
+
delete templateConfig.compaction;
|
|
6509
|
+
} else {
|
|
6510
|
+
const comp = templateConfig.compaction ?? {};
|
|
6511
|
+
if (body.compaction.maxContextTokens === null) {
|
|
6512
|
+
delete comp.maxContextTokens;
|
|
6513
|
+
} else if (body.compaction.maxContextTokens !== void 0) {
|
|
6514
|
+
comp.maxContextTokens = body.compaction.maxContextTokens;
|
|
6515
|
+
}
|
|
6516
|
+
templateConfig.compaction = comp;
|
|
6517
|
+
}
|
|
6518
|
+
}
|
|
6519
|
+
writeFileSync8(configJsonPath, `${JSON.stringify(templateConfig, null, 2)}
|
|
6520
|
+
`);
|
|
6521
|
+
}
|
|
6522
|
+
if (entry.mindType === "spirit" && body.model !== void 0) {
|
|
6523
|
+
try {
|
|
6524
|
+
const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-GGMKENLN.js");
|
|
6525
|
+
const globalConfig = readGlobalConfig2();
|
|
6526
|
+
globalConfig.spiritModel = body.model;
|
|
6527
|
+
writeGlobalConfig2(globalConfig);
|
|
6528
|
+
} catch (err) {
|
|
6529
|
+
logger_default.warn("failed to sync spirit model to global config", logger_default.errorData(err));
|
|
6530
|
+
}
|
|
6531
|
+
}
|
|
5586
6532
|
return c.json({ ok: true });
|
|
5587
6533
|
}
|
|
5588
6534
|
).get("/:name/delivery/pending", async (c) => {
|
|
@@ -5603,7 +6549,7 @@ ${user.trimEnd()}
|
|
|
5603
6549
|
if (!body.systemPrompt || !body.message) {
|
|
5604
6550
|
return c.json({ error: "systemPrompt and message required" }, 400);
|
|
5605
6551
|
}
|
|
5606
|
-
const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-
|
|
6552
|
+
const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-PSILB5WD.js");
|
|
5607
6553
|
if (!isAiConfigured()) {
|
|
5608
6554
|
return c.json({ error: "AI service not configured" }, 503);
|
|
5609
6555
|
}
|
|
@@ -5905,18 +6851,18 @@ ${user.trimEnd()}
|
|
|
5905
6851
|
sinceTimestamp = new Date(Date.now() - 36e5).toISOString().replace("T", " ").slice(0, 19);
|
|
5906
6852
|
}
|
|
5907
6853
|
const conditions = [
|
|
5908
|
-
eq6(
|
|
5909
|
-
eq6(
|
|
5910
|
-
sql3`${
|
|
6854
|
+
eq6(summaries.mind, name),
|
|
6855
|
+
eq6(summaries.period, "turn"),
|
|
6856
|
+
sql3`${summaries.created_at} > ${sinceTimestamp}`
|
|
5911
6857
|
];
|
|
5912
6858
|
if (currentSession) {
|
|
5913
|
-
conditions.push(sql3`${
|
|
6859
|
+
conditions.push(sql3`${turns.session} != ${currentSession}`);
|
|
5914
6860
|
}
|
|
5915
6861
|
const rows = await db.select({
|
|
5916
|
-
session:
|
|
5917
|
-
content:
|
|
5918
|
-
created_at:
|
|
5919
|
-
}).from(
|
|
6862
|
+
session: turns.session,
|
|
6863
|
+
content: summaries.content,
|
|
6864
|
+
created_at: summaries.created_at
|
|
6865
|
+
}).from(summaries).innerJoin(turns, eq6(turns.id, summaries.period_key)).where(and5(...conditions)).orderBy(desc4(summaries.created_at)).limit(50);
|
|
5920
6866
|
if (rows.length === 0) {
|
|
5921
6867
|
return c.json({ context: null });
|
|
5922
6868
|
}
|
|
@@ -5944,20 +6890,64 @@ ${lines.join("\n")}` });
|
|
|
5944
6890
|
conditions.push(eq6(mindHistory.session, session));
|
|
5945
6891
|
}
|
|
5946
6892
|
const effectivePreset = full ? "all" : preset;
|
|
6893
|
+
if (!effectivePreset || effectivePreset === "summary") {
|
|
6894
|
+
const sumConditions = [eq6(summaries.mind, name), eq6(summaries.period, "turn")];
|
|
6895
|
+
if (session) {
|
|
6896
|
+
sumConditions.push(eq6(turns.session, session));
|
|
6897
|
+
const sumRows2 = await db.select({
|
|
6898
|
+
id: summaries.id,
|
|
6899
|
+
mind: summaries.mind,
|
|
6900
|
+
period: summaries.period,
|
|
6901
|
+
period_key: summaries.period_key,
|
|
6902
|
+
content: summaries.content,
|
|
6903
|
+
metadata: summaries.metadata,
|
|
6904
|
+
created_at: summaries.created_at,
|
|
6905
|
+
session: turns.session
|
|
6906
|
+
}).from(summaries).innerJoin(turns, eq6(turns.id, summaries.period_key)).where(and5(...sumConditions)).orderBy(desc4(summaries.created_at)).limit(limit).offset(offset);
|
|
6907
|
+
return c.json(
|
|
6908
|
+
sumRows2.map((r) => ({
|
|
6909
|
+
id: r.id,
|
|
6910
|
+
mind: r.mind,
|
|
6911
|
+
type: "summary",
|
|
6912
|
+
channel: null,
|
|
6913
|
+
session: r.session,
|
|
6914
|
+
sender: null,
|
|
6915
|
+
message_id: null,
|
|
6916
|
+
content: r.content,
|
|
6917
|
+
metadata: r.metadata,
|
|
6918
|
+
turn_id: r.period_key,
|
|
6919
|
+
created_at: r.created_at
|
|
6920
|
+
}))
|
|
6921
|
+
);
|
|
6922
|
+
}
|
|
6923
|
+
const sumRows = await db.select().from(summaries).where(and5(...sumConditions)).orderBy(desc4(summaries.created_at)).limit(limit).offset(offset);
|
|
6924
|
+
return c.json(
|
|
6925
|
+
sumRows.map((r) => ({
|
|
6926
|
+
id: r.id,
|
|
6927
|
+
mind: r.mind,
|
|
6928
|
+
type: "summary",
|
|
6929
|
+
channel: null,
|
|
6930
|
+
session: null,
|
|
6931
|
+
sender: null,
|
|
6932
|
+
message_id: null,
|
|
6933
|
+
content: r.content,
|
|
6934
|
+
metadata: r.metadata,
|
|
6935
|
+
turn_id: r.period_key,
|
|
6936
|
+
created_at: r.created_at
|
|
6937
|
+
}))
|
|
6938
|
+
);
|
|
6939
|
+
}
|
|
5947
6940
|
switch (effectivePreset) {
|
|
5948
6941
|
case "all":
|
|
5949
6942
|
break;
|
|
5950
6943
|
case "conversation":
|
|
5951
|
-
conditions.push(sql3`${mindHistory.type} IN ('
|
|
6944
|
+
conditions.push(sql3`${mindHistory.type} IN ('inbound','outbound','tool_use')`);
|
|
5952
6945
|
break;
|
|
5953
6946
|
case "detailed":
|
|
5954
6947
|
conditions.push(
|
|
5955
|
-
sql3`${mindHistory.type} IN ('
|
|
6948
|
+
sql3`${mindHistory.type} IN ('inbound','outbound','tool_use','tool_result','text','thinking')`
|
|
5956
6949
|
);
|
|
5957
6950
|
break;
|
|
5958
|
-
default:
|
|
5959
|
-
conditions.push(sql3`${mindHistory.type} IN ('summary')`);
|
|
5960
|
-
break;
|
|
5961
6951
|
}
|
|
5962
6952
|
const rows = await db.select().from(mindHistory).where(and5(...conditions)).orderBy(desc4(mindHistory.created_at)).limit(limit).offset(offset);
|
|
5963
6953
|
return c.json(rows);
|
|
@@ -6132,23 +7122,20 @@ var app16 = new Hono18().get("/:name/clock/status", async (c) => {
|
|
|
6132
7122
|
const sleepConfig = sleepManager?.getSleepConfig(name) ?? null;
|
|
6133
7123
|
const schedules = readSchedules(name);
|
|
6134
7124
|
const now = /* @__PURE__ */ new Date();
|
|
6135
|
-
const in24h = new Date(now.getTime() + 24 * 60 * 6e4);
|
|
6136
7125
|
const upcoming = [];
|
|
6137
7126
|
const previous = [];
|
|
6138
7127
|
for (const s of schedules) {
|
|
6139
7128
|
if (!s.enabled) continue;
|
|
6140
7129
|
if (s.fireAt) {
|
|
6141
7130
|
const fireDate = new Date(s.fireAt);
|
|
6142
|
-
if (fireDate >= now
|
|
7131
|
+
if (fireDate >= now) {
|
|
6143
7132
|
upcoming.push({ id: s.id, at: fireDate.toISOString(), type: "timer" });
|
|
6144
7133
|
}
|
|
6145
7134
|
} else if (s.cron) {
|
|
6146
7135
|
try {
|
|
6147
7136
|
const interval = CronExpressionParser.parse(s.cron);
|
|
6148
7137
|
const next = interval.next().toDate();
|
|
6149
|
-
|
|
6150
|
-
upcoming.push({ id: s.id, at: next.toISOString(), type: "cron" });
|
|
6151
|
-
}
|
|
7138
|
+
upcoming.push({ id: s.id, at: next.toISOString(), type: "cron" });
|
|
6152
7139
|
} catch {
|
|
6153
7140
|
slog2.warn(`invalid cron "${s.cron}" for schedule "${s.id}" of ${name}`);
|
|
6154
7141
|
}
|
|
@@ -6160,9 +7147,61 @@ var app16 = new Hono18().get("/:name/clock/status", async (c) => {
|
|
|
6160
7147
|
}
|
|
6161
7148
|
}
|
|
6162
7149
|
}
|
|
7150
|
+
if (sleepState?.sleeping) {
|
|
7151
|
+
if (sleepState.scheduledWakeAt) {
|
|
7152
|
+
upcoming.push({ id: "sleep", at: sleepState.scheduledWakeAt, type: "cron" });
|
|
7153
|
+
}
|
|
7154
|
+
if (sleepState.sleepingSince) {
|
|
7155
|
+
previous.push({ id: "sleep", at: sleepState.sleepingSince });
|
|
7156
|
+
}
|
|
7157
|
+
} else if (sleepConfig?.enabled && sleepConfig.schedule) {
|
|
7158
|
+
try {
|
|
7159
|
+
const sleepInterval = CronExpressionParser.parse(sleepConfig.schedule.sleep);
|
|
7160
|
+
const nextSleep = sleepInterval.next().toDate();
|
|
7161
|
+
upcoming.push({ id: "sleep", at: nextSleep.toISOString(), type: "cron" });
|
|
7162
|
+
} catch {
|
|
7163
|
+
}
|
|
7164
|
+
try {
|
|
7165
|
+
const prevWakeInterval = CronExpressionParser.parse(sleepConfig.schedule.wake);
|
|
7166
|
+
const prevWake = prevWakeInterval.prev().toDate();
|
|
7167
|
+
previous.push({ id: "sleep", at: prevWake.toISOString() });
|
|
7168
|
+
} catch {
|
|
7169
|
+
}
|
|
7170
|
+
}
|
|
6163
7171
|
upcoming.sort((a, b) => a.at.localeCompare(b.at));
|
|
6164
7172
|
previous.sort((a, b) => b.at.localeCompare(a.at));
|
|
6165
7173
|
return c.json({ sleep: sleepState, sleepConfig, schedules, upcoming, previous });
|
|
7174
|
+
}).get("/:name/sleep/config", async (c) => {
|
|
7175
|
+
const name = c.req.param("name");
|
|
7176
|
+
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
7177
|
+
const config2 = readVoluteConfig(mindDir(name));
|
|
7178
|
+
return c.json(config2?.sleep ?? { enabled: false });
|
|
7179
|
+
}).put("/:name/sleep/config", requireSelf(), async (c) => {
|
|
7180
|
+
const name = c.req.param("name");
|
|
7181
|
+
const entry = await findMind(name);
|
|
7182
|
+
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
7183
|
+
const body = await c.req.json();
|
|
7184
|
+
if (body.schedule) {
|
|
7185
|
+
for (const field of ["sleep", "wake"]) {
|
|
7186
|
+
if (body.schedule[field]) {
|
|
7187
|
+
try {
|
|
7188
|
+
CronExpressionParser.parse(body.schedule[field]);
|
|
7189
|
+
} catch {
|
|
7190
|
+
return c.json({ error: `Invalid ${field} cron: ${body.schedule[field]}` }, 400);
|
|
7191
|
+
}
|
|
7192
|
+
}
|
|
7193
|
+
}
|
|
7194
|
+
}
|
|
7195
|
+
const dir = mindDir(name);
|
|
7196
|
+
const config2 = readVoluteConfig(dir) ?? {};
|
|
7197
|
+
const sleep = config2.sleep ?? {};
|
|
7198
|
+
if (body.enabled !== void 0) sleep.enabled = body.enabled;
|
|
7199
|
+
if (body.schedule !== void 0) sleep.schedule = body.schedule;
|
|
7200
|
+
if (body.wakeTriggers !== void 0) sleep.wakeTriggers = body.wakeTriggers;
|
|
7201
|
+
config2.sleep = sleep;
|
|
7202
|
+
writeVoluteConfig(dir, config2);
|
|
7203
|
+
getSleepManagerIfReady()?.invalidateSleepConfig(name);
|
|
7204
|
+
return c.json({ ok: true });
|
|
6166
7205
|
}).get("/:name/schedules", async (c) => {
|
|
6167
7206
|
const name = c.req.param("name");
|
|
6168
7207
|
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
@@ -6290,7 +7329,7 @@ var app16 = new Hono18().get("/:name/clock/status", async (c) => {
|
|
|
6290
7329
|
const body = await c.req.text();
|
|
6291
7330
|
const message = `[webhook: ${event}] ${body}`;
|
|
6292
7331
|
try {
|
|
6293
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
7332
|
+
const { sendSystemMessage } = await import("./system-chat-TYLOL7SX.js");
|
|
6294
7333
|
await sendSystemMessage(name, message);
|
|
6295
7334
|
return c.json({ ok: true });
|
|
6296
7335
|
} catch (err) {
|
|
@@ -6301,7 +7340,7 @@ var app16 = new Hono18().get("/:name/clock/status", async (c) => {
|
|
|
6301
7340
|
var schedules_default = app16;
|
|
6302
7341
|
|
|
6303
7342
|
// src/web/api/setup.ts
|
|
6304
|
-
import { mkdirSync as
|
|
7343
|
+
import { mkdirSync as mkdirSync8 } from "fs";
|
|
6305
7344
|
import { homedir as homedir2 } from "os";
|
|
6306
7345
|
import { resolve as resolve14 } from "path";
|
|
6307
7346
|
import { Hono as Hono19 } from "hono";
|
|
@@ -6311,8 +7350,8 @@ var setup = new Hono19();
|
|
|
6311
7350
|
function writeSetupConfig(systemName, description) {
|
|
6312
7351
|
const configHome = process.env.VOLUTE_HOME ?? resolve14(homedir2(), ".volute");
|
|
6313
7352
|
const mindsDir = resolve14(configHome, "minds");
|
|
6314
|
-
|
|
6315
|
-
|
|
7353
|
+
mkdirSync8(configHome, { recursive: true });
|
|
7354
|
+
mkdirSync8(mindsDir, { recursive: true });
|
|
6316
7355
|
const existingConfig = readGlobalConfig();
|
|
6317
7356
|
const setupConfig = {
|
|
6318
7357
|
type: "local",
|
|
@@ -6343,7 +7382,7 @@ setup.get("/status", async (c) => {
|
|
|
6343
7382
|
let hasAccount = false;
|
|
6344
7383
|
if (hasSystem) {
|
|
6345
7384
|
try {
|
|
6346
|
-
const { listUsersByType: listUsersByType2 } = await import("./auth-
|
|
7385
|
+
const { listUsersByType: listUsersByType2 } = await import("./auth-ZFZXJZDQ.js");
|
|
6347
7386
|
const brains = await listUsersByType2("brain");
|
|
6348
7387
|
hasAccount = brains.length > 0;
|
|
6349
7388
|
} catch (err) {
|
|
@@ -6528,7 +7567,7 @@ setup.post("/account", async (c) => {
|
|
|
6528
7567
|
}
|
|
6529
7568
|
}
|
|
6530
7569
|
try {
|
|
6531
|
-
const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-
|
|
7570
|
+
const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-ZFZXJZDQ.js");
|
|
6532
7571
|
const user = await createUser2(body.username.trim(), body.password);
|
|
6533
7572
|
if (body.displayName?.trim()) {
|
|
6534
7573
|
await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
|
|
@@ -6574,7 +7613,7 @@ setup.post("/models", async (c) => {
|
|
|
6574
7613
|
return c.json({ error: "Spirit model is required" }, 400);
|
|
6575
7614
|
}
|
|
6576
7615
|
try {
|
|
6577
|
-
const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-
|
|
7616
|
+
const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-PSILB5WD.js");
|
|
6578
7617
|
setEnabledModels3(body.models);
|
|
6579
7618
|
const config2 = readGlobalConfig();
|
|
6580
7619
|
config2.spiritModel = body.spiritModel.trim();
|
|
@@ -6592,8 +7631,8 @@ setup.post("/complete", async (c) => {
|
|
|
6592
7631
|
return c.json({ error: "Setup already complete" }, 400);
|
|
6593
7632
|
}
|
|
6594
7633
|
try {
|
|
6595
|
-
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-
|
|
6596
|
-
const { startSpiritFull } = await import("./mind-service-
|
|
7634
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-4JP4TY4C.js");
|
|
7635
|
+
const { startSpiritFull } = await import("./mind-service-VIKZJK2M.js");
|
|
6597
7636
|
await ensureSpiritProject();
|
|
6598
7637
|
await syncSpiritTemplate();
|
|
6599
7638
|
const warnings = [];
|
|
@@ -6609,8 +7648,8 @@ setup.post("/complete", async (c) => {
|
|
|
6609
7648
|
}
|
|
6610
7649
|
let spiritConversationId;
|
|
6611
7650
|
try {
|
|
6612
|
-
const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-
|
|
6613
|
-
const { createConversation: createConversation6, findDMConversation: findDMConversation2 } = await import("./conversations-
|
|
7651
|
+
const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-ZFZXJZDQ.js");
|
|
7652
|
+
const { createConversation: createConversation6, findDMConversation: findDMConversation2 } = await import("./conversations-HL2JP5GI.js");
|
|
6614
7653
|
const spiritUser = await getOrCreateMindUser2("volute");
|
|
6615
7654
|
const brains = await listUsersByType2("brain");
|
|
6616
7655
|
const admin2 = brains.find((u) => u.role === "admin");
|
|
@@ -6633,8 +7672,8 @@ setup.post("/complete", async (c) => {
|
|
|
6633
7672
|
logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
|
|
6634
7673
|
if (spiritConversationId && spiritStarted) {
|
|
6635
7674
|
try {
|
|
6636
|
-
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-
|
|
6637
|
-
const { listUsersByType: listUsers6 } = await import("./auth-
|
|
7675
|
+
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-V3R6NXJP.js");
|
|
7676
|
+
const { listUsersByType: listUsers6 } = await import("./auth-ZFZXJZDQ.js");
|
|
6638
7677
|
const admins = await listUsers6("brain");
|
|
6639
7678
|
const admin2 = admins.find((u) => u.role === "admin");
|
|
6640
7679
|
const adminName = admin2?.display_name || admin2?.username || "the admin";
|
|
@@ -6693,7 +7732,7 @@ var app17 = new Hono20().post("/:name/shared/merge", requireAdmin, async (c) =>
|
|
|
6693
7732
|
var shared_default = app17;
|
|
6694
7733
|
|
|
6695
7734
|
// src/web/api/skills.ts
|
|
6696
|
-
import { existsSync as existsSync10, mkdtempSync, readdirSync as readdirSync3, rmSync as
|
|
7735
|
+
import { existsSync as existsSync10, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync6 } from "fs";
|
|
6697
7736
|
import { tmpdir } from "os";
|
|
6698
7737
|
import { join, resolve as resolve15 } from "path";
|
|
6699
7738
|
import AdmZip from "adm-zip";
|
|
@@ -6747,6 +7786,16 @@ var app18 = new Hono21().get("/", async (c) => {
|
|
|
6747
7786
|
removed.add(skill);
|
|
6748
7787
|
writeGlobalConfig({ ...config2, defaultSkills: updated, removedDefaultSkills: [...removed] });
|
|
6749
7788
|
return c.json({ skills: updated });
|
|
7789
|
+
}).get("/auto-update", (c) => {
|
|
7790
|
+
return c.json({ enabled: isAutoUpdateSkillsEnabled() });
|
|
7791
|
+
}).put("/auto-update", requireAdmin, async (c) => {
|
|
7792
|
+
const body = await c.req.json();
|
|
7793
|
+
if (typeof body.enabled !== "boolean") {
|
|
7794
|
+
return c.json({ error: "body.enabled must be a boolean" }, 400);
|
|
7795
|
+
}
|
|
7796
|
+
const config2 = readGlobalConfig();
|
|
7797
|
+
writeGlobalConfig({ ...config2, autoUpdateSkills: body.enabled });
|
|
7798
|
+
return c.json({ enabled: body.enabled });
|
|
6750
7799
|
}).post("/upload", requireAdmin, async (c) => {
|
|
6751
7800
|
const body = await c.req.parseBody();
|
|
6752
7801
|
const file = body.file;
|
|
@@ -6790,7 +7839,7 @@ var app18 = new Hono21().get("/", async (c) => {
|
|
|
6790
7839
|
}
|
|
6791
7840
|
throw e;
|
|
6792
7841
|
} finally {
|
|
6793
|
-
|
|
7842
|
+
rmSync6(tmpDir, { recursive: true, force: true });
|
|
6794
7843
|
}
|
|
6795
7844
|
}).get("/:id", async (c) => {
|
|
6796
7845
|
const id = c.req.param("id");
|
|
@@ -7113,13 +8162,13 @@ var app22 = new Hono25().use("*", authMiddleware).get("/", async (c) => {
|
|
|
7113
8162
|
var events_default = app22;
|
|
7114
8163
|
|
|
7115
8164
|
// src/web/api/variants.ts
|
|
7116
|
-
import { existsSync as existsSync11, mkdirSync as
|
|
8165
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
7117
8166
|
import { resolve as resolve17 } from "path";
|
|
7118
8167
|
import { Hono as Hono26 } from "hono";
|
|
7119
8168
|
|
|
7120
8169
|
// src/lib/spawn-server.ts
|
|
7121
8170
|
import { spawn as spawn4 } from "child_process";
|
|
7122
|
-
import { closeSync, mkdirSync as
|
|
8171
|
+
import { closeSync, mkdirSync as mkdirSync9, openSync, readFileSync as readFileSync11 } from "fs";
|
|
7123
8172
|
import { resolve as resolve16 } from "path";
|
|
7124
8173
|
function tsxBin(cwd) {
|
|
7125
8174
|
return resolve16(cwd, "node_modules", ".bin", "tsx");
|
|
@@ -7158,7 +8207,7 @@ function spawnAttached(cwd, port) {
|
|
|
7158
8207
|
}
|
|
7159
8208
|
function spawnDetached(cwd, port, logDir) {
|
|
7160
8209
|
const logsDir = logDir ?? resolve16(cwd, ".mind", "logs");
|
|
7161
|
-
|
|
8210
|
+
mkdirSync9(logsDir, { recursive: true });
|
|
7162
8211
|
const logPath = resolve16(logsDir, "mind.log");
|
|
7163
8212
|
const logFd = openSync(logPath, "a");
|
|
7164
8213
|
const child = spawn4(tsxBin(cwd), ["src/server.ts", "--port", String(port)], {
|
|
@@ -7279,7 +8328,7 @@ var app23 = new Hono26().get("/:name/variants", async (c) => {
|
|
|
7279
8328
|
if (existsSync11(variantDir)) {
|
|
7280
8329
|
return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
|
|
7281
8330
|
}
|
|
7282
|
-
|
|
8331
|
+
mkdirSync10(resolve17(projectRoot, ".variants"), { recursive: true });
|
|
7283
8332
|
try {
|
|
7284
8333
|
await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
|
|
7285
8334
|
} catch (e) {
|
|
@@ -7302,7 +8351,7 @@ var app23 = new Hono26().get("/:name/variants", async (c) => {
|
|
|
7302
8351
|
return c.json({ error: `npm install failed: ${msg}` }, 500);
|
|
7303
8352
|
}
|
|
7304
8353
|
if (body.soul) {
|
|
7305
|
-
|
|
8354
|
+
writeFileSync9(resolve17(variantDir, "home/SOUL.md"), body.soul);
|
|
7306
8355
|
}
|
|
7307
8356
|
const variantPort = body.port ?? await nextPort();
|
|
7308
8357
|
await addVariant(variantName, mindName, variantPort, variantDir, variantName);
|
|
@@ -7397,8 +8446,8 @@ var app23 = new Hono26().get("/:name/variants", async (c) => {
|
|
|
7397
8446
|
await cleanupVariant(variantName, projectRoot, variantEntry.dir);
|
|
7398
8447
|
if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
|
|
7399
8448
|
try {
|
|
7400
|
-
const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-
|
|
7401
|
-
const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-
|
|
8449
|
+
const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-EJRTKE36.js");
|
|
8450
|
+
const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-UYV5S6QT.js");
|
|
7402
8451
|
const tmpl = parentEntry.template ?? "claude";
|
|
7403
8452
|
await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
|
|
7404
8453
|
} catch (err) {
|
|
@@ -7622,8 +8671,8 @@ async function fanOutToMinds(opts) {
|
|
|
7622
8671
|
);
|
|
7623
8672
|
const participantNames = participants.map((p) => p.username);
|
|
7624
8673
|
const isDM = opts.isDM ?? participants.length === 2;
|
|
7625
|
-
const { getMindManager: getMindManager2 } = await import("./mind-manager-
|
|
7626
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
8674
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-MWW3BTS4.js");
|
|
8675
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-BJK2ROPX.js");
|
|
7627
8676
|
const manager = getMindManager2();
|
|
7628
8677
|
const sm = getSleepManagerIfReady2();
|
|
7629
8678
|
const targetMinds = mindParticipants.map((ap) => {
|
|
@@ -8188,25 +9237,25 @@ async function startDaemon(opts) {
|
|
|
8188
9237
|
}
|
|
8189
9238
|
const DAEMON_PID_PATH = resolve19(systemDir, "daemon.pid");
|
|
8190
9239
|
const DAEMON_JSON_PATH = resolve19(systemDir, "daemon.json");
|
|
8191
|
-
|
|
9240
|
+
mkdirSync11(home, { recursive: true });
|
|
8192
9241
|
ensureSystemDir();
|
|
8193
9242
|
try {
|
|
8194
9243
|
await ensureSharedRepo();
|
|
8195
9244
|
} catch (err) {
|
|
8196
9245
|
logger_default.warn("failed to initialize shared repo", logger_default.errorData(err));
|
|
8197
9246
|
}
|
|
8198
|
-
const { migrateSetupCompleted } = await import("./setup-
|
|
9247
|
+
const { migrateSetupCompleted } = await import("./setup-GGMKENLN.js");
|
|
8199
9248
|
migrateSetupCompleted();
|
|
8200
|
-
await (await import("./db-
|
|
9249
|
+
await (await import("./db-RYX3SS2W.js")).getDb();
|
|
8201
9250
|
try {
|
|
8202
9251
|
const { eq: eq8, and: and6 } = await import("drizzle-orm");
|
|
8203
|
-
const { users: users2 } = await import("./schema-
|
|
8204
|
-
const db = await (await import("./db-
|
|
9252
|
+
const { users: users2 } = await import("./schema-ETMABTW4.js");
|
|
9253
|
+
const db = await (await import("./db-RYX3SS2W.js")).getDb();
|
|
8205
9254
|
await db.update(users2).set({ role: "system" }).where(and6(eq8(users2.user_type, "system"), eq8(users2.role, "user")));
|
|
8206
9255
|
} catch (err) {
|
|
8207
9256
|
logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
|
|
8208
9257
|
}
|
|
8209
|
-
const { initSandbox } = await import("./sandbox-
|
|
9258
|
+
const { initSandbox } = await import("./sandbox-SI5HMBP3.js");
|
|
8210
9259
|
await initSandbox();
|
|
8211
9260
|
try {
|
|
8212
9261
|
await syncBuiltinSkills();
|
|
@@ -8220,13 +9269,20 @@ async function startDaemon(opts) {
|
|
|
8220
9269
|
logger_default.error("failed to load extensions", logger_default.errorData(err));
|
|
8221
9270
|
}
|
|
8222
9271
|
await initDefaultSkills();
|
|
9272
|
+
if (isAutoUpdateSkillsEnabled()) {
|
|
9273
|
+
try {
|
|
9274
|
+
await autoUpdateMindSkills();
|
|
9275
|
+
} catch (err) {
|
|
9276
|
+
logger_default.error("failed to auto-update mind skills", logger_default.errorData(err));
|
|
9277
|
+
}
|
|
9278
|
+
}
|
|
8223
9279
|
try {
|
|
8224
9280
|
await ensureSystemChannel();
|
|
8225
9281
|
} catch (err) {
|
|
8226
9282
|
logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
|
|
8227
9283
|
}
|
|
8228
9284
|
try {
|
|
8229
|
-
const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-
|
|
9285
|
+
const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-ZFZXJZDQ.js");
|
|
8230
9286
|
await getOrCreateSystemUser2();
|
|
8231
9287
|
} catch (err) {
|
|
8232
9288
|
logger_default.warn(
|
|
@@ -8237,7 +9293,7 @@ async function startDaemon(opts) {
|
|
|
8237
9293
|
const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes(32).toString("hex");
|
|
8238
9294
|
let tls;
|
|
8239
9295
|
if (opts.tailscale) {
|
|
8240
|
-
const { getTailscaleTls } = await import("./tailscale-
|
|
9296
|
+
const { getTailscaleTls } = await import("./tailscale-ZEUK7GKZ.js");
|
|
8241
9297
|
const tlsConfig = await getTailscaleTls();
|
|
8242
9298
|
tls = { key: tlsConfig.key, cert: tlsConfig.cert };
|
|
8243
9299
|
logger_default.info("Tailscale HTTPS enabled", { hostname: tlsConfig.hostname });
|
|
@@ -8258,11 +9314,11 @@ async function startDaemon(opts) {
|
|
|
8258
9314
|
process.env.VOLUTE_DAEMON_TOKEN = token;
|
|
8259
9315
|
process.env.VOLUTE_DAEMON_PORT = String(daemonPort);
|
|
8260
9316
|
process.env.VOLUTE_DAEMON_HOSTNAME = hostname;
|
|
8261
|
-
|
|
9317
|
+
writeFileSync10(DAEMON_PID_PATH, myPid, { mode: 420 });
|
|
8262
9318
|
const daemonConfig = { port, hostname, token };
|
|
8263
9319
|
if (internalPort) daemonConfig.internalPort = internalPort;
|
|
8264
9320
|
if (tls) daemonConfig.tls = true;
|
|
8265
|
-
|
|
9321
|
+
writeFileSync10(DAEMON_JSON_PATH, `${JSON.stringify(daemonConfig, null, 2)}
|
|
8266
9322
|
`, { mode: 420 });
|
|
8267
9323
|
const delivery = initDeliveryManager();
|
|
8268
9324
|
const manager = initMindManager();
|
|
@@ -8276,6 +9332,8 @@ async function startDaemon(opts) {
|
|
|
8276
9332
|
tokenBudget.start();
|
|
8277
9333
|
const sleepManager = initSleepManager();
|
|
8278
9334
|
sleepManager.start();
|
|
9335
|
+
const summarizer = initSummarizer();
|
|
9336
|
+
summarizer.start();
|
|
8279
9337
|
const unsubscribeWebhook = initWebhook();
|
|
8280
9338
|
await completeOrphanedTurns();
|
|
8281
9339
|
const allMinds = await readAllMinds();
|
|
@@ -8307,10 +9365,10 @@ async function startDaemon(opts) {
|
|
|
8307
9365
|
await Promise.all(workers);
|
|
8308
9366
|
}
|
|
8309
9367
|
try {
|
|
8310
|
-
const { isSetupComplete: isSetupComplete2 } = await import("./setup-
|
|
9368
|
+
const { isSetupComplete: isSetupComplete2 } = await import("./setup-GGMKENLN.js");
|
|
8311
9369
|
if (isSetupComplete2()) {
|
|
8312
|
-
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-
|
|
8313
|
-
const { startSpiritFull } = await import("./mind-service-
|
|
9370
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-4JP4TY4C.js");
|
|
9371
|
+
const { startSpiritFull } = await import("./mind-service-VIKZJK2M.js");
|
|
8314
9372
|
await ensureSpiritProject();
|
|
8315
9373
|
await syncSpiritTemplate();
|
|
8316
9374
|
const spiritEntry = await findMind("volute");
|
|
@@ -8327,7 +9385,7 @@ async function startDaemon(opts) {
|
|
|
8327
9385
|
bridgeManager.startBridges(daemonPort).catch((err) => {
|
|
8328
9386
|
logger_default.warn("failed to start bridges", logger_default.errorData(err));
|
|
8329
9387
|
});
|
|
8330
|
-
import("./cloud-sync-
|
|
9388
|
+
import("./cloud-sync-TG3TIX5H.js").then(
|
|
8331
9389
|
({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
|
|
8332
9390
|
logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
|
|
8333
9391
|
})
|
|
@@ -8335,7 +9393,7 @@ async function startDaemon(opts) {
|
|
|
8335
9393
|
logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
|
|
8336
9394
|
});
|
|
8337
9395
|
try {
|
|
8338
|
-
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-
|
|
9396
|
+
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-YCH4UVQ2.js");
|
|
8339
9397
|
backfillTemplateHashes();
|
|
8340
9398
|
notifyVersionUpdate().catch((err) => {
|
|
8341
9399
|
logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
|
|
@@ -8393,6 +9451,7 @@ async function startDaemon(opts) {
|
|
|
8393
9451
|
safe("scheduler.saveState", () => scheduler.saveState());
|
|
8394
9452
|
safe("mailPoller.stop", () => mailPoller.stop());
|
|
8395
9453
|
safe("tokenBudget.stop", () => tokenBudget.stop());
|
|
9454
|
+
safe("summarizer.stop", () => summarizer.stop());
|
|
8396
9455
|
safe("stopApiKeyRefresh", stopApiKeyRefresh);
|
|
8397
9456
|
safe("delivery.dispose", () => delivery.dispose());
|
|
8398
9457
|
await safe("bridgeManager.stopAll", () => bridgeManager.stopAll());
|