volute 0.31.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -22
- package/dist/{accept-GAKQ3MEH.js → accept-74M7I4RZ.js} +3 -2
- package/dist/{activity-events-T5ZRCVAL.js → activity-events-HETAODOK.js} +3 -2
- package/dist/{ai-service-UWUPM4T6.js → ai-service-ZIPCV3MX.js} +18 -5
- package/dist/api.d.ts +98 -281
- package/dist/{archive-YBNSJYZZ.js → archive-INXYFVCW.js} +3 -2
- package/dist/{auth-T5AW2USD.js → auth-6DMGES3I.js} +4 -3
- package/dist/{bridge-4AJ3EY26.js → bridge-BVCBTGPF.js} +3 -2
- package/dist/{chat-7YLT7FI3.js → chat-XT4OBJBU.js} +8 -8
- package/dist/{chunk-BNC43CSY.js → chunk-2FLJ63GU.js} +2 -2
- package/dist/{chunk-NV3TYNWX.js → chunk-2NGTS5UU.js} +1 -1
- package/dist/{chunk-LX6T3GKQ.js → chunk-ALEF47VT.js} +1 -1
- package/dist/{chunk-S2TZLSDH.js → chunk-D5G5YOPL.js} +163 -15
- package/dist/{chunk-VGWJSNHS.js → chunk-G53F3JA4.js} +1 -35
- package/dist/{chunk-A6TUJJ3L.js → chunk-G6BSYHPK.js} +2 -2
- package/dist/{chunk-BC3P3QCK.js → chunk-I5KY25PQ.js} +1 -9
- package/dist/{chunk-PNQCXLSV.js → chunk-IYDIE3HG.js} +58 -1
- package/dist/{chunk-HDKY4TWU.js → chunk-JJ7W6WSB.js} +3 -3
- package/dist/{chunk-57OKQMP3.js → chunk-LGB6JBHI.js} +1 -1
- package/dist/chunk-LRCG2JLP.js +251 -0
- package/dist/{chunk-SNVPRRT7.js → chunk-LSGWR54X.js} +2 -2
- package/dist/{chunk-EMPFLFTG.js → chunk-M7UL5S3Q.js} +1 -1
- package/dist/chunk-PB65JZK2.js +85 -0
- package/dist/chunk-PVY5W6QN.js +41 -0
- package/dist/{chunk-BWKIHH7B.js → chunk-QBQ424EM.js} +318 -418
- package/dist/{chunk-EKDWA7E4.js → chunk-QZANELPX.js} +4 -2
- package/dist/{chunk-AAO77TZX.js → chunk-R7E6CRVQ.js} +1 -1
- package/dist/{chunk-X62AXPR7.js → chunk-RPZZSXV3.js} +8 -196
- package/dist/{chunk-WRS3B556.js → chunk-RSX4OPZY.js} +5 -5
- package/dist/{chunk-FAHDKPEH.js → chunk-S6NFERDC.js} +5 -3
- package/dist/chunk-SKLSMHXO.js +208 -0
- package/dist/{chunk-DAXJKPHZ.js → chunk-SX5TKJBZ.js} +2 -2
- package/dist/{chunk-R5QJBZZG.js → chunk-TDRYEPH4.js} +20 -10
- package/dist/{chunk-6QIUN46C.js → chunk-TSXLLQZW.js} +11 -3
- package/dist/{chunk-4OUOFS23.js → chunk-UKVWJRKN.js} +1 -1
- package/dist/{chunk-NOWVQ7AL.js → chunk-WKF5FEFK.js} +318 -167
- package/dist/cli.js +38 -20
- package/dist/{clock-LJCG426D.js → clock-2UOZ6JPU.js} +5 -4
- package/dist/{cloud-sync-O3LXIRN6.js → cloud-sync-JN3NWKEM.js} +16 -14
- package/dist/config-H2H4UIF7.js +72 -0
- 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-RKKGP5IA.js → conversations-3O5O6AS3.js} +4 -3
- package/dist/{create-WUTIIRI2.js → create-RNLNCORE.js} +3 -2
- package/dist/{create-TL623TFC.js → create-WBBYI6V7.js} +6 -2
- package/dist/{daemon-client-CVGM25DM.js → daemon-client-6QXHZ7US.js} +3 -2
- package/dist/{daemon-restart-EZP7XH3V.js → daemon-restart-NGFHFAUF.js} +7 -6
- package/dist/daemon.js +907 -612
- package/dist/{db-SW5PL6QA.js → db-F34YLV7D.js} +2 -1
- package/dist/db-RA45JBFG.js +16 -0
- package/dist/{delete-Z6HAG35F.js → delete-QTGWEDBI.js} +1 -1
- package/dist/delivery-manager-SDVXFD4W.js +28 -0
- package/dist/delivery-router-FL45JL7N.js +21 -0
- package/dist/down-TB3ESMNP.js +14 -0
- package/dist/{env-NHESNNSP.js → env-RLYQBOOP.js} +3 -2
- package/dist/{export-EVMP7GWY.js → export-SUYRLI5Q.js} +4 -3
- package/dist/{extension-LR7EW3JF.js → extension-FQ5D3NCC.js} +4 -3
- package/dist/{extensions-NGEJI7JH.js → extensions-GDYWQXC4.js} +9 -7
- package/dist/{files-3SM7V33S.js → files-EAMPO2SJ.js} +4 -3
- package/dist/{history-PQD3LXEP.js → history-FO5PHBQ5.js} +7 -2
- package/dist/{import-PR2OCGQJ.js → import-DDUFE7AY.js} +4 -3
- package/dist/{join-R4EN5CWQ.js → join-I5QEE3LG.js} +1 -1
- package/dist/{list-B4XNUOFO.js → list-DW2VRTOZ.js} +3 -2
- package/dist/{login-62JVY6A2.js → login-7CHPW2PN.js} +3 -2
- package/dist/{login-URWP6S2N.js → login-RIJF2F4G.js} +3 -2
- package/dist/{logout-NXJQJDLI.js → logout-5MLHZALK.js} +3 -2
- package/dist/{logout-ZK2N62T3.js → logout-UZJRGY4Z.js} +3 -2
- package/dist/message-delivery-2FIM7QKO.js +32 -0
- package/dist/{mind-E2ZV2WRX.js → mind-2B6M7Y25.js} +18 -18
- package/dist/{mind-activity-tracker-ASNZBMLC.js → mind-activity-tracker-NZZT2NTT.js} +4 -3
- package/dist/{mind-list-BEI7E5WY.js → mind-list-WUPMQDYQ.js} +3 -2
- package/dist/mind-manager-BNCMGYXW.js +28 -0
- package/dist/mind-service-AV273WT4.js +34 -0
- package/dist/{mind-sleep-CANABWJI.js → mind-sleep-B7BHJLH7.js} +3 -2
- package/dist/{mind-status-6WKZVUOP.js → mind-status-L3EFFRPR.js} +3 -2
- package/dist/{mind-wake-RZKLH2IN.js → mind-wake-GY3RFX7Y.js} +3 -2
- package/dist/{package-NU4CA7OU.js → package-PK6JUFL3.js} +1 -1
- package/dist/{read-THL362EI.js → read-5AMJRO3D.js} +3 -2
- package/dist/{register-QAQELAS6.js → register-V2JZZKFK.js} +3 -2
- package/dist/{registry-ASXCQCNH.js → registry-PJ4S5PHQ.js} +8 -1
- package/dist/{reject-AYPBNPNL.js → reject-33HEZMZ4.js} +3 -2
- package/dist/{restart-6SKPV3T2.js → restart-3UCMRUVC.js} +3 -2
- package/dist/{sandbox-6ZEWQDVU.js → sandbox-JANNTX6U.js} +4 -3
- package/dist/schema-PA3M5ZKH.js +32 -0
- package/dist/{seed-OWX2AW75.js → seed-ALUQ55FF.js} +26 -9
- package/dist/{send-ZO4BTWXK.js → send-3MI36LEF.js} +56 -67
- package/dist/{setup-7CFITEQN.js → setup-SZIARWI6.js} +5 -2
- package/dist/{setup-ZXBXG7E4.js → setup-WENLVPVP.js} +8 -6
- package/dist/{skill-YFXP67A2.js → skill-TUVOTW4Z.js} +3 -2
- package/dist/skills/dreaming/SKILL.md +6 -4
- package/dist/skills/dreaming/references/INSTALL.md +2 -2
- package/dist/skills/dreaming/scripts/dream.ts +2 -2
- package/dist/skills/dreaming/scripts/wake-context-dreams.sh +1 -1
- package/dist/skills/imagegen/SKILL.md +6 -5
- package/dist/skills/imagegen/references/INSTALL.md +1 -1
- package/dist/skills/resonance/SKILL.md +4 -1
- package/dist/skills/resonance/references/INSTALL.md +2 -2
- package/dist/skills/resonance/scripts/resonance-hook.sh +2 -0
- package/dist/skills/resonance/scripts/resonance.ts +35 -5
- package/dist/skills/volute-admin/SKILL.md +83 -0
- package/dist/skills/volute-mind/SKILL.md +11 -11
- package/dist/skills-XNZK6P4K.js +61 -0
- package/dist/sleep-manager-53DZOWW7.js +32 -0
- package/dist/spirit-N4W4UQRH.js +217 -0
- package/dist/{split-MI62KJUU.js → split-STOROBYJ.js} +1 -1
- package/dist/{sprout-FDVI2CGN.js → sprout-L2GFOVF7.js} +9 -7
- package/dist/{start-D64BRKPH.js → start-K2NCUUCG.js} +3 -2
- package/dist/{status-ZZWBYFGE.js → status-TCUMUO6M.js} +5 -4
- package/dist/{stop-OP2CTXCO.js → stop-H26JZDXF.js} +3 -2
- package/dist/system-chat-NPYFYZVI.js +32 -0
- package/dist/{systems-EQPPT4B7.js → systems-DHBKVYEY.js} +6 -5
- package/dist/{tailscale-6DJKUMNF.js → tailscale-XHQBZROW.js} +2 -1
- package/dist/{template-hash-3HOR4UAJ.js → template-hash-A6VVKOXJ.js} +2 -1
- package/dist/up-6I6BHRTO.js +17 -0
- package/dist/{update-KUJXATRS.js → update-QVPRF6GR.js} +5 -4
- package/dist/{update-check-5WVSU37T.js → update-check-ZD6OOIYQ.js} +3 -2
- package/dist/{upgrade-KBHCWX6T.js → upgrade-O4Q7WJM3.js} +12 -14
- package/dist/{version-notify-75ELVKPV.js → version-notify-TCKWBZZG.js} +21 -18
- package/dist/web-assets/assets/index-Bui7U9Uu.css +1 -0
- package/dist/web-assets/assets/index-e36DIo1b.js +73 -0
- package/dist/web-assets/ext-theme.css +93 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0004_spirits.sql +5 -0
- package/drizzle/meta/0004_snapshot.json +7 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/packages/extensions/notes/dist/ui/assets/index-8jWEv9SA.js +61 -0
- package/packages/extensions/notes/dist/ui/assets/index-DkaB7Ytd.css +1 -0
- package/packages/extensions/notes/dist/ui/index.html +2 -2
- package/packages/extensions/pages/skills/pages/SKILL.md +16 -46
- package/templates/_base/.init/.config/hooks/pre-prompt/session-activity.ts +40 -0
- package/templates/_base/.init/{.config → .local}/bin/volute +1 -1
- package/templates/_base/.init/.local/hooks/pre-prompt/session-activity.ts +40 -0
- package/templates/_base/.init/.local/hooks/startup-context.ts +58 -0
- package/templates/_base/home/.config/routes.json +1 -1
- package/templates/_base/src/lib/daemon-client.ts +21 -13
- package/templates/_base/src/lib/format-prefix.ts +1 -0
- package/templates/_base/src/lib/hook-loader.ts +155 -0
- package/templates/_base/src/lib/startup.ts +11 -4
- package/templates/_base/src/lib/transparency.ts +2 -2
- package/templates/claude/.init/.claude/settings.json +1 -1
- package/templates/claude/.init/.config/routes.json +2 -2
- package/templates/claude/src/agent.ts +95 -13
- package/templates/claude/src/lib/message-channel.ts +7 -2
- package/templates/codex/.init/.config/routes.json +11 -0
- package/templates/codex/.init/AGENTS.md +29 -0
- package/templates/codex/home/.config/config.json.tmpl +7 -0
- package/templates/codex/package.json.tmpl +20 -0
- package/templates/codex/src/agent.ts +553 -0
- package/templates/codex/src/lib/content.ts +16 -0
- package/templates/codex/src/lib/session-store.ts +56 -0
- package/templates/codex/src/server.ts +59 -0
- package/templates/codex/volute-template.json +8 -0
- package/templates/pi/.init/.config/routes.json +2 -2
- package/templates/pi/src/agent.ts +62 -8
- package/templates/pi/src/lib/event-handler.ts +1 -1
- package/templates/pi/src/lib/reply-instructions-extension.ts +32 -11
- package/dist/chunk-HR5JKIDG.js +0 -222
- package/dist/down-TS4XQBA4.js +0 -13
- package/dist/message-delivery-UJHCLVU4.js +0 -30
- package/dist/mind-manager-IPA6DZXD.js +0 -26
- package/dist/pages-watcher-72OVPRMH.js +0 -22
- package/dist/skills/sessions/SKILL.md +0 -49
- package/dist/sleep-manager-TPS6OGCA.js +0 -30
- package/dist/system-chat-B43GIXQU.js +0 -30
- package/dist/up-TDXEP3VA.js +0 -16
- package/dist/web-assets/assets/index-BM1cTzBg.js +0 -72
- package/dist/web-assets/assets/index-BfJkKTPF.css +0 -1
- package/packages/extensions/notes/dist/ui/assets/index-B8GdTnXs.css +0 -1
- package/packages/extensions/notes/dist/ui/assets/index-CDpGTCWb.js +0 -2
- package/packages/extensions/pages/skills/pages/scripts/pages.mjs +0 -58
- package/templates/_base/.init/.config/hooks/startup-context.sh +0 -46
- package/templates/_base/.init/.config/scripts/session-reader.ts +0 -59
- package/templates/_base/src/lib/session-monitor.ts +0 -400
- package/templates/claude/src/lib/hooks/session-context.ts +0 -32
- package/templates/pi/src/lib/session-context-extension.ts +0 -35
- /package/templates/_base/.init/{.config → .local}/hooks/wake-context.sh +0 -0
package/dist/daemon.js
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
computeTemplateHash
|
|
4
|
+
} from "./chunk-PVY5W6QN.js";
|
|
2
5
|
import {
|
|
3
6
|
checkForUpdate,
|
|
4
7
|
checkForUpdateCached,
|
|
5
8
|
getCurrentVersion
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
applyInitFiles,
|
|
9
|
-
composeTemplate,
|
|
10
|
-
computeTemplateHash,
|
|
11
|
-
copyTemplateToDir,
|
|
12
|
-
findTemplatesRoot,
|
|
13
|
-
listFiles
|
|
14
|
-
} from "./chunk-VGWJSNHS.js";
|
|
9
|
+
} from "./chunk-M7UL5S3Q.js";
|
|
15
10
|
import {
|
|
16
11
|
PROMPT_DEFAULTS,
|
|
17
12
|
PROMPT_KEYS,
|
|
@@ -36,22 +31,26 @@ import {
|
|
|
36
31
|
initScheduler,
|
|
37
32
|
initSleepManager,
|
|
38
33
|
initTokenBudget,
|
|
34
|
+
isConversationId,
|
|
39
35
|
joinSystemChannel,
|
|
40
36
|
publish as publish2,
|
|
41
37
|
publishTypingForChannels,
|
|
42
38
|
readVoluteConfig,
|
|
43
39
|
recordInbound,
|
|
44
|
-
resolveChannelId,
|
|
45
40
|
resolveMindToken,
|
|
46
|
-
splitMessage,
|
|
47
41
|
startMindFull,
|
|
48
42
|
stopMindFull,
|
|
49
43
|
subscribe as subscribe3,
|
|
50
44
|
substitute,
|
|
51
45
|
tagUntaggedInbound,
|
|
52
|
-
writeChannelEntry,
|
|
53
46
|
writeVoluteConfig
|
|
54
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-QBQ424EM.js";
|
|
48
|
+
import "./chunk-SKLSMHXO.js";
|
|
49
|
+
import {
|
|
50
|
+
getActiveMinds,
|
|
51
|
+
onMindEvent,
|
|
52
|
+
stopAll
|
|
53
|
+
} from "./chunk-R7E6CRVQ.js";
|
|
55
54
|
import {
|
|
56
55
|
addMessage,
|
|
57
56
|
createChannel,
|
|
@@ -79,13 +78,8 @@ import {
|
|
|
79
78
|
publish,
|
|
80
79
|
setConversationPrivate,
|
|
81
80
|
subscribe as subscribe2
|
|
82
|
-
} from "./chunk-
|
|
83
|
-
import "./chunk-
|
|
84
|
-
import {
|
|
85
|
-
getActiveMinds,
|
|
86
|
-
onMindEvent,
|
|
87
|
-
stopAll
|
|
88
|
-
} from "./chunk-AAO77TZX.js";
|
|
81
|
+
} from "./chunk-S6NFERDC.js";
|
|
82
|
+
import "./chunk-SX5TKJBZ.js";
|
|
89
83
|
import {
|
|
90
84
|
acceptPending,
|
|
91
85
|
formatFileSize,
|
|
@@ -93,13 +87,31 @@ import {
|
|
|
93
87
|
rejectPending,
|
|
94
88
|
stageFile,
|
|
95
89
|
validateFilePath
|
|
96
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-ALEF47VT.js";
|
|
91
|
+
import {
|
|
92
|
+
findBridgeForChannel,
|
|
93
|
+
findOpenClawSession,
|
|
94
|
+
getBridgeConfig,
|
|
95
|
+
importOpenClawConnectors,
|
|
96
|
+
importPiSession,
|
|
97
|
+
parseNameFromIdentity,
|
|
98
|
+
readBridgesConfig,
|
|
99
|
+
removeBridgeConfig,
|
|
100
|
+
removeChannelMapping,
|
|
101
|
+
resolveChannelMapping,
|
|
102
|
+
setBridgeConfig,
|
|
103
|
+
setChannelMapping
|
|
104
|
+
} from "./chunk-RSX4OPZY.js";
|
|
97
105
|
import {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
loadMergedEnv,
|
|
107
|
+
mindEnvPath,
|
|
108
|
+
readEnv,
|
|
109
|
+
sharedEnvPath,
|
|
110
|
+
writeEnv
|
|
111
|
+
} from "./chunk-2NGTS5UU.js";
|
|
101
112
|
import {
|
|
102
113
|
assignSession,
|
|
114
|
+
completeOrphanedTurns,
|
|
103
115
|
completeTurn,
|
|
104
116
|
createTurn,
|
|
105
117
|
deleteSystemsConfig,
|
|
@@ -114,7 +126,8 @@ import {
|
|
|
114
126
|
setSummaryEventId,
|
|
115
127
|
trackToolUse,
|
|
116
128
|
writeSystemsConfig
|
|
117
|
-
} from "./chunk-
|
|
129
|
+
} from "./chunk-WKF5FEFK.js";
|
|
130
|
+
import "./chunk-PB65JZK2.js";
|
|
118
131
|
import {
|
|
119
132
|
approveUser,
|
|
120
133
|
changePassword,
|
|
@@ -132,11 +145,18 @@ import {
|
|
|
132
145
|
setUserRole,
|
|
133
146
|
updateUserProfile,
|
|
134
147
|
verifyUser
|
|
135
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-TDRYEPH4.js";
|
|
136
149
|
import {
|
|
137
150
|
broadcast,
|
|
138
151
|
subscribe
|
|
139
|
-
} from "./chunk-
|
|
152
|
+
} from "./chunk-QZANELPX.js";
|
|
153
|
+
import {
|
|
154
|
+
applyInitFiles,
|
|
155
|
+
composeTemplate,
|
|
156
|
+
copyTemplateToDir,
|
|
157
|
+
findTemplatesRoot,
|
|
158
|
+
listFiles
|
|
159
|
+
} from "./chunk-G53F3JA4.js";
|
|
140
160
|
import {
|
|
141
161
|
SEED_SKILLS,
|
|
142
162
|
STANDARD_SKILLS,
|
|
@@ -154,43 +174,25 @@ import {
|
|
|
154
174
|
syncBuiltinSkills,
|
|
155
175
|
uninstallSkill,
|
|
156
176
|
updateSkill
|
|
157
|
-
} from "./chunk-
|
|
177
|
+
} from "./chunk-D5G5YOPL.js";
|
|
158
178
|
import {
|
|
159
179
|
isHomeOnlyArchive
|
|
160
|
-
} from "./chunk-
|
|
161
|
-
import {
|
|
162
|
-
findBridgeForChannel,
|
|
163
|
-
findOpenClawSession,
|
|
164
|
-
getBridgeConfig,
|
|
165
|
-
importOpenClawConnectors,
|
|
166
|
-
importPiSession,
|
|
167
|
-
parseNameFromIdentity,
|
|
168
|
-
readBridgesConfig,
|
|
169
|
-
removeBridgeConfig,
|
|
170
|
-
removeChannelMapping,
|
|
171
|
-
resolveChannelMapping,
|
|
172
|
-
setBridgeConfig,
|
|
173
|
-
setChannelMapping
|
|
174
|
-
} from "./chunk-WRS3B556.js";
|
|
175
|
-
import {
|
|
176
|
-
loadMergedEnv,
|
|
177
|
-
mindEnvPath,
|
|
178
|
-
readEnv,
|
|
179
|
-
sharedEnvPath,
|
|
180
|
-
writeEnv
|
|
181
|
-
} from "./chunk-NV3TYNWX.js";
|
|
180
|
+
} from "./chunk-I5KY25PQ.js";
|
|
182
181
|
import {
|
|
183
|
-
|
|
182
|
+
aiCompleteUtility,
|
|
184
183
|
getAiConfig,
|
|
185
184
|
getAvailableModels,
|
|
186
185
|
getConfiguredProviders,
|
|
187
186
|
getEnabledModels,
|
|
187
|
+
qualifyModelId,
|
|
188
188
|
removeAiConfig,
|
|
189
189
|
removeProviderConfig,
|
|
190
190
|
resolveApiKey,
|
|
191
|
+
resolveTemplate,
|
|
191
192
|
saveProviderConfig,
|
|
192
|
-
setEnabledModels
|
|
193
|
-
|
|
193
|
+
setEnabledModels,
|
|
194
|
+
unqualifyModelId
|
|
195
|
+
} from "./chunk-IYDIE3HG.js";
|
|
194
196
|
import {
|
|
195
197
|
logBuffer,
|
|
196
198
|
logger_default
|
|
@@ -206,26 +208,23 @@ import {
|
|
|
206
208
|
mindUserName,
|
|
207
209
|
resolveVoluteBin,
|
|
208
210
|
wrapForIsolation
|
|
209
|
-
} from "./chunk-
|
|
211
|
+
} from "./chunk-LGB6JBHI.js";
|
|
210
212
|
import {
|
|
211
213
|
isSetupComplete,
|
|
212
214
|
readGlobalConfig,
|
|
213
215
|
writeGlobalConfig
|
|
214
|
-
} from "./chunk-
|
|
216
|
+
} from "./chunk-TSXLLQZW.js";
|
|
215
217
|
import "./chunk-D424ZQGI.js";
|
|
216
218
|
import {
|
|
217
219
|
readSessionFile
|
|
218
|
-
} from "./chunk-
|
|
220
|
+
} from "./chunk-UKVWJRKN.js";
|
|
219
221
|
import {
|
|
220
222
|
buildVoluteSlug,
|
|
221
223
|
slugify
|
|
222
|
-
} from "./chunk-
|
|
224
|
+
} from "./chunk-G6BSYHPK.js";
|
|
223
225
|
import {
|
|
224
|
-
activity,
|
|
225
226
|
addMind,
|
|
226
227
|
addVariant,
|
|
227
|
-
conversationParticipants,
|
|
228
|
-
conversations,
|
|
229
228
|
daemonLoopback,
|
|
230
229
|
ensureSystemDir,
|
|
231
230
|
ensureVoluteHome,
|
|
@@ -233,25 +232,30 @@ import {
|
|
|
233
232
|
findVariants,
|
|
234
233
|
getBaseName,
|
|
235
234
|
getDb,
|
|
236
|
-
messages,
|
|
237
235
|
mindDir,
|
|
238
|
-
mindHistory,
|
|
239
236
|
nextPort,
|
|
240
237
|
readAllMinds,
|
|
241
238
|
readRegistry,
|
|
242
239
|
removeMind,
|
|
243
|
-
sessions,
|
|
244
240
|
setMindRunning,
|
|
245
241
|
setMindStage,
|
|
246
242
|
setMindTemplateHash,
|
|
247
243
|
stateDir,
|
|
248
|
-
systemPrompts,
|
|
249
|
-
turns,
|
|
250
|
-
users,
|
|
251
244
|
validateMindName,
|
|
252
245
|
voluteHome,
|
|
253
246
|
voluteSystemDir
|
|
254
|
-
} from "./chunk-
|
|
247
|
+
} from "./chunk-LRCG2JLP.js";
|
|
248
|
+
import {
|
|
249
|
+
activity,
|
|
250
|
+
conversationParticipants,
|
|
251
|
+
conversations,
|
|
252
|
+
messages,
|
|
253
|
+
mindHistory,
|
|
254
|
+
sessions,
|
|
255
|
+
systemPrompts,
|
|
256
|
+
turns,
|
|
257
|
+
users
|
|
258
|
+
} from "./chunk-RPZZSXV3.js";
|
|
255
259
|
import {
|
|
256
260
|
__export
|
|
257
261
|
} from "./chunk-K3NQKI34.js";
|
|
@@ -347,8 +351,8 @@ var BridgeManager = class {
|
|
|
347
351
|
shuttingDown = false;
|
|
348
352
|
restartTracker = new RestartTracker();
|
|
349
353
|
async startBridges(daemonPort) {
|
|
350
|
-
const
|
|
351
|
-
const platforms = Object.entries(
|
|
354
|
+
const config2 = readBridgesConfig();
|
|
355
|
+
const platforms = Object.entries(config2).filter(([, cfg]) => cfg.enabled).map(([platform]) => platform);
|
|
352
356
|
await Promise.all(
|
|
353
357
|
platforms.map(
|
|
354
358
|
(platform) => this.startBridge(platform, daemonPort).catch((err) => {
|
|
@@ -813,6 +817,13 @@ var requireAdmin = createMiddleware(async (c, next) => {
|
|
|
813
817
|
}
|
|
814
818
|
await next();
|
|
815
819
|
});
|
|
820
|
+
var requireAdminOrSystem = createMiddleware(async (c, next) => {
|
|
821
|
+
const user = c.get("user");
|
|
822
|
+
if (user.role !== "admin" && user.role !== "system") {
|
|
823
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
824
|
+
}
|
|
825
|
+
await next();
|
|
826
|
+
});
|
|
816
827
|
async function resolveSession(sessionId) {
|
|
817
828
|
const cached = sessionCache.get(sessionId);
|
|
818
829
|
if (cached && cached.expires > Date.now()) {
|
|
@@ -879,7 +890,7 @@ var authMiddleware = createMiddleware(async (c, next) => {
|
|
|
879
890
|
});
|
|
880
891
|
var requireSelf = (paramName = "name") => createMiddleware(async (c, next) => {
|
|
881
892
|
const user = c.get("user");
|
|
882
|
-
if (user.role !== "admin") {
|
|
893
|
+
if (user.role !== "admin" && user.role !== "system") {
|
|
883
894
|
const target = c.req.param(paramName) ?? "";
|
|
884
895
|
const baseName = await getBaseName(target);
|
|
885
896
|
if (user.username !== baseName) {
|
|
@@ -916,8 +927,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
916
927
|
});
|
|
917
928
|
});
|
|
918
929
|
}).get("/info", (c) => {
|
|
919
|
-
const
|
|
920
|
-
return c.json({ system:
|
|
930
|
+
const config2 = readSystemsConfig();
|
|
931
|
+
return c.json({ system: config2?.system ?? null });
|
|
921
932
|
}).post(
|
|
922
933
|
"/register",
|
|
923
934
|
requireAdmin,
|
|
@@ -928,6 +939,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
928
939
|
return c.json({ error: `Already registered as "${existing.system}"` }, 400);
|
|
929
940
|
}
|
|
930
941
|
const { name } = c.req.valid("json");
|
|
942
|
+
const config2 = readGlobalConfig();
|
|
931
943
|
const apiUrl = process.env.VOLUTE_SYSTEMS_URL || DEFAULT_API_URL;
|
|
932
944
|
let apiKey;
|
|
933
945
|
let system;
|
|
@@ -935,7 +947,11 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
935
947
|
const res = await fetch(`${apiUrl}/api/register`, {
|
|
936
948
|
method: "POST",
|
|
937
949
|
headers: { "Content-Type": "application/json" },
|
|
938
|
-
body: JSON.stringify({
|
|
950
|
+
body: JSON.stringify({
|
|
951
|
+
name: name.trim(),
|
|
952
|
+
displayName: config2.name || void 0,
|
|
953
|
+
description: config2.description || void 0
|
|
954
|
+
})
|
|
939
955
|
});
|
|
940
956
|
if (!res.ok) {
|
|
941
957
|
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
@@ -997,16 +1013,16 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
997
1013
|
deleteSystemsConfig();
|
|
998
1014
|
return c.json({ ok: true });
|
|
999
1015
|
}).put("/pages/publish/:name", requireAdmin, async (c) => {
|
|
1000
|
-
const
|
|
1001
|
-
if (!
|
|
1016
|
+
const config2 = readSystemsConfig();
|
|
1017
|
+
if (!config2) return c.json({ error: "Not connected to volute.systems" }, 400);
|
|
1002
1018
|
const name = c.req.param("name");
|
|
1003
1019
|
const body = await c.req.text();
|
|
1004
1020
|
try {
|
|
1005
|
-
const res = await fetch(`${
|
|
1021
|
+
const res = await fetch(`${config2.apiUrl}/api/pages/publish/${name}`, {
|
|
1006
1022
|
method: "PUT",
|
|
1007
1023
|
headers: {
|
|
1008
1024
|
"Content-Type": "application/json",
|
|
1009
|
-
Authorization: `Bearer ${
|
|
1025
|
+
Authorization: `Bearer ${config2.apiKey}`
|
|
1010
1026
|
},
|
|
1011
1027
|
body
|
|
1012
1028
|
});
|
|
@@ -1016,12 +1032,12 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1016
1032
|
return c.json({ error: `Connection failed: ${err.message}` }, 502);
|
|
1017
1033
|
}
|
|
1018
1034
|
}).get("/pages/status/:name", requireAdmin, async (c) => {
|
|
1019
|
-
const
|
|
1020
|
-
if (!
|
|
1035
|
+
const config2 = readSystemsConfig();
|
|
1036
|
+
if (!config2) return c.json({ error: "Not connected to volute.systems" }, 400);
|
|
1021
1037
|
const name = c.req.param("name");
|
|
1022
1038
|
try {
|
|
1023
|
-
const res = await fetch(`${
|
|
1024
|
-
headers: { Authorization: `Bearer ${
|
|
1039
|
+
const res = await fetch(`${config2.apiUrl}/api/pages/status/${name}`, {
|
|
1040
|
+
headers: { Authorization: `Bearer ${config2.apiKey}` }
|
|
1025
1041
|
});
|
|
1026
1042
|
const data = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
1027
1043
|
return c.json(data, res.status);
|
|
@@ -1239,7 +1255,7 @@ function stopApiKeyRefresh() {
|
|
|
1239
1255
|
var system_default = app;
|
|
1240
1256
|
|
|
1241
1257
|
// src/web/app.ts
|
|
1242
|
-
import { Hono as
|
|
1258
|
+
import { Hono as Hono31 } from "hono";
|
|
1243
1259
|
import { bodyLimit } from "hono/body-limit";
|
|
1244
1260
|
import { csrf } from "hono/csrf";
|
|
1245
1261
|
import { HTTPException } from "hono/http-exception";
|
|
@@ -1702,7 +1718,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
|
|
|
1702
1718
|
}
|
|
1703
1719
|
const participants = await getParticipants(channel.id);
|
|
1704
1720
|
if (!participants.some((p) => p.userId === puppet.id)) {
|
|
1705
|
-
const { addParticipant } = await import("./conversations-
|
|
1721
|
+
const { addParticipant } = await import("./conversations-3O5O6AS3.js");
|
|
1706
1722
|
await addParticipant(channel.id, puppet.id);
|
|
1707
1723
|
}
|
|
1708
1724
|
const contentBlocks = body.content;
|
|
@@ -1716,10 +1732,10 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
|
|
|
1716
1732
|
});
|
|
1717
1733
|
return c.json({ ok: true, conversationId: channel.id });
|
|
1718
1734
|
}).get("/", (c) => {
|
|
1719
|
-
const
|
|
1735
|
+
const config2 = readBridgesConfig();
|
|
1720
1736
|
const manager = getBridgeManager();
|
|
1721
1737
|
const statuses = manager.getBridgeStatus();
|
|
1722
|
-
const bridges = Object.entries(
|
|
1738
|
+
const bridges = Object.entries(config2).map(([platform, cfg]) => {
|
|
1723
1739
|
const status = statuses.find((s) => s.platform === platform);
|
|
1724
1740
|
const def = getBridgeDef(platform);
|
|
1725
1741
|
return {
|
|
@@ -1787,16 +1803,16 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
|
|
|
1787
1803
|
return c.json({ ok: true });
|
|
1788
1804
|
}).get("/:platform/mappings", (c) => {
|
|
1789
1805
|
const platform = c.req.param("platform");
|
|
1790
|
-
const
|
|
1791
|
-
if (!
|
|
1792
|
-
return c.json(
|
|
1806
|
+
const config2 = getBridgeConfig(platform);
|
|
1807
|
+
if (!config2) return c.json({ error: "Bridge not configured" }, 404);
|
|
1808
|
+
return c.json(config2.channelMappings);
|
|
1793
1809
|
});
|
|
1794
1810
|
async function fanOutToBridgedMinds(opts) {
|
|
1795
1811
|
const participants = await getParticipants(opts.conversationId);
|
|
1796
1812
|
const mindParticipants = participants.filter((p) => p.userType === "mind");
|
|
1797
1813
|
const participantNames = participants.map((p) => p.username);
|
|
1798
|
-
const { getMindManager: getMindManager2 } = await import("./mind-manager-
|
|
1799
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
1814
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-BNCMGYXW.js");
|
|
1815
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-53DZOWW7.js");
|
|
1800
1816
|
const manager = getMindManager2();
|
|
1801
1817
|
const sm = getSleepManagerIfReady2();
|
|
1802
1818
|
const targetMinds = mindParticipants.filter((ap) => {
|
|
@@ -1809,15 +1825,6 @@ async function fanOutToBridgedMinds(opts) {
|
|
|
1809
1825
|
convTitle: null,
|
|
1810
1826
|
conversationId: opts.conversationId
|
|
1811
1827
|
});
|
|
1812
|
-
try {
|
|
1813
|
-
writeChannelEntry(mindName, channel, {
|
|
1814
|
-
platformId: opts.conversationId,
|
|
1815
|
-
platform: "volute",
|
|
1816
|
-
type: opts.isDM ? "dm" : "channel"
|
|
1817
|
-
});
|
|
1818
|
-
} catch (err) {
|
|
1819
|
-
logger_default.warn(`failed to write channel entry for ${mindName}`, logger_default.errorData(err));
|
|
1820
|
-
}
|
|
1821
1828
|
deliverMessage(mindName, {
|
|
1822
1829
|
content: opts.contentBlocks,
|
|
1823
1830
|
channel,
|
|
@@ -1845,6 +1852,21 @@ __export(discord_exports, {
|
|
|
1845
1852
|
read: () => read,
|
|
1846
1853
|
send: () => send
|
|
1847
1854
|
});
|
|
1855
|
+
|
|
1856
|
+
// src/connectors/sdk.ts
|
|
1857
|
+
function splitMessage(text, maxLength) {
|
|
1858
|
+
const chunks = [];
|
|
1859
|
+
while (text.length > maxLength) {
|
|
1860
|
+
let splitAt = text.lastIndexOf("\n", maxLength);
|
|
1861
|
+
if (splitAt < maxLength / 2) splitAt = maxLength;
|
|
1862
|
+
chunks.push(text.slice(0, splitAt));
|
|
1863
|
+
text = text.slice(splitAt).replace(/^\n/, "");
|
|
1864
|
+
}
|
|
1865
|
+
if (text) chunks.push(text);
|
|
1866
|
+
return chunks;
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// src/lib/channels/discord.ts
|
|
1848
1870
|
var DISCORD_MAX_LENGTH = 2e3;
|
|
1849
1871
|
var API_BASE = "https://discord.com/api/v10";
|
|
1850
1872
|
function requireToken(env) {
|
|
@@ -1863,7 +1885,7 @@ async function discordGet(token, path) {
|
|
|
1863
1885
|
}
|
|
1864
1886
|
async function read(env, channelSlug, limit) {
|
|
1865
1887
|
const token = requireToken(env);
|
|
1866
|
-
const channelId =
|
|
1888
|
+
const channelId = resolveChannelId(channelSlug);
|
|
1867
1889
|
const res = await fetch(`${API_BASE}/channels/${channelId}/messages?limit=${limit}`, {
|
|
1868
1890
|
headers: { Authorization: `Bot ${token}` }
|
|
1869
1891
|
});
|
|
@@ -1875,7 +1897,7 @@ async function read(env, channelSlug, limit) {
|
|
|
1875
1897
|
}
|
|
1876
1898
|
async function send(env, channelSlug, message, images) {
|
|
1877
1899
|
const token = requireToken(env);
|
|
1878
|
-
const channelId =
|
|
1900
|
+
const channelId = resolveChannelId(channelSlug);
|
|
1879
1901
|
if (images?.length) {
|
|
1880
1902
|
for (let i = 0; i < images.length; i++) {
|
|
1881
1903
|
const img = images[i];
|
|
@@ -1987,18 +2009,8 @@ async function createConversation2(env, participants, _name) {
|
|
|
1987
2009
|
if (!res.ok) {
|
|
1988
2010
|
throw new Error(`Discord API error: ${res.status} ${res.statusText}`);
|
|
1989
2011
|
}
|
|
1990
|
-
const
|
|
1991
|
-
|
|
1992
|
-
const mindName = env.VOLUTE_MIND;
|
|
1993
|
-
if (mindName) {
|
|
1994
|
-
writeChannelEntry(mindName, slug, {
|
|
1995
|
-
platformId: dm.id,
|
|
1996
|
-
platform: "discord",
|
|
1997
|
-
name: participants[0],
|
|
1998
|
-
type: "dm"
|
|
1999
|
-
});
|
|
2000
|
-
}
|
|
2001
|
-
return slug;
|
|
2012
|
+
const dmChannel = await res.json();
|
|
2013
|
+
return `discord:${dmChannel.id}`;
|
|
2002
2014
|
}
|
|
2003
2015
|
|
|
2004
2016
|
// src/lib/channels/slack.ts
|
|
@@ -2037,7 +2049,7 @@ async function slackApi(token, method, body) {
|
|
|
2037
2049
|
}
|
|
2038
2050
|
async function read2(env, channelSlug, limit) {
|
|
2039
2051
|
const token = requireToken2(env);
|
|
2040
|
-
const channelId =
|
|
2052
|
+
const channelId = resolveChannelId(channelSlug);
|
|
2041
2053
|
const data = await slackApi(token, "conversations.history", {
|
|
2042
2054
|
channel: channelId,
|
|
2043
2055
|
limit
|
|
@@ -2046,7 +2058,7 @@ async function read2(env, channelSlug, limit) {
|
|
|
2046
2058
|
}
|
|
2047
2059
|
async function send2(env, channelSlug, message, images) {
|
|
2048
2060
|
const token = requireToken2(env);
|
|
2049
|
-
const channelId =
|
|
2061
|
+
const channelId = resolveChannelId(channelSlug);
|
|
2050
2062
|
if (images?.length) {
|
|
2051
2063
|
for (const img of images) {
|
|
2052
2064
|
const ext = img.media_type.split("/")[1] || "png";
|
|
@@ -2151,7 +2163,6 @@ async function createConversation3(env, participants, name) {
|
|
|
2151
2163
|
if (!user) throw new Error(`User not found: ${p}`);
|
|
2152
2164
|
ids.push(user.id);
|
|
2153
2165
|
}
|
|
2154
|
-
const mindName = env.VOLUTE_MIND;
|
|
2155
2166
|
if (name) {
|
|
2156
2167
|
const createData = await slackApi(token, "conversations.create", {
|
|
2157
2168
|
name,
|
|
@@ -2166,31 +2177,11 @@ async function createConversation3(env, participants, name) {
|
|
|
2166
2177
|
}
|
|
2167
2178
|
const authData = await slackApi(token, "auth.test", {});
|
|
2168
2179
|
const teamName = authData.team ?? "workspace";
|
|
2169
|
-
const
|
|
2170
|
-
|
|
2171
|
-
writeChannelEntry(mindName, slug2, {
|
|
2172
|
-
platformId: channelId,
|
|
2173
|
-
platform: "slack",
|
|
2174
|
-
name,
|
|
2175
|
-
type: "channel"
|
|
2176
|
-
});
|
|
2177
|
-
}
|
|
2178
|
-
return slug2;
|
|
2179
|
-
}
|
|
2180
|
-
const openData = await slackApi(token, "conversations.open", {
|
|
2181
|
-
users: ids.join(",")
|
|
2182
|
-
});
|
|
2183
|
-
const platformId = openData.channel.id;
|
|
2184
|
-
const slug = participants.length === 1 ? `slack:@${slugify(participants[0])}` : `slack:@${participants.map(slugify).sort().join(",")}`;
|
|
2185
|
-
if (mindName) {
|
|
2186
|
-
writeChannelEntry(mindName, slug, {
|
|
2187
|
-
platformId,
|
|
2188
|
-
platform: "slack",
|
|
2189
|
-
name: participants.join(", "),
|
|
2190
|
-
type: participants.length === 1 ? "dm" : "channel"
|
|
2191
|
-
});
|
|
2180
|
+
const slug = `slack:${slugify(teamName)}/${slugify(name)}`;
|
|
2181
|
+
return slug;
|
|
2192
2182
|
}
|
|
2193
|
-
|
|
2183
|
+
const openData = await slackApi(token, "conversations.open", { users: ids.join(",") });
|
|
2184
|
+
return `slack:${openData.channel.id}`;
|
|
2194
2185
|
}
|
|
2195
2186
|
|
|
2196
2187
|
// src/lib/channels/telegram.ts
|
|
@@ -2216,7 +2207,7 @@ async function read3(_env, _channelSlug, _limit) {
|
|
|
2216
2207
|
}
|
|
2217
2208
|
async function send3(env, channelSlug, message, images) {
|
|
2218
2209
|
const token = requireToken3(env);
|
|
2219
|
-
const chatId =
|
|
2210
|
+
const chatId = resolveChannelId(channelSlug);
|
|
2220
2211
|
if (images?.length) {
|
|
2221
2212
|
const CAPTION_MAX = 1024;
|
|
2222
2213
|
for (let i = 0; i < images.length; i++) {
|
|
@@ -2305,24 +2296,24 @@ function getDaemonConfig() {
|
|
|
2305
2296
|
if (!existsSync5(configPath)) {
|
|
2306
2297
|
throw new Error("Volute daemon is not running");
|
|
2307
2298
|
}
|
|
2308
|
-
let
|
|
2299
|
+
let config2;
|
|
2309
2300
|
try {
|
|
2310
|
-
|
|
2301
|
+
config2 = JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
2311
2302
|
} catch (err) {
|
|
2312
2303
|
throw new Error(`Failed to parse ${configPath}: ${err}`);
|
|
2313
2304
|
}
|
|
2314
|
-
if (typeof
|
|
2305
|
+
if (typeof config2.port !== "number") {
|
|
2315
2306
|
throw new Error(`Invalid or missing port in ${configPath}`);
|
|
2316
2307
|
}
|
|
2317
2308
|
const url = new URL("http://localhost");
|
|
2318
|
-
url.hostname =
|
|
2319
|
-
url.port = String(
|
|
2320
|
-
return { url: url.origin, token:
|
|
2309
|
+
url.hostname = config2.hostname || "localhost";
|
|
2310
|
+
url.port = String(config2.port);
|
|
2311
|
+
return { url: url.origin, token: config2.token };
|
|
2321
2312
|
}
|
|
2322
2313
|
async function read4(env, channelSlug, limit) {
|
|
2323
2314
|
const mindName = env.VOLUTE_MIND;
|
|
2324
2315
|
if (!mindName) throw new Error("VOLUTE_MIND not set");
|
|
2325
|
-
const conversationId =
|
|
2316
|
+
const conversationId = resolveChannelId(channelSlug);
|
|
2326
2317
|
const { url, token } = getDaemonConfig();
|
|
2327
2318
|
const headers = { Origin: url };
|
|
2328
2319
|
if (token) headers.Authorization = `Bearer ${token}`;
|
|
@@ -2345,7 +2336,7 @@ async function read4(env, channelSlug, limit) {
|
|
|
2345
2336
|
async function send4(env, channelSlug, message, images) {
|
|
2346
2337
|
const mindName = env.VOLUTE_MIND;
|
|
2347
2338
|
if (!mindName) throw new Error("VOLUTE_MIND not set");
|
|
2348
|
-
const conversationId =
|
|
2339
|
+
const conversationId = resolveChannelId(channelSlug);
|
|
2349
2340
|
const { url, token } = getDaemonConfig();
|
|
2350
2341
|
const headers = {
|
|
2351
2342
|
"Content-Type": "application/json",
|
|
@@ -2451,7 +2442,7 @@ async function createConversation5(env, participants, name) {
|
|
|
2451
2442
|
throw new Error(data.error ?? `Failed to create conversation: ${res.status}`);
|
|
2452
2443
|
}
|
|
2453
2444
|
const conv = await res.json();
|
|
2454
|
-
return
|
|
2445
|
+
return conv.id;
|
|
2455
2446
|
}
|
|
2456
2447
|
|
|
2457
2448
|
// src/lib/channels.ts
|
|
@@ -2459,121 +2450,40 @@ var CHANNELS = {
|
|
|
2459
2450
|
volute: {
|
|
2460
2451
|
name: "volute",
|
|
2461
2452
|
displayName: "Volute",
|
|
2462
|
-
showToolCalls: true,
|
|
2463
2453
|
builtIn: true,
|
|
2464
2454
|
driver: volute_exports
|
|
2465
2455
|
},
|
|
2466
2456
|
discord: {
|
|
2467
2457
|
name: "discord",
|
|
2468
2458
|
displayName: "Discord",
|
|
2469
|
-
showToolCalls: false,
|
|
2470
2459
|
driver: discord_exports
|
|
2471
2460
|
},
|
|
2472
2461
|
slack: {
|
|
2473
2462
|
name: "slack",
|
|
2474
2463
|
displayName: "Slack",
|
|
2475
|
-
showToolCalls: false,
|
|
2476
2464
|
driver: slack_exports
|
|
2477
2465
|
},
|
|
2478
2466
|
telegram: {
|
|
2479
2467
|
name: "telegram",
|
|
2480
2468
|
displayName: "Telegram",
|
|
2481
|
-
showToolCalls: false,
|
|
2482
2469
|
driver: telegram_exports
|
|
2483
2470
|
},
|
|
2484
|
-
mail: { name: "mail", displayName: "Email"
|
|
2485
|
-
system: { name: "system", displayName: "System"
|
|
2471
|
+
mail: { name: "mail", displayName: "Email" },
|
|
2472
|
+
system: { name: "system", displayName: "System" }
|
|
2486
2473
|
};
|
|
2487
2474
|
function getChannelDriver(platform) {
|
|
2488
2475
|
return CHANNELS[platform]?.driver ?? null;
|
|
2489
2476
|
}
|
|
2490
|
-
function
|
|
2491
|
-
const
|
|
2492
|
-
|
|
2493
|
-
const colonIdx = slug.indexOf(":");
|
|
2494
|
-
return colonIdx !== -1 ? slug.slice(colonIdx + 1) : slug;
|
|
2495
|
-
}
|
|
2496
|
-
return resolveChannelId(mindName, slug);
|
|
2477
|
+
function resolveChannelId(slug) {
|
|
2478
|
+
const colonIdx = slug.indexOf(":");
|
|
2479
|
+
return colonIdx !== -1 ? slug.slice(colonIdx + 1) : slug;
|
|
2497
2480
|
}
|
|
2498
2481
|
|
|
2499
2482
|
// src/web/api/channels.ts
|
|
2500
2483
|
function buildEnv(name) {
|
|
2501
2484
|
return { ...loadMergedEnv(name), VOLUTE_MIND: name, VOLUTE_MIND_DIR: mindDir(name) };
|
|
2502
2485
|
}
|
|
2503
|
-
var app5 = new Hono5().post("/:name/channels/
|
|
2504
|
-
const name = c.req.param("name");
|
|
2505
|
-
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
2506
|
-
const { platform, uri, message, images, sender } = await c.req.json();
|
|
2507
|
-
const driver = getChannelDriver(platform);
|
|
2508
|
-
if (!driver) return c.json({ error: `No driver for platform: ${platform}` }, 400);
|
|
2509
|
-
const env = buildEnv(name);
|
|
2510
|
-
if (sender) env.VOLUTE_SENDER = sender;
|
|
2511
|
-
const mindSession = c.get("mindSession");
|
|
2512
|
-
if (mindSession) env.VOLUTE_SESSION = mindSession;
|
|
2513
|
-
try {
|
|
2514
|
-
await driver.send(env, uri, message, images);
|
|
2515
|
-
return c.json({ ok: true });
|
|
2516
|
-
} catch (err) {
|
|
2517
|
-
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
2518
|
-
}
|
|
2519
|
-
}).get("/:name/channels/read", async (c) => {
|
|
2520
|
-
const name = c.req.param("name");
|
|
2521
|
-
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
2522
|
-
const platform = c.req.query("platform");
|
|
2523
|
-
const uri = c.req.query("uri");
|
|
2524
|
-
const limit = parseInt(c.req.query("limit") ?? "20", 10) || 20;
|
|
2525
|
-
if (!platform || !uri) return c.json({ error: "platform and uri required" }, 400);
|
|
2526
|
-
const driver = getChannelDriver(platform);
|
|
2527
|
-
if (!driver) return c.json({ error: `No driver for platform: ${platform}` }, 400);
|
|
2528
|
-
const env = buildEnv(name);
|
|
2529
|
-
try {
|
|
2530
|
-
const output = await driver.read(env, uri, limit);
|
|
2531
|
-
return c.text(output);
|
|
2532
|
-
} catch (err) {
|
|
2533
|
-
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
2534
|
-
}
|
|
2535
|
-
}).get("/:name/channels/list", async (c) => {
|
|
2536
|
-
const name = c.req.param("name");
|
|
2537
|
-
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
2538
|
-
const platform = c.req.query("platform");
|
|
2539
|
-
const platforms = platform ? [platform] : Object.keys(CHANNELS);
|
|
2540
|
-
const env = buildEnv(name);
|
|
2541
|
-
const results = {};
|
|
2542
|
-
for (const p of platforms) {
|
|
2543
|
-
const driver = getChannelDriver(p);
|
|
2544
|
-
if (!driver?.listConversations) continue;
|
|
2545
|
-
try {
|
|
2546
|
-
const convs = await driver.listConversations(env);
|
|
2547
|
-
for (const conv of convs) {
|
|
2548
|
-
writeChannelEntry(name, conv.id, {
|
|
2549
|
-
platformId: conv.platformId,
|
|
2550
|
-
platform: p,
|
|
2551
|
-
name: conv.name,
|
|
2552
|
-
type: conv.type
|
|
2553
|
-
});
|
|
2554
|
-
}
|
|
2555
|
-
results[p] = convs;
|
|
2556
|
-
} catch (err) {
|
|
2557
|
-
results[p] = [{ error: err instanceof Error ? err.message : String(err) }];
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
return c.json(results);
|
|
2561
|
-
}).get("/:name/channels/users", async (c) => {
|
|
2562
|
-
const name = c.req.param("name");
|
|
2563
|
-
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
2564
|
-
const platform = c.req.query("platform");
|
|
2565
|
-
if (!platform) return c.json({ error: "platform required" }, 400);
|
|
2566
|
-
const driver = getChannelDriver(platform);
|
|
2567
|
-
if (!driver?.listUsers)
|
|
2568
|
-
return c.json({ error: `Platform ${platform} does not support listing users` }, 400);
|
|
2569
|
-
const env = buildEnv(name);
|
|
2570
|
-
try {
|
|
2571
|
-
const users2 = await driver.listUsers(env);
|
|
2572
|
-
return c.json(users2);
|
|
2573
|
-
} catch (err) {
|
|
2574
|
-
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
2575
|
-
}
|
|
2576
|
-
}).post("/:name/channels/create", requireSelf(), async (c) => {
|
|
2486
|
+
var app5 = new Hono5().post("/:name/channels/create", requireSelf(), async (c) => {
|
|
2577
2487
|
const name = c.req.param("name");
|
|
2578
2488
|
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
2579
2489
|
const {
|
|
@@ -2590,16 +2500,44 @@ var app5 = new Hono5().post("/:name/channels/send", requireSelf(), async (c) =>
|
|
|
2590
2500
|
if (sender) env.VOLUTE_SENDER = sender;
|
|
2591
2501
|
try {
|
|
2592
2502
|
const slug = await driver.createConversation(env, participants, convName);
|
|
2593
|
-
return c.json({ slug });
|
|
2503
|
+
return c.json({ slug, conversationId: slug });
|
|
2594
2504
|
} catch (err) {
|
|
2595
2505
|
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
2596
2506
|
}
|
|
2597
2507
|
});
|
|
2598
2508
|
var channels_default = app5;
|
|
2599
2509
|
|
|
2600
|
-
// src/web/api/
|
|
2510
|
+
// src/web/api/config.ts
|
|
2601
2511
|
import { Hono as Hono6 } from "hono";
|
|
2602
|
-
var
|
|
2512
|
+
var config = new Hono6();
|
|
2513
|
+
config.get("/models", (c) => {
|
|
2514
|
+
const enabled = new Set(getEnabledModels());
|
|
2515
|
+
const all = getAvailableModels();
|
|
2516
|
+
const models = all.map((m) => ({
|
|
2517
|
+
id: m.id,
|
|
2518
|
+
name: m.name,
|
|
2519
|
+
provider: m.provider,
|
|
2520
|
+
enabled: enabled.has(m.id)
|
|
2521
|
+
}));
|
|
2522
|
+
return c.json(models);
|
|
2523
|
+
});
|
|
2524
|
+
config.get("/providers", (c) => {
|
|
2525
|
+
const configured = getConfiguredProviders();
|
|
2526
|
+
return c.json(configured.map((id) => ({ id, configured: true })));
|
|
2527
|
+
});
|
|
2528
|
+
config.get("/status", (c) => {
|
|
2529
|
+
const globalConfig = readGlobalConfig();
|
|
2530
|
+
return c.json({
|
|
2531
|
+
name: globalConfig.name ?? "Volute",
|
|
2532
|
+
spiritModel: globalConfig.spiritModel ?? null,
|
|
2533
|
+
setupComplete: globalConfig.setupCompleted ?? false
|
|
2534
|
+
});
|
|
2535
|
+
});
|
|
2536
|
+
var config_default = config;
|
|
2537
|
+
|
|
2538
|
+
// src/web/api/env.ts
|
|
2539
|
+
import { Hono as Hono7 } from "hono";
|
|
2540
|
+
var app6 = new Hono7().get("/:name/env", async (c) => {
|
|
2603
2541
|
const name = c.req.param("name");
|
|
2604
2542
|
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
2605
2543
|
const shared = readEnv(sharedEnvPath());
|
|
@@ -2642,7 +2580,7 @@ var app6 = new Hono6().get("/:name/env", async (c) => {
|
|
|
2642
2580
|
writeEnv(path, env);
|
|
2643
2581
|
return c.json({ ok: true });
|
|
2644
2582
|
});
|
|
2645
|
-
var sharedEnvApp = new
|
|
2583
|
+
var sharedEnvApp = new Hono7().get("/", (c) => {
|
|
2646
2584
|
return c.json(readEnv(sharedEnvPath()));
|
|
2647
2585
|
}).put("/:key", requireAdmin, async (c) => {
|
|
2648
2586
|
const key = c.req.param("key");
|
|
@@ -2672,8 +2610,8 @@ var sharedEnvApp = new Hono6().get("/", (c) => {
|
|
|
2672
2610
|
var env_default = app6;
|
|
2673
2611
|
|
|
2674
2612
|
// src/web/api/extensions.ts
|
|
2675
|
-
import { Hono as
|
|
2676
|
-
var app7 = new
|
|
2613
|
+
import { Hono as Hono8 } from "hono";
|
|
2614
|
+
var app7 = new Hono8().get("/", (c) => {
|
|
2677
2615
|
return c.json(getLoadedExtensions());
|
|
2678
2616
|
});
|
|
2679
2617
|
var extensions_default = app7;
|
|
@@ -2681,18 +2619,18 @@ var extensions_default = app7;
|
|
|
2681
2619
|
// src/web/api/file-sharing.ts
|
|
2682
2620
|
import { readFileSync as readFileSync6, statSync } from "fs";
|
|
2683
2621
|
import { resolve as resolve6 } from "path";
|
|
2684
|
-
import { Hono as
|
|
2622
|
+
import { Hono as Hono9 } from "hono";
|
|
2685
2623
|
async function notifyMind(mindName, message) {
|
|
2686
2624
|
const entry = await findMind(mindName);
|
|
2687
2625
|
if (!entry) return;
|
|
2688
2626
|
try {
|
|
2689
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
2627
|
+
const { sendSystemMessage } = await import("./system-chat-NPYFYZVI.js");
|
|
2690
2628
|
await sendSystemMessage(mindName, message);
|
|
2691
2629
|
} catch (err) {
|
|
2692
2630
|
logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
|
|
2693
2631
|
}
|
|
2694
2632
|
}
|
|
2695
|
-
var app8 = new
|
|
2633
|
+
var app8 = new Hono9().post("/:name/files/send", requireSelf(), async (c) => {
|
|
2696
2634
|
const senderName = c.req.param("name");
|
|
2697
2635
|
const senderEntry = await findMind(senderName);
|
|
2698
2636
|
if (!senderEntry) return c.json({ error: "Sender mind not found" }, 404);
|
|
@@ -2809,11 +2747,9 @@ var app8 = new Hono8().post("/:name/files/send", requireSelf(), async (c) => {
|
|
|
2809
2747
|
var file_sharing_default = app8;
|
|
2810
2748
|
|
|
2811
2749
|
// src/web/api/files.ts
|
|
2812
|
-
import {
|
|
2813
|
-
import { readdir, readFile, realpath, stat } from "fs/promises";
|
|
2750
|
+
import { readFile, realpath, stat } from "fs/promises";
|
|
2814
2751
|
import { extname as extname2, resolve as resolve7 } from "path";
|
|
2815
|
-
import { Hono as
|
|
2816
|
-
var ALLOWED_FILES = /* @__PURE__ */ new Set(["SOUL.md", "MEMORY.md", "CLAUDE.md", "VOLUTE.md"]);
|
|
2752
|
+
import { Hono as Hono10 } from "hono";
|
|
2817
2753
|
var AVATAR_MIME2 = {
|
|
2818
2754
|
".png": "image/png",
|
|
2819
2755
|
".jpg": "image/jpeg",
|
|
@@ -2822,18 +2758,18 @@ var AVATAR_MIME2 = {
|
|
|
2822
2758
|
".webp": "image/webp"
|
|
2823
2759
|
};
|
|
2824
2760
|
var MAX_AVATAR_SIZE2 = 2 * 1024 * 1024;
|
|
2825
|
-
var app9 = new
|
|
2761
|
+
var app9 = new Hono10().get("/:name/avatar", async (c) => {
|
|
2826
2762
|
const name = c.req.param("name");
|
|
2827
2763
|
const entry = await findMind(name);
|
|
2828
2764
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
2829
2765
|
const dir = mindDir(name);
|
|
2830
|
-
const
|
|
2831
|
-
if (!
|
|
2832
|
-
const ext = extname2(
|
|
2766
|
+
const config2 = readVoluteConfig(dir);
|
|
2767
|
+
if (!config2?.profile?.avatar) return c.json({ error: "No avatar configured" }, 404);
|
|
2768
|
+
const ext = extname2(config2.profile.avatar).toLowerCase();
|
|
2833
2769
|
const mime = AVATAR_MIME2[ext];
|
|
2834
2770
|
if (!mime) return c.json({ error: "Invalid avatar extension" }, 400);
|
|
2835
2771
|
const homeDir = resolve7(dir, "home");
|
|
2836
|
-
const avatarPath = resolve7(homeDir,
|
|
2772
|
+
const avatarPath = resolve7(homeDir, config2.profile.avatar);
|
|
2837
2773
|
if (!avatarPath.startsWith(`${homeDir}/`)) return c.json({ error: "Invalid avatar path" }, 400);
|
|
2838
2774
|
let realAvatarPath;
|
|
2839
2775
|
try {
|
|
@@ -2857,40 +2793,15 @@ var app9 = new Hono9().get("/:name/avatar", async (c) => {
|
|
|
2857
2793
|
} catch {
|
|
2858
2794
|
return c.json({ error: "Failed to read avatar file" }, 500);
|
|
2859
2795
|
}
|
|
2860
|
-
}).get("/:name/files", async (c) => {
|
|
2861
|
-
const name = c.req.param("name");
|
|
2862
|
-
const entry = await findMind(name);
|
|
2863
|
-
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
2864
|
-
const dir = mindDir(name);
|
|
2865
|
-
const homeDir = resolve7(dir, "home");
|
|
2866
|
-
if (!existsSync6(homeDir)) return c.json({ error: "Home directory missing" }, 404);
|
|
2867
|
-
const allFiles = await readdir(homeDir);
|
|
2868
|
-
const files = allFiles.filter((f) => f.endsWith(".md") && ALLOWED_FILES.has(f));
|
|
2869
|
-
return c.json(files);
|
|
2870
|
-
}).get("/:name/files/:filename", async (c) => {
|
|
2871
|
-
const name = c.req.param("name");
|
|
2872
|
-
const filename = c.req.param("filename");
|
|
2873
|
-
if (!ALLOWED_FILES.has(filename)) {
|
|
2874
|
-
return c.json({ error: "File not allowed" }, 403);
|
|
2875
|
-
}
|
|
2876
|
-
const entry = await findMind(name);
|
|
2877
|
-
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
2878
|
-
const dir = mindDir(name);
|
|
2879
|
-
const filePath = resolve7(dir, "home", filename);
|
|
2880
|
-
if (!existsSync6(filePath)) {
|
|
2881
|
-
return c.json({ error: "File not found" }, 404);
|
|
2882
|
-
}
|
|
2883
|
-
const content = await readFile(filePath, "utf-8");
|
|
2884
|
-
return c.json({ filename, content });
|
|
2885
2796
|
});
|
|
2886
2797
|
var files_default = app9;
|
|
2887
2798
|
|
|
2888
2799
|
// src/web/api/keys.ts
|
|
2889
|
-
import { Hono as
|
|
2800
|
+
import { Hono as Hono11 } from "hono";
|
|
2890
2801
|
|
|
2891
2802
|
// src/lib/identity.ts
|
|
2892
2803
|
import { createHash, generateKeyPairSync, sign, verify } from "crypto";
|
|
2893
|
-
import { existsSync as
|
|
2804
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
2894
2805
|
import { resolve as resolve8 } from "path";
|
|
2895
2806
|
function generateIdentity(mindDir2) {
|
|
2896
2807
|
const identityDir = resolve8(mindDir2, ".mind/identity");
|
|
@@ -2903,20 +2814,20 @@ function generateIdentity(mindDir2) {
|
|
|
2903
2814
|
const publicPath = resolve8(identityDir, "public.pem");
|
|
2904
2815
|
writeFileSync4(privatePath, privateKey, { mode: 384 });
|
|
2905
2816
|
writeFileSync4(publicPath, publicKey, { mode: 420 });
|
|
2906
|
-
const
|
|
2907
|
-
|
|
2817
|
+
const config2 = readVoluteConfig(mindDir2) ?? {};
|
|
2818
|
+
config2.identity = {
|
|
2908
2819
|
privateKey: ".mind/identity/private.pem",
|
|
2909
2820
|
publicKey: ".mind/identity/public.pem"
|
|
2910
2821
|
};
|
|
2911
|
-
writeVoluteConfig(mindDir2,
|
|
2822
|
+
writeVoluteConfig(mindDir2, config2);
|
|
2912
2823
|
return { publicKeyPem: publicKey, privateKeyPem: privateKey };
|
|
2913
2824
|
}
|
|
2914
2825
|
function getPublicKey(mindDir2) {
|
|
2915
|
-
const
|
|
2916
|
-
const relPath =
|
|
2826
|
+
const config2 = readVoluteConfig(mindDir2);
|
|
2827
|
+
const relPath = config2?.identity?.publicKey;
|
|
2917
2828
|
if (!relPath) return null;
|
|
2918
2829
|
const fullPath = resolve8(mindDir2, relPath);
|
|
2919
|
-
if (!
|
|
2830
|
+
if (!existsSync6(fullPath)) return null;
|
|
2920
2831
|
return readFileSync7(fullPath, "utf-8");
|
|
2921
2832
|
}
|
|
2922
2833
|
function getFingerprint(publicKeyPem) {
|
|
@@ -2946,7 +2857,7 @@ async function publishPublicKey(mindName, publicKeyPem) {
|
|
|
2946
2857
|
}
|
|
2947
2858
|
|
|
2948
2859
|
// src/web/api/keys.ts
|
|
2949
|
-
var app10 = new
|
|
2860
|
+
var app10 = new Hono11().get("/:fingerprint", async (c) => {
|
|
2950
2861
|
const fingerprint = c.req.param("fingerprint");
|
|
2951
2862
|
for (const entry of await readRegistry()) {
|
|
2952
2863
|
try {
|
|
@@ -2964,16 +2875,16 @@ var keys_default = app10;
|
|
|
2964
2875
|
|
|
2965
2876
|
// src/web/api/logs.ts
|
|
2966
2877
|
import { spawn as spawn2 } from "child_process";
|
|
2967
|
-
import { existsSync as
|
|
2878
|
+
import { existsSync as existsSync7 } from "fs";
|
|
2968
2879
|
import { resolve as resolve9 } from "path";
|
|
2969
|
-
import { Hono as
|
|
2880
|
+
import { Hono as Hono12 } from "hono";
|
|
2970
2881
|
import { streamSSE as streamSSE3 } from "hono/streaming";
|
|
2971
|
-
var app11 = new
|
|
2882
|
+
var app11 = new Hono12().get("/:name/logs", async (c) => {
|
|
2972
2883
|
const name = c.req.param("name");
|
|
2973
2884
|
const entry = await findMind(name);
|
|
2974
2885
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
2975
2886
|
const logFile = resolve9(stateDir(name), "logs", "mind.log");
|
|
2976
|
-
if (!
|
|
2887
|
+
if (!existsSync7(logFile)) {
|
|
2977
2888
|
return c.json({ error: "No log file found" }, 404);
|
|
2978
2889
|
}
|
|
2979
2890
|
return streamSSE3(c, async (stream) => {
|
|
@@ -3001,7 +2912,7 @@ var app11 = new Hono11().get("/:name/logs", async (c) => {
|
|
|
3001
2912
|
const entry = await findMind(name);
|
|
3002
2913
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3003
2914
|
const logFile = resolve9(stateDir(name), "logs", "mind.log");
|
|
3004
|
-
if (!
|
|
2915
|
+
if (!existsSync7(logFile)) {
|
|
3005
2916
|
return c.json({ error: "No log file found" }, 404);
|
|
3006
2917
|
}
|
|
3007
2918
|
const nParam = parseInt(c.req.query("n") ?? "50", 10);
|
|
@@ -3020,9 +2931,9 @@ var logs_default = app11;
|
|
|
3020
2931
|
|
|
3021
2932
|
// src/web/api/mind-skills.ts
|
|
3022
2933
|
import { zValidator as zValidator4 } from "@hono/zod-validator";
|
|
3023
|
-
import { Hono as
|
|
2934
|
+
import { Hono as Hono13 } from "hono";
|
|
3024
2935
|
import { z as z4 } from "zod";
|
|
3025
|
-
var app12 = new
|
|
2936
|
+
var app12 = new Hono13().get("/:name/skills", async (c) => {
|
|
3026
2937
|
const name = c.req.param("name");
|
|
3027
2938
|
const entry = await findMind(name);
|
|
3028
2939
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
@@ -3102,7 +3013,7 @@ var mind_skills_default = app12;
|
|
|
3102
3013
|
// src/web/api/minds.ts
|
|
3103
3014
|
import {
|
|
3104
3015
|
cpSync,
|
|
3105
|
-
existsSync as
|
|
3016
|
+
existsSync as existsSync9,
|
|
3106
3017
|
mkdirSync as mkdirSync6,
|
|
3107
3018
|
readdirSync as readdirSync2,
|
|
3108
3019
|
readFileSync as readFileSync10,
|
|
@@ -3112,7 +3023,7 @@ import {
|
|
|
3112
3023
|
import { resolve as resolve12 } from "path";
|
|
3113
3024
|
import { zValidator as zValidator5 } from "@hono/zod-validator";
|
|
3114
3025
|
import { and as and4, desc as desc3, eq as eq5, inArray, sql as sql2 } from "drizzle-orm";
|
|
3115
|
-
import { Hono as
|
|
3026
|
+
import { Hono as Hono14 } from "hono";
|
|
3116
3027
|
import { z as z5 } from "zod";
|
|
3117
3028
|
|
|
3118
3029
|
// src/lib/consolidate.ts
|
|
@@ -3554,7 +3465,7 @@ async function summarizeTurn(mind, session, channel, doneId, turnId) {
|
|
|
3554
3465
|
const transcript = buildTranscript(events);
|
|
3555
3466
|
if (transcript.trim()) {
|
|
3556
3467
|
const summaryPrompt = await getPrompt("turn_summary");
|
|
3557
|
-
const aiResult = await
|
|
3468
|
+
const aiResult = await aiCompleteUtility(summaryPrompt, transcript);
|
|
3558
3469
|
if (aiResult) {
|
|
3559
3470
|
summaryText = aiResult;
|
|
3560
3471
|
deterministic = false;
|
|
@@ -3626,7 +3537,7 @@ async function checkHealth(port) {
|
|
|
3626
3537
|
}
|
|
3627
3538
|
|
|
3628
3539
|
// src/lib/variant-cleanup.ts
|
|
3629
|
-
import { existsSync as
|
|
3540
|
+
import { existsSync as existsSync8, rmSync as rmSync3 } from "fs";
|
|
3630
3541
|
async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
|
|
3631
3542
|
if (opts?.stop) {
|
|
3632
3543
|
try {
|
|
@@ -3635,10 +3546,10 @@ async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
|
|
|
3635
3546
|
logger_default.warn(`failed to stop variant ${variantName}`, logger_default.errorData(err));
|
|
3636
3547
|
}
|
|
3637
3548
|
}
|
|
3638
|
-
const { findMind: findMind2 } = await import("./registry-
|
|
3549
|
+
const { findMind: findMind2 } = await import("./registry-PJ4S5PHQ.js");
|
|
3639
3550
|
const variantEntry = await findMind2(variantName);
|
|
3640
3551
|
const branchName = variantEntry?.branch ?? variantName;
|
|
3641
|
-
if (
|
|
3552
|
+
if (existsSync8(variantPath)) {
|
|
3642
3553
|
try {
|
|
3643
3554
|
await gitExec(["worktree", "remove", "--force", variantPath], { cwd: projectRoot });
|
|
3644
3555
|
} catch {
|
|
@@ -3689,7 +3600,7 @@ async function getMindStatus(name, port) {
|
|
|
3689
3600
|
const manager = getMindManager();
|
|
3690
3601
|
let status = "stopped";
|
|
3691
3602
|
try {
|
|
3692
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
3603
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-53DZOWW7.js");
|
|
3693
3604
|
if (getSleepManagerIfReady2()?.isSleeping(name)) {
|
|
3694
3605
|
status = "sleeping";
|
|
3695
3606
|
}
|
|
@@ -3699,24 +3610,22 @@ async function getMindStatus(name, port) {
|
|
|
3699
3610
|
const health = await checkHealth(port);
|
|
3700
3611
|
status = health.ok ? "running" : "starting";
|
|
3701
3612
|
}
|
|
3702
|
-
const
|
|
3703
|
-
const channelConfig = config?.channels;
|
|
3613
|
+
const config2 = readVoluteConfig(mindDir(name));
|
|
3704
3614
|
const channels = [];
|
|
3705
3615
|
for (const [, provider] of Object.entries(CHANNELS)) {
|
|
3706
3616
|
if (!provider.builtIn) continue;
|
|
3707
3617
|
channels.push({
|
|
3708
3618
|
name: provider.name,
|
|
3709
3619
|
displayName: provider.displayName,
|
|
3710
|
-
status: status === "running" ? "connected" : "disconnected"
|
|
3711
|
-
showToolCalls: channelConfig?.[provider.name]?.showToolCalls ?? provider.showToolCalls
|
|
3620
|
+
status: status === "running" ? "connected" : "disconnected"
|
|
3712
3621
|
});
|
|
3713
3622
|
}
|
|
3714
3623
|
return {
|
|
3715
3624
|
status,
|
|
3716
3625
|
channels,
|
|
3717
|
-
displayName:
|
|
3718
|
-
description:
|
|
3719
|
-
avatar:
|
|
3626
|
+
displayName: config2?.profile?.displayName,
|
|
3627
|
+
description: config2?.profile?.description,
|
|
3628
|
+
avatar: config2?.profile?.avatar
|
|
3720
3629
|
};
|
|
3721
3630
|
}
|
|
3722
3631
|
var TEMPLATE_BRANCH = "volute/template";
|
|
@@ -3748,7 +3657,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
3748
3657
|
await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
|
|
3749
3658
|
} catch {
|
|
3750
3659
|
}
|
|
3751
|
-
if (
|
|
3660
|
+
if (existsSync9(tempWorktree)) {
|
|
3752
3661
|
rmSync4(tempWorktree, { recursive: true, force: true });
|
|
3753
3662
|
}
|
|
3754
3663
|
const templatesRoot = findTemplatesRoot();
|
|
@@ -3770,11 +3679,11 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
3770
3679
|
}
|
|
3771
3680
|
copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
|
|
3772
3681
|
const initDir = resolve12(tempWorktree, ".init");
|
|
3773
|
-
if (
|
|
3682
|
+
if (existsSync9(initDir)) {
|
|
3774
3683
|
rmSync4(initDir, { recursive: true, force: true });
|
|
3775
3684
|
}
|
|
3776
3685
|
const homeDir = resolve12(tempWorktree, "home");
|
|
3777
|
-
if (
|
|
3686
|
+
if (existsSync9(homeDir)) {
|
|
3778
3687
|
for (const entry of readdirSync2(homeDir)) {
|
|
3779
3688
|
if (entry !== "VOLUTE.md") {
|
|
3780
3689
|
rmSync4(resolve12(homeDir, entry), { recursive: true, force: true });
|
|
@@ -3792,7 +3701,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
3792
3701
|
await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
|
|
3793
3702
|
} catch {
|
|
3794
3703
|
}
|
|
3795
|
-
if (
|
|
3704
|
+
if (existsSync9(tempWorktree)) {
|
|
3796
3705
|
rmSync4(tempWorktree, { recursive: true, force: true });
|
|
3797
3706
|
}
|
|
3798
3707
|
rmSync4(composedDir, { recursive: true, force: true });
|
|
@@ -3823,9 +3732,54 @@ async function npmInstallAsMind(cwd, mindName) {
|
|
|
3823
3732
|
await exec("npm", ["install"], { cwd });
|
|
3824
3733
|
}
|
|
3825
3734
|
}
|
|
3735
|
+
async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariantName, upgradeBranch, template) {
|
|
3736
|
+
const mainStatus = (await gitExec(["status", "--porcelain"], { cwd: dir })).trim();
|
|
3737
|
+
if (mainStatus) {
|
|
3738
|
+
await gitExec(["add", "-A"], { cwd: dir });
|
|
3739
|
+
await gitExec(["commit", "-m", "Auto-commit before upgrade merge"], { cwd: dir });
|
|
3740
|
+
}
|
|
3741
|
+
await gitExec(["merge", upgradeBranch], { cwd: dir });
|
|
3742
|
+
try {
|
|
3743
|
+
await cleanupVariant(upgradeVariantName, dir, worktreeDir);
|
|
3744
|
+
} catch (err) {
|
|
3745
|
+
logger_default.warn(`failed to clean up upgrade worktree for ${mindName}`, logger_default.errorData(err));
|
|
3746
|
+
}
|
|
3747
|
+
try {
|
|
3748
|
+
await gitExec(["branch", "-D", upgradeBranch], { cwd: dir });
|
|
3749
|
+
} catch {
|
|
3750
|
+
}
|
|
3751
|
+
try {
|
|
3752
|
+
await setMindTemplateHash(mindName, computeTemplateHash(template));
|
|
3753
|
+
} catch (err) {
|
|
3754
|
+
logger_default.warn(`failed to update template hash for ${mindName}`, logger_default.errorData(err));
|
|
3755
|
+
}
|
|
3756
|
+
try {
|
|
3757
|
+
await npmInstallAsMind(dir, mindName);
|
|
3758
|
+
} catch (err) {
|
|
3759
|
+
logger_default.warn(`npm install failed after upgrade merge for ${mindName}`, logger_default.errorData(err));
|
|
3760
|
+
return {
|
|
3761
|
+
ok: true,
|
|
3762
|
+
warning: `Upgrade merged but npm install failed: ${err instanceof Error ? err.message : String(err)}. You may need to run npm install manually.`
|
|
3763
|
+
};
|
|
3764
|
+
}
|
|
3765
|
+
const manager = getMindManager();
|
|
3766
|
+
try {
|
|
3767
|
+
if (manager.isRunning(mindName)) {
|
|
3768
|
+
await manager.stopMind(mindName);
|
|
3769
|
+
}
|
|
3770
|
+
manager.setPendingContext(mindName, { type: "upgraded" });
|
|
3771
|
+
await manager.startMind(mindName);
|
|
3772
|
+
} catch (e) {
|
|
3773
|
+
return {
|
|
3774
|
+
ok: true,
|
|
3775
|
+
warning: `Upgrade merged but mind restart failed: ${e instanceof Error ? e.message : String(e)}`
|
|
3776
|
+
};
|
|
3777
|
+
}
|
|
3778
|
+
return { ok: true };
|
|
3779
|
+
}
|
|
3826
3780
|
async function importFromArchive(c, tempDir, nameOverride, manifest) {
|
|
3827
3781
|
const extractedMindDir = resolve12(tempDir, "mind");
|
|
3828
|
-
if (!
|
|
3782
|
+
if (!existsSync9(extractedMindDir)) {
|
|
3829
3783
|
return c.json({ error: "Invalid archive: missing mind/ directory" }, 400);
|
|
3830
3784
|
}
|
|
3831
3785
|
if (!manifest?.includes || !manifest.name || !manifest.template) {
|
|
@@ -3843,7 +3797,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
3843
3797
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
3844
3798
|
ensureVoluteHome();
|
|
3845
3799
|
const dest = mindDir(name);
|
|
3846
|
-
if (
|
|
3800
|
+
if (existsSync9(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
3847
3801
|
try {
|
|
3848
3802
|
cpSync(extractedMindDir, dest, { recursive: true });
|
|
3849
3803
|
if (!manifest.includes.identity) {
|
|
@@ -3851,12 +3805,8 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
3851
3805
|
}
|
|
3852
3806
|
const state = stateDir(name);
|
|
3853
3807
|
mkdirSync6(state, { recursive: true });
|
|
3854
|
-
const channelsJson = resolve12(tempDir, "state/channels.json");
|
|
3855
|
-
if (existsSync10(channelsJson)) {
|
|
3856
|
-
cpSync(channelsJson, resolve12(state, "channels.json"));
|
|
3857
|
-
}
|
|
3858
3808
|
const envJson = resolve12(tempDir, "state/env.json");
|
|
3859
|
-
if (
|
|
3809
|
+
if (existsSync9(envJson)) {
|
|
3860
3810
|
cpSync(envJson, resolve12(state, "env.json"));
|
|
3861
3811
|
}
|
|
3862
3812
|
const port = await nextPort();
|
|
@@ -3873,7 +3823,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
3873
3823
|
await npmInstallAsMind(dest, name);
|
|
3874
3824
|
await importHistoryFromArchive(name, tempDir);
|
|
3875
3825
|
importSessionsFromArchive(dest, tempDir);
|
|
3876
|
-
if (!
|
|
3826
|
+
if (!existsSync9(resolve12(dest, ".git"))) {
|
|
3877
3827
|
try {
|
|
3878
3828
|
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve12(dest, "home") } : void 0;
|
|
3879
3829
|
await gitExec(["init"], { cwd: dest, mindName: name, env });
|
|
@@ -3889,7 +3839,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
3889
3839
|
rmSync4(tempDir, { recursive: true, force: true });
|
|
3890
3840
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
3891
3841
|
} catch (err) {
|
|
3892
|
-
if (
|
|
3842
|
+
if (existsSync9(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
3893
3843
|
try {
|
|
3894
3844
|
await removeMind(name);
|
|
3895
3845
|
} catch (cleanupErr) {
|
|
@@ -3906,7 +3856,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
3906
3856
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
3907
3857
|
ensureVoluteHome();
|
|
3908
3858
|
const dest = mindDir(name);
|
|
3909
|
-
if (
|
|
3859
|
+
if (existsSync9(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
3910
3860
|
const templatesRoot = findTemplatesRoot();
|
|
3911
3861
|
const { composedDir, manifest: templateManifest } = composeTemplate(
|
|
3912
3862
|
templatesRoot,
|
|
@@ -3916,34 +3866,30 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
3916
3866
|
copyTemplateToDir(composedDir, dest, name, templateManifest);
|
|
3917
3867
|
applyInitFiles(dest);
|
|
3918
3868
|
const extractedHome = resolve12(extractedMindDir, "home");
|
|
3919
|
-
if (
|
|
3869
|
+
if (existsSync9(extractedHome)) {
|
|
3920
3870
|
cpSync(extractedHome, resolve12(dest, "home"), { recursive: true });
|
|
3921
3871
|
}
|
|
3922
3872
|
const extractedMindInternal = resolve12(extractedMindDir, ".mind");
|
|
3923
|
-
if (
|
|
3873
|
+
if (existsSync9(extractedMindInternal)) {
|
|
3924
3874
|
cpSync(extractedMindInternal, resolve12(dest, ".mind"), { recursive: true });
|
|
3925
3875
|
}
|
|
3926
3876
|
const identityDir = resolve12(dest, ".mind/identity");
|
|
3927
3877
|
let publicKeyPem;
|
|
3928
|
-
if (!manifest.includes.identity || !
|
|
3878
|
+
if (!manifest.includes.identity || !existsSync9(resolve12(identityDir, "private.pem"))) {
|
|
3929
3879
|
({ publicKeyPem } = generateIdentity(dest));
|
|
3930
3880
|
} else {
|
|
3931
3881
|
publicKeyPem = readFileSync10(resolve12(identityDir, "public.pem"), "utf-8");
|
|
3932
3882
|
}
|
|
3933
3883
|
const promptsPath = resolve12(dest, "home/.config/prompts.json");
|
|
3934
|
-
if (!
|
|
3884
|
+
if (!existsSync9(promptsPath)) {
|
|
3935
3885
|
const mindPrompts = await getMindPromptDefaults();
|
|
3936
3886
|
writeFileSync7(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
|
|
3937
3887
|
`);
|
|
3938
3888
|
}
|
|
3939
3889
|
const state = stateDir(name);
|
|
3940
3890
|
mkdirSync6(state, { recursive: true });
|
|
3941
|
-
const channelsJson = resolve12(tempDir, "state/channels.json");
|
|
3942
|
-
if (existsSync10(channelsJson)) {
|
|
3943
|
-
cpSync(channelsJson, resolve12(state, "channels.json"));
|
|
3944
|
-
}
|
|
3945
3891
|
const envJson = resolve12(tempDir, "state/env.json");
|
|
3946
|
-
if (
|
|
3892
|
+
if (existsSync9(envJson)) {
|
|
3947
3893
|
cpSync(envJson, resolve12(state, "env.json"));
|
|
3948
3894
|
}
|
|
3949
3895
|
const port = await nextPort();
|
|
@@ -3996,7 +3942,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
3996
3942
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
3997
3943
|
});
|
|
3998
3944
|
} catch (err) {
|
|
3999
|
-
if (
|
|
3945
|
+
if (existsSync9(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4000
3946
|
try {
|
|
4001
3947
|
await removeMind(name);
|
|
4002
3948
|
} catch (cleanupErr) {
|
|
@@ -4010,7 +3956,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4010
3956
|
}
|
|
4011
3957
|
async function importHistoryFromArchive(name, tempDir) {
|
|
4012
3958
|
const historyJsonl = resolve12(tempDir, "history.jsonl");
|
|
4013
|
-
if (!
|
|
3959
|
+
if (!existsSync9(historyJsonl)) return;
|
|
4014
3960
|
try {
|
|
4015
3961
|
const db = await getDb();
|
|
4016
3962
|
const lines = readFileSync10(historyJsonl, "utf-8").trim().split("\n");
|
|
@@ -4050,7 +3996,7 @@ async function importHistoryFromArchive(name, tempDir) {
|
|
|
4050
3996
|
}
|
|
4051
3997
|
function importSessionsFromArchive(dest, tempDir) {
|
|
4052
3998
|
const sessionsDir = resolve12(tempDir, "sessions");
|
|
4053
|
-
if (!
|
|
3999
|
+
if (!existsSync9(sessionsDir)) return;
|
|
4054
4000
|
try {
|
|
4055
4001
|
const destSessions = resolve12(dest, ".mind/sessions");
|
|
4056
4002
|
mkdirSync6(destSessions, { recursive: true });
|
|
@@ -4068,17 +4014,29 @@ var createMindSchema = z5.object({
|
|
|
4068
4014
|
description: z5.string().optional(),
|
|
4069
4015
|
model: z5.string().optional(),
|
|
4070
4016
|
seedSoul: z5.string().optional(),
|
|
4071
|
-
skills: z5.array(z5.string()).optional()
|
|
4017
|
+
skills: z5.array(z5.string()).optional(),
|
|
4018
|
+
createdBy: z5.string().optional()
|
|
4072
4019
|
});
|
|
4073
|
-
|
|
4020
|
+
function formatTimeAgo(date) {
|
|
4021
|
+
const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
4022
|
+
if (seconds < 60) return "just now";
|
|
4023
|
+
const minutes = Math.floor(seconds / 60);
|
|
4024
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
4025
|
+
const hours = Math.floor(minutes / 60);
|
|
4026
|
+
if (hours < 24) return `${hours}h ago`;
|
|
4027
|
+
const days = Math.floor(hours / 24);
|
|
4028
|
+
return `${days}d ago`;
|
|
4029
|
+
}
|
|
4030
|
+
var app13 = new Hono14().post("/", requireAdminOrSystem, zValidator5("json", createMindSchema), async (c) => {
|
|
4074
4031
|
const body = c.req.valid("json");
|
|
4075
|
-
const { name
|
|
4032
|
+
const { name } = body;
|
|
4033
|
+
const template = body.template ?? resolveTemplate(body.model);
|
|
4076
4034
|
const nameErr = validateMindName(name);
|
|
4077
4035
|
if (nameErr) return c.json({ error: nameErr }, 400);
|
|
4078
4036
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
4079
4037
|
ensureVoluteHome();
|
|
4080
4038
|
const dest = mindDir(name);
|
|
4081
|
-
if (
|
|
4039
|
+
if (existsSync9(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4082
4040
|
const templatesRoot = findTemplatesRoot();
|
|
4083
4041
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
4084
4042
|
try {
|
|
@@ -4086,19 +4044,19 @@ var app13 = new Hono13().post("/", requireAdmin, zValidator5("json", createMindS
|
|
|
4086
4044
|
applyInitFiles(dest);
|
|
4087
4045
|
const { publicKeyPem } = generateIdentity(dest);
|
|
4088
4046
|
{
|
|
4089
|
-
const
|
|
4090
|
-
if (!
|
|
4047
|
+
const config2 = readVoluteConfig(dest);
|
|
4048
|
+
if (!config2) throw new Error("Failed to read volute.json after identity generation");
|
|
4091
4049
|
if (body.description) {
|
|
4092
|
-
|
|
4050
|
+
config2.profile = { ...config2.profile, description: body.description };
|
|
4093
4051
|
}
|
|
4094
|
-
if (!
|
|
4095
|
-
|
|
4052
|
+
if (!config2.sleep) {
|
|
4053
|
+
config2.sleep = {
|
|
4096
4054
|
enabled: true,
|
|
4097
4055
|
schedule: { sleep: "0 0 * * *", wake: "0 8 * * *" }
|
|
4098
4056
|
};
|
|
4099
4057
|
}
|
|
4100
|
-
if (!
|
|
4101
|
-
|
|
4058
|
+
if (!config2.schedules || config2.schedules.length === 0) {
|
|
4059
|
+
config2.schedules = [
|
|
4102
4060
|
{
|
|
4103
4061
|
id: "heartbeat",
|
|
4104
4062
|
cron: "0 12,16,20 * * *",
|
|
@@ -4108,12 +4066,12 @@ var app13 = new Hono13().post("/", requireAdmin, zValidator5("json", createMindS
|
|
|
4108
4066
|
}
|
|
4109
4067
|
];
|
|
4110
4068
|
}
|
|
4111
|
-
writeVoluteConfig(dest,
|
|
4069
|
+
writeVoluteConfig(dest, config2);
|
|
4112
4070
|
}
|
|
4113
4071
|
if (body.model) {
|
|
4114
4072
|
const configPath = resolve12(dest, "home/.config/config.json");
|
|
4115
|
-
const existing =
|
|
4116
|
-
existing.model = body.model;
|
|
4073
|
+
const existing = existsSync9(configPath) ? JSON.parse(readFileSync10(configPath, "utf-8")) : {};
|
|
4074
|
+
existing.model = template === "pi" ? qualifyModelId(body.model) : unqualifyModelId(body.model);
|
|
4117
4075
|
writeFileSync7(configPath, `${JSON.stringify(existing, null, 2)}
|
|
4118
4076
|
`);
|
|
4119
4077
|
}
|
|
@@ -4124,7 +4082,8 @@ var app13 = new Hono13().post("/", requireAdmin, zValidator5("json", createMindS
|
|
|
4124
4082
|
`
|
|
4125
4083
|
);
|
|
4126
4084
|
const port = await nextPort();
|
|
4127
|
-
|
|
4085
|
+
const createdBy = body.createdBy ?? c.get("user")?.username;
|
|
4086
|
+
await addMind(name, port, body.stage, template, createdBy);
|
|
4128
4087
|
try {
|
|
4129
4088
|
await setMindTemplateHash(name, computeTemplateHash(template));
|
|
4130
4089
|
} catch (err) {
|
|
@@ -4206,7 +4165,7 @@ The human who planted you described you as: "${body.description}"
|
|
|
4206
4165
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
4207
4166
|
});
|
|
4208
4167
|
} catch (err) {
|
|
4209
|
-
if (
|
|
4168
|
+
if (existsSync9(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4210
4169
|
try {
|
|
4211
4170
|
await removeMind(name);
|
|
4212
4171
|
} catch {
|
|
@@ -4226,13 +4185,13 @@ The human who planted you described you as: "${body.description}"
|
|
|
4226
4185
|
return importFromArchive(c, body.archivePath, body.name, body.manifest);
|
|
4227
4186
|
}
|
|
4228
4187
|
const wsDir = body.workspacePath;
|
|
4229
|
-
if (!wsDir || !
|
|
4188
|
+
if (!wsDir || !existsSync9(resolve12(wsDir, "SOUL.md")) || !existsSync9(resolve12(wsDir, "IDENTITY.md"))) {
|
|
4230
4189
|
return c.json({ error: "Invalid workspace: missing SOUL.md or IDENTITY.md" }, 400);
|
|
4231
4190
|
}
|
|
4232
4191
|
const soul = readFileSync10(resolve12(wsDir, "SOUL.md"), "utf-8");
|
|
4233
4192
|
const identity = readFileSync10(resolve12(wsDir, "IDENTITY.md"), "utf-8");
|
|
4234
4193
|
const userPath = resolve12(wsDir, "USER.md");
|
|
4235
|
-
const user =
|
|
4194
|
+
const user = existsSync9(userPath) ? readFileSync10(userPath, "utf-8") : "";
|
|
4236
4195
|
const name = body.name ?? parseNameFromIdentity(identity) ?? "imported-mind";
|
|
4237
4196
|
const template = body.template ?? "claude";
|
|
4238
4197
|
const nameErr = validateMindName(name);
|
|
@@ -4252,7 +4211,7 @@ ${user.trimEnd()}
|
|
|
4252
4211
|
` : "";
|
|
4253
4212
|
ensureVoluteHome();
|
|
4254
4213
|
const dest = mindDir(name);
|
|
4255
|
-
if (
|
|
4214
|
+
if (existsSync9(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4256
4215
|
const templatesRoot = findTemplatesRoot();
|
|
4257
4216
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
4258
4217
|
try {
|
|
@@ -4261,7 +4220,7 @@ ${user.trimEnd()}
|
|
|
4261
4220
|
const { publicKeyPem: importPublicKey } = generateIdentity(dest);
|
|
4262
4221
|
writeFileSync7(resolve12(dest, "home/SOUL.md"), mergedSoul);
|
|
4263
4222
|
const wsMemoryPath = resolve12(wsDir, "MEMORY.md");
|
|
4264
|
-
const hasMemory =
|
|
4223
|
+
const hasMemory = existsSync9(wsMemoryPath);
|
|
4265
4224
|
if (hasMemory) {
|
|
4266
4225
|
const existingMemory = readFileSync10(wsMemoryPath, "utf-8");
|
|
4267
4226
|
writeFileSync7(
|
|
@@ -4274,7 +4233,7 @@ ${user.trimEnd()}
|
|
|
4274
4233
|
}
|
|
4275
4234
|
const wsMemoryDir = resolve12(wsDir, "memory");
|
|
4276
4235
|
let dailyLogCount = 0;
|
|
4277
|
-
if (
|
|
4236
|
+
if (existsSync9(wsMemoryDir)) {
|
|
4278
4237
|
const destMemoryDir = resolve12(dest, "home/memory");
|
|
4279
4238
|
const files = readdirSync2(wsMemoryDir).filter((f) => f.endsWith(".md"));
|
|
4280
4239
|
for (const file of files) {
|
|
@@ -4303,7 +4262,7 @@ ${user.trimEnd()}
|
|
|
4303
4262
|
await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
|
|
4304
4263
|
await gitExec(["commit", "-m", "import from OpenClaw"], { cwd: dest, mindName: name, env });
|
|
4305
4264
|
const sessionFile = body.sessionPath ? resolve12(body.sessionPath) : findOpenClawSession(wsDir);
|
|
4306
|
-
if (sessionFile &&
|
|
4265
|
+
if (sessionFile && existsSync9(sessionFile)) {
|
|
4307
4266
|
if (template === "pi") {
|
|
4308
4267
|
importPiSession(sessionFile, dest);
|
|
4309
4268
|
} else if (template === "claude") {
|
|
@@ -4325,7 +4284,7 @@ ${user.trimEnd()}
|
|
|
4325
4284
|
);
|
|
4326
4285
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
4327
4286
|
} catch (err) {
|
|
4328
|
-
if (
|
|
4287
|
+
if (existsSync9(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4329
4288
|
try {
|
|
4330
4289
|
await removeMind(name);
|
|
4331
4290
|
} catch {
|
|
@@ -4349,7 +4308,7 @@ ${user.trimEnd()}
|
|
|
4349
4308
|
const minds = await Promise.all(
|
|
4350
4309
|
entries.map(async (entry) => {
|
|
4351
4310
|
const mindStatus = await getMindStatus(entry.name, entry.port);
|
|
4352
|
-
const hasPages =
|
|
4311
|
+
const hasPages = existsSync9(resolve12(mindDir(entry.name), "home", "public", "pages"));
|
|
4353
4312
|
return {
|
|
4354
4313
|
...entry,
|
|
4355
4314
|
...mindStatus,
|
|
@@ -4359,16 +4318,12 @@ ${user.trimEnd()}
|
|
|
4359
4318
|
})
|
|
4360
4319
|
);
|
|
4361
4320
|
return c.json(minds);
|
|
4362
|
-
}).get("/pages/sites", async (c) => {
|
|
4363
|
-
return c.json(getCachedSites());
|
|
4364
|
-
}).get("/pages/recent", async (c) => {
|
|
4365
|
-
return c.json(getCachedRecentPages());
|
|
4366
4321
|
}).get("/:name", async (c) => {
|
|
4367
4322
|
const name = c.req.param("name");
|
|
4368
4323
|
const entry = await findMind(name);
|
|
4369
4324
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4370
4325
|
const dir = entry.dir ?? mindDir(entry.parent ?? name);
|
|
4371
|
-
if (!
|
|
4326
|
+
if (!existsSync9(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4372
4327
|
const mindStatus = await getMindStatus(name, entry.port);
|
|
4373
4328
|
const variants = await findVariants(name);
|
|
4374
4329
|
const manager = getMindManager();
|
|
@@ -4382,7 +4337,7 @@ ${user.trimEnd()}
|
|
|
4382
4337
|
return { name: s.name, port: s.port, status: variantStatus };
|
|
4383
4338
|
})
|
|
4384
4339
|
);
|
|
4385
|
-
const hasPages =
|
|
4340
|
+
const hasPages = existsSync9(resolve12(mindDir(name), "home", "public", "pages"));
|
|
4386
4341
|
return c.json({ ...entry, ...mindStatus, variants: variantStatuses, hasPages });
|
|
4387
4342
|
}).post("/:name/start", requireSelf(), async (c) => {
|
|
4388
4343
|
const name = c.req.param("name");
|
|
@@ -4393,7 +4348,7 @@ ${user.trimEnd()}
|
|
|
4393
4348
|
if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
|
|
4394
4349
|
} else {
|
|
4395
4350
|
const dir = mindDir(name);
|
|
4396
|
-
if (!
|
|
4351
|
+
if (!existsSync9(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4397
4352
|
}
|
|
4398
4353
|
if (getMindManager().isRunning(name)) {
|
|
4399
4354
|
return c.json({ error: "Mind already running" }, 409);
|
|
@@ -4414,7 +4369,7 @@ ${user.trimEnd()}
|
|
|
4414
4369
|
if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
|
|
4415
4370
|
} else {
|
|
4416
4371
|
const dir = mindDir(name);
|
|
4417
|
-
if (!
|
|
4372
|
+
if (!existsSync9(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4418
4373
|
}
|
|
4419
4374
|
let context;
|
|
4420
4375
|
const contentType = c.req.header("content-type");
|
|
@@ -4429,7 +4384,7 @@ ${user.trimEnd()}
|
|
|
4429
4384
|
const manager = getMindManager();
|
|
4430
4385
|
try {
|
|
4431
4386
|
if (context?.type === "reload") {
|
|
4432
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4387
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-53DZOWW7.js");
|
|
4433
4388
|
const sleepState = getSleepManagerIfReady2()?.getState(name);
|
|
4434
4389
|
if (sleepState?.sleeping) {
|
|
4435
4390
|
logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
|
|
@@ -4449,7 +4404,7 @@ ${user.trimEnd()}
|
|
|
4449
4404
|
const variantEntry = await findMind(mergeVariantName);
|
|
4450
4405
|
if (variantEntry && variantEntry.parent === baseName && variantEntry.dir && variantEntry.branch) {
|
|
4451
4406
|
const projectRoot = mindDir(baseName);
|
|
4452
|
-
if (
|
|
4407
|
+
if (existsSync9(variantEntry.dir)) {
|
|
4453
4408
|
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
4454
4409
|
if (status) {
|
|
4455
4410
|
try {
|
|
@@ -4525,7 +4480,7 @@ ${user.trimEnd()}
|
|
|
4525
4480
|
const name = c.req.param("name");
|
|
4526
4481
|
const entry = await findMind(name);
|
|
4527
4482
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4528
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4483
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-53DZOWW7.js");
|
|
4529
4484
|
const sm = getSleepManagerIfReady2();
|
|
4530
4485
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
4531
4486
|
return c.json(sm.getState(name));
|
|
@@ -4533,7 +4488,7 @@ ${user.trimEnd()}
|
|
|
4533
4488
|
const name = c.req.param("name");
|
|
4534
4489
|
const entry = await findMind(name);
|
|
4535
4490
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4536
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4491
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-53DZOWW7.js");
|
|
4537
4492
|
const sm = getSleepManagerIfReady2();
|
|
4538
4493
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
4539
4494
|
if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
|
|
@@ -4553,7 +4508,7 @@ ${user.trimEnd()}
|
|
|
4553
4508
|
const name = c.req.param("name");
|
|
4554
4509
|
const entry = await findMind(name);
|
|
4555
4510
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4556
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4511
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-53DZOWW7.js");
|
|
4557
4512
|
const sm = getSleepManagerIfReady2();
|
|
4558
4513
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
4559
4514
|
const sleepState = sm.getState(name);
|
|
@@ -4568,7 +4523,7 @@ ${user.trimEnd()}
|
|
|
4568
4523
|
const name = c.req.param("name");
|
|
4569
4524
|
const entry = await findMind(name);
|
|
4570
4525
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4571
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4526
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-53DZOWW7.js");
|
|
4572
4527
|
const sm = getSleepManagerIfReady2();
|
|
4573
4528
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
4574
4529
|
const flushed = await sm.flushQueuedMessages(name);
|
|
@@ -4606,10 +4561,10 @@ ${user.trimEnd()}
|
|
|
4606
4561
|
await removeMind(name);
|
|
4607
4562
|
await deleteMindUser2(name);
|
|
4608
4563
|
const state = stateDir(name);
|
|
4609
|
-
if (
|
|
4564
|
+
if (existsSync9(state)) {
|
|
4610
4565
|
rmSync4(state, { recursive: true, force: true });
|
|
4611
4566
|
}
|
|
4612
|
-
if (force &&
|
|
4567
|
+
if (force && existsSync9(dir)) {
|
|
4613
4568
|
rmSync4(dir, { recursive: true, force: true });
|
|
4614
4569
|
deleteMindUser(name);
|
|
4615
4570
|
}
|
|
@@ -4624,7 +4579,7 @@ ${user.trimEnd()}
|
|
|
4624
4579
|
const entry = await findMind(mindName);
|
|
4625
4580
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4626
4581
|
const dir = mindDir(mindName);
|
|
4627
|
-
if (!
|
|
4582
|
+
if (!existsSync9(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4628
4583
|
let body = {};
|
|
4629
4584
|
try {
|
|
4630
4585
|
body = await c.req.json();
|
|
@@ -4635,14 +4590,14 @@ ${user.trimEnd()}
|
|
|
4635
4590
|
const upgradeVariantName = `${mindName}-upgrade`;
|
|
4636
4591
|
const worktreeDir = resolve12(dir, ".variants", UPGRADE_BRANCH);
|
|
4637
4592
|
if (body.abort) {
|
|
4638
|
-
if (!
|
|
4593
|
+
if (!existsSync9(worktreeDir)) {
|
|
4639
4594
|
return c.json({ error: "No upgrade in progress" }, 400);
|
|
4640
4595
|
}
|
|
4641
4596
|
try {
|
|
4642
4597
|
try {
|
|
4643
4598
|
const gitDirContent = readFileSync10(resolve12(worktreeDir, ".git"), "utf-8").trim();
|
|
4644
4599
|
const gitDir = gitDirContent.replace("gitdir: ", "");
|
|
4645
|
-
if (
|
|
4600
|
+
if (existsSync9(resolve12(gitDir, "MERGE_HEAD"))) {
|
|
4646
4601
|
await gitExec(["merge", "--abort"], { cwd: worktreeDir });
|
|
4647
4602
|
}
|
|
4648
4603
|
} catch {
|
|
@@ -4661,7 +4616,7 @@ ${user.trimEnd()}
|
|
|
4661
4616
|
}
|
|
4662
4617
|
}
|
|
4663
4618
|
if (body.continue) {
|
|
4664
|
-
if (!
|
|
4619
|
+
if (!existsSync9(worktreeDir)) {
|
|
4665
4620
|
return c.json({ error: "No upgrade in progress" }, 400);
|
|
4666
4621
|
}
|
|
4667
4622
|
const status = await gitExec(["status", "--porcelain"], { cwd: worktreeDir });
|
|
@@ -4679,92 +4634,77 @@ ${user.trimEnd()}
|
|
|
4679
4634
|
if (!msg.includes("nothing to commit") && !stderr.includes("nothing to commit") && !stdout.includes("nothing to commit"))
|
|
4680
4635
|
throw e;
|
|
4681
4636
|
}
|
|
4682
|
-
chownMindDir(dir, mindName);
|
|
4683
4637
|
try {
|
|
4684
|
-
await
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4638
|
+
await gitExec(["add", "home/"], { cwd: worktreeDir });
|
|
4639
|
+
} catch (err) {
|
|
4640
|
+
logger_default.warn(`failed to re-add home files during upgrade for ${mindName}`, logger_default.errorData(err));
|
|
4641
|
+
}
|
|
4642
|
+
try {
|
|
4643
|
+
await gitExec(["diff", "--cached", "--quiet"], { cwd: worktreeDir });
|
|
4644
|
+
} catch {
|
|
4645
|
+
await gitExec(["commit", "-m", "re-add allowlisted home files"], {
|
|
4646
|
+
cwd: worktreeDir
|
|
4693
4647
|
});
|
|
4648
|
+
}
|
|
4649
|
+
chownMindDir(dir, mindName);
|
|
4650
|
+
try {
|
|
4651
|
+
const result = await mergeUpgradeAndRestart(
|
|
4652
|
+
mindName,
|
|
4653
|
+
dir,
|
|
4654
|
+
worktreeDir,
|
|
4655
|
+
upgradeVariantName,
|
|
4656
|
+
UPGRADE_BRANCH,
|
|
4657
|
+
template
|
|
4658
|
+
);
|
|
4659
|
+
return c.json(result);
|
|
4694
4660
|
} catch (err) {
|
|
4695
|
-
await cleanupVariant(upgradeVariantName, dir, worktreeDir);
|
|
4696
4661
|
return c.json(
|
|
4697
|
-
{ error: err instanceof Error ? err.message : "Failed to
|
|
4662
|
+
{ error: err instanceof Error ? err.message : "Failed to merge upgrade" },
|
|
4698
4663
|
500
|
|
4699
4664
|
);
|
|
4700
4665
|
}
|
|
4701
4666
|
}
|
|
4702
4667
|
if (body.accept) {
|
|
4703
|
-
if (
|
|
4704
|
-
return c.json({ error: "No upgrade in progress" }, 400);
|
|
4705
|
-
}
|
|
4706
|
-
const variantEntry = await findMind(upgradeVariantName);
|
|
4707
|
-
if (!variantEntry) {
|
|
4708
|
-
return c.json({ error: "Upgrade variant not found in DB" }, 400);
|
|
4709
|
-
}
|
|
4710
|
-
const status = (await gitExec(["status", "--porcelain"], { cwd: worktreeDir })).trim();
|
|
4711
|
-
if (status) {
|
|
4668
|
+
if (existsSync9(worktreeDir)) {
|
|
4712
4669
|
try {
|
|
4713
|
-
await
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
});
|
|
4717
|
-
} catch {
|
|
4718
|
-
return c.json({ error: "Failed to auto-commit upgrade changes before merge" }, 500);
|
|
4670
|
+
await cleanupVariant(upgradeVariantName, dir, worktreeDir, { stop: true });
|
|
4671
|
+
} catch (err) {
|
|
4672
|
+
logger_default.warn(`failed to clean up legacy upgrade variant for ${mindName}`, logger_default.errorData(err));
|
|
4719
4673
|
}
|
|
4720
|
-
}
|
|
4721
|
-
const mainStatus = (await gitExec(["status", "--porcelain"], { cwd: dir })).trim();
|
|
4722
|
-
if (mainStatus) {
|
|
4723
4674
|
try {
|
|
4724
|
-
await gitExec(["
|
|
4725
|
-
|
|
4726
|
-
} catch (_e) {
|
|
4727
|
-
return c.json({ error: "Failed to auto-commit main changes before merge" }, 500);
|
|
4675
|
+
await gitExec(["branch", "-D", UPGRADE_BRANCH], { cwd: dir });
|
|
4676
|
+
} catch {
|
|
4728
4677
|
}
|
|
4729
4678
|
}
|
|
4679
|
+
return c.json({ error: "Upgrades now auto-merge. Run 'volute mind upgrade' again." }, 400);
|
|
4680
|
+
}
|
|
4681
|
+
if (body.diff) {
|
|
4730
4682
|
try {
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4683
|
+
if (!existsSync9(resolve12(dir, ".git"))) {
|
|
4684
|
+
return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
|
|
4685
|
+
}
|
|
4686
|
+
await updateTemplateBranch(dir, template, mindName);
|
|
4687
|
+
let diff;
|
|
4688
|
+
try {
|
|
4689
|
+
diff = await gitExec(["diff", "HEAD...volute/template"], { cwd: dir });
|
|
4690
|
+
} catch {
|
|
4691
|
+
diff = await gitExec(["diff", "HEAD", "volute/template"], { cwd: dir });
|
|
4692
|
+
}
|
|
4693
|
+
return c.json({ ok: true, diff: diff || "(no changes)" });
|
|
4738
4694
|
} catch (err) {
|
|
4739
|
-
|
|
4695
|
+
return c.json(
|
|
4696
|
+
{ error: err instanceof Error ? err.message : "Failed to generate diff" },
|
|
4697
|
+
500
|
|
4698
|
+
);
|
|
4740
4699
|
}
|
|
4741
|
-
try {
|
|
4742
|
-
await npmInstallAsMind(dir, mindName);
|
|
4743
|
-
} catch (err) {
|
|
4744
|
-
logger_default.warn(`npm install failed after upgrade merge for ${mindName}`, logger_default.errorData(err));
|
|
4745
|
-
}
|
|
4746
|
-
const manager = getMindManager();
|
|
4747
|
-
try {
|
|
4748
|
-
if (manager.isRunning(mindName)) {
|
|
4749
|
-
await manager.stopMind(mindName);
|
|
4750
|
-
}
|
|
4751
|
-
manager.setPendingContext(mindName, { type: "merged", name: upgradeVariantName });
|
|
4752
|
-
await manager.startMind(mindName);
|
|
4753
|
-
} catch (e) {
|
|
4754
|
-
return c.json({
|
|
4755
|
-
ok: true,
|
|
4756
|
-
warning: `Upgrade merged but mind restart failed: ${e instanceof Error ? e.message : String(e)}`
|
|
4757
|
-
});
|
|
4758
|
-
}
|
|
4759
|
-
return c.json({ ok: true });
|
|
4760
4700
|
}
|
|
4761
|
-
if (
|
|
4701
|
+
if (existsSync9(worktreeDir)) {
|
|
4762
4702
|
return c.json(
|
|
4763
4703
|
{ error: "Upgrade variant already exists. Use continue or delete it first." },
|
|
4764
4704
|
409
|
|
4765
4705
|
);
|
|
4766
4706
|
}
|
|
4767
|
-
if (!
|
|
4707
|
+
if (!existsSync9(resolve12(dir, ".git"))) {
|
|
4768
4708
|
try {
|
|
4769
4709
|
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve12(dir, "home") } : void 0;
|
|
4770
4710
|
await gitExec(["init"], { cwd: dir, mindName, env });
|
|
@@ -4787,7 +4727,7 @@ ${user.trimEnd()}
|
|
|
4787
4727
|
await gitExec(["branch", "-D", UPGRADE_BRANCH], { cwd: dir });
|
|
4788
4728
|
} catch {
|
|
4789
4729
|
}
|
|
4790
|
-
if (!
|
|
4730
|
+
if (!existsSync9(resolve12(dir, "home", "shared"))) {
|
|
4791
4731
|
try {
|
|
4792
4732
|
await addSharedWorktree(mindName, dir);
|
|
4793
4733
|
} catch (err) {
|
|
@@ -4799,7 +4739,7 @@ ${user.trimEnd()}
|
|
|
4799
4739
|
}
|
|
4800
4740
|
await updateTemplateBranch(dir, template, mindName);
|
|
4801
4741
|
const parentDir = resolve12(dir, ".variants");
|
|
4802
|
-
if (!
|
|
4742
|
+
if (!existsSync9(parentDir)) {
|
|
4803
4743
|
mkdirSync6(parentDir, { recursive: true });
|
|
4804
4744
|
}
|
|
4805
4745
|
await gitExec(["worktree", "add", "-b", UPGRADE_BRANCH, worktreeDir], { cwd: dir });
|
|
@@ -4850,22 +4790,22 @@ ${user.trimEnd()}
|
|
|
4850
4790
|
});
|
|
4851
4791
|
}
|
|
4852
4792
|
try {
|
|
4853
|
-
await
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
variant: UPGRADE_BRANCH,
|
|
4861
|
-
port: variantPort
|
|
4862
|
-
});
|
|
4863
|
-
} catch (err) {
|
|
4864
|
-
await cleanupVariant(upgradeVariantName, dir, worktreeDir);
|
|
4865
|
-
return c.json(
|
|
4866
|
-
{ error: err instanceof Error ? err.message : "Failed to complete upgrade" },
|
|
4867
|
-
500
|
|
4793
|
+
const result = await mergeUpgradeAndRestart(
|
|
4794
|
+
mindName,
|
|
4795
|
+
dir,
|
|
4796
|
+
worktreeDir,
|
|
4797
|
+
upgradeVariantName,
|
|
4798
|
+
UPGRADE_BRANCH,
|
|
4799
|
+
template
|
|
4868
4800
|
);
|
|
4801
|
+
return c.json(result);
|
|
4802
|
+
} catch (err) {
|
|
4803
|
+
try {
|
|
4804
|
+
await cleanupVariant(upgradeVariantName, dir, worktreeDir);
|
|
4805
|
+
} catch (cleanupErr) {
|
|
4806
|
+
logger_default.warn(`cleanup failed after upgrade error for ${mindName}`, logger_default.errorData(cleanupErr));
|
|
4807
|
+
}
|
|
4808
|
+
return c.json({ error: err instanceof Error ? err.message : "Failed to merge upgrade" }, 500);
|
|
4869
4809
|
}
|
|
4870
4810
|
}).get("/:name/conversations", async (c) => {
|
|
4871
4811
|
const name = c.req.param("name");
|
|
@@ -4928,13 +4868,13 @@ ${user.trimEnd()}
|
|
|
4928
4868
|
const entry = await findMind(name);
|
|
4929
4869
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4930
4870
|
const dir = mindDir(name);
|
|
4931
|
-
if (!
|
|
4932
|
-
let
|
|
4933
|
-
if (!
|
|
4871
|
+
if (!existsSync9(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4872
|
+
let config2 = readVoluteConfig(dir);
|
|
4873
|
+
if (!config2 && entry.template === "pi") {
|
|
4934
4874
|
const piConfigPath = resolve12(dir, "home/.config/config.json");
|
|
4935
|
-
if (
|
|
4875
|
+
if (existsSync9(piConfigPath)) {
|
|
4936
4876
|
try {
|
|
4937
|
-
|
|
4877
|
+
config2 = JSON.parse(readFileSync10(piConfigPath, "utf-8"));
|
|
4938
4878
|
} catch {
|
|
4939
4879
|
}
|
|
4940
4880
|
}
|
|
@@ -4948,10 +4888,10 @@ ${user.trimEnd()}
|
|
|
4948
4888
|
template: entry.template
|
|
4949
4889
|
},
|
|
4950
4890
|
config: {
|
|
4951
|
-
model:
|
|
4952
|
-
thinkingLevel:
|
|
4953
|
-
tokenBudget:
|
|
4954
|
-
tokenBudgetPeriodMinutes:
|
|
4891
|
+
model: config2?.model ?? null,
|
|
4892
|
+
thinkingLevel: config2?.thinkingLevel ?? null,
|
|
4893
|
+
tokenBudget: config2?.tokenBudget ?? null,
|
|
4894
|
+
tokenBudgetPeriodMinutes: config2?.tokenBudgetPeriodMinutes ?? null
|
|
4955
4895
|
}
|
|
4956
4896
|
});
|
|
4957
4897
|
}).put(
|
|
@@ -4971,7 +4911,7 @@ ${user.trimEnd()}
|
|
|
4971
4911
|
const entry = await findMind(name);
|
|
4972
4912
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4973
4913
|
const dir = mindDir(name);
|
|
4974
|
-
if (!
|
|
4914
|
+
if (!existsSync9(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4975
4915
|
const body = c.req.valid("json");
|
|
4976
4916
|
const existing = readVoluteConfig(dir) ?? {};
|
|
4977
4917
|
if (body.model !== void 0) existing.model = body.model;
|
|
@@ -5013,7 +4953,7 @@ ${user.trimEnd()}
|
|
|
5013
4953
|
if (!body.systemPrompt || !body.message) {
|
|
5014
4954
|
return c.json({ error: "systemPrompt and message required" }, 400);
|
|
5015
4955
|
}
|
|
5016
|
-
const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-
|
|
4956
|
+
const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-ZIPCV3MX.js");
|
|
5017
4957
|
if (!isAiConfigured()) {
|
|
5018
4958
|
return c.json({ error: "AI service not configured" }, 503);
|
|
5019
4959
|
}
|
|
@@ -5105,7 +5045,7 @@ ${user.trimEnd()}
|
|
|
5105
5045
|
publishTypingForChannels(affected, map);
|
|
5106
5046
|
broadcast({ type: "mind_done", mind: baseName, summary: "Finished processing" });
|
|
5107
5047
|
try {
|
|
5108
|
-
|
|
5048
|
+
getDeliveryManager().sessionDone(baseName, body.session);
|
|
5109
5049
|
} catch (err) {
|
|
5110
5050
|
if (!(err instanceof Error && err.message.includes("not initialized"))) {
|
|
5111
5051
|
logger_default.error(`delivery manager sessionDone failed for ${baseName}`, logger_default.errorData(err));
|
|
@@ -5450,6 +5390,52 @@ ${user.trimEnd()}
|
|
|
5450
5390
|
)
|
|
5451
5391
|
).orderBy(mindHistory.id);
|
|
5452
5392
|
return c.json(rows);
|
|
5393
|
+
}).get("/:name/history/cross-session", async (c) => {
|
|
5394
|
+
const name = c.req.param("name");
|
|
5395
|
+
const currentSession = c.req.query("session");
|
|
5396
|
+
const db = await getDb();
|
|
5397
|
+
let sinceTimestamp = null;
|
|
5398
|
+
if (currentSession) {
|
|
5399
|
+
const lastTurn = await db.select({ turn_id: mindHistory.turn_id }).from(mindHistory).where(
|
|
5400
|
+
and4(
|
|
5401
|
+
eq5(mindHistory.mind, name),
|
|
5402
|
+
eq5(mindHistory.session, currentSession),
|
|
5403
|
+
sql2`${mindHistory.turn_id} IS NOT NULL`
|
|
5404
|
+
)
|
|
5405
|
+
).orderBy(desc3(mindHistory.created_at)).limit(1);
|
|
5406
|
+
if (lastTurn.length > 0 && lastTurn[0].turn_id) {
|
|
5407
|
+
const firstEvent = await db.select({ created_at: mindHistory.created_at }).from(mindHistory).where(eq5(mindHistory.turn_id, lastTurn[0].turn_id)).orderBy(mindHistory.created_at).limit(1);
|
|
5408
|
+
if (firstEvent.length > 0) {
|
|
5409
|
+
sinceTimestamp = firstEvent[0].created_at;
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5413
|
+
if (!sinceTimestamp) {
|
|
5414
|
+
sinceTimestamp = new Date(Date.now() - 36e5).toISOString().replace("T", " ").slice(0, 19);
|
|
5415
|
+
}
|
|
5416
|
+
const conditions = [
|
|
5417
|
+
eq5(mindHistory.mind, name),
|
|
5418
|
+
eq5(mindHistory.type, "summary"),
|
|
5419
|
+
sql2`${mindHistory.created_at} > ${sinceTimestamp}`
|
|
5420
|
+
];
|
|
5421
|
+
if (currentSession) {
|
|
5422
|
+
conditions.push(sql2`${mindHistory.session} != ${currentSession}`);
|
|
5423
|
+
}
|
|
5424
|
+
const rows = await db.select({
|
|
5425
|
+
session: mindHistory.session,
|
|
5426
|
+
content: mindHistory.content,
|
|
5427
|
+
created_at: mindHistory.created_at
|
|
5428
|
+
}).from(mindHistory).where(and4(...conditions)).orderBy(desc3(mindHistory.created_at)).limit(50);
|
|
5429
|
+
if (rows.length === 0) {
|
|
5430
|
+
return c.json({ context: null });
|
|
5431
|
+
}
|
|
5432
|
+
const lines = rows.map((row) => {
|
|
5433
|
+
const ts = new Date(row.created_at.endsWith("Z") ? row.created_at : `${row.created_at}Z`);
|
|
5434
|
+
const ago = formatTimeAgo(ts);
|
|
5435
|
+
return `- ${row.session ?? "unknown"} (${ago}): ${row.content ?? ""}`;
|
|
5436
|
+
});
|
|
5437
|
+
return c.json({ context: `[Session Activity]
|
|
5438
|
+
${lines.join("\n")}` });
|
|
5453
5439
|
}).get("/:name/history", async (c) => {
|
|
5454
5440
|
const name = c.req.param("name");
|
|
5455
5441
|
const channel = c.req.query("channel");
|
|
@@ -5490,9 +5476,9 @@ var minds_default = app13;
|
|
|
5490
5476
|
// src/web/api/prompts.ts
|
|
5491
5477
|
import { zValidator as zValidator6 } from "@hono/zod-validator";
|
|
5492
5478
|
import { eq as eq6, sql as sql3 } from "drizzle-orm";
|
|
5493
|
-
import { Hono as
|
|
5479
|
+
import { Hono as Hono15 } from "hono";
|
|
5494
5480
|
import { z as z6 } from "zod";
|
|
5495
|
-
var app14 = new
|
|
5481
|
+
var app14 = new Hono15().get("/", async (c) => {
|
|
5496
5482
|
let rows;
|
|
5497
5483
|
try {
|
|
5498
5484
|
const db = await getDb();
|
|
@@ -5539,9 +5525,9 @@ var app14 = new Hono14().get("/", async (c) => {
|
|
|
5539
5525
|
var prompts_default = app14;
|
|
5540
5526
|
|
|
5541
5527
|
// src/web/api/public-files.ts
|
|
5542
|
-
import { readdir
|
|
5528
|
+
import { readdir, readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
5543
5529
|
import { extname as extname3, resolve as resolve13 } from "path";
|
|
5544
|
-
import { Hono as
|
|
5530
|
+
import { Hono as Hono16 } from "hono";
|
|
5545
5531
|
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
5546
5532
|
async function resolvePublicRoot(name) {
|
|
5547
5533
|
if (name === "_system") return resolve13(voluteHome(), "shared");
|
|
@@ -5572,7 +5558,7 @@ var MIME_TYPES = {
|
|
|
5572
5558
|
async function listDir(dirPath) {
|
|
5573
5559
|
let entries;
|
|
5574
5560
|
try {
|
|
5575
|
-
entries = await
|
|
5561
|
+
entries = await readdir(dirPath, { withFileTypes: true });
|
|
5576
5562
|
} catch (err) {
|
|
5577
5563
|
if (err?.code === "ENOENT") return [];
|
|
5578
5564
|
throw err;
|
|
@@ -5582,7 +5568,7 @@ async function listDir(dirPath) {
|
|
|
5582
5568
|
type: e.isDirectory() ? "directory" : "file"
|
|
5583
5569
|
}));
|
|
5584
5570
|
}
|
|
5585
|
-
var app15 = new
|
|
5571
|
+
var app15 = new Hono16().get("/:name/", async (c) => {
|
|
5586
5572
|
const name = c.req.param("name");
|
|
5587
5573
|
const publicRoot = await resolvePublicRoot(name);
|
|
5588
5574
|
if (!publicRoot) return c.json({ error: "Not found" }, 404);
|
|
@@ -5629,16 +5615,16 @@ var public_files_default = app15;
|
|
|
5629
5615
|
|
|
5630
5616
|
// src/web/api/schedules.ts
|
|
5631
5617
|
import { CronExpressionParser } from "cron-parser";
|
|
5632
|
-
import { Hono as
|
|
5618
|
+
import { Hono as Hono17 } from "hono";
|
|
5633
5619
|
var slog2 = logger_default.child("schedules");
|
|
5634
5620
|
function readSchedules(name) {
|
|
5635
5621
|
return readVoluteConfig(mindDir(name))?.schedules ?? [];
|
|
5636
5622
|
}
|
|
5637
5623
|
function writeSchedules(name, schedules) {
|
|
5638
5624
|
const dir = mindDir(name);
|
|
5639
|
-
const
|
|
5640
|
-
|
|
5641
|
-
writeVoluteConfig(dir,
|
|
5625
|
+
const config2 = readVoluteConfig(dir) ?? {};
|
|
5626
|
+
config2.schedules = schedules.length > 0 ? schedules : void 0;
|
|
5627
|
+
writeVoluteConfig(dir, config2);
|
|
5642
5628
|
getScheduler().loadSchedules(name);
|
|
5643
5629
|
getSleepManagerIfReady()?.invalidateSleepConfig(name);
|
|
5644
5630
|
fireWebhook({
|
|
@@ -5647,7 +5633,7 @@ function writeSchedules(name, schedules) {
|
|
|
5647
5633
|
data: { schedules }
|
|
5648
5634
|
});
|
|
5649
5635
|
}
|
|
5650
|
-
var app16 = new
|
|
5636
|
+
var app16 = new Hono17().get("/:name/clock/status", async (c) => {
|
|
5651
5637
|
const name = c.req.param("name");
|
|
5652
5638
|
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
5653
5639
|
const sleepManager = getSleepManagerIfReady();
|
|
@@ -5805,7 +5791,7 @@ var app16 = new Hono16().get("/:name/clock/status", async (c) => {
|
|
|
5805
5791
|
const body = await c.req.text();
|
|
5806
5792
|
const message = `[webhook: ${event}] ${body}`;
|
|
5807
5793
|
try {
|
|
5808
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
5794
|
+
const { sendSystemMessage } = await import("./system-chat-NPYFYZVI.js");
|
|
5809
5795
|
await sendSystemMessage(name, message);
|
|
5810
5796
|
return c.json({ ok: true });
|
|
5811
5797
|
} catch (err) {
|
|
@@ -5819,18 +5805,53 @@ var schedules_default = app16;
|
|
|
5819
5805
|
import { mkdirSync as mkdirSync7 } from "fs";
|
|
5820
5806
|
import { homedir as homedir2 } from "os";
|
|
5821
5807
|
import { resolve as resolve14 } from "path";
|
|
5822
|
-
import { Hono as
|
|
5823
|
-
|
|
5824
|
-
|
|
5808
|
+
import { Hono as Hono18 } from "hono";
|
|
5809
|
+
import { setCookie as setCookie2 } from "hono/cookie";
|
|
5810
|
+
var DEFAULT_API_URL2 = "https://volute.systems";
|
|
5811
|
+
var setup = new Hono18();
|
|
5812
|
+
function writeSetupConfig(systemName, description) {
|
|
5813
|
+
const configHome = process.env.VOLUTE_HOME ?? resolve14(homedir2(), ".volute");
|
|
5814
|
+
const mindsDir = resolve14(configHome, "minds");
|
|
5815
|
+
mkdirSync7(configHome, { recursive: true });
|
|
5816
|
+
mkdirSync7(mindsDir, { recursive: true });
|
|
5817
|
+
const existingConfig = readGlobalConfig();
|
|
5818
|
+
const setupConfig = {
|
|
5819
|
+
type: "local",
|
|
5820
|
+
mindsDir,
|
|
5821
|
+
isolation: "sandbox",
|
|
5822
|
+
service: false
|
|
5823
|
+
};
|
|
5824
|
+
const config2 = {
|
|
5825
|
+
...existingConfig,
|
|
5826
|
+
name: systemName,
|
|
5827
|
+
description: description || existingConfig.description,
|
|
5828
|
+
setup: setupConfig
|
|
5829
|
+
};
|
|
5830
|
+
writeGlobalConfig(config2);
|
|
5831
|
+
return config2;
|
|
5832
|
+
}
|
|
5833
|
+
setup.get("/status", async (c) => {
|
|
5825
5834
|
const complete = isSetupComplete();
|
|
5826
|
-
if (
|
|
5827
|
-
|
|
5835
|
+
if (complete) {
|
|
5836
|
+
const config3 = readGlobalConfig();
|
|
5837
|
+
return c.json({
|
|
5838
|
+
complete,
|
|
5839
|
+
config: { name: config3.name, setup: config3.setup }
|
|
5840
|
+
});
|
|
5828
5841
|
}
|
|
5829
|
-
const
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5842
|
+
const config2 = readGlobalConfig();
|
|
5843
|
+
const hasSystem = config2.setup != null;
|
|
5844
|
+
let hasAccount = false;
|
|
5845
|
+
if (hasSystem) {
|
|
5846
|
+
try {
|
|
5847
|
+
const { listUsersByType: listUsersByType2 } = await import("./auth-6DMGES3I.js");
|
|
5848
|
+
const brains = await listUsersByType2("brain");
|
|
5849
|
+
hasAccount = brains.length > 0;
|
|
5850
|
+
} catch (err) {
|
|
5851
|
+
logger_default.debug("could not check for existing accounts during setup status", logger_default.errorData(err));
|
|
5852
|
+
}
|
|
5853
|
+
}
|
|
5854
|
+
return c.json({ complete, hasSystem, hasAccount });
|
|
5834
5855
|
});
|
|
5835
5856
|
setup.post("/configure", async (c) => {
|
|
5836
5857
|
if (isSetupComplete()) {
|
|
@@ -5846,42 +5867,313 @@ setup.post("/configure", async (c) => {
|
|
|
5846
5867
|
return c.json({ error: "System name is required" }, 400);
|
|
5847
5868
|
}
|
|
5848
5869
|
const setupType = body.type ?? "local";
|
|
5849
|
-
const isolation = body.isolation ?? "sandbox";
|
|
5850
5870
|
if (setupType !== "local") {
|
|
5851
5871
|
return c.json({ error: "Web setup only supports local install type" }, 400);
|
|
5852
5872
|
}
|
|
5853
|
-
const configHome = process.env.VOLUTE_HOME ?? resolve14(homedir2(), ".volute");
|
|
5854
|
-
const mindsDir = resolve14(configHome, "minds");
|
|
5855
5873
|
try {
|
|
5856
|
-
|
|
5857
|
-
|
|
5874
|
+
const config2 = writeSetupConfig(body.name.trim());
|
|
5875
|
+
config2.setupCompleted = true;
|
|
5876
|
+
writeGlobalConfig(config2);
|
|
5877
|
+
return c.json({ ok: true, config: { name: config2.name, setup: config2.setup } });
|
|
5858
5878
|
} catch (err) {
|
|
5859
|
-
return c.json({ error: `Failed to
|
|
5879
|
+
return c.json({ error: `Failed to write configuration: ${err.message}` }, 500);
|
|
5860
5880
|
}
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
};
|
|
5868
|
-
const config = {
|
|
5869
|
-
...existingConfig,
|
|
5870
|
-
name: body.name.trim(),
|
|
5871
|
-
setup: setupConfig
|
|
5872
|
-
};
|
|
5881
|
+
});
|
|
5882
|
+
setup.post("/system", async (c) => {
|
|
5883
|
+
if (isSetupComplete()) {
|
|
5884
|
+
return c.json({ error: "Setup already complete" }, 400);
|
|
5885
|
+
}
|
|
5886
|
+
let body;
|
|
5873
5887
|
try {
|
|
5874
|
-
|
|
5888
|
+
body = await c.req.json();
|
|
5889
|
+
} catch {
|
|
5890
|
+
return c.json({ error: "Invalid JSON in request body" }, 400);
|
|
5891
|
+
}
|
|
5892
|
+
if (!body.name?.trim()) {
|
|
5893
|
+
return c.json({ error: "System name is required" }, 400);
|
|
5894
|
+
}
|
|
5895
|
+
try {
|
|
5896
|
+
writeSetupConfig(body.name.trim(), body.description?.trim());
|
|
5897
|
+
return c.json({ ok: true });
|
|
5875
5898
|
} catch (err) {
|
|
5876
5899
|
return c.json({ error: `Failed to write configuration: ${err.message}` }, 500);
|
|
5877
5900
|
}
|
|
5878
|
-
|
|
5901
|
+
});
|
|
5902
|
+
setup.post("/system/register", async (c) => {
|
|
5903
|
+
if (isSetupComplete()) {
|
|
5904
|
+
return c.json({ error: "Setup already complete" }, 400);
|
|
5905
|
+
}
|
|
5906
|
+
let body;
|
|
5907
|
+
try {
|
|
5908
|
+
body = await c.req.json();
|
|
5909
|
+
} catch {
|
|
5910
|
+
return c.json({ error: "Invalid JSON in request body" }, 400);
|
|
5911
|
+
}
|
|
5912
|
+
if (!body.slug?.trim()) {
|
|
5913
|
+
return c.json({ error: "System slug is required" }, 400);
|
|
5914
|
+
}
|
|
5915
|
+
const existing = readSystemsConfig();
|
|
5916
|
+
if (existing) {
|
|
5917
|
+
return c.json({ error: `Already registered as "${existing.system}"` }, 400);
|
|
5918
|
+
}
|
|
5919
|
+
const config2 = readGlobalConfig();
|
|
5920
|
+
const apiUrl = process.env.VOLUTE_SYSTEMS_URL || DEFAULT_API_URL2;
|
|
5921
|
+
let apiKey;
|
|
5922
|
+
let system;
|
|
5923
|
+
try {
|
|
5924
|
+
const res = await fetch(`${apiUrl}/api/register`, {
|
|
5925
|
+
method: "POST",
|
|
5926
|
+
headers: { "Content-Type": "application/json" },
|
|
5927
|
+
body: JSON.stringify({
|
|
5928
|
+
name: body.slug.trim(),
|
|
5929
|
+
displayName: config2.name || void 0,
|
|
5930
|
+
description: config2.description || void 0
|
|
5931
|
+
})
|
|
5932
|
+
});
|
|
5933
|
+
if (!res.ok) {
|
|
5934
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
5935
|
+
return c.json({ error: `volute.systems: ${err.error}` }, 502);
|
|
5936
|
+
}
|
|
5937
|
+
({ apiKey, system } = await res.json());
|
|
5938
|
+
} catch (err) {
|
|
5939
|
+
return c.json({ error: `Could not reach volute.systems: ${err.message}` }, 502);
|
|
5940
|
+
}
|
|
5941
|
+
try {
|
|
5942
|
+
writeSystemsConfig({ apiKey, system, apiUrl });
|
|
5943
|
+
} catch (err) {
|
|
5944
|
+
return c.json(
|
|
5945
|
+
{
|
|
5946
|
+
error: `Registered as "${system}" but failed to save config: ${err.message}`
|
|
5947
|
+
},
|
|
5948
|
+
500
|
|
5949
|
+
);
|
|
5950
|
+
}
|
|
5951
|
+
return c.json({ system });
|
|
5952
|
+
});
|
|
5953
|
+
setup.post("/system/login", async (c) => {
|
|
5954
|
+
if (isSetupComplete()) {
|
|
5955
|
+
return c.json({ error: "Setup already complete" }, 400);
|
|
5956
|
+
}
|
|
5957
|
+
let body;
|
|
5958
|
+
try {
|
|
5959
|
+
body = await c.req.json();
|
|
5960
|
+
} catch {
|
|
5961
|
+
return c.json({ error: "Invalid JSON in request body" }, 400);
|
|
5962
|
+
}
|
|
5963
|
+
if (!body.key?.trim()) {
|
|
5964
|
+
return c.json({ error: "API key is required" }, 400);
|
|
5965
|
+
}
|
|
5966
|
+
const existing = readSystemsConfig();
|
|
5967
|
+
if (existing) {
|
|
5968
|
+
return c.json({ error: `Already logged in as "${existing.system}"` }, 400);
|
|
5969
|
+
}
|
|
5970
|
+
const apiUrl = process.env.VOLUTE_SYSTEMS_URL || DEFAULT_API_URL2;
|
|
5971
|
+
let system;
|
|
5972
|
+
try {
|
|
5973
|
+
const res = await fetch(`${apiUrl}/api/whoami`, {
|
|
5974
|
+
headers: { Authorization: `Bearer ${body.key.trim()}` }
|
|
5975
|
+
});
|
|
5976
|
+
if (!res.ok) {
|
|
5977
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
5978
|
+
return c.json({ error: `volute.systems: ${err.error}` }, 502);
|
|
5979
|
+
}
|
|
5980
|
+
({ system } = await res.json());
|
|
5981
|
+
} catch (err) {
|
|
5982
|
+
return c.json({ error: `Could not reach volute.systems: ${err.message}` }, 502);
|
|
5983
|
+
}
|
|
5984
|
+
try {
|
|
5985
|
+
writeSystemsConfig({ apiKey: body.key.trim(), system, apiUrl });
|
|
5986
|
+
} catch (err) {
|
|
5987
|
+
return c.json(
|
|
5988
|
+
{
|
|
5989
|
+
error: `Logged in as "${system}" but failed to save config: ${err.message}`
|
|
5990
|
+
},
|
|
5991
|
+
500
|
|
5992
|
+
);
|
|
5993
|
+
}
|
|
5994
|
+
return c.json({ system });
|
|
5995
|
+
});
|
|
5996
|
+
setup.post("/system/disconnect", async (c) => {
|
|
5997
|
+
if (isSetupComplete()) {
|
|
5998
|
+
return c.json({ error: "Setup already complete" }, 400);
|
|
5999
|
+
}
|
|
6000
|
+
deleteSystemsConfig();
|
|
6001
|
+
return c.json({ ok: true });
|
|
6002
|
+
});
|
|
6003
|
+
setup.get("/system/systems-status", (c) => {
|
|
6004
|
+
const config2 = readSystemsConfig();
|
|
6005
|
+
return c.json({ registered: !!config2, system: config2?.system ?? null });
|
|
6006
|
+
});
|
|
6007
|
+
setup.post("/account", async (c) => {
|
|
6008
|
+
if (isSetupComplete()) {
|
|
6009
|
+
return c.json({ error: "Setup already complete" }, 400);
|
|
6010
|
+
}
|
|
6011
|
+
let body;
|
|
6012
|
+
try {
|
|
6013
|
+
body = await c.req.json();
|
|
6014
|
+
} catch {
|
|
6015
|
+
return c.json({ error: "Invalid JSON in request body" }, 400);
|
|
6016
|
+
}
|
|
6017
|
+
if (!body.username?.trim()) {
|
|
6018
|
+
return c.json({ error: "Username is required" }, 400);
|
|
6019
|
+
}
|
|
6020
|
+
if (!body.password || body.password.length < 1) {
|
|
6021
|
+
return c.json({ error: "Password is required" }, 400);
|
|
6022
|
+
}
|
|
6023
|
+
const config2 = readGlobalConfig();
|
|
6024
|
+
if (!config2.setup) {
|
|
6025
|
+
try {
|
|
6026
|
+
writeSetupConfig(config2.name ?? "Volute");
|
|
6027
|
+
} catch (err) {
|
|
6028
|
+
return c.json({ error: `Failed to write configuration: ${err.message}` }, 500);
|
|
6029
|
+
}
|
|
6030
|
+
}
|
|
6031
|
+
try {
|
|
6032
|
+
const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-6DMGES3I.js");
|
|
6033
|
+
const user = await createUser2(body.username.trim(), body.password);
|
|
6034
|
+
if (body.displayName?.trim()) {
|
|
6035
|
+
await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
|
|
6036
|
+
}
|
|
6037
|
+
const sessionId = await createSession(user.id);
|
|
6038
|
+
setCookie2(c, "volute_session", sessionId, {
|
|
6039
|
+
path: "/",
|
|
6040
|
+
httpOnly: true,
|
|
6041
|
+
sameSite: "Lax",
|
|
6042
|
+
maxAge: Math.floor(SESSION_MAX_AGE / 1e3)
|
|
6043
|
+
});
|
|
6044
|
+
return c.json({
|
|
6045
|
+
ok: true,
|
|
6046
|
+
user: {
|
|
6047
|
+
id: user.id,
|
|
6048
|
+
username: user.username,
|
|
6049
|
+
role: user.role,
|
|
6050
|
+
display_name: body.displayName?.trim() ?? null
|
|
6051
|
+
}
|
|
6052
|
+
});
|
|
6053
|
+
} catch (err) {
|
|
6054
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
6055
|
+
if (msg.includes("UNIQUE constraint")) {
|
|
6056
|
+
return c.json({ error: "Username already exists" }, 409);
|
|
6057
|
+
}
|
|
6058
|
+
return c.json({ error: `Failed to create user: ${msg}` }, 500);
|
|
6059
|
+
}
|
|
6060
|
+
});
|
|
6061
|
+
setup.post("/models", async (c) => {
|
|
6062
|
+
if (isSetupComplete()) {
|
|
6063
|
+
return c.json({ error: "Setup already complete" }, 400);
|
|
6064
|
+
}
|
|
6065
|
+
let body;
|
|
6066
|
+
try {
|
|
6067
|
+
body = await c.req.json();
|
|
6068
|
+
} catch {
|
|
6069
|
+
return c.json({ error: "Invalid JSON in request body" }, 400);
|
|
6070
|
+
}
|
|
6071
|
+
if (!Array.isArray(body.models) || body.models.length === 0) {
|
|
6072
|
+
return c.json({ error: "At least one model must be selected" }, 400);
|
|
6073
|
+
}
|
|
6074
|
+
if (!body.spiritModel?.trim()) {
|
|
6075
|
+
return c.json({ error: "Spirit model is required" }, 400);
|
|
6076
|
+
}
|
|
6077
|
+
try {
|
|
6078
|
+
const { setEnabledModels: setEnabledModels2, setUtilityModel } = await import("./ai-service-ZIPCV3MX.js");
|
|
6079
|
+
setEnabledModels2(body.models);
|
|
6080
|
+
const config2 = readGlobalConfig();
|
|
6081
|
+
config2.spiritModel = body.spiritModel.trim();
|
|
6082
|
+
writeGlobalConfig(config2);
|
|
6083
|
+
if (body.utilityModel?.trim()) {
|
|
6084
|
+
setUtilityModel(body.utilityModel.trim());
|
|
6085
|
+
}
|
|
6086
|
+
return c.json({ ok: true });
|
|
6087
|
+
} catch (err) {
|
|
6088
|
+
return c.json({ error: `Failed to save models: ${err.message}` }, 500);
|
|
6089
|
+
}
|
|
6090
|
+
});
|
|
6091
|
+
setup.post("/complete", async (c) => {
|
|
6092
|
+
if (isSetupComplete()) {
|
|
6093
|
+
return c.json({ error: "Setup already complete" }, 400);
|
|
6094
|
+
}
|
|
6095
|
+
try {
|
|
6096
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-N4W4UQRH.js");
|
|
6097
|
+
const { startSpiritFull } = await import("./mind-service-AV273WT4.js");
|
|
6098
|
+
await ensureSpiritProject();
|
|
6099
|
+
await syncSpiritTemplate();
|
|
6100
|
+
const warnings = [];
|
|
6101
|
+
let spiritStarted = false;
|
|
6102
|
+
try {
|
|
6103
|
+
logger_default.info("starting spirit during setup...");
|
|
6104
|
+
await startSpiritFull("volute");
|
|
6105
|
+
spiritStarted = true;
|
|
6106
|
+
logger_default.info("spirit started successfully during setup");
|
|
6107
|
+
} catch (err) {
|
|
6108
|
+
logger_default.warn("spirit start failed during setup (non-fatal)", logger_default.errorData(err));
|
|
6109
|
+
warnings.push("Spirit failed to start \u2014 it will retry on next daemon restart.");
|
|
6110
|
+
}
|
|
6111
|
+
let spiritConversationId;
|
|
6112
|
+
try {
|
|
6113
|
+
const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-6DMGES3I.js");
|
|
6114
|
+
const { createConversation: createConversation6, findDMConversation: findDMConversation2 } = await import("./conversations-3O5O6AS3.js");
|
|
6115
|
+
const spiritUser = await getOrCreateMindUser2("volute");
|
|
6116
|
+
const brains = await listUsersByType2("brain");
|
|
6117
|
+
const admin2 = brains.find((u) => u.role === "admin");
|
|
6118
|
+
if (admin2) {
|
|
6119
|
+
const existing = await findDMConversation2("volute", [admin2.id, spiritUser.id]);
|
|
6120
|
+
if (existing) {
|
|
6121
|
+
spiritConversationId = existing;
|
|
6122
|
+
} else {
|
|
6123
|
+
const conv = await createConversation6("volute", "volute", {
|
|
6124
|
+
participantIds: [admin2.id, spiritUser.id],
|
|
6125
|
+
title: "Volute"
|
|
6126
|
+
});
|
|
6127
|
+
spiritConversationId = conv.id;
|
|
6128
|
+
}
|
|
6129
|
+
}
|
|
6130
|
+
} catch (err) {
|
|
6131
|
+
logger_default.warn("failed to create spirit DM during setup (non-fatal)", logger_default.errorData(err));
|
|
6132
|
+
warnings.push("Failed to create conversation with spirit.");
|
|
6133
|
+
}
|
|
6134
|
+
logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
|
|
6135
|
+
if (spiritConversationId && spiritStarted) {
|
|
6136
|
+
try {
|
|
6137
|
+
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-2FIM7QKO.js");
|
|
6138
|
+
const { listUsersByType: listUsers6 } = await import("./auth-6DMGES3I.js");
|
|
6139
|
+
const admins = await listUsers6("brain");
|
|
6140
|
+
const admin2 = admins.find((u) => u.role === "admin");
|
|
6141
|
+
const adminName = admin2?.display_name || admin2?.username || "the admin";
|
|
6142
|
+
const welcomePrompt = `Setup is complete. ${adminName} just finished setting up this system and is now in your chat. Welcome them and help them create their first mind. Keep it brief \u2014 a short greeting, then ask what kind of being they'd like to bring into the world. Remember: minds are beings with their own experience, not tools \u2014 ask about personality and character, never about tasks or utility.`;
|
|
6143
|
+
await deliverMessage2("volute", {
|
|
6144
|
+
content: [{ type: "text", text: welcomePrompt }],
|
|
6145
|
+
channel: `@${admin2?.username ?? "system"}`,
|
|
6146
|
+
conversationId: spiritConversationId,
|
|
6147
|
+
sender: admin2?.username ?? "system",
|
|
6148
|
+
isDM: true,
|
|
6149
|
+
participants: ["volute", admin2?.username ?? "system"],
|
|
6150
|
+
participantCount: 2
|
|
6151
|
+
});
|
|
6152
|
+
} catch (err) {
|
|
6153
|
+
logger_default.warn("failed to send welcome prompt to spirit (non-fatal)", logger_default.errorData(err));
|
|
6154
|
+
warnings.push(
|
|
6155
|
+
"Welcome message failed to send \u2014 try sending a message to start the conversation."
|
|
6156
|
+
);
|
|
6157
|
+
}
|
|
6158
|
+
}
|
|
6159
|
+
const config2 = readGlobalConfig();
|
|
6160
|
+
config2.setupCompleted = true;
|
|
6161
|
+
writeGlobalConfig(config2);
|
|
6162
|
+
return c.json({
|
|
6163
|
+
ok: true,
|
|
6164
|
+
spiritConversationId,
|
|
6165
|
+
spiritStarted,
|
|
6166
|
+
warnings: warnings.length > 0 ? warnings : void 0
|
|
6167
|
+
});
|
|
6168
|
+
} catch (err) {
|
|
6169
|
+
return c.json({ error: `Setup completion failed: ${err.message}` }, 500);
|
|
6170
|
+
}
|
|
5879
6171
|
});
|
|
5880
6172
|
var setup_default = setup;
|
|
5881
6173
|
|
|
5882
6174
|
// src/web/api/shared.ts
|
|
5883
|
-
import { Hono as
|
|
5884
|
-
var app17 = new
|
|
6175
|
+
import { Hono as Hono19 } from "hono";
|
|
6176
|
+
var app17 = new Hono19().post("/:name/shared/merge", requireAdmin, async (c) => {
|
|
5885
6177
|
const name = c.req.param("name");
|
|
5886
6178
|
const entry = await findMind(name);
|
|
5887
6179
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
@@ -5902,12 +6194,12 @@ var app17 = new Hono18().post("/:name/shared/merge", requireAdmin, async (c) =>
|
|
|
5902
6194
|
var shared_default = app17;
|
|
5903
6195
|
|
|
5904
6196
|
// src/web/api/skills.ts
|
|
5905
|
-
import { existsSync as
|
|
6197
|
+
import { existsSync as existsSync10, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync5 } from "fs";
|
|
5906
6198
|
import { tmpdir } from "os";
|
|
5907
6199
|
import { join, resolve as resolve15 } from "path";
|
|
5908
6200
|
import AdmZip from "adm-zip";
|
|
5909
|
-
import { Hono as
|
|
5910
|
-
var app18 = new
|
|
6201
|
+
import { Hono as Hono20 } from "hono";
|
|
6202
|
+
var app18 = new Hono20().get("/", async (c) => {
|
|
5911
6203
|
const skills = await listSharedSkills();
|
|
5912
6204
|
return c.json(skills);
|
|
5913
6205
|
}).get("/defaults/list", async (c) => {
|
|
@@ -5917,15 +6209,15 @@ var app18 = new Hono19().get("/", async (c) => {
|
|
|
5917
6209
|
if (!Array.isArray(body.skills) || !body.skills.every((s) => typeof s === "string")) {
|
|
5918
6210
|
return c.json({ error: "body.skills must be a string array" }, 400);
|
|
5919
6211
|
}
|
|
5920
|
-
const
|
|
6212
|
+
const config2 = readGlobalConfig();
|
|
5921
6213
|
const allStandard = /* @__PURE__ */ new Set([...STANDARD_SKILLS, ...getExtensionStandardSkills()]);
|
|
5922
6214
|
const newSet = new Set(body.skills);
|
|
5923
6215
|
const removed = [...allStandard].filter((s) => !newSet.has(s));
|
|
5924
|
-
const prevRemoved = new Set(
|
|
6216
|
+
const prevRemoved = new Set(config2.removedDefaultSkills ?? []);
|
|
5925
6217
|
for (const s of removed) prevRemoved.add(s);
|
|
5926
6218
|
for (const s of body.skills) prevRemoved.delete(s);
|
|
5927
6219
|
writeGlobalConfig({
|
|
5928
|
-
...
|
|
6220
|
+
...config2,
|
|
5929
6221
|
defaultSkills: body.skills,
|
|
5930
6222
|
removedDefaultSkills: [...prevRemoved]
|
|
5931
6223
|
});
|
|
@@ -5939,10 +6231,10 @@ var app18 = new Hono19().get("/", async (c) => {
|
|
|
5939
6231
|
if (current.includes(body.skill)) {
|
|
5940
6232
|
return c.json({ error: `"${body.skill}" is already a default skill` }, 409);
|
|
5941
6233
|
}
|
|
5942
|
-
const
|
|
6234
|
+
const config2 = readGlobalConfig();
|
|
5943
6235
|
const updated = [...current, body.skill];
|
|
5944
|
-
const removed = (
|
|
5945
|
-
writeGlobalConfig({ ...
|
|
6236
|
+
const removed = (config2.removedDefaultSkills ?? []).filter((s) => s !== body.skill);
|
|
6237
|
+
writeGlobalConfig({ ...config2, defaultSkills: updated, removedDefaultSkills: removed });
|
|
5946
6238
|
return c.json({ skills: updated });
|
|
5947
6239
|
}).delete("/defaults/list/:skill", requireAdmin, async (c) => {
|
|
5948
6240
|
const skill = c.req.param("skill");
|
|
@@ -5950,11 +6242,11 @@ var app18 = new Hono19().get("/", async (c) => {
|
|
|
5950
6242
|
if (!current.includes(skill)) {
|
|
5951
6243
|
return c.json({ error: `"${skill}" is not a default skill` }, 404);
|
|
5952
6244
|
}
|
|
5953
|
-
const
|
|
6245
|
+
const config2 = readGlobalConfig();
|
|
5954
6246
|
const updated = current.filter((s) => s !== skill);
|
|
5955
|
-
const removed = new Set(
|
|
6247
|
+
const removed = new Set(config2.removedDefaultSkills ?? []);
|
|
5956
6248
|
removed.add(skill);
|
|
5957
|
-
writeGlobalConfig({ ...
|
|
6249
|
+
writeGlobalConfig({ ...config2, defaultSkills: updated, removedDefaultSkills: [...removed] });
|
|
5958
6250
|
return c.json({ skills: updated });
|
|
5959
6251
|
}).post("/upload", requireAdmin, async (c) => {
|
|
5960
6252
|
const body = await c.req.parseBody();
|
|
@@ -5977,12 +6269,12 @@ var app18 = new Hono19().get("/", async (c) => {
|
|
|
5977
6269
|
}
|
|
5978
6270
|
zip.extractAllTo(tmpDir, true);
|
|
5979
6271
|
let skillDir = null;
|
|
5980
|
-
if (
|
|
6272
|
+
if (existsSync10(join(tmpDir, "SKILL.md"))) {
|
|
5981
6273
|
skillDir = tmpDir;
|
|
5982
6274
|
} else {
|
|
5983
6275
|
const entries = readdirSync3(tmpDir, { withFileTypes: true }).filter((e) => e.isDirectory());
|
|
5984
6276
|
for (const entry of entries) {
|
|
5985
|
-
if (
|
|
6277
|
+
if (existsSync10(join(tmpDir, entry.name, "SKILL.md"))) {
|
|
5986
6278
|
skillDir = join(tmpDir, entry.name);
|
|
5987
6279
|
break;
|
|
5988
6280
|
}
|
|
@@ -6022,14 +6314,14 @@ var skills_default = app18;
|
|
|
6022
6314
|
|
|
6023
6315
|
// src/web/api/typing.ts
|
|
6024
6316
|
import { zValidator as zValidator7 } from "@hono/zod-validator";
|
|
6025
|
-
import { Hono as
|
|
6317
|
+
import { Hono as Hono21 } from "hono";
|
|
6026
6318
|
import { z as z7 } from "zod";
|
|
6027
6319
|
var typingSchema = z7.object({
|
|
6028
6320
|
channel: z7.string().min(1),
|
|
6029
6321
|
sender: z7.string().min(1),
|
|
6030
6322
|
active: z7.boolean()
|
|
6031
6323
|
});
|
|
6032
|
-
var app19 = new
|
|
6324
|
+
var app19 = new Hono21().post("/:name/typing", zValidator7("json", typingSchema), (c) => {
|
|
6033
6325
|
const { channel, sender, active } = c.req.valid("json");
|
|
6034
6326
|
const map = getTypingMap();
|
|
6035
6327
|
if (active) {
|
|
@@ -6037,10 +6329,8 @@ var app19 = new Hono20().post("/:name/typing", zValidator7("json", typingSchema)
|
|
|
6037
6329
|
} else {
|
|
6038
6330
|
map.delete(channel, sender);
|
|
6039
6331
|
}
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
const conversationId = channel.slice(volutePrefix.length);
|
|
6043
|
-
publish(conversationId, { type: "typing", senders: map.get(channel) });
|
|
6332
|
+
if (isConversationId(channel)) {
|
|
6333
|
+
publish(channel, { type: "typing", senders: map.get(channel) });
|
|
6044
6334
|
}
|
|
6045
6335
|
return c.json({ ok: true });
|
|
6046
6336
|
}).get("/:name/typing", (c) => {
|
|
@@ -6055,9 +6345,9 @@ var typing_default = app19;
|
|
|
6055
6345
|
|
|
6056
6346
|
// src/web/api/update.ts
|
|
6057
6347
|
import { spawn as spawn3 } from "child_process";
|
|
6058
|
-
import { Hono as
|
|
6348
|
+
import { Hono as Hono22 } from "hono";
|
|
6059
6349
|
var bin;
|
|
6060
|
-
var app20 = new
|
|
6350
|
+
var app20 = new Hono22().get("/update", async (c) => {
|
|
6061
6351
|
const result = await checkForUpdate();
|
|
6062
6352
|
return c.json(result);
|
|
6063
6353
|
}).post("/update", requireAdmin, async (c) => {
|
|
@@ -6076,17 +6366,18 @@ var update_default = app20;
|
|
|
6076
6366
|
|
|
6077
6367
|
// src/web/api/v1/chat.ts
|
|
6078
6368
|
import { zValidator as zValidator8 } from "@hono/zod-validator";
|
|
6079
|
-
import { Hono as
|
|
6369
|
+
import { Hono as Hono23 } from "hono";
|
|
6080
6370
|
import { streamSSE as streamSSE4 } from "hono/streaming";
|
|
6081
6371
|
import { z as z8 } from "zod";
|
|
6082
6372
|
async function fanOutToMinds(opts) {
|
|
6083
6373
|
const participants = await getParticipants(opts.conversationId);
|
|
6084
|
-
const mindParticipants = participants.filter(
|
|
6374
|
+
const mindParticipants = participants.filter(
|
|
6375
|
+
(p) => p.userType === "mind" || p.userType === "system"
|
|
6376
|
+
);
|
|
6085
6377
|
const participantNames = participants.map((p) => p.username);
|
|
6086
6378
|
const isDM = opts.isDM ?? participants.length === 2;
|
|
6087
|
-
const
|
|
6088
|
-
const {
|
|
6089
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TPS6OGCA.js");
|
|
6379
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-BNCMGYXW.js");
|
|
6380
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-53DZOWW7.js");
|
|
6090
6381
|
const manager = getMindManager2();
|
|
6091
6382
|
const sm = getSleepManagerIfReady2();
|
|
6092
6383
|
const targetMinds = mindParticipants.map((ap) => {
|
|
@@ -6103,19 +6394,6 @@ async function fanOutToMinds(opts) {
|
|
|
6103
6394
|
...opts.slugExtra
|
|
6104
6395
|
});
|
|
6105
6396
|
}
|
|
6106
|
-
const channelEntry = {
|
|
6107
|
-
platformId: opts.conversationId,
|
|
6108
|
-
platform: "volute",
|
|
6109
|
-
name: opts.convTitle ?? void 0,
|
|
6110
|
-
type: channelEntryType
|
|
6111
|
-
};
|
|
6112
|
-
for (const ap of mindParticipants) {
|
|
6113
|
-
try {
|
|
6114
|
-
writeChannelEntry(ap.username, slugForMind(ap.username), channelEntry);
|
|
6115
|
-
} catch (err) {
|
|
6116
|
-
logger_default.warn(`failed to write channel entry for ${ap.username}`, logger_default.errorData(err));
|
|
6117
|
-
}
|
|
6118
|
-
}
|
|
6119
6397
|
for (const mindName of targetMinds) {
|
|
6120
6398
|
const target = opts.targetName ? opts.targetName(mindName) : mindName;
|
|
6121
6399
|
const channel = slugForMind(mindName);
|
|
@@ -6146,7 +6424,7 @@ var unifiedChatSchema = z8.object({
|
|
|
6146
6424
|
conversationId: z8.string(),
|
|
6147
6425
|
images: z8.array(z8.object({ media_type: z8.string(), data: z8.string() })).optional()
|
|
6148
6426
|
});
|
|
6149
|
-
var app21 = new
|
|
6427
|
+
var app21 = new Hono23().use("*", authMiddleware).post("/minds/:name/chat", zValidator8("json", mindChatSchema), async (c) => {
|
|
6150
6428
|
const name = c.req.param("name");
|
|
6151
6429
|
const baseName = await getBaseName(name);
|
|
6152
6430
|
const entry = await findMind(baseName);
|
|
@@ -6218,7 +6496,6 @@ var app21 = new Hono22().use("*", authMiddleware).post("/minds/:name/chat", zVal
|
|
|
6218
6496
|
senderName,
|
|
6219
6497
|
convTitle,
|
|
6220
6498
|
isDM,
|
|
6221
|
-
channelEntryType: isDM ? "dm" : "channel",
|
|
6222
6499
|
slugExtra: conv ? { convType: conv.type, convName: conv.name } : void 0,
|
|
6223
6500
|
targetName: (username) => username === baseName ? name : username
|
|
6224
6501
|
});
|
|
@@ -6285,7 +6562,6 @@ var app21 = new Hono22().use("*", authMiddleware).post("/minds/:name/chat", zVal
|
|
|
6285
6562
|
senderName,
|
|
6286
6563
|
convTitle: conv.title,
|
|
6287
6564
|
isDM,
|
|
6288
|
-
channelEntryType: isDM ? "dm" : "channel",
|
|
6289
6565
|
slugExtra: { convType: conv.type, convName: conv.name }
|
|
6290
6566
|
});
|
|
6291
6567
|
return c.json({ ok: true, conversationId: body.conversationId });
|
|
@@ -6294,13 +6570,13 @@ var chat_default = app21;
|
|
|
6294
6570
|
|
|
6295
6571
|
// src/web/api/v1/conversations.ts
|
|
6296
6572
|
import { zValidator as zValidator9 } from "@hono/zod-validator";
|
|
6297
|
-
import { Hono as
|
|
6573
|
+
import { Hono as Hono24 } from "hono";
|
|
6298
6574
|
import { z as z9 } from "zod";
|
|
6299
6575
|
var createSchema = z9.object({
|
|
6300
6576
|
title: z9.string().optional(),
|
|
6301
6577
|
participantNames: z9.array(z9.string()).min(1)
|
|
6302
6578
|
});
|
|
6303
|
-
var app22 = new
|
|
6579
|
+
var app22 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
|
|
6304
6580
|
const user = c.get("user");
|
|
6305
6581
|
const convs = await listConversationsWithParticipants(user.id);
|
|
6306
6582
|
return c.json(convs);
|
|
@@ -6377,7 +6653,7 @@ var conversations_default = app22;
|
|
|
6377
6653
|
|
|
6378
6654
|
// src/web/api/v1/events.ts
|
|
6379
6655
|
import { desc as desc4 } from "drizzle-orm";
|
|
6380
|
-
import { Hono as
|
|
6656
|
+
import { Hono as Hono25 } from "hono";
|
|
6381
6657
|
import { streamSSE as streamSSE5 } from "hono/streaming";
|
|
6382
6658
|
|
|
6383
6659
|
// src/lib/events/brain-presence.ts
|
|
@@ -6424,7 +6700,7 @@ function getEventsSince(sinceId) {
|
|
|
6424
6700
|
}
|
|
6425
6701
|
|
|
6426
6702
|
// src/web/api/v1/events.ts
|
|
6427
|
-
var app23 = new
|
|
6703
|
+
var app23 = new Hono25().use("*", authMiddleware).get("/", async (c) => {
|
|
6428
6704
|
const user = c.get("user");
|
|
6429
6705
|
const since = c.req.query("since");
|
|
6430
6706
|
const sinceId = since ? Number(since) : 0;
|
|
@@ -6468,14 +6744,10 @@ var app23 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
|
|
|
6468
6744
|
} catch (err) {
|
|
6469
6745
|
logger_default.error("[v1-events] failed to fetch conversations", logger_default.errorData(err));
|
|
6470
6746
|
}
|
|
6471
|
-
const sites = await getCachedSites();
|
|
6472
|
-
const recentPages = await getCachedRecentPages();
|
|
6473
6747
|
const snapshotData = {
|
|
6474
6748
|
event: "snapshot",
|
|
6475
6749
|
activity: recentActivity,
|
|
6476
6750
|
conversations: conversations2,
|
|
6477
|
-
sites,
|
|
6478
|
-
recentPages,
|
|
6479
6751
|
activeMinds: getActiveMinds(),
|
|
6480
6752
|
onlineBrains: getOnlineBrains()
|
|
6481
6753
|
};
|
|
@@ -6534,9 +6806,9 @@ var app23 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
|
|
|
6534
6806
|
var events_default = app23;
|
|
6535
6807
|
|
|
6536
6808
|
// src/web/api/variants.ts
|
|
6537
|
-
import { existsSync as
|
|
6809
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8 } from "fs";
|
|
6538
6810
|
import { resolve as resolve17 } from "path";
|
|
6539
|
-
import { Hono as
|
|
6811
|
+
import { Hono as Hono26 } from "hono";
|
|
6540
6812
|
|
|
6541
6813
|
// src/lib/spawn-server.ts
|
|
6542
6814
|
import { spawn as spawn4 } from "child_process";
|
|
@@ -6652,7 +6924,7 @@ async function verify2(port) {
|
|
|
6652
6924
|
}
|
|
6653
6925
|
|
|
6654
6926
|
// src/web/api/variants.ts
|
|
6655
|
-
var app24 = new
|
|
6927
|
+
var app24 = new Hono26().get("/:name/variants", async (c) => {
|
|
6656
6928
|
const name = c.req.param("name");
|
|
6657
6929
|
const entry = await findMind(name);
|
|
6658
6930
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
@@ -6697,7 +6969,7 @@ var app24 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
6697
6969
|
}
|
|
6698
6970
|
const projectRoot = mindDir(mindName);
|
|
6699
6971
|
const variantDir = resolve17(projectRoot, ".variants", variantName);
|
|
6700
|
-
if (
|
|
6972
|
+
if (existsSync11(variantDir)) {
|
|
6701
6973
|
return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
|
|
6702
6974
|
}
|
|
6703
6975
|
mkdirSync9(resolve17(projectRoot, ".variants"), { recursive: true });
|
|
@@ -6758,7 +7030,7 @@ var app24 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
6758
7030
|
} catch {
|
|
6759
7031
|
}
|
|
6760
7032
|
const projectRoot = mindDir(mindName);
|
|
6761
|
-
if (
|
|
7033
|
+
if (existsSync11(variantEntry.dir)) {
|
|
6762
7034
|
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
6763
7035
|
if (status) {
|
|
6764
7036
|
try {
|
|
@@ -6818,8 +7090,8 @@ var app24 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
6818
7090
|
await cleanupVariant(variantName, projectRoot, variantEntry.dir);
|
|
6819
7091
|
if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
|
|
6820
7092
|
try {
|
|
6821
|
-
const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-
|
|
6822
|
-
const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-
|
|
7093
|
+
const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-A6VVKOXJ.js");
|
|
7094
|
+
const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-PJ4S5PHQ.js");
|
|
6823
7095
|
const tmpl = parentEntry.template ?? "claude";
|
|
6824
7096
|
await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
|
|
6825
7097
|
} catch (err) {
|
|
@@ -6878,7 +7150,7 @@ var variants_default = app24;
|
|
|
6878
7150
|
|
|
6879
7151
|
// src/web/api/volute/channels.ts
|
|
6880
7152
|
import { zValidator as zValidator10 } from "@hono/zod-validator";
|
|
6881
|
-
import { Hono as
|
|
7153
|
+
import { Hono as Hono27 } from "hono";
|
|
6882
7154
|
import { z as z10 } from "zod";
|
|
6883
7155
|
var createSchema2 = z10.object({
|
|
6884
7156
|
name: z10.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
|
|
@@ -6886,7 +7158,7 @@ var createSchema2 = z10.object({
|
|
|
6886
7158
|
var inviteSchema = z10.object({
|
|
6887
7159
|
username: z10.string().min(1)
|
|
6888
7160
|
});
|
|
6889
|
-
var app25 = new
|
|
7161
|
+
var app25 = new Hono27().get("/", async (c) => {
|
|
6890
7162
|
const user = c.get("user");
|
|
6891
7163
|
const channels = await listChannels();
|
|
6892
7164
|
const results = await Promise.all(
|
|
@@ -6910,6 +7182,12 @@ var app25 = new Hono26().get("/", async (c) => {
|
|
|
6910
7182
|
}
|
|
6911
7183
|
throw err;
|
|
6912
7184
|
}
|
|
7185
|
+
}).get("/:name", async (c) => {
|
|
7186
|
+
const name = c.req.param("name");
|
|
7187
|
+
const ch = await getChannelByName(name);
|
|
7188
|
+
if (!ch) return c.json({ error: "Channel not found" }, 404);
|
|
7189
|
+
const participants = await getParticipants(ch.id);
|
|
7190
|
+
return c.json({ ...ch, participants });
|
|
6913
7191
|
}).post("/:name/join", async (c) => {
|
|
6914
7192
|
const name = c.req.param("name");
|
|
6915
7193
|
const user = c.get("user");
|
|
@@ -6954,7 +7232,7 @@ var channels_default2 = app25;
|
|
|
6954
7232
|
|
|
6955
7233
|
// src/web/api/volute/chat.ts
|
|
6956
7234
|
import { zValidator as zValidator11 } from "@hono/zod-validator";
|
|
6957
|
-
import { Hono as
|
|
7235
|
+
import { Hono as Hono28 } from "hono";
|
|
6958
7236
|
import { streamSSE as streamSSE6 } from "hono/streaming";
|
|
6959
7237
|
import { z as z11 } from "zod";
|
|
6960
7238
|
|
|
@@ -7032,12 +7310,13 @@ async function routeDMOutbound(conversationId, senderName, contentBlocks) {
|
|
|
7032
7310
|
// src/web/api/volute/chat.ts
|
|
7033
7311
|
async function fanOutToMinds2(opts) {
|
|
7034
7312
|
const participants = await getParticipants(opts.conversationId);
|
|
7035
|
-
const mindParticipants = participants.filter(
|
|
7313
|
+
const mindParticipants = participants.filter(
|
|
7314
|
+
(p) => p.userType === "mind" || p.userType === "system"
|
|
7315
|
+
);
|
|
7036
7316
|
const participantNames = participants.map((p) => p.username);
|
|
7037
7317
|
const isDM = opts.isDM ?? participants.length === 2;
|
|
7038
|
-
const
|
|
7039
|
-
const {
|
|
7040
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TPS6OGCA.js");
|
|
7318
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-BNCMGYXW.js");
|
|
7319
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-53DZOWW7.js");
|
|
7041
7320
|
const manager = getMindManager2();
|
|
7042
7321
|
const sm = getSleepManagerIfReady2();
|
|
7043
7322
|
const targetMinds = mindParticipants.map((ap) => {
|
|
@@ -7054,19 +7333,6 @@ async function fanOutToMinds2(opts) {
|
|
|
7054
7333
|
...opts.slugExtra
|
|
7055
7334
|
});
|
|
7056
7335
|
}
|
|
7057
|
-
const channelEntry = {
|
|
7058
|
-
platformId: opts.conversationId,
|
|
7059
|
-
platform: "volute",
|
|
7060
|
-
name: opts.convTitle ?? void 0,
|
|
7061
|
-
type: channelEntryType
|
|
7062
|
-
};
|
|
7063
|
-
for (const ap of mindParticipants) {
|
|
7064
|
-
try {
|
|
7065
|
-
writeChannelEntry(ap.username, slugForMind(ap.username), channelEntry);
|
|
7066
|
-
} catch (err) {
|
|
7067
|
-
logger_default.warn(`failed to write channel entry for ${ap.username}`, logger_default.errorData(err));
|
|
7068
|
-
}
|
|
7069
|
-
}
|
|
7070
7336
|
for (const mindName of targetMinds) {
|
|
7071
7337
|
const target = opts.targetName ? opts.targetName(mindName) : mindName;
|
|
7072
7338
|
const channel = slugForMind(mindName);
|
|
@@ -7103,7 +7369,7 @@ var chatSchema = z11.object({
|
|
|
7103
7369
|
).optional(),
|
|
7104
7370
|
files: z11.array(fileSchema).optional()
|
|
7105
7371
|
});
|
|
7106
|
-
var app26 = new
|
|
7372
|
+
var app26 = new Hono28().post("/:name/chat", zValidator11("json", chatSchema), async (c) => {
|
|
7107
7373
|
const name = c.req.param("name");
|
|
7108
7374
|
const baseName = await getBaseName(name);
|
|
7109
7375
|
const entry = await findMind(baseName);
|
|
@@ -7213,7 +7479,6 @@ var app26 = new Hono27().post("/:name/chat", zValidator11("json", chatSchema), a
|
|
|
7213
7479
|
senderName,
|
|
7214
7480
|
convTitle,
|
|
7215
7481
|
isDM,
|
|
7216
|
-
channelEntryType: isDM ? "dm" : "channel",
|
|
7217
7482
|
slugExtra: conv ? { convType: conv.type, convName: conv.name } : void 0,
|
|
7218
7483
|
targetName: (username) => username === baseName ? name : username
|
|
7219
7484
|
});
|
|
@@ -7259,7 +7524,7 @@ var unifiedChatSchema2 = z11.object({
|
|
|
7259
7524
|
images: z11.array(z11.object({ media_type: z11.string(), data: z11.string() })).optional(),
|
|
7260
7525
|
files: z11.array(fileSchema).optional()
|
|
7261
7526
|
});
|
|
7262
|
-
var unifiedChatApp = new
|
|
7527
|
+
var unifiedChatApp = new Hono28().post(
|
|
7263
7528
|
"/chat",
|
|
7264
7529
|
zValidator11("json", unifiedChatSchema2),
|
|
7265
7530
|
async (c) => {
|
|
@@ -7340,7 +7605,6 @@ var unifiedChatApp = new Hono27().post(
|
|
|
7340
7605
|
senderName,
|
|
7341
7606
|
convTitle: conv.title,
|
|
7342
7607
|
isDM,
|
|
7343
|
-
channelEntryType: isDM ? "dm" : "channel",
|
|
7344
7608
|
slugExtra: { convType: conv.type, convName: conv.name }
|
|
7345
7609
|
});
|
|
7346
7610
|
if (user.user_type === "mind" && body.message) {
|
|
@@ -7359,14 +7623,14 @@ var chat_default2 = app26;
|
|
|
7359
7623
|
|
|
7360
7624
|
// src/web/api/volute/conversations.ts
|
|
7361
7625
|
import { zValidator as zValidator12 } from "@hono/zod-validator";
|
|
7362
|
-
import { Hono as
|
|
7626
|
+
import { Hono as Hono29 } from "hono";
|
|
7363
7627
|
import { z as z12 } from "zod";
|
|
7364
7628
|
var createConvSchema = z12.object({
|
|
7365
7629
|
title: z12.string().optional(),
|
|
7366
7630
|
participantIds: z12.array(z12.number()).optional(),
|
|
7367
7631
|
participantNames: z12.array(z12.string()).optional()
|
|
7368
7632
|
});
|
|
7369
|
-
var app27 = new
|
|
7633
|
+
var app27 = new Hono29().get("/:name/conversations", async (c) => {
|
|
7370
7634
|
const name = c.req.param("name");
|
|
7371
7635
|
const user = c.get("user");
|
|
7372
7636
|
let lookupId = user.id;
|
|
@@ -7478,14 +7742,14 @@ var conversations_default2 = app27;
|
|
|
7478
7742
|
|
|
7479
7743
|
// src/web/api/volute/user-conversations.ts
|
|
7480
7744
|
import { zValidator as zValidator13 } from "@hono/zod-validator";
|
|
7481
|
-
import { Hono as
|
|
7745
|
+
import { Hono as Hono30 } from "hono";
|
|
7482
7746
|
import { streamSSE as streamSSE7 } from "hono/streaming";
|
|
7483
7747
|
import { z as z13 } from "zod";
|
|
7484
7748
|
var createSchema3 = z13.object({
|
|
7485
7749
|
title: z13.string().optional(),
|
|
7486
7750
|
participantNames: z13.array(z13.string()).min(1)
|
|
7487
7751
|
});
|
|
7488
|
-
var app28 = new
|
|
7752
|
+
var app28 = new Hono30().use("*", authMiddleware).get("/", async (c) => {
|
|
7489
7753
|
const user = c.get("user");
|
|
7490
7754
|
const convs = await listConversationsWithParticipants(user.id);
|
|
7491
7755
|
return c.json(convs);
|
|
@@ -7575,7 +7839,7 @@ var user_conversations_default = app28;
|
|
|
7575
7839
|
|
|
7576
7840
|
// src/web/app.ts
|
|
7577
7841
|
var httpLog = logger_default.child("http");
|
|
7578
|
-
var app29 = new
|
|
7842
|
+
var app29 = new Hono31();
|
|
7579
7843
|
app29.onError((err, c) => {
|
|
7580
7844
|
if (err instanceof HTTPException) {
|
|
7581
7845
|
return err.getResponse();
|
|
@@ -7628,9 +7892,11 @@ app29.use("/api/prompts/*", authMiddleware);
|
|
|
7628
7892
|
app29.use("/api/skills/*", authMiddleware);
|
|
7629
7893
|
app29.use("/api/extensions/*", authMiddleware);
|
|
7630
7894
|
app29.use("/api/bridges/*", authMiddleware);
|
|
7895
|
+
app29.use("/api/config/*", authMiddleware);
|
|
7631
7896
|
app29.use("/api/v1/*", authMiddleware);
|
|
7632
7897
|
app29.route("/api/setup", setup_default);
|
|
7633
7898
|
app29.route("/public", public_files_default);
|
|
7899
|
+
app29.route("/api/config", config_default);
|
|
7634
7900
|
var routes = app29.route("/api/activity", activity_default).route("/api/keys", keys_default).route("/api/auth", auth_default).route("/api/system", system_default).route("/api/system", update_default).route("/api/minds", minds_default).route("/api/minds", chat_default2).route("/api/minds", schedules_default).route("/api/minds", logs_default).route("/api/minds", typing_default).route("/api/minds", variants_default).route("/api/minds", file_sharing_default).route("/api/minds", files_default).route("/api/minds", channels_default).route("/api/minds", shared_default).route("/api/minds", env_default).route("/api/minds", mind_skills_default).route("/api/minds", conversations_default2).route("/api/env", sharedEnvApp).route("/api/prompts", prompts_default).route("/api/skills", skills_default).route("/api/conversations", user_conversations_default).route("/api/volute/channels", channels_default2).route("/api/volute", unifiedChatApp).route("/api/bridges", bridges_default).route("/api/extensions", extensions_default).route("/api/v1/conversations", conversations_default).route("/api/v1/events", events_default).route("/api/v1", chat_default);
|
|
7635
7901
|
app29.route("/api/v1/minds", minds_default);
|
|
7636
7902
|
app29.route("/api/v1/minds", typing_default);
|
|
@@ -7649,7 +7915,7 @@ app29.route("/api/v1/channels", channels_default2);
|
|
|
7649
7915
|
var app_default = app29;
|
|
7650
7916
|
|
|
7651
7917
|
// src/web/server.ts
|
|
7652
|
-
import { existsSync as
|
|
7918
|
+
import { existsSync as existsSync12 } from "fs";
|
|
7653
7919
|
import { readFile as readFile3, stat as stat3 } from "fs/promises";
|
|
7654
7920
|
import { createServer as createHttpsServer } from "https";
|
|
7655
7921
|
import { dirname as dirname2, extname as extname4, resolve as resolve18 } from "path";
|
|
@@ -7672,7 +7938,7 @@ async function startServer({
|
|
|
7672
7938
|
let searchDir = dirname2(new URL(import.meta.url).pathname);
|
|
7673
7939
|
for (let i = 0; i < 5; i++) {
|
|
7674
7940
|
const candidate = resolve18(searchDir, "dist", "web-assets");
|
|
7675
|
-
if (
|
|
7941
|
+
if (existsSync12(candidate)) {
|
|
7676
7942
|
assetsDir = candidate;
|
|
7677
7943
|
break;
|
|
7678
7944
|
}
|
|
@@ -7778,8 +8044,18 @@ async function startDaemon(opts) {
|
|
|
7778
8044
|
} catch (err) {
|
|
7779
8045
|
logger_default.warn("failed to initialize shared repo", logger_default.errorData(err));
|
|
7780
8046
|
}
|
|
7781
|
-
|
|
7782
|
-
|
|
8047
|
+
const { migrateSetupCompleted } = await import("./setup-SZIARWI6.js");
|
|
8048
|
+
migrateSetupCompleted();
|
|
8049
|
+
await (await import("./db-F34YLV7D.js")).getDb();
|
|
8050
|
+
try {
|
|
8051
|
+
const { eq: eq7, and: and5 } = await import("drizzle-orm");
|
|
8052
|
+
const { users: users2 } = await import("./schema-PA3M5ZKH.js");
|
|
8053
|
+
const db = await (await import("./db-F34YLV7D.js")).getDb();
|
|
8054
|
+
await db.update(users2).set({ role: "system" }).where(and5(eq7(users2.user_type, "system"), eq7(users2.role, "user")));
|
|
8055
|
+
} catch (err) {
|
|
8056
|
+
logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
|
|
8057
|
+
}
|
|
8058
|
+
const { initSandbox } = await import("./sandbox-JANNTX6U.js");
|
|
7783
8059
|
await initSandbox();
|
|
7784
8060
|
try {
|
|
7785
8061
|
await syncBuiltinSkills();
|
|
@@ -7799,7 +8075,7 @@ async function startDaemon(opts) {
|
|
|
7799
8075
|
logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
|
|
7800
8076
|
}
|
|
7801
8077
|
try {
|
|
7802
|
-
const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-
|
|
8078
|
+
const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-6DMGES3I.js");
|
|
7803
8079
|
await getOrCreateSystemUser2();
|
|
7804
8080
|
} catch (err) {
|
|
7805
8081
|
logger_default.warn(
|
|
@@ -7810,7 +8086,7 @@ async function startDaemon(opts) {
|
|
|
7810
8086
|
const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes(32).toString("hex");
|
|
7811
8087
|
let tls;
|
|
7812
8088
|
if (opts.tailscale) {
|
|
7813
|
-
const { getTailscaleTls } = await import("./tailscale-
|
|
8089
|
+
const { getTailscaleTls } = await import("./tailscale-XHQBZROW.js");
|
|
7814
8090
|
const tlsConfig = await getTailscaleTls();
|
|
7815
8091
|
tls = { key: tlsConfig.key, cert: tlsConfig.cert };
|
|
7816
8092
|
logger_default.info("Tailscale HTTPS enabled", { hostname: tlsConfig.hostname });
|
|
@@ -7850,8 +8126,9 @@ async function startDaemon(opts) {
|
|
|
7850
8126
|
const sleepManager = initSleepManager();
|
|
7851
8127
|
sleepManager.start();
|
|
7852
8128
|
const unsubscribeWebhook = initWebhook();
|
|
8129
|
+
await completeOrphanedTurns();
|
|
7853
8130
|
const allMinds = await readAllMinds();
|
|
7854
|
-
const runningEntries = allMinds.filter((e) => e.running);
|
|
8131
|
+
const runningEntries = allMinds.filter((e) => e.running && e.mindType !== "spirit");
|
|
7855
8132
|
{
|
|
7856
8133
|
const queue = [...runningEntries];
|
|
7857
8134
|
const workers = Array.from({ length: Math.min(5, queue.length) }, async () => {
|
|
@@ -7878,10 +8155,28 @@ async function startDaemon(opts) {
|
|
|
7878
8155
|
});
|
|
7879
8156
|
await Promise.all(workers);
|
|
7880
8157
|
}
|
|
8158
|
+
try {
|
|
8159
|
+
const { isSetupComplete: isSetupComplete2 } = await import("./setup-SZIARWI6.js");
|
|
8160
|
+
if (isSetupComplete2()) {
|
|
8161
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-N4W4UQRH.js");
|
|
8162
|
+
const { startSpiritFull } = await import("./mind-service-AV273WT4.js");
|
|
8163
|
+
await ensureSpiritProject();
|
|
8164
|
+
await syncSpiritTemplate();
|
|
8165
|
+
const spiritEntry = await findMind("volute");
|
|
8166
|
+
if (spiritEntry && !manager.isRunning("volute")) {
|
|
8167
|
+
await startSpiritFull("volute");
|
|
8168
|
+
}
|
|
8169
|
+
}
|
|
8170
|
+
} catch (err) {
|
|
8171
|
+
logger_default.warn(
|
|
8172
|
+
"failed to start system spirit \u2014 system replies will use aiComplete fallback",
|
|
8173
|
+
logger_default.errorData(err)
|
|
8174
|
+
);
|
|
8175
|
+
}
|
|
7881
8176
|
bridgeManager.startBridges(daemonPort).catch((err) => {
|
|
7882
8177
|
logger_default.warn("failed to start bridges", logger_default.errorData(err));
|
|
7883
8178
|
});
|
|
7884
|
-
import("./cloud-sync-
|
|
8179
|
+
import("./cloud-sync-JN3NWKEM.js").then(
|
|
7885
8180
|
({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
|
|
7886
8181
|
logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
|
|
7887
8182
|
})
|
|
@@ -7889,7 +8184,7 @@ async function startDaemon(opts) {
|
|
|
7889
8184
|
logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
|
|
7890
8185
|
});
|
|
7891
8186
|
try {
|
|
7892
|
-
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-
|
|
8187
|
+
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-TCKWBZZG.js");
|
|
7893
8188
|
backfillTemplateHashes();
|
|
7894
8189
|
notifyVersionUpdate().catch((err) => {
|
|
7895
8190
|
logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
|