volute 0.35.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{accept-ZBDVVCEU.js → accept-AHAOUFBK.js} +4 -4
- package/dist/activity-events-N6HCHU4P.js +15 -0
- package/dist/{ai-service-LURBEDDB.js → ai-service-C2YNARGH.js} +6 -6
- package/dist/{api-client-3A77HMH7.js → api-client-LC5YRA32.js} +1 -1
- package/dist/{archive-ESU2FUN4.js → archive-AWIJTVQV.js} +4 -4
- package/dist/{auth-WX4TESEI.js → auth-2QOOPMBX.js} +6 -6
- package/dist/{bridge-PXIO6PS2.js → bridge-F3ZJEKDN.js} +4 -4
- package/dist/{chat-QXAJF3FU.js → chat-5Y4FD77E.js} +9 -9
- package/dist/{chunk-BDYXIWA5.js → chunk-2NHRJ3YO.js} +13 -2
- package/dist/{chunk-AN2W47GW.js → chunk-3F7XK5Q7.js} +2 -2
- package/dist/{chunk-AOB6GVRM.js → chunk-46DYYHN6.js} +8 -3
- package/dist/{chunk-WZRZFFCL.js → chunk-5DPRTREW.js} +146 -186
- package/dist/{chunk-QWTR6AWZ.js → chunk-7AZQFSOV.js} +2 -2
- package/dist/{chunk-BMZQYACC.js → chunk-A6FLW5XD.js} +19 -4
- package/dist/{chunk-N5LMGYXX.js → chunk-BIEWHAAM.js} +2 -2
- package/dist/{chunk-5N7Y5WAM.js → chunk-CJ26DXZL.js} +29 -13
- package/dist/{chunk-ZSR72JB3.js → chunk-CU6OFXMM.js} +1 -1
- package/dist/{chunk-N446KRP7.js → chunk-GVVVMZ4J.js} +2 -2
- package/dist/chunk-K3NQKI34.js +10 -0
- package/dist/{chunk-F7ZNLYKZ.js → chunk-KAB6UGOL.js} +2 -2
- package/dist/{chunk-WJPROOU5.js → chunk-KBRGHKVU.js} +681 -3726
- package/dist/{chunk-PWQ2ITYG.js → chunk-KXXJYY62.js} +6 -6
- package/dist/{chunk-NJK5SDGR.js → chunk-LGNUFVMR.js} +1 -1
- package/dist/chunk-LQ6Z4FXN.js +87 -0
- package/dist/{chunk-J6CJQDWI.js → chunk-MQRS4J24.js} +2 -2
- package/dist/{chunk-CORXD635.js → chunk-N42QMDID.js} +3 -3
- package/dist/{chunk-IJHIXLVN.js → chunk-NYP3LBIV.js} +15 -13
- package/dist/{chunk-FT5KETXZ.js → chunk-ORNY3MZR.js} +4 -4
- package/dist/{chunk-A2ZLHBHG.js → chunk-PMMHVSCR.js} +2 -2
- package/dist/chunk-QQQI6ISK.js +853 -0
- package/dist/chunk-RG5TOL4O.js +18 -0
- package/dist/{chunk-VHJRZM2S.js → chunk-SNW2NPP4.js} +2 -2
- package/dist/chunk-SZJWC2GA.js +125 -0
- package/dist/{chunk-BKF4WQCY.js → chunk-T2TP6ZC6.js} +20 -8
- package/dist/{chunk-2TGZJFAT.js → chunk-TNZ5XQA4.js} +3 -3
- package/dist/{chunk-QCH6K235.js → chunk-UI7RPV2B.js} +1 -1
- package/dist/{chunk-XRQSAMX2.js → chunk-UIM5NHPP.js} +3 -3
- package/dist/{chunk-5XJYUFZH.js → chunk-UQFYNZKT.js} +76 -30
- package/dist/{chunk-OTC67N2Z.js → chunk-WC635OPK.js} +1 -1
- package/dist/{chunk-BV65KRHM.js → chunk-XLBQYIHH.js} +2 -2
- package/dist/{chunk-VY3RB2V7.js → chunk-Z6TIXE77.js} +3 -3
- package/dist/cli.js +24 -24
- package/dist/{clock-HSEKS5AR.js → clock-BMLJ2TR6.js} +8 -8
- package/dist/{cloud-sync-6JL4C24T.js → cloud-sync-OIX576NA.js} +20 -21
- package/dist/{config-UTS7QULS.js → config-QB7W3Z7P.js} +4 -4
- package/dist/connectors/discord-bridge.js +4 -4
- package/dist/connectors/slack-bridge.js +4 -4
- package/dist/connectors/telegram-bridge.js +4 -4
- package/dist/{conversations-2PW57WO2.js → conversations-G6YRSABR.js} +16 -10
- package/dist/{create-5BPOOJAN.js → create-C3BBFYV7.js} +4 -4
- package/dist/{create-UVCK2CS6.js → create-PN73742N.js} +4 -4
- package/dist/{daemon-client-RVIKXGFQ.js → daemon-client-2MIPKY3E.js} +1 -1
- package/dist/{daemon-restart-HSZ3BCX5.js → daemon-restart-L2O6L7NR.js} +9 -9
- package/dist/daemon.js +690 -1281
- package/dist/db-CBOCDYVA.js +9 -0
- package/dist/{db-BDMH4SZ2.js → db-IJL6B26S.js} +1 -1
- package/dist/{delete-L5PAVDGQ.js → delete-NLXES2C7.js} +3 -3
- package/dist/delivery-manager-4PVBUZJB.js +30 -0
- package/dist/{delivery-router-HEJSJAHQ.js → delivery-router-QTFEZ26O.js} +5 -5
- package/dist/down-25L2RKCQ.js +17 -0
- package/dist/echo-text-T5ZLGMA7.js +31 -0
- package/dist/{env-E4XHO2BI.js → env-IQ6Q2333.js} +6 -6
- package/dist/exec-ONYZEA5B.js +17 -0
- package/dist/{export-OAS6QVBN.js → export-JPDBQESV.js} +6 -6
- package/dist/{extension-D74CNM7G.js → extension-LZYHBNLV.js} +26 -7
- package/dist/extensions-CLYXNGYB.js +50 -0
- package/dist/{files-CWTK6V3H.js → files-LAQ3NXQK.js} +7 -7
- package/dist/{import-5A3T7QV4.js → import-EROF27RH.js} +12 -11
- package/dist/{isolation-TK5RX2WM.js → isolation-G5J3MTKU.js} +4 -4
- package/dist/{join-DF5XSJAC.js → join-6SZCA5FX.js} +3 -3
- package/dist/{list-PDMQM7ZV.js → list-KHJZJPEJ.js} +11 -5
- package/dist/{login-7TE6CIZF.js → login-F6YMAVLE.js} +6 -6
- package/dist/{login-GOTAYLXP.js → login-GYTH67ES.js} +4 -4
- package/dist/{logout-T4XS6LRU.js → logout-HHPH52KZ.js} +6 -6
- package/dist/{logout-6KIA74EV.js → logout-YHQLOFLR.js} +4 -4
- package/dist/message-delivery-N2V5APCS.js +40 -0
- package/dist/{mind-5IEYKV7I.js → mind-M57ET546.js} +19 -19
- package/dist/mind-activity-tracker-42ENM32S.js +18 -0
- package/dist/{mind-history-IE2QH7U5.js → mind-history-WHCNZ6I5.js} +86 -19
- package/dist/{mind-list-GEWHWAL4.js → mind-list-H3HC2ZRG.js} +4 -4
- package/dist/mind-manager-LS2AIXHQ.js +30 -0
- package/dist/{mind-profile-DCBDVF5B.js → mind-profile-7VYRJGFZ.js} +2 -2
- package/dist/mind-service-UDXF5WC2.js +36 -0
- package/dist/{mind-sleep-ITCF6OQA.js → mind-sleep-ZL5ZXFTM.js} +4 -4
- package/dist/{mind-status-X4SX3YUG.js → mind-status-ZWULKOUO.js} +4 -4
- package/dist/{mind-wake-KXMKMGWX.js → mind-wake-HK5ORGUK.js} +4 -4
- package/dist/{package-D2FSVFAX.js → package-5FGU5QNP.js} +6 -6
- package/dist/{read-67VRP2DO.js → read-CP7MYMJQ.js} +8 -8
- package/dist/{read-stdin-3X5VYKNS.js → read-stdin-4B5UYPPM.js} +1 -1
- package/dist/{register-SB7NXCOE.js → register-XOBFEMI4.js} +4 -4
- package/dist/{registry-GBSNW3HG.js → registry-KMELPC3X.js} +3 -3
- package/dist/{reject-MUR2KWJ4.js → reject-43AGXB6B.js} +4 -4
- package/dist/{restart-5EGG4JXU.js → restart-O5QIYQJT.js} +5 -5
- package/dist/{sandbox-R37VIU36.js → sandbox-PQYEICEF.js} +6 -6
- package/dist/scheduler-NTC74JYH.js +30 -0
- package/dist/{schema-XVZ2CLKW.js → schema-K575EBPE.js} +4 -2
- package/dist/{seed-EQORWX77.js → seed-55VC3A57.js} +2 -2
- package/dist/{seed-check-KJNTL72M.js → seed-check-HZPVFJKZ.js} +2 -2
- package/dist/{seed-cmd-ZM2XGVU2.js → seed-cmd-2KOEQZK6.js} +4 -4
- package/dist/{seed-create-DRWGGHEI.js → seed-create-Y2Z5JWBB.js} +6 -6
- package/dist/{seed-sprout-JYXGXOP3.js → seed-sprout-OLSIWXZN.js} +15 -15
- package/dist/{send-JBJJQ7CA.js → send-7CIP5GLS.js} +8 -8
- package/dist/{service-WNPCNHOX.js → service-YMHWPDXW.js} +6 -6
- package/dist/{setup-BJ4YAY26.js → setup-6Z34JJEB.js} +32 -37
- package/dist/{setup-RHJRFURI.js → setup-PF7JSFMO.js} +6 -4
- package/dist/{skill-TAAKEYBV.js → skill-ICN6Y2ZF.js} +6 -6
- package/dist/skills/tending/SKILL.md +52 -0
- package/dist/{skills-EKMCQ46K.js → skills-FDMLJGZ3.js} +8 -8
- package/dist/sleep-manager-TQP5ZJI5.js +34 -0
- package/dist/spirit-SM6ARJ2N.js +24 -0
- package/dist/{split-AWVOYOPZ.js → split-5YBEQTBF.js} +3 -3
- package/dist/{sprout-HE4TITMK.js → sprout-G6G57IOY.js} +2 -2
- package/dist/src-LT6ZBYYX.js +2133 -0
- package/dist/src-O4PRLMKM.js +425 -0
- package/dist/src-OYWRPLC6.js +617 -0
- package/dist/{start-3UXOPXQG.js → start-LMXXRR3X.js} +5 -5
- package/dist/{status-ZK34WYIM.js → status-MC2P7DBG.js} +7 -7
- package/dist/{stop-3XYIBGFM.js → stop-TWDKVEUX.js} +5 -5
- package/dist/system-chat-NNXYCSVL.js +34 -0
- package/dist/{systems-O43WGQY6.js → systems-Y2WZV2K4.js} +7 -7
- package/dist/{tailscale-ZIZ2HWJ5.js → tailscale-LTYNKIPZ.js} +4 -4
- package/dist/template-hash-SSIBEEYK.js +9 -0
- package/dist/up-5JXV6BZS.js +19 -0
- package/dist/{update-ANE5ZM7F.js → update-UOP2INF2.js} +7 -7
- package/dist/{update-check-UV55CBEP.js → update-check-IKS7SGK5.js} +4 -4
- package/dist/{upgrade-ZMDGC7M2.js → upgrade-RXFZR5FI.js} +3 -3
- package/dist/{variant-QWL2WSRI.js → variant-HHDTW74J.js} +1 -1
- package/dist/{version-notify-FXSEMXWW.js → version-notify-CSE4NBYM.js} +22 -23
- package/dist/{volute-config-D2XVS2YI.js → volute-config-TS62GS6A.js} +2 -2
- package/dist/web-assets/assets/index-B3xLeex8.js +75 -0
- package/dist/web-assets/assets/index-Dr4A90Lo.css +1 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0006_channels.sql +17 -0
- package/drizzle/0007_drop_conversation_name_title.sql +11 -0
- package/drizzle/0008_performance_indexes.sql +6 -0
- package/drizzle/meta/0006_snapshot.json +7 -0
- package/drizzle/meta/0007_snapshot.json +7 -0
- package/drizzle/meta/_journal.json +21 -0
- package/package.json +5 -5
- package/templates/_base/home/.config/routes.json +2 -2
- package/templates/_base/home/VOLUTE.md +1 -2
- package/templates/_base/src/lib/context-breakdown.ts +22 -16
- package/templates/_base/src/lib/format-prefix.ts +1 -7
- package/templates/claude/.init/.config/routes.json +2 -2
- package/templates/codex/.init/.config/routes.json +2 -2
- package/templates/pi/.init/.config/routes.json +2 -2
- package/dist/activity-events-ZW4SDL2C.js +0 -15
- package/dist/chunk-7KJOFUNN.js +0 -22
- package/dist/chunk-MDJGMOSD.js +0 -207
- package/dist/db-BVBJ57TU.js +0 -9
- package/dist/delivery-manager-H5ZVBMCQ.js +0 -31
- package/dist/down-74VXM45A.js +0 -17
- package/dist/exec-PY7THYH4.js +0 -17
- package/dist/extensions-XDDFY72A.js +0 -49
- package/dist/lib-DYEZMGW7.js +0 -6588
- package/dist/message-delivery-GRC4W6P7.js +0 -41
- package/dist/mind-activity-tracker-QBLIV7ZJ.js +0 -18
- package/dist/mind-manager-HFLB5653.js +0 -31
- package/dist/mind-service-X2CAA6W6.js +0 -37
- package/dist/scheduler-Y7O4CJXL.js +0 -31
- package/dist/sleep-manager-7KFK3USC.js +0 -35
- package/dist/spirit-ZFRDXMG7.js +0 -23
- package/dist/system-chat-IDPHYHY4.js +0 -35
- package/dist/template-hash-A7FNHTB7.js +0 -9
- package/dist/up-77ICEDEW.js +0 -19
- package/dist/web-assets/assets/index-BhxWKvbB.css +0 -1
- package/dist/web-assets/assets/index-CHVKJ9II.js +0 -75
package/dist/daemon.js
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
checkForUpdate,
|
|
4
|
-
checkForUpdateCached,
|
|
5
|
-
getCurrentVersion
|
|
6
|
-
} from "./chunk-OTC67N2Z.js";
|
|
7
|
-
import {
|
|
8
|
-
computeTemplateHash
|
|
9
|
-
} from "./chunk-F7ZNLYKZ.js";
|
|
10
2
|
import {
|
|
11
3
|
acceptPending,
|
|
12
4
|
formatFileSize,
|
|
@@ -14,7 +6,39 @@ import {
|
|
|
14
6
|
rejectPending,
|
|
15
7
|
stageFile,
|
|
16
8
|
validateFilePath
|
|
17
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-XLBQYIHH.js";
|
|
10
|
+
import {
|
|
11
|
+
findOpenClawSession,
|
|
12
|
+
importOpenClawConnectors,
|
|
13
|
+
importPiSession,
|
|
14
|
+
parseNameFromIdentity
|
|
15
|
+
} from "./chunk-SZJWC2GA.js";
|
|
16
|
+
import {
|
|
17
|
+
checkForUpdate,
|
|
18
|
+
checkForUpdateCached,
|
|
19
|
+
getCurrentVersion
|
|
20
|
+
} from "./chunk-WC635OPK.js";
|
|
21
|
+
import {
|
|
22
|
+
isHomeOnlyArchive
|
|
23
|
+
} from "./chunk-BIEWHAAM.js";
|
|
24
|
+
import {
|
|
25
|
+
computeTemplateHash
|
|
26
|
+
} from "./chunk-KAB6UGOL.js";
|
|
27
|
+
import {
|
|
28
|
+
PLATFORMS,
|
|
29
|
+
echoTextToChannel,
|
|
30
|
+
getPlatformDriver,
|
|
31
|
+
routeOutboundBridge
|
|
32
|
+
} from "./chunk-QQQI6ISK.js";
|
|
33
|
+
import {
|
|
34
|
+
getBridgeConfig,
|
|
35
|
+
readBridgesConfig,
|
|
36
|
+
removeBridgeConfig,
|
|
37
|
+
removeChannelMapping,
|
|
38
|
+
resolveChannelMapping,
|
|
39
|
+
setBridgeConfig,
|
|
40
|
+
setChannelMapping
|
|
41
|
+
} from "./chunk-LQ6Z4FXN.js";
|
|
18
42
|
import {
|
|
19
43
|
PROMPT_DEFAULTS,
|
|
20
44
|
PROMPT_KEYS,
|
|
@@ -31,6 +55,7 @@ import {
|
|
|
31
55
|
generateSystemReply,
|
|
32
56
|
getActiveTurnId,
|
|
33
57
|
getAllDiscoveredExtensions,
|
|
58
|
+
getAllDiscoveredExtensionsDetailed,
|
|
34
59
|
getDeliveryManager,
|
|
35
60
|
getExtensionStandardSkills,
|
|
36
61
|
getLastToolUseEventId,
|
|
@@ -76,15 +101,22 @@ import {
|
|
|
76
101
|
trackToolUse,
|
|
77
102
|
uninstallNpmExtension,
|
|
78
103
|
writeSystemsConfig
|
|
79
|
-
} from "./chunk-
|
|
80
|
-
import
|
|
104
|
+
} from "./chunk-KBRGHKVU.js";
|
|
105
|
+
import {
|
|
106
|
+
loadMergedEnv,
|
|
107
|
+
mindEnvPath,
|
|
108
|
+
readEnv,
|
|
109
|
+
sharedEnvPath,
|
|
110
|
+
writeEnv
|
|
111
|
+
} from "./chunk-PMMHVSCR.js";
|
|
112
|
+
import "./chunk-UQFYNZKT.js";
|
|
81
113
|
import {
|
|
82
114
|
applyInitFiles,
|
|
83
115
|
composeTemplate,
|
|
84
116
|
copyTemplateToDir,
|
|
85
117
|
findTemplatesRoot,
|
|
86
118
|
listFiles
|
|
87
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-46DYYHN6.js";
|
|
88
120
|
import {
|
|
89
121
|
SEED_SKILLS,
|
|
90
122
|
STANDARD_SKILLS,
|
|
@@ -104,16 +136,33 @@ import {
|
|
|
104
136
|
syncBuiltinSkills,
|
|
105
137
|
uninstallSkill,
|
|
106
138
|
updateSkill
|
|
107
|
-
} from "./chunk-
|
|
139
|
+
} from "./chunk-NYP3LBIV.js";
|
|
140
|
+
import {
|
|
141
|
+
readVoluteConfig,
|
|
142
|
+
writeVoluteConfig
|
|
143
|
+
} from "./chunk-CU6OFXMM.js";
|
|
144
|
+
import "./chunk-KXXJYY62.js";
|
|
108
145
|
import {
|
|
109
146
|
extractTextContent
|
|
110
|
-
} from "./chunk-
|
|
147
|
+
} from "./chunk-7AZQFSOV.js";
|
|
111
148
|
import {
|
|
112
149
|
getActiveMinds,
|
|
113
150
|
onMindEvent,
|
|
114
151
|
stopAll
|
|
115
|
-
} from "./chunk-
|
|
116
|
-
import
|
|
152
|
+
} from "./chunk-GVVVMZ4J.js";
|
|
153
|
+
import {
|
|
154
|
+
exec,
|
|
155
|
+
gitExec,
|
|
156
|
+
resolveVoluteBin
|
|
157
|
+
} from "./chunk-3F7XK5Q7.js";
|
|
158
|
+
import {
|
|
159
|
+
chownMindDir,
|
|
160
|
+
createMindUser,
|
|
161
|
+
deleteMindUser,
|
|
162
|
+
ensureVoluteGroup,
|
|
163
|
+
isIsolationEnabled,
|
|
164
|
+
wrapForIsolation
|
|
165
|
+
} from "./chunk-SNW2NPP4.js";
|
|
117
166
|
import {
|
|
118
167
|
approveUser,
|
|
119
168
|
changePassword,
|
|
@@ -132,7 +181,28 @@ import {
|
|
|
132
181
|
syncMindProfile,
|
|
133
182
|
updateUserProfile,
|
|
134
183
|
verifyUser
|
|
135
|
-
} from "./chunk-
|
|
184
|
+
} from "./chunk-UIM5NHPP.js";
|
|
185
|
+
import {
|
|
186
|
+
getAiConfig,
|
|
187
|
+
getAvailableModels,
|
|
188
|
+
getConfiguredProviders,
|
|
189
|
+
getEnabledModels,
|
|
190
|
+
getUtilityModel,
|
|
191
|
+
qualifyModelId,
|
|
192
|
+
removeAiConfig,
|
|
193
|
+
removeProviderConfig,
|
|
194
|
+
resolveApiKey,
|
|
195
|
+
resolveTemplate,
|
|
196
|
+
saveProviderConfig,
|
|
197
|
+
setEnabledModels,
|
|
198
|
+
setUtilityModel,
|
|
199
|
+
unqualifyModelId
|
|
200
|
+
} from "./chunk-ORNY3MZR.js";
|
|
201
|
+
import {
|
|
202
|
+
isSetupComplete,
|
|
203
|
+
readGlobalConfig,
|
|
204
|
+
writeGlobalConfig
|
|
205
|
+
} from "./chunk-A6FLW5XD.js";
|
|
136
206
|
import {
|
|
137
207
|
addMessage,
|
|
138
208
|
createChannel,
|
|
@@ -140,7 +210,10 @@ import {
|
|
|
140
210
|
deleteConversationForUser,
|
|
141
211
|
findDMConversation,
|
|
142
212
|
fireWebhook,
|
|
213
|
+
formatChannelSettings,
|
|
143
214
|
getChannelByName,
|
|
215
|
+
getChannelName,
|
|
216
|
+
getChannelSettings,
|
|
144
217
|
getConversation,
|
|
145
218
|
getMessages,
|
|
146
219
|
getMessagesPaginated,
|
|
@@ -159,83 +232,20 @@ import {
|
|
|
159
232
|
markConversationRead,
|
|
160
233
|
publish,
|
|
161
234
|
setConversationPrivate,
|
|
162
|
-
subscribe as subscribe2
|
|
163
|
-
|
|
235
|
+
subscribe as subscribe2,
|
|
236
|
+
updateChannelSettings
|
|
237
|
+
} from "./chunk-5DPRTREW.js";
|
|
164
238
|
import {
|
|
165
239
|
broadcast,
|
|
166
240
|
subscribe
|
|
167
|
-
} from "./chunk-
|
|
168
|
-
import {
|
|
169
|
-
readVoluteConfig,
|
|
170
|
-
writeVoluteConfig
|
|
171
|
-
} from "./chunk-ZSR72JB3.js";
|
|
172
|
-
import "./chunk-PWQ2ITYG.js";
|
|
173
|
-
import {
|
|
174
|
-
findBridgeForChannel,
|
|
175
|
-
findOpenClawSession,
|
|
176
|
-
getBridgeConfig,
|
|
177
|
-
importOpenClawConnectors,
|
|
178
|
-
importPiSession,
|
|
179
|
-
parseNameFromIdentity,
|
|
180
|
-
readBridgesConfig,
|
|
181
|
-
removeBridgeConfig,
|
|
182
|
-
removeChannelMapping,
|
|
183
|
-
resolveChannelMapping,
|
|
184
|
-
setBridgeConfig,
|
|
185
|
-
setChannelMapping
|
|
186
|
-
} from "./chunk-MDJGMOSD.js";
|
|
187
|
-
import {
|
|
188
|
-
loadMergedEnv,
|
|
189
|
-
mindEnvPath,
|
|
190
|
-
readEnv,
|
|
191
|
-
sharedEnvPath,
|
|
192
|
-
writeEnv
|
|
193
|
-
} from "./chunk-A2ZLHBHG.js";
|
|
194
|
-
import {
|
|
195
|
-
isHomeOnlyArchive
|
|
196
|
-
} from "./chunk-N5LMGYXX.js";
|
|
197
|
-
import {
|
|
198
|
-
getAiConfig,
|
|
199
|
-
getAvailableModels,
|
|
200
|
-
getConfiguredProviders,
|
|
201
|
-
getEnabledModels,
|
|
202
|
-
getUtilityModel,
|
|
203
|
-
qualifyModelId,
|
|
204
|
-
removeAiConfig,
|
|
205
|
-
removeProviderConfig,
|
|
206
|
-
resolveApiKey,
|
|
207
|
-
resolveTemplate,
|
|
208
|
-
saveProviderConfig,
|
|
209
|
-
setEnabledModels,
|
|
210
|
-
setUtilityModel,
|
|
211
|
-
unqualifyModelId
|
|
212
|
-
} from "./chunk-FT5KETXZ.js";
|
|
241
|
+
} from "./chunk-N42QMDID.js";
|
|
213
242
|
import {
|
|
214
243
|
logBuffer,
|
|
215
244
|
logger_default
|
|
216
|
-
} from "./chunk-
|
|
217
|
-
import {
|
|
218
|
-
exec,
|
|
219
|
-
gitExec,
|
|
220
|
-
resolveVoluteBin
|
|
221
|
-
} from "./chunk-AN2W47GW.js";
|
|
222
|
-
import {
|
|
223
|
-
chownMindDir,
|
|
224
|
-
createMindUser,
|
|
225
|
-
deleteMindUser,
|
|
226
|
-
ensureVoluteGroup,
|
|
227
|
-
isIsolationEnabled,
|
|
228
|
-
wrapForIsolation
|
|
229
|
-
} from "./chunk-VHJRZM2S.js";
|
|
230
|
-
import {
|
|
231
|
-
isSetupComplete,
|
|
232
|
-
readGlobalConfig,
|
|
233
|
-
writeGlobalConfig
|
|
234
|
-
} from "./chunk-BMZQYACC.js";
|
|
245
|
+
} from "./chunk-T2TP6ZC6.js";
|
|
235
246
|
import {
|
|
236
|
-
buildVoluteSlug
|
|
237
|
-
|
|
238
|
-
} from "./chunk-NJK5SDGR.js";
|
|
247
|
+
buildVoluteSlug
|
|
248
|
+
} from "./chunk-LGNUFVMR.js";
|
|
239
249
|
import {
|
|
240
250
|
addMind,
|
|
241
251
|
addVariant,
|
|
@@ -258,9 +268,10 @@ import {
|
|
|
258
268
|
validateMindName,
|
|
259
269
|
voluteHome,
|
|
260
270
|
voluteSystemDir
|
|
261
|
-
} from "./chunk-
|
|
271
|
+
} from "./chunk-2NHRJ3YO.js";
|
|
262
272
|
import {
|
|
263
273
|
activity,
|
|
274
|
+
channels,
|
|
264
275
|
conversationParticipants,
|
|
265
276
|
conversations,
|
|
266
277
|
mindHistory,
|
|
@@ -269,16 +280,14 @@ import {
|
|
|
269
280
|
systemPrompts,
|
|
270
281
|
turns,
|
|
271
282
|
users
|
|
272
|
-
} from "./chunk-
|
|
273
|
-
import
|
|
274
|
-
__export
|
|
275
|
-
} from "./chunk-7KJOFUNN.js";
|
|
283
|
+
} from "./chunk-CJ26DXZL.js";
|
|
284
|
+
import "./chunk-K3NQKI34.js";
|
|
276
285
|
|
|
277
286
|
// packages/daemon/src/daemon.ts
|
|
278
287
|
import { randomBytes } from "crypto";
|
|
279
|
-
import { mkdirSync as mkdirSync10, readFileSync as
|
|
288
|
+
import { mkdirSync as mkdirSync10, readFileSync as readFileSync10, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "fs";
|
|
280
289
|
import { homedir as homedir3 } from "os";
|
|
281
|
-
import { resolve as
|
|
290
|
+
import { resolve as resolve16 } from "path";
|
|
282
291
|
import { format } from "util";
|
|
283
292
|
|
|
284
293
|
// packages/daemon/src/lib/daemon/bridge-manager.ts
|
|
@@ -286,7 +295,7 @@ import { spawn } from "child_process";
|
|
|
286
295
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, unlinkSync, writeFileSync } from "fs";
|
|
287
296
|
import { dirname, resolve as resolve2 } from "path";
|
|
288
297
|
|
|
289
|
-
// packages/daemon/src/lib/bridge-defs.ts
|
|
298
|
+
// packages/daemon/src/lib/bridges/bridge-defs.ts
|
|
290
299
|
import { existsSync, readFileSync } from "fs";
|
|
291
300
|
import { resolve } from "path";
|
|
292
301
|
var BUILTIN_DEFS = {
|
|
@@ -488,8 +497,8 @@ var BridgeManager = class {
|
|
|
488
497
|
if (!tracked) return;
|
|
489
498
|
this.stopping.add(platform);
|
|
490
499
|
this.bridges.delete(platform);
|
|
491
|
-
await new Promise((
|
|
492
|
-
tracked.child.on("exit", () =>
|
|
500
|
+
await new Promise((resolve17) => {
|
|
501
|
+
tracked.child.on("exit", () => resolve17());
|
|
493
502
|
try {
|
|
494
503
|
if (tracked.child.pid) {
|
|
495
504
|
process.kill(-tracked.child.pid, "SIGTERM");
|
|
@@ -500,7 +509,7 @@ var BridgeManager = class {
|
|
|
500
509
|
if (err instanceof Error && err.code !== "ESRCH") {
|
|
501
510
|
blog.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
|
|
502
511
|
}
|
|
503
|
-
|
|
512
|
+
resolve17();
|
|
504
513
|
}
|
|
505
514
|
setTimeout(() => {
|
|
506
515
|
try {
|
|
@@ -511,7 +520,7 @@ var BridgeManager = class {
|
|
|
511
520
|
}
|
|
512
521
|
} catch {
|
|
513
522
|
}
|
|
514
|
-
|
|
523
|
+
resolve17();
|
|
515
524
|
}, 5e3);
|
|
516
525
|
});
|
|
517
526
|
this.stopping.delete(platform);
|
|
@@ -599,7 +608,7 @@ function getBridgeManager() {
|
|
|
599
608
|
return instance;
|
|
600
609
|
}
|
|
601
610
|
|
|
602
|
-
// packages/daemon/src/lib/history-cleanup.ts
|
|
611
|
+
// packages/daemon/src/lib/util/history-cleanup.ts
|
|
603
612
|
import { and, eq, lt } from "drizzle-orm";
|
|
604
613
|
var LOG_RETENTION_MS = 24 * 60 * 60 * 1e3;
|
|
605
614
|
async function cleanExpiredLogs() {
|
|
@@ -816,6 +825,11 @@ import { timingSafeEqual } from "crypto";
|
|
|
816
825
|
import { eq as eq2, lt as lt2 } from "drizzle-orm";
|
|
817
826
|
import { getCookie } from "hono/cookie";
|
|
818
827
|
import { createMiddleware } from "hono/factory";
|
|
828
|
+
var MIND_USER_CACHE_TTL = 5 * 60 * 1e3;
|
|
829
|
+
var mindUserCache = /* @__PURE__ */ new Map();
|
|
830
|
+
function invalidateMindUserCache(mindName) {
|
|
831
|
+
mindUserCache.delete(mindName);
|
|
832
|
+
}
|
|
819
833
|
function isValidDaemonToken(token) {
|
|
820
834
|
const expected = process.env.VOLUTE_DAEMON_TOKEN;
|
|
821
835
|
if (!expected || token.length !== expected.length) return false;
|
|
@@ -906,7 +920,14 @@ var authMiddleware = createMiddleware(async (c, next) => {
|
|
|
906
920
|
}
|
|
907
921
|
const mindName = resolveMindToken(token);
|
|
908
922
|
if (mindName) {
|
|
909
|
-
const
|
|
923
|
+
const cached = mindUserCache.get(mindName);
|
|
924
|
+
let mindUser;
|
|
925
|
+
if (cached && Date.now() - cached.ts < MIND_USER_CACHE_TTL) {
|
|
926
|
+
mindUser = cached.user;
|
|
927
|
+
} else {
|
|
928
|
+
mindUser = await getOrCreateMindUser(mindName);
|
|
929
|
+
mindUserCache.set(mindName, { user: mindUser, ts: Date.now() });
|
|
930
|
+
}
|
|
910
931
|
c.set("user", mindUser);
|
|
911
932
|
const mindSessionHeader = c.req.header("X-Volute-Session");
|
|
912
933
|
if (mindSessionHeader) c.set("mindSession", mindSessionHeader);
|
|
@@ -963,10 +984,10 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
963
984
|
stream.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
|
|
964
985
|
});
|
|
965
986
|
});
|
|
966
|
-
await new Promise((
|
|
987
|
+
await new Promise((resolve17) => {
|
|
967
988
|
stream.onAbort(() => {
|
|
968
989
|
unsubscribe();
|
|
969
|
-
|
|
990
|
+
resolve17();
|
|
970
991
|
});
|
|
971
992
|
});
|
|
972
993
|
});
|
|
@@ -1271,14 +1292,16 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1271
1292
|
cleanupOAuthFlows();
|
|
1272
1293
|
const flowId = crypto.randomUUID();
|
|
1273
1294
|
const needsManualCode = !!oauthProvider.usesCallbackServer;
|
|
1295
|
+
const abortController = new AbortController();
|
|
1274
1296
|
const flow = {
|
|
1275
1297
|
status: "pending",
|
|
1276
1298
|
needsManualCode,
|
|
1299
|
+
abortController,
|
|
1277
1300
|
createdAt: Date.now()
|
|
1278
1301
|
};
|
|
1279
1302
|
oauthFlows.set(flowId, flow);
|
|
1280
|
-
const promptPromise = needsManualCode ? new Promise((
|
|
1281
|
-
flow.resolveCode =
|
|
1303
|
+
const promptPromise = needsManualCode ? new Promise((resolve17) => {
|
|
1304
|
+
flow.resolveCode = resolve17;
|
|
1282
1305
|
}) : void 0;
|
|
1283
1306
|
oauthProvider.login({
|
|
1284
1307
|
onAuth: (info) => {
|
|
@@ -1294,7 +1317,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1294
1317
|
}
|
|
1295
1318
|
return "";
|
|
1296
1319
|
},
|
|
1297
|
-
onManualCodeInput: needsManualCode ? () => promptPromise : void 0
|
|
1320
|
+
onManualCodeInput: needsManualCode ? () => promptPromise : void 0,
|
|
1321
|
+
signal: abortController.signal
|
|
1298
1322
|
}).then(async (credentials) => {
|
|
1299
1323
|
saveProviderConfig(provider, { oauth: credentials });
|
|
1300
1324
|
const existing = oauthFlows.get(flowId);
|
|
@@ -1307,7 +1331,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1307
1331
|
existing.error = err instanceof Error ? err.message : String(err);
|
|
1308
1332
|
}
|
|
1309
1333
|
});
|
|
1310
|
-
await new Promise((
|
|
1334
|
+
await new Promise((resolve17) => setTimeout(resolve17, 2e3));
|
|
1311
1335
|
const state = oauthFlows.get(flowId);
|
|
1312
1336
|
return c.json({
|
|
1313
1337
|
flowId,
|
|
@@ -1348,6 +1372,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1348
1372
|
status: flow.status,
|
|
1349
1373
|
waitingForCode: flow.waitingForCode
|
|
1350
1374
|
};
|
|
1375
|
+
if (flow.url) result.url = flow.url;
|
|
1376
|
+
if (flow.instructions) result.instructions = flow.instructions;
|
|
1351
1377
|
if (flow.error) result.error = flow.error;
|
|
1352
1378
|
if (flow.status !== "pending") {
|
|
1353
1379
|
setTimeout(() => oauthFlows.delete(flowId), 3e4);
|
|
@@ -1402,13 +1428,12 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1402
1428
|
}
|
|
1403
1429
|
);
|
|
1404
1430
|
var oauthFlows = /* @__PURE__ */ new Map();
|
|
1405
|
-
var OAUTH_FLOW_TTL_MS = 10 * 60 * 1e3;
|
|
1406
1431
|
function cleanupOAuthFlows() {
|
|
1407
|
-
const now = Date.now();
|
|
1408
1432
|
for (const [id, flow] of oauthFlows) {
|
|
1409
|
-
if (
|
|
1410
|
-
|
|
1433
|
+
if (flow.status === "pending") {
|
|
1434
|
+
flow.abortController?.abort();
|
|
1411
1435
|
}
|
|
1436
|
+
oauthFlows.delete(id);
|
|
1412
1437
|
}
|
|
1413
1438
|
}
|
|
1414
1439
|
var PROVIDER_TEMPLATES = {
|
|
@@ -1563,8 +1588,8 @@ var app2 = new Hono2().get("/events", async (c) => {
|
|
|
1563
1588
|
});
|
|
1564
1589
|
}, 15e3);
|
|
1565
1590
|
cleanups.push(() => clearInterval(keepAlive));
|
|
1566
|
-
await new Promise((
|
|
1567
|
-
stream.onAbort(() =>
|
|
1591
|
+
await new Promise((resolve17) => {
|
|
1592
|
+
stream.onAbort(() => resolve17());
|
|
1568
1593
|
});
|
|
1569
1594
|
} finally {
|
|
1570
1595
|
for (const cleanup of cleanups) {
|
|
@@ -1848,7 +1873,7 @@ import { zValidator as zValidator3 } from "@hono/zod-validator";
|
|
|
1848
1873
|
import { Hono as Hono4 } from "hono";
|
|
1849
1874
|
import { z as z3 } from "zod";
|
|
1850
1875
|
|
|
1851
|
-
// packages/daemon/src/lib/puppets.ts
|
|
1876
|
+
// packages/daemon/src/lib/chat/puppets.ts
|
|
1852
1877
|
import { and as and2, eq as eq3 } from "drizzle-orm";
|
|
1853
1878
|
async function findOrCreatePuppet(platform, platformId, displayName) {
|
|
1854
1879
|
const username = `${platform}:${platformId}`;
|
|
@@ -1936,11 +1961,9 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
|
|
|
1936
1961
|
}
|
|
1937
1962
|
const mindUser = await getOrCreateMindUser(mindName);
|
|
1938
1963
|
const participantIds = [puppet.id, mindUser.id];
|
|
1939
|
-
let conversationId = await findDMConversation(
|
|
1964
|
+
let conversationId = await findDMConversation(participantIds);
|
|
1940
1965
|
if (!conversationId) {
|
|
1941
|
-
const
|
|
1942
|
-
const conv = await createConversation(mindName, "volute", {
|
|
1943
|
-
title,
|
|
1966
|
+
const conv = await createConversation({
|
|
1944
1967
|
participantIds: [puppet.id, mindUser.id],
|
|
1945
1968
|
type: "dm"
|
|
1946
1969
|
});
|
|
@@ -1969,7 +1992,7 @@ var app4 = new Hono4().post("/:platform/inbound", zValidator3("json", inboundSch
|
|
|
1969
1992
|
}
|
|
1970
1993
|
const participants = await getParticipants(channel.id);
|
|
1971
1994
|
if (!participants.some((p) => p.userId === puppet.id)) {
|
|
1972
|
-
const { addParticipant } = await import("./conversations-
|
|
1995
|
+
const { addParticipant } = await import("./conversations-G6YRSABR.js");
|
|
1973
1996
|
await addParticipant(channel.id, puppet.id);
|
|
1974
1997
|
}
|
|
1975
1998
|
const contentBlocks = body.content;
|
|
@@ -2062,8 +2085,8 @@ async function fanOutToBridgedMinds(opts) {
|
|
|
2062
2085
|
const participants = await getParticipants(opts.conversationId);
|
|
2063
2086
|
const mindParticipants = participants.filter((p) => p.userType === "mind");
|
|
2064
2087
|
const participantNames = participants.map((p) => p.username);
|
|
2065
|
-
const { getMindManager: getMindManager2 } = await import("./mind-manager-
|
|
2066
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
2088
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-LS2AIXHQ.js");
|
|
2089
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TQP5ZJI5.js");
|
|
2067
2090
|
const manager = getMindManager2();
|
|
2068
2091
|
const sm = getSleepManagerIfReady2();
|
|
2069
2092
|
const targetMinds = mindParticipants.filter((ap) => {
|
|
@@ -2073,7 +2096,6 @@ async function fanOutToBridgedMinds(opts) {
|
|
|
2073
2096
|
const channel = buildVoluteSlug({
|
|
2074
2097
|
participants,
|
|
2075
2098
|
mindUsername: mindName,
|
|
2076
|
-
convTitle: null,
|
|
2077
2099
|
conversationId: opts.conversationId
|
|
2078
2100
|
});
|
|
2079
2101
|
deliverMessage(mindName, {
|
|
@@ -2089,661 +2111,10 @@ async function fanOutToBridgedMinds(opts) {
|
|
|
2089
2111
|
});
|
|
2090
2112
|
}
|
|
2091
2113
|
}
|
|
2092
|
-
var bridges_default = app4;
|
|
2093
|
-
|
|
2094
|
-
// packages/daemon/src/web/api/channels.ts
|
|
2095
|
-
import { Hono as Hono5 } from "hono";
|
|
2096
|
-
|
|
2097
|
-
// packages/daemon/src/lib/channels/discord.ts
|
|
2098
|
-
var discord_exports = {};
|
|
2099
|
-
__export(discord_exports, {
|
|
2100
|
-
createConversation: () => createConversation2,
|
|
2101
|
-
listConversations: () => listConversations,
|
|
2102
|
-
listUsers: () => listUsers2,
|
|
2103
|
-
read: () => read,
|
|
2104
|
-
send: () => send
|
|
2105
|
-
});
|
|
2106
|
-
|
|
2107
|
-
// packages/daemon/src/connectors/sdk.ts
|
|
2108
|
-
function splitMessage(text, maxLength) {
|
|
2109
|
-
const chunks = [];
|
|
2110
|
-
while (text.length > maxLength) {
|
|
2111
|
-
let splitAt = text.lastIndexOf("\n", maxLength);
|
|
2112
|
-
if (splitAt < maxLength / 2) splitAt = maxLength;
|
|
2113
|
-
chunks.push(text.slice(0, splitAt));
|
|
2114
|
-
text = text.slice(splitAt).replace(/^\n/, "");
|
|
2115
|
-
}
|
|
2116
|
-
if (text) chunks.push(text);
|
|
2117
|
-
return chunks;
|
|
2118
|
-
}
|
|
2119
|
-
|
|
2120
|
-
// packages/daemon/src/lib/channels/discord.ts
|
|
2121
|
-
var DISCORD_MAX_LENGTH = 2e3;
|
|
2122
|
-
var API_BASE = "https://discord.com/api/v10";
|
|
2123
|
-
function requireToken(env) {
|
|
2124
|
-
const token = env.DISCORD_TOKEN;
|
|
2125
|
-
if (!token) throw new Error("DISCORD_TOKEN not set");
|
|
2126
|
-
return token;
|
|
2127
|
-
}
|
|
2128
|
-
async function discordGet(token, path) {
|
|
2129
|
-
const res = await fetch(`${API_BASE}${path}`, {
|
|
2130
|
-
headers: { Authorization: `Bot ${token}` }
|
|
2131
|
-
});
|
|
2132
|
-
if (!res.ok) {
|
|
2133
|
-
throw new Error(`Discord API error: ${res.status} ${res.statusText}`);
|
|
2134
|
-
}
|
|
2135
|
-
return res.json();
|
|
2136
|
-
}
|
|
2137
|
-
async function read(env, channelSlug, limit) {
|
|
2138
|
-
const token = requireToken(env);
|
|
2139
|
-
const channelId = resolveChannelId(channelSlug);
|
|
2140
|
-
const res = await fetch(`${API_BASE}/channels/${channelId}/messages?limit=${limit}`, {
|
|
2141
|
-
headers: { Authorization: `Bot ${token}` }
|
|
2142
|
-
});
|
|
2143
|
-
if (!res.ok) {
|
|
2144
|
-
throw new Error(`Discord API error: ${res.status} ${res.statusText}`);
|
|
2145
|
-
}
|
|
2146
|
-
const messages = await res.json();
|
|
2147
|
-
return messages.reverse().map((m) => `${m.author.username}: ${m.content}`).join("\n");
|
|
2148
|
-
}
|
|
2149
|
-
async function send(env, channelSlug, message, images) {
|
|
2150
|
-
const token = requireToken(env);
|
|
2151
|
-
const channelId = resolveChannelId(channelSlug);
|
|
2152
|
-
if (images?.length) {
|
|
2153
|
-
for (let i = 0; i < images.length; i++) {
|
|
2154
|
-
const img = images[i];
|
|
2155
|
-
const ext = img.media_type.split("/")[1] || "png";
|
|
2156
|
-
const form = new FormData();
|
|
2157
|
-
const content = i === 0 ? message.slice(0, DISCORD_MAX_LENGTH) : "";
|
|
2158
|
-
form.append("payload_json", JSON.stringify({ content }));
|
|
2159
|
-
form.append(
|
|
2160
|
-
"files[0]",
|
|
2161
|
-
new Blob([Buffer.from(img.data, "base64")], { type: img.media_type }),
|
|
2162
|
-
`image.${ext}`
|
|
2163
|
-
);
|
|
2164
|
-
const res = await fetch(`${API_BASE}/channels/${channelId}/messages`, {
|
|
2165
|
-
method: "POST",
|
|
2166
|
-
headers: { Authorization: `Bot ${token}` },
|
|
2167
|
-
body: form
|
|
2168
|
-
});
|
|
2169
|
-
if (!res.ok) {
|
|
2170
|
-
const body = await res.text().catch(() => "");
|
|
2171
|
-
const partial = i > 0 ? ` (${i}/${images.length} images were already sent)` : "";
|
|
2172
|
-
throw new Error(`Discord API error: ${res.status} ${body || res.statusText}${partial}`);
|
|
2173
|
-
}
|
|
2174
|
-
}
|
|
2175
|
-
return;
|
|
2176
|
-
}
|
|
2177
|
-
const chunks = splitMessage(message, DISCORD_MAX_LENGTH);
|
|
2178
|
-
for (let i = 0; i < chunks.length; i++) {
|
|
2179
|
-
const res = await fetch(`${API_BASE}/channels/${channelId}/messages`, {
|
|
2180
|
-
method: "POST",
|
|
2181
|
-
headers: {
|
|
2182
|
-
Authorization: `Bot ${token}`,
|
|
2183
|
-
"Content-Type": "application/json"
|
|
2184
|
-
},
|
|
2185
|
-
body: JSON.stringify({ content: chunks[i] })
|
|
2186
|
-
});
|
|
2187
|
-
if (!res.ok) {
|
|
2188
|
-
const partial = i > 0 ? ` (${i}/${chunks.length} chunks were already sent)` : "";
|
|
2189
|
-
throw new Error(`Discord API error: ${res.status} ${res.statusText}${partial}`);
|
|
2190
|
-
}
|
|
2191
|
-
}
|
|
2192
|
-
}
|
|
2193
|
-
async function listConversations(env) {
|
|
2194
|
-
const token = requireToken(env);
|
|
2195
|
-
const results = [];
|
|
2196
|
-
const guilds = await discordGet(token, "/users/@me/guilds");
|
|
2197
|
-
for (const guild of guilds) {
|
|
2198
|
-
const channels = await discordGet(token, `/guilds/${guild.id}/channels`);
|
|
2199
|
-
for (const ch of channels) {
|
|
2200
|
-
if (ch.type !== 0) continue;
|
|
2201
|
-
results.push({
|
|
2202
|
-
id: `discord:${slugify(guild.name)}/${slugify(ch.name)}`,
|
|
2203
|
-
platformId: ch.id,
|
|
2204
|
-
name: `#${ch.name}`,
|
|
2205
|
-
type: "channel"
|
|
2206
|
-
});
|
|
2207
|
-
}
|
|
2208
|
-
}
|
|
2209
|
-
const dms = await discordGet(token, "/users/@me/channels");
|
|
2210
|
-
for (const dm of dms) {
|
|
2211
|
-
const recipients = dm.recipients?.map((r) => r.username) ?? [];
|
|
2212
|
-
const slug = recipients.length === 0 ? `discord:${dm.id}` : recipients.length === 1 ? `discord:@${slugify(recipients[0])}` : `discord:@${recipients.map(slugify).sort().join(",")}`;
|
|
2213
|
-
results.push({
|
|
2214
|
-
id: slug,
|
|
2215
|
-
platformId: dm.id,
|
|
2216
|
-
name: recipients.join(", ") || "DM",
|
|
2217
|
-
type: dm.type === 1 ? "dm" : "channel"
|
|
2218
|
-
});
|
|
2219
|
-
}
|
|
2220
|
-
return results;
|
|
2221
|
-
}
|
|
2222
|
-
async function listUsers2(env) {
|
|
2223
|
-
const token = requireToken(env);
|
|
2224
|
-
const seen = /* @__PURE__ */ new Map();
|
|
2225
|
-
const guilds = await discordGet(token, "/users/@me/guilds");
|
|
2226
|
-
for (const guild of guilds) {
|
|
2227
|
-
const members = await discordGet(token, `/guilds/${guild.id}/members?limit=1000`);
|
|
2228
|
-
for (const m of members) {
|
|
2229
|
-
if (!seen.has(m.user.id)) {
|
|
2230
|
-
seen.set(m.user.id, {
|
|
2231
|
-
id: m.user.id,
|
|
2232
|
-
username: m.user.username,
|
|
2233
|
-
type: m.user.bot ? "bot" : "human"
|
|
2234
|
-
});
|
|
2235
|
-
}
|
|
2236
|
-
}
|
|
2237
|
-
}
|
|
2238
|
-
return [...seen.values()];
|
|
2239
|
-
}
|
|
2240
|
-
async function createConversation2(env, participants, _name) {
|
|
2241
|
-
const token = requireToken(env);
|
|
2242
|
-
if (participants.length !== 1) {
|
|
2243
|
-
throw new Error(
|
|
2244
|
-
"Discord group creation not supported via bot \u2014 use threads in an existing channel"
|
|
2245
|
-
);
|
|
2246
|
-
}
|
|
2247
|
-
const allUsers = await listUsers2(env);
|
|
2248
|
-
const target = allUsers.find((u) => u.username.toLowerCase() === participants[0].toLowerCase());
|
|
2249
|
-
if (!target) {
|
|
2250
|
-
throw new Error(`User not found: ${participants[0]}`);
|
|
2251
|
-
}
|
|
2252
|
-
const res = await fetch(`${API_BASE}/users/@me/channels`, {
|
|
2253
|
-
method: "POST",
|
|
2254
|
-
headers: {
|
|
2255
|
-
Authorization: `Bot ${token}`,
|
|
2256
|
-
"Content-Type": "application/json"
|
|
2257
|
-
},
|
|
2258
|
-
body: JSON.stringify({ recipient_id: target.id })
|
|
2259
|
-
});
|
|
2260
|
-
if (!res.ok) {
|
|
2261
|
-
throw new Error(`Discord API error: ${res.status} ${res.statusText}`);
|
|
2262
|
-
}
|
|
2263
|
-
const dmChannel = await res.json();
|
|
2264
|
-
return `discord:${dmChannel.id}`;
|
|
2265
|
-
}
|
|
2266
|
-
|
|
2267
|
-
// packages/daemon/src/lib/channels/slack.ts
|
|
2268
|
-
var slack_exports = {};
|
|
2269
|
-
__export(slack_exports, {
|
|
2270
|
-
createConversation: () => createConversation3,
|
|
2271
|
-
listConversations: () => listConversations2,
|
|
2272
|
-
listUsers: () => listUsers3,
|
|
2273
|
-
read: () => read2,
|
|
2274
|
-
send: () => send2
|
|
2275
|
-
});
|
|
2276
|
-
var SLACK_MAX_LENGTH = 4e3;
|
|
2277
|
-
var API_BASE2 = "https://slack.com/api";
|
|
2278
|
-
function requireToken2(env) {
|
|
2279
|
-
const token = env.SLACK_BOT_TOKEN;
|
|
2280
|
-
if (!token) throw new Error("SLACK_BOT_TOKEN not set");
|
|
2281
|
-
return token;
|
|
2282
|
-
}
|
|
2283
|
-
async function slackApi(token, method, body) {
|
|
2284
|
-
const res = await fetch(`${API_BASE2}/${method}`, {
|
|
2285
|
-
method: "POST",
|
|
2286
|
-
headers: {
|
|
2287
|
-
Authorization: `Bearer ${token}`,
|
|
2288
|
-
"Content-Type": "application/json"
|
|
2289
|
-
},
|
|
2290
|
-
body: JSON.stringify(body)
|
|
2291
|
-
});
|
|
2292
|
-
if (!res.ok) {
|
|
2293
|
-
throw new Error(`Slack API HTTP error: ${res.status} ${res.statusText}`);
|
|
2294
|
-
}
|
|
2295
|
-
const data = await res.json();
|
|
2296
|
-
if (!data.ok) {
|
|
2297
|
-
throw new Error(`Slack API error: ${data.error}`);
|
|
2298
|
-
}
|
|
2299
|
-
return data;
|
|
2300
|
-
}
|
|
2301
|
-
async function read2(env, channelSlug, limit) {
|
|
2302
|
-
const token = requireToken2(env);
|
|
2303
|
-
const channelId = resolveChannelId(channelSlug);
|
|
2304
|
-
const data = await slackApi(token, "conversations.history", {
|
|
2305
|
-
channel: channelId,
|
|
2306
|
-
limit
|
|
2307
|
-
});
|
|
2308
|
-
return data.messages.reverse().map((m) => `${m.user ?? m.bot_id ?? "unknown"}: ${m.text}`).join("\n");
|
|
2309
|
-
}
|
|
2310
|
-
async function send2(env, channelSlug, message, images) {
|
|
2311
|
-
const token = requireToken2(env);
|
|
2312
|
-
const channelId = resolveChannelId(channelSlug);
|
|
2313
|
-
if (images?.length) {
|
|
2314
|
-
for (const img of images) {
|
|
2315
|
-
const ext = img.media_type.split("/")[1] || "png";
|
|
2316
|
-
const filename = `image.${ext}`;
|
|
2317
|
-
const binary = Buffer.from(img.data, "base64");
|
|
2318
|
-
const uploadData = await slackApi(token, "files.getUploadURLExternal", {
|
|
2319
|
-
filename,
|
|
2320
|
-
length: binary.length
|
|
2321
|
-
});
|
|
2322
|
-
const uploadRes = await fetch(uploadData.upload_url, {
|
|
2323
|
-
method: "POST",
|
|
2324
|
-
body: binary
|
|
2325
|
-
});
|
|
2326
|
-
if (!uploadRes.ok) {
|
|
2327
|
-
throw new Error(`Slack file upload failed: ${uploadRes.status} ${uploadRes.statusText}`);
|
|
2328
|
-
}
|
|
2329
|
-
await slackApi(token, "files.completeUploadExternal", {
|
|
2330
|
-
files: [{ id: uploadData.file_id }],
|
|
2331
|
-
channel_id: channelId
|
|
2332
|
-
});
|
|
2333
|
-
}
|
|
2334
|
-
if (message) {
|
|
2335
|
-
const chunks2 = splitMessage(message, SLACK_MAX_LENGTH);
|
|
2336
|
-
for (const chunk of chunks2) {
|
|
2337
|
-
await slackApi(token, "chat.postMessage", {
|
|
2338
|
-
channel: channelId,
|
|
2339
|
-
text: chunk
|
|
2340
|
-
});
|
|
2341
|
-
}
|
|
2342
|
-
}
|
|
2343
|
-
return;
|
|
2344
|
-
}
|
|
2345
|
-
const chunks = splitMessage(message, SLACK_MAX_LENGTH);
|
|
2346
|
-
for (let i = 0; i < chunks.length; i++) {
|
|
2347
|
-
try {
|
|
2348
|
-
await slackApi(token, "chat.postMessage", {
|
|
2349
|
-
channel: channelId,
|
|
2350
|
-
text: chunks[i]
|
|
2351
|
-
});
|
|
2352
|
-
} catch (err) {
|
|
2353
|
-
const partial = i > 0 ? ` (${i}/${chunks.length} chunks were already sent)` : "";
|
|
2354
|
-
throw new Error(`${err instanceof Error ? err.message : err}${partial}`);
|
|
2355
|
-
}
|
|
2356
|
-
}
|
|
2357
|
-
}
|
|
2358
|
-
async function listConversations2(env) {
|
|
2359
|
-
const token = requireToken2(env);
|
|
2360
|
-
const authData = await slackApi(token, "auth.test", {});
|
|
2361
|
-
const teamName = authData.team ?? "workspace";
|
|
2362
|
-
const data = await slackApi(token, "conversations.list", {
|
|
2363
|
-
types: "public_channel,private_channel,mpim,im",
|
|
2364
|
-
limit: 1e3
|
|
2365
|
-
});
|
|
2366
|
-
const userMap = /* @__PURE__ */ new Map();
|
|
2367
|
-
const imChannels = data.channels.filter((ch) => ch.is_im && ch.user);
|
|
2368
|
-
if (imChannels.length > 0) {
|
|
2369
|
-
const users2 = await listUsers3(env);
|
|
2370
|
-
for (const u of users2) {
|
|
2371
|
-
userMap.set(u.id, u.username);
|
|
2372
|
-
}
|
|
2373
|
-
}
|
|
2374
|
-
return data.channels.map((ch) => {
|
|
2375
|
-
let type = "channel";
|
|
2376
|
-
if (ch.is_im) type = "dm";
|
|
2377
|
-
let slug;
|
|
2378
|
-
let name;
|
|
2379
|
-
if (ch.is_im && ch.user) {
|
|
2380
|
-
const username = userMap.get(ch.user) ?? ch.user;
|
|
2381
|
-
slug = `slack:@${slugify(username)}`;
|
|
2382
|
-
name = username;
|
|
2383
|
-
} else if (ch.name) {
|
|
2384
|
-
slug = `slack:${slugify(teamName)}/${slugify(ch.name)}`;
|
|
2385
|
-
name = ch.name;
|
|
2386
|
-
} else {
|
|
2387
|
-
slug = `slack:${ch.id}`;
|
|
2388
|
-
name = ch.id;
|
|
2389
|
-
}
|
|
2390
|
-
return {
|
|
2391
|
-
id: slug,
|
|
2392
|
-
platformId: ch.id,
|
|
2393
|
-
name,
|
|
2394
|
-
type,
|
|
2395
|
-
participantCount: ch.num_members
|
|
2396
|
-
};
|
|
2397
|
-
});
|
|
2398
|
-
}
|
|
2399
|
-
async function listUsers3(env) {
|
|
2400
|
-
const token = requireToken2(env);
|
|
2401
|
-
const data = await slackApi(token, "users.list", {});
|
|
2402
|
-
return data.members.filter((m) => !m.deleted).map((m) => ({
|
|
2403
|
-
id: m.id,
|
|
2404
|
-
username: m.name,
|
|
2405
|
-
type: m.is_bot ? "bot" : "human"
|
|
2406
|
-
}));
|
|
2407
|
-
}
|
|
2408
|
-
async function createConversation3(env, participants, name) {
|
|
2409
|
-
const token = requireToken2(env);
|
|
2410
|
-
const allUsers = await listUsers3(env);
|
|
2411
|
-
const ids = [];
|
|
2412
|
-
for (const p of participants) {
|
|
2413
|
-
const user = allUsers.find((u) => u.username.toLowerCase() === p.toLowerCase());
|
|
2414
|
-
if (!user) throw new Error(`User not found: ${p}`);
|
|
2415
|
-
ids.push(user.id);
|
|
2416
|
-
}
|
|
2417
|
-
if (name) {
|
|
2418
|
-
const createData = await slackApi(token, "conversations.create", {
|
|
2419
|
-
name,
|
|
2420
|
-
is_private: true
|
|
2421
|
-
});
|
|
2422
|
-
const channelId = createData.channel.id;
|
|
2423
|
-
for (const userId of ids) {
|
|
2424
|
-
await slackApi(token, "conversations.invite", {
|
|
2425
|
-
channel: channelId,
|
|
2426
|
-
users: userId
|
|
2427
|
-
});
|
|
2428
|
-
}
|
|
2429
|
-
const authData = await slackApi(token, "auth.test", {});
|
|
2430
|
-
const teamName = authData.team ?? "workspace";
|
|
2431
|
-
const slug = `slack:${slugify(teamName)}/${slugify(name)}`;
|
|
2432
|
-
return slug;
|
|
2433
|
-
}
|
|
2434
|
-
const openData = await slackApi(token, "conversations.open", { users: ids.join(",") });
|
|
2435
|
-
return `slack:${openData.channel.id}`;
|
|
2436
|
-
}
|
|
2437
|
-
|
|
2438
|
-
// packages/daemon/src/lib/channels/telegram.ts
|
|
2439
|
-
var telegram_exports = {};
|
|
2440
|
-
__export(telegram_exports, {
|
|
2441
|
-
createConversation: () => createConversation4,
|
|
2442
|
-
listConversations: () => listConversations3,
|
|
2443
|
-
listUsers: () => listUsers4,
|
|
2444
|
-
read: () => read3,
|
|
2445
|
-
send: () => send3
|
|
2446
|
-
});
|
|
2447
|
-
var TELEGRAM_MAX_LENGTH = 4096;
|
|
2448
|
-
var API_BASE3 = "https://api.telegram.org";
|
|
2449
|
-
function requireToken3(env) {
|
|
2450
|
-
const token = env.TELEGRAM_BOT_TOKEN;
|
|
2451
|
-
if (!token) throw new Error("TELEGRAM_BOT_TOKEN not set");
|
|
2452
|
-
return token;
|
|
2453
|
-
}
|
|
2454
|
-
async function read3(_env, _channelSlug, _limit) {
|
|
2455
|
-
throw new Error(
|
|
2456
|
-
"Telegram Bot API does not support reading chat history. Use volute chat send instead."
|
|
2457
|
-
);
|
|
2458
|
-
}
|
|
2459
|
-
async function send3(env, channelSlug, message, images) {
|
|
2460
|
-
const token = requireToken3(env);
|
|
2461
|
-
const chatId = resolveChannelId(channelSlug);
|
|
2462
|
-
if (images?.length) {
|
|
2463
|
-
const CAPTION_MAX = 1024;
|
|
2464
|
-
for (let i = 0; i < images.length; i++) {
|
|
2465
|
-
const img = images[i];
|
|
2466
|
-
const ext = img.media_type.split("/")[1] || "png";
|
|
2467
|
-
const form = new FormData();
|
|
2468
|
-
form.append("chat_id", chatId);
|
|
2469
|
-
form.append(
|
|
2470
|
-
"photo",
|
|
2471
|
-
new Blob([Buffer.from(img.data, "base64")], { type: img.media_type }),
|
|
2472
|
-
`image.${ext}`
|
|
2473
|
-
);
|
|
2474
|
-
if (i === 0 && message) {
|
|
2475
|
-
form.append("caption", message.slice(0, CAPTION_MAX));
|
|
2476
|
-
}
|
|
2477
|
-
const res = await fetch(`${API_BASE3}/bot${token}/sendPhoto`, {
|
|
2478
|
-
method: "POST",
|
|
2479
|
-
body: form
|
|
2480
|
-
});
|
|
2481
|
-
if (!res.ok) {
|
|
2482
|
-
const body = await res.text().catch(() => "");
|
|
2483
|
-
const partial = i > 0 ? ` (${i}/${images.length} images were already sent)` : "";
|
|
2484
|
-
throw new Error(`Telegram API error: ${res.status} ${body}${partial}`);
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
|
-
if (message && message.length > CAPTION_MAX) {
|
|
2488
|
-
const remaining = message.slice(CAPTION_MAX);
|
|
2489
|
-
const chunks2 = splitMessage(remaining, TELEGRAM_MAX_LENGTH);
|
|
2490
|
-
for (const chunk of chunks2) {
|
|
2491
|
-
const res = await fetch(`${API_BASE3}/bot${token}/sendMessage`, {
|
|
2492
|
-
method: "POST",
|
|
2493
|
-
headers: { "Content-Type": "application/json" },
|
|
2494
|
-
body: JSON.stringify({ chat_id: chatId, text: chunk })
|
|
2495
|
-
});
|
|
2496
|
-
if (!res.ok) {
|
|
2497
|
-
const body = await res.text().catch(() => "");
|
|
2498
|
-
throw new Error(`Telegram API error: ${res.status} ${body}`);
|
|
2499
|
-
}
|
|
2500
|
-
}
|
|
2501
|
-
}
|
|
2502
|
-
return;
|
|
2503
|
-
}
|
|
2504
|
-
const chunks = splitMessage(message, TELEGRAM_MAX_LENGTH);
|
|
2505
|
-
for (let i = 0; i < chunks.length; i++) {
|
|
2506
|
-
const res = await fetch(`${API_BASE3}/bot${token}/sendMessage`, {
|
|
2507
|
-
method: "POST",
|
|
2508
|
-
headers: { "Content-Type": "application/json" },
|
|
2509
|
-
body: JSON.stringify({ chat_id: chatId, text: chunks[i] })
|
|
2510
|
-
});
|
|
2511
|
-
if (!res.ok) {
|
|
2512
|
-
const body = await res.text().catch(() => "");
|
|
2513
|
-
const partial = i > 0 ? ` (${i}/${chunks.length} chunks were already sent)` : "";
|
|
2514
|
-
throw new Error(`Telegram API error: ${res.status} ${body}${partial}`);
|
|
2515
|
-
}
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
async function listConversations3() {
|
|
2519
|
-
throw new Error(
|
|
2520
|
-
"Telegram Bot API does not support listing conversations. Users must message the bot first."
|
|
2521
|
-
);
|
|
2522
|
-
}
|
|
2523
|
-
async function listUsers4() {
|
|
2524
|
-
throw new Error(
|
|
2525
|
-
"Telegram Bot API does not support listing users. Users must message the bot first."
|
|
2526
|
-
);
|
|
2527
|
-
}
|
|
2528
|
-
async function createConversation4() {
|
|
2529
|
-
throw new Error(
|
|
2530
|
-
"Telegram Bot API does not support creating conversations. Users must message the bot first."
|
|
2531
|
-
);
|
|
2532
|
-
}
|
|
2533
|
-
|
|
2534
|
-
// packages/daemon/src/lib/channels/volute.ts
|
|
2535
|
-
var volute_exports = {};
|
|
2536
|
-
__export(volute_exports, {
|
|
2537
|
-
createConversation: () => createConversation5,
|
|
2538
|
-
listConversations: () => listConversations4,
|
|
2539
|
-
listUsers: () => listUsers5,
|
|
2540
|
-
read: () => read4,
|
|
2541
|
-
send: () => send4
|
|
2542
|
-
});
|
|
2543
|
-
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
2544
|
-
import { resolve as resolve4 } from "path";
|
|
2545
|
-
function readSessionFile(mindDir2) {
|
|
2546
|
-
try {
|
|
2547
|
-
const p = resolve4(mindDir2, ".mind", "current-session");
|
|
2548
|
-
if (existsSync4(p)) return readFileSync4(p, "utf-8").trim() || void 0;
|
|
2549
|
-
} catch (err) {
|
|
2550
|
-
const code = err.code;
|
|
2551
|
-
if (code !== "ENOENT") {
|
|
2552
|
-
console.error(`[volute] failed to read session file: ${code ?? err}`);
|
|
2553
|
-
}
|
|
2554
|
-
}
|
|
2555
|
-
return void 0;
|
|
2556
|
-
}
|
|
2557
|
-
function getDaemonConfig() {
|
|
2558
|
-
const configPath = resolve4(voluteSystemDir(), "daemon.json");
|
|
2559
|
-
if (!existsSync4(configPath)) {
|
|
2560
|
-
throw new Error("Volute daemon is not running");
|
|
2561
|
-
}
|
|
2562
|
-
let config2;
|
|
2563
|
-
try {
|
|
2564
|
-
config2 = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
2565
|
-
} catch (err) {
|
|
2566
|
-
throw new Error(`Failed to parse ${configPath}: ${err}`);
|
|
2567
|
-
}
|
|
2568
|
-
if (typeof config2.port !== "number") {
|
|
2569
|
-
throw new Error(`Invalid or missing port in ${configPath}`);
|
|
2570
|
-
}
|
|
2571
|
-
const url = new URL("http://localhost");
|
|
2572
|
-
url.hostname = config2.hostname || "localhost";
|
|
2573
|
-
url.port = String(config2.port);
|
|
2574
|
-
return { url: url.origin, token: config2.token };
|
|
2575
|
-
}
|
|
2576
|
-
async function read4(env, channelSlug, limit) {
|
|
2577
|
-
const mindName = env.VOLUTE_MIND;
|
|
2578
|
-
if (!mindName) throw new Error("VOLUTE_MIND not set");
|
|
2579
|
-
const conversationId = resolveChannelId(channelSlug);
|
|
2580
|
-
const { url, token } = getDaemonConfig();
|
|
2581
|
-
const headers = { Origin: url };
|
|
2582
|
-
if (token) headers.Authorization = `Bearer ${token}`;
|
|
2583
|
-
const res = await fetch(
|
|
2584
|
-
`${url}/api/minds/${encodeURIComponent(mindName)}/conversations/${encodeURIComponent(conversationId)}/messages`,
|
|
2585
|
-
{ headers }
|
|
2586
|
-
);
|
|
2587
|
-
if (!res.ok) {
|
|
2588
|
-
throw new Error(`Failed to read conversation: ${res.status} ${res.statusText}`);
|
|
2589
|
-
}
|
|
2590
|
-
const data = await res.json();
|
|
2591
|
-
if (!Array.isArray(data.items)) {
|
|
2592
|
-
throw new Error("Unexpected response format when reading conversation messages");
|
|
2593
|
-
}
|
|
2594
|
-
return data.items.slice(-limit).map((m) => {
|
|
2595
|
-
const text = Array.isArray(m.content) ? m.content.filter((b) => b.type === "text").map((b) => b.text).join("") : m.content;
|
|
2596
|
-
return `${m.sender_name ?? m.role}: ${text}`;
|
|
2597
|
-
}).join("\n");
|
|
2598
|
-
}
|
|
2599
|
-
async function send4(env, channelSlug, message, images) {
|
|
2600
|
-
const mindName = env.VOLUTE_MIND;
|
|
2601
|
-
if (!mindName) throw new Error("VOLUTE_MIND not set");
|
|
2602
|
-
const conversationId = resolveChannelId(channelSlug);
|
|
2603
|
-
const { url, token } = getDaemonConfig();
|
|
2604
|
-
const headers = {
|
|
2605
|
-
"Content-Type": "application/json",
|
|
2606
|
-
Origin: url
|
|
2607
|
-
};
|
|
2608
|
-
if (token) headers.Authorization = `Bearer ${token}`;
|
|
2609
|
-
const voluteSession = env.VOLUTE_SESSION || (env.VOLUTE_MIND_DIR ? readSessionFile(env.VOLUTE_MIND_DIR) : void 0);
|
|
2610
|
-
if (voluteSession) headers["X-Volute-Session"] = voluteSession;
|
|
2611
|
-
const res = await fetch(`${url}/api/v1/chat`, {
|
|
2612
|
-
method: "POST",
|
|
2613
|
-
headers,
|
|
2614
|
-
body: JSON.stringify({
|
|
2615
|
-
message,
|
|
2616
|
-
conversationId,
|
|
2617
|
-
sender: env.VOLUTE_SENDER ?? mindName,
|
|
2618
|
-
images,
|
|
2619
|
-
targetMind: mindName
|
|
2620
|
-
})
|
|
2621
|
-
});
|
|
2622
|
-
if (!res.ok) {
|
|
2623
|
-
const data = await res.json().catch(() => ({}));
|
|
2624
|
-
throw new Error(data.error ?? `Failed to send: ${res.status}`);
|
|
2625
|
-
}
|
|
2626
|
-
}
|
|
2627
|
-
async function listConversations4(env) {
|
|
2628
|
-
const mindName = env.VOLUTE_MIND;
|
|
2629
|
-
if (!mindName) throw new Error("VOLUTE_MIND not set");
|
|
2630
|
-
const { url, token } = getDaemonConfig();
|
|
2631
|
-
const headers = { Origin: url };
|
|
2632
|
-
if (token) headers.Authorization = `Bearer ${token}`;
|
|
2633
|
-
const res = await fetch(`${url}/api/minds/${encodeURIComponent(mindName)}/conversations`, {
|
|
2634
|
-
headers
|
|
2635
|
-
});
|
|
2636
|
-
if (!res.ok) {
|
|
2637
|
-
throw new Error(`Failed to list conversations: ${res.status} ${res.statusText}`);
|
|
2638
|
-
}
|
|
2639
|
-
const convs = await res.json();
|
|
2640
|
-
const results = [];
|
|
2641
|
-
for (const conv of convs) {
|
|
2642
|
-
let participants = [];
|
|
2643
|
-
try {
|
|
2644
|
-
const pRes = await fetch(
|
|
2645
|
-
`${url}/api/minds/${encodeURIComponent(mindName)}/conversations/${encodeURIComponent(conv.id)}/participants`,
|
|
2646
|
-
{ headers }
|
|
2647
|
-
);
|
|
2648
|
-
if (pRes.ok) {
|
|
2649
|
-
participants = await pRes.json();
|
|
2650
|
-
} else {
|
|
2651
|
-
console.error(`[volute] failed to fetch participants for ${conv.id}: HTTP ${pRes.status}`);
|
|
2652
|
-
}
|
|
2653
|
-
} catch (err) {
|
|
2654
|
-
console.error(`[volute] failed to fetch participants for ${conv.id}:`, err);
|
|
2655
|
-
}
|
|
2656
|
-
const slug = buildVoluteSlug({
|
|
2657
|
-
participants,
|
|
2658
|
-
mindUsername: mindName,
|
|
2659
|
-
convTitle: conv.title,
|
|
2660
|
-
conversationId: conv.id,
|
|
2661
|
-
convType: conv.type,
|
|
2662
|
-
convName: conv.name
|
|
2663
|
-
});
|
|
2664
|
-
const convType = conv.type === "channel" ? "channel" : "dm";
|
|
2665
|
-
results.push({
|
|
2666
|
-
id: slug,
|
|
2667
|
-
platformId: conv.id,
|
|
2668
|
-
name: conv.type === "channel" ? `#${conv.name}` : conv.title ?? "(untitled)",
|
|
2669
|
-
type: convType,
|
|
2670
|
-
participantCount: participants.length
|
|
2671
|
-
});
|
|
2672
|
-
}
|
|
2673
|
-
return results;
|
|
2674
|
-
}
|
|
2675
|
-
async function listUsers5(_env) {
|
|
2676
|
-
const { url, token } = getDaemonConfig();
|
|
2677
|
-
const headers = { Origin: url };
|
|
2678
|
-
if (token) headers.Authorization = `Bearer ${token}`;
|
|
2679
|
-
const res = await fetch(`${url}/api/auth/users`, { headers });
|
|
2680
|
-
if (!res.ok) {
|
|
2681
|
-
throw new Error(`Failed to list users: ${res.status} ${res.statusText}`);
|
|
2682
|
-
}
|
|
2683
|
-
const data = await res.json();
|
|
2684
|
-
return data.map((u) => ({
|
|
2685
|
-
id: String(u.id),
|
|
2686
|
-
username: u.username,
|
|
2687
|
-
type: u.user_type
|
|
2688
|
-
}));
|
|
2689
|
-
}
|
|
2690
|
-
async function createConversation5(env, participants, name) {
|
|
2691
|
-
const mindName = env.VOLUTE_MIND;
|
|
2692
|
-
if (!mindName) throw new Error("VOLUTE_MIND not set");
|
|
2693
|
-
const { url, token } = getDaemonConfig();
|
|
2694
|
-
const headers = {
|
|
2695
|
-
"Content-Type": "application/json",
|
|
2696
|
-
Origin: url
|
|
2697
|
-
};
|
|
2698
|
-
if (token) headers.Authorization = `Bearer ${token}`;
|
|
2699
|
-
const res = await fetch(`${url}/api/minds/${encodeURIComponent(mindName)}/conversations`, {
|
|
2700
|
-
method: "POST",
|
|
2701
|
-
headers,
|
|
2702
|
-
body: JSON.stringify({ participantNames: participants, title: name })
|
|
2703
|
-
});
|
|
2704
|
-
if (!res.ok) {
|
|
2705
|
-
const data = await res.json().catch(() => ({}));
|
|
2706
|
-
throw new Error(data.error ?? `Failed to create conversation: ${res.status}`);
|
|
2707
|
-
}
|
|
2708
|
-
const conv = await res.json();
|
|
2709
|
-
return conv.id;
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
// packages/daemon/src/lib/channels.ts
|
|
2713
|
-
var CHANNELS = {
|
|
2714
|
-
volute: {
|
|
2715
|
-
name: "volute",
|
|
2716
|
-
displayName: "Volute",
|
|
2717
|
-
builtIn: true,
|
|
2718
|
-
driver: volute_exports
|
|
2719
|
-
},
|
|
2720
|
-
discord: {
|
|
2721
|
-
name: "discord",
|
|
2722
|
-
displayName: "Discord",
|
|
2723
|
-
driver: discord_exports
|
|
2724
|
-
},
|
|
2725
|
-
slack: {
|
|
2726
|
-
name: "slack",
|
|
2727
|
-
displayName: "Slack",
|
|
2728
|
-
driver: slack_exports
|
|
2729
|
-
},
|
|
2730
|
-
telegram: {
|
|
2731
|
-
name: "telegram",
|
|
2732
|
-
displayName: "Telegram",
|
|
2733
|
-
driver: telegram_exports
|
|
2734
|
-
},
|
|
2735
|
-
mail: { name: "mail", displayName: "Email" },
|
|
2736
|
-
system: { name: "system", displayName: "System" }
|
|
2737
|
-
};
|
|
2738
|
-
function getChannelDriver(platform) {
|
|
2739
|
-
return CHANNELS[platform]?.driver ?? null;
|
|
2740
|
-
}
|
|
2741
|
-
function resolveChannelId(slug) {
|
|
2742
|
-
const colonIdx = slug.indexOf(":");
|
|
2743
|
-
return colonIdx !== -1 ? slug.slice(colonIdx + 1) : slug;
|
|
2744
|
-
}
|
|
2114
|
+
var bridges_default = app4;
|
|
2745
2115
|
|
|
2746
2116
|
// packages/daemon/src/web/api/channels.ts
|
|
2117
|
+
import { Hono as Hono5 } from "hono";
|
|
2747
2118
|
function buildEnv(name) {
|
|
2748
2119
|
return { ...loadMergedEnv(name), VOLUTE_MIND: name, VOLUTE_MIND_DIR: mindDir(name) };
|
|
2749
2120
|
}
|
|
@@ -2756,7 +2127,7 @@ var app5 = new Hono5().post("/:name/channels/create", requireSelf(), async (c) =
|
|
|
2756
2127
|
name: convName,
|
|
2757
2128
|
sender
|
|
2758
2129
|
} = await c.req.json();
|
|
2759
|
-
const driver =
|
|
2130
|
+
const driver = getPlatformDriver(platform);
|
|
2760
2131
|
if (!driver?.createConversation) {
|
|
2761
2132
|
return c.json({ error: `Platform ${platform} does not support creating conversations` }, 400);
|
|
2762
2133
|
}
|
|
@@ -2878,7 +2249,8 @@ import { Hono as Hono8 } from "hono";
|
|
|
2878
2249
|
var app7 = new Hono8().get("/", (c) => {
|
|
2879
2250
|
return c.json(getLoadedExtensions());
|
|
2880
2251
|
}).get("/all", (c) => {
|
|
2881
|
-
|
|
2252
|
+
const detail = c.req.query("detail") === "true";
|
|
2253
|
+
return c.json(detail ? getAllDiscoveredExtensionsDetailed() : getAllDiscoveredExtensions());
|
|
2882
2254
|
}).put("/:id/enabled", async (c) => {
|
|
2883
2255
|
const { id } = c.req.param();
|
|
2884
2256
|
const body = await c.req.json().catch(() => null);
|
|
@@ -2919,14 +2291,14 @@ var app7 = new Hono8().get("/", (c) => {
|
|
|
2919
2291
|
var extensions_default = app7;
|
|
2920
2292
|
|
|
2921
2293
|
// packages/daemon/src/web/api/file-sharing.ts
|
|
2922
|
-
import { readFileSync as
|
|
2923
|
-
import { resolve as
|
|
2294
|
+
import { readFileSync as readFileSync4, statSync } from "fs";
|
|
2295
|
+
import { resolve as resolve4 } from "path";
|
|
2924
2296
|
import { Hono as Hono9 } from "hono";
|
|
2925
2297
|
async function notifyMind(mindName, message) {
|
|
2926
2298
|
const entry = await findMind(mindName);
|
|
2927
2299
|
if (!entry) return;
|
|
2928
2300
|
try {
|
|
2929
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
2301
|
+
const { sendSystemMessage } = await import("./system-chat-NNXYCSVL.js");
|
|
2930
2302
|
await sendSystemMessage(mindName, message);
|
|
2931
2303
|
} catch (err) {
|
|
2932
2304
|
logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
|
|
@@ -2945,7 +2317,7 @@ var app8 = new Hono9().post("/:name/files/send", requireSelf(), async (c) => {
|
|
|
2945
2317
|
const pathErr = validateFilePath(body.filePath);
|
|
2946
2318
|
if (pathErr) return c.json({ error: pathErr }, 400);
|
|
2947
2319
|
const senderDir = mindDir(senderName);
|
|
2948
|
-
const filePath =
|
|
2320
|
+
const filePath = resolve4(senderDir, "home", body.filePath);
|
|
2949
2321
|
const MAX_FILE_SIZE3 = 50 * 1024 * 1024;
|
|
2950
2322
|
const stat3 = statSync(filePath, { throwIfNoEntry: false });
|
|
2951
2323
|
if (!stat3) return c.json({ error: `File not found: ${body.filePath}` }, 404);
|
|
@@ -2959,7 +2331,7 @@ var app8 = new Hono9().post("/:name/files/send", requireSelf(), async (c) => {
|
|
|
2959
2331
|
}
|
|
2960
2332
|
let content;
|
|
2961
2333
|
try {
|
|
2962
|
-
content =
|
|
2334
|
+
content = readFileSync4(filePath);
|
|
2963
2335
|
} catch (err) {
|
|
2964
2336
|
const code = err.code;
|
|
2965
2337
|
if (code === "ENOENT") {
|
|
@@ -3051,7 +2423,7 @@ var file_sharing_default = app8;
|
|
|
3051
2423
|
// packages/daemon/src/web/api/files.ts
|
|
3052
2424
|
import { mkdirSync as mkdirSync3, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
3053
2425
|
import { readdir, readFile, realpath, stat } from "fs/promises";
|
|
3054
|
-
import { extname as extname2, resolve as
|
|
2426
|
+
import { extname as extname2, resolve as resolve5 } from "path";
|
|
3055
2427
|
import { Hono as Hono10 } from "hono";
|
|
3056
2428
|
var AVATAR_MIME2 = {
|
|
3057
2429
|
".png": "image/png",
|
|
@@ -3096,13 +2468,13 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
|
|
|
3096
2468
|
return c.json({ error: "Invalid file type (png, jpg, gif, webp only)" }, 400);
|
|
3097
2469
|
}
|
|
3098
2470
|
const dir = entry.dir ?? mindDir(name);
|
|
3099
|
-
const homeDir =
|
|
2471
|
+
const homeDir = resolve5(dir, "home");
|
|
3100
2472
|
const filename = `avatar${ext}`;
|
|
3101
|
-
const avatarPath =
|
|
2473
|
+
const avatarPath = resolve5(homeDir, filename);
|
|
3102
2474
|
const config2 = readVoluteConfig(dir) ?? {};
|
|
3103
2475
|
const oldAvatar = config2.profile?.avatar;
|
|
3104
2476
|
if (oldAvatar && oldAvatar !== filename) {
|
|
3105
|
-
rmSync2(
|
|
2477
|
+
rmSync2(resolve5(homeDir, oldAvatar), { force: true });
|
|
3106
2478
|
}
|
|
3107
2479
|
const buffer2 = Buffer.from(await file.arrayBuffer());
|
|
3108
2480
|
mkdirSync3(homeDir, { recursive: true });
|
|
@@ -3124,8 +2496,8 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
|
|
|
3124
2496
|
const ext = extname2(config2.profile.avatar).toLowerCase();
|
|
3125
2497
|
const mime = AVATAR_MIME2[ext];
|
|
3126
2498
|
if (!mime) return c.json({ error: "Invalid avatar extension" }, 400);
|
|
3127
|
-
const homeDir =
|
|
3128
|
-
const avatarPath =
|
|
2499
|
+
const homeDir = resolve5(dir, "home");
|
|
2500
|
+
const avatarPath = resolve5(homeDir, config2.profile.avatar);
|
|
3129
2501
|
if (!avatarPath.startsWith(`${homeDir}/`)) return c.json({ error: "Invalid avatar path" }, 400);
|
|
3130
2502
|
let realAvatarPath;
|
|
3131
2503
|
try {
|
|
@@ -3153,7 +2525,7 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
|
|
|
3153
2525
|
const name = c.req.param("name");
|
|
3154
2526
|
const entry = await findMind(name);
|
|
3155
2527
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3156
|
-
const homeDir =
|
|
2528
|
+
const homeDir = resolve5(entry.dir ?? mindDir(name), "home");
|
|
3157
2529
|
let entries;
|
|
3158
2530
|
try {
|
|
3159
2531
|
entries = await readdir(homeDir, { withFileTypes: true });
|
|
@@ -3168,10 +2540,10 @@ var app9 = new Hono10().post("/:name/avatar", requireSelf(), async (c) => {
|
|
|
3168
2540
|
const name = c.req.param("name");
|
|
3169
2541
|
const entry = await findMind(name);
|
|
3170
2542
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3171
|
-
const homeDir =
|
|
2543
|
+
const homeDir = resolve5(entry.dir ?? mindDir(name), "home");
|
|
3172
2544
|
const wildcard = c.req.path.replace(new RegExp(`^.*/minds/${name}/files`), "") || "/";
|
|
3173
2545
|
const relativePath = wildcard.slice(1);
|
|
3174
|
-
const requestedPath =
|
|
2546
|
+
const requestedPath = resolve5(homeDir, relativePath);
|
|
3175
2547
|
if (requestedPath !== homeDir && !requestedPath.startsWith(`${homeDir}/`))
|
|
3176
2548
|
return c.text("Forbidden", 403);
|
|
3177
2549
|
if (relativePath.split("/").some((seg) => seg.startsWith("."))) return c.text("Forbidden", 403);
|
|
@@ -3305,14 +2677,14 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3305
2677
|
for (const r of triggerRows) triggerMap.set(r.id, r);
|
|
3306
2678
|
}
|
|
3307
2679
|
const allChannelSlugs = /* @__PURE__ */ new Set();
|
|
3308
|
-
for (const [,
|
|
3309
|
-
for (const ch of
|
|
2680
|
+
for (const [, channels2] of msgsByTurnChannel) {
|
|
2681
|
+
for (const ch of channels2.keys()) allChannelSlugs.add(ch);
|
|
3310
2682
|
}
|
|
3311
2683
|
const dmSlugMinds = /* @__PURE__ */ new Map();
|
|
3312
|
-
for (const [turnId,
|
|
2684
|
+
for (const [turnId, channels2] of msgsByTurnChannel) {
|
|
3313
2685
|
const mindName = turnMindMap.get(turnId);
|
|
3314
2686
|
if (!mindName) continue;
|
|
3315
|
-
for (const ch of
|
|
2687
|
+
for (const ch of channels2.keys()) {
|
|
3316
2688
|
if (ch.startsWith("@")) {
|
|
3317
2689
|
let minds = dmSlugMinds.get(ch);
|
|
3318
2690
|
if (!minds) {
|
|
@@ -3334,16 +2706,13 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3334
2706
|
return { slug: s, name };
|
|
3335
2707
|
});
|
|
3336
2708
|
if (channelNames.length > 0) {
|
|
3337
|
-
const channelRows = await db.select({
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
conversations.name,
|
|
3342
|
-
channelNames.map((c2) => c2.name)
|
|
3343
|
-
)
|
|
2709
|
+
const channelRows = await db.select({ conversationId: channels.conversation_id, name: channels.name }).from(channels).where(
|
|
2710
|
+
inArray(
|
|
2711
|
+
channels.name,
|
|
2712
|
+
channelNames.map((c2) => c2.name)
|
|
3344
2713
|
)
|
|
3345
2714
|
);
|
|
3346
|
-
const nameToId = new Map(channelRows.map((r) => [r.name, r.
|
|
2715
|
+
const nameToId = new Map(channelRows.map((r) => [r.name, r.conversationId]));
|
|
3347
2716
|
for (const { slug, name } of channelNames) {
|
|
3348
2717
|
const id = nameToId.get(name);
|
|
3349
2718
|
if (id) channelIdMap.set(slug, id);
|
|
@@ -3365,17 +2734,31 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3365
2734
|
conversationParticipants,
|
|
3366
2735
|
eq4(conversations.id, conversationParticipants.conversation_id)
|
|
3367
2736
|
).innerJoin(users, eq4(conversationParticipants.user_id, users.id)).where(and3(eq4(conversations.type, "dm"), inArray(users.username, targetNames)));
|
|
2737
|
+
const dmCandidates = [];
|
|
3368
2738
|
for (const row of dmRows) {
|
|
3369
2739
|
const slug = `@${row.targetUsername}`;
|
|
3370
2740
|
const mindNames = dmSlugMinds.get(slug);
|
|
3371
2741
|
if (mindNames && !channelIdMap.has(slug)) {
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
2742
|
+
dmCandidates.push({ slug, conversationId: row.id, mindNames: [...mindNames] });
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
if (dmCandidates.length > 0) {
|
|
2746
|
+
const candidateConvIds = dmCandidates.map((d) => d.conversationId);
|
|
2747
|
+
const allMindNames = [...new Set(dmCandidates.flatMap((d) => d.mindNames))];
|
|
2748
|
+
const verifyRows = await db.select({
|
|
2749
|
+
conversation_id: conversationParticipants.conversation_id,
|
|
2750
|
+
username: users.username
|
|
2751
|
+
}).from(conversationParticipants).innerJoin(users, eq4(conversationParticipants.user_id, users.id)).where(
|
|
2752
|
+
and3(
|
|
2753
|
+
inArray(conversationParticipants.conversation_id, candidateConvIds),
|
|
2754
|
+
inArray(users.username, allMindNames)
|
|
2755
|
+
)
|
|
2756
|
+
);
|
|
2757
|
+
const verifiedConvs = new Set(verifyRows.map((r) => r.conversation_id));
|
|
2758
|
+
for (const candidate of dmCandidates) {
|
|
2759
|
+
if (verifiedConvs.has(candidate.conversationId)) {
|
|
2760
|
+
channelIdMap.set(candidate.slug, candidate.conversationId);
|
|
2761
|
+
}
|
|
3379
2762
|
}
|
|
3380
2763
|
}
|
|
3381
2764
|
}
|
|
@@ -3447,7 +2830,7 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3447
2830
|
const stream = new ReadableStream({
|
|
3448
2831
|
start(controller) {
|
|
3449
2832
|
const encoder = new TextEncoder();
|
|
3450
|
-
const
|
|
2833
|
+
const send = (data) => {
|
|
3451
2834
|
controller.enqueue(encoder.encode(`data: ${data}
|
|
3452
2835
|
|
|
3453
2836
|
`));
|
|
@@ -3464,7 +2847,7 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3464
2847
|
if (mindFilter) {
|
|
3465
2848
|
unsubscribe = subscribe3(mindFilter, (event) => {
|
|
3466
2849
|
try {
|
|
3467
|
-
|
|
2850
|
+
send(JSON.stringify(event));
|
|
3468
2851
|
} catch {
|
|
3469
2852
|
clearInterval(pingInterval);
|
|
3470
2853
|
unsubscribe?.();
|
|
@@ -3473,7 +2856,7 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3473
2856
|
} else {
|
|
3474
2857
|
unsubscribe = subscribeAll((event) => {
|
|
3475
2858
|
try {
|
|
3476
|
-
|
|
2859
|
+
send(JSON.stringify(event));
|
|
3477
2860
|
} catch {
|
|
3478
2861
|
clearInterval(pingInterval);
|
|
3479
2862
|
unsubscribe?.();
|
|
@@ -3506,7 +2889,7 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3506
2889
|
const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 200);
|
|
3507
2890
|
if (ids) {
|
|
3508
2891
|
const db2 = await getDb();
|
|
3509
|
-
const idList = ids.split(",").map((s) => parseInt(s, 10)).filter((n) => !isNaN(n));
|
|
2892
|
+
const idList = ids.split(",").map((s) => parseInt(s, 10)).filter((n) => !Number.isNaN(n));
|
|
3510
2893
|
if (idList.length === 0) return c.json([]);
|
|
3511
2894
|
const rows2 = await db2.select().from(summaries).where(inArray(summaries.id, idList));
|
|
3512
2895
|
const result2 = rows2.map((r) => {
|
|
@@ -3550,25 +2933,58 @@ var history = new Hono11().get("/turns", async (c) => {
|
|
|
3550
2933
|
return { ...r, metadata };
|
|
3551
2934
|
});
|
|
3552
2935
|
return c.json(result);
|
|
2936
|
+
}).get("/activity", async (c) => {
|
|
2937
|
+
const mind = c.req.query("mind");
|
|
2938
|
+
const from = c.req.query("from");
|
|
2939
|
+
const to = c.req.query("to");
|
|
2940
|
+
const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "100", 10) || 100, 1), 500);
|
|
2941
|
+
const db = await getDb();
|
|
2942
|
+
const conditions = [];
|
|
2943
|
+
if (mind) conditions.push(eq4(activity.mind, mind));
|
|
2944
|
+
if (from) conditions.push(gte(activity.created_at, from));
|
|
2945
|
+
if (to) conditions.push(sql`${activity.created_at} <= ${to}`);
|
|
2946
|
+
conditions.push(
|
|
2947
|
+
sql`${activity.type} NOT IN ('mind_started', 'mind_stopped', 'mind_active', 'mind_idle', 'mind_done', 'mind_sleeping', 'mind_waking', 'brain_online', 'brain_offline')`
|
|
2948
|
+
);
|
|
2949
|
+
const rows = await db.select({
|
|
2950
|
+
id: activity.id,
|
|
2951
|
+
type: activity.type,
|
|
2952
|
+
mind: activity.mind,
|
|
2953
|
+
summary: activity.summary,
|
|
2954
|
+
metadata: activity.metadata,
|
|
2955
|
+
created_at: activity.created_at
|
|
2956
|
+
}).from(activity).where(conditions.length > 0 ? and3(...conditions) : void 0).orderBy(desc2(activity.created_at)).limit(limit);
|
|
2957
|
+
const result = rows.map((r) => {
|
|
2958
|
+
let metadata = null;
|
|
2959
|
+
if (r.metadata) {
|
|
2960
|
+
try {
|
|
2961
|
+
metadata = JSON.parse(r.metadata);
|
|
2962
|
+
} catch (err) {
|
|
2963
|
+
logger_default.debug(`malformed activity metadata for id ${r.id}`, logger_default.errorData(err));
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
return { ...r, metadata };
|
|
2967
|
+
});
|
|
2968
|
+
return c.json(result);
|
|
3553
2969
|
});
|
|
3554
2970
|
var history_default = history;
|
|
3555
2971
|
|
|
3556
2972
|
// packages/daemon/src/web/api/keys.ts
|
|
3557
2973
|
import { Hono as Hono12 } from "hono";
|
|
3558
2974
|
|
|
3559
|
-
// packages/daemon/src/lib/identity.ts
|
|
2975
|
+
// packages/daemon/src/lib/mind/identity.ts
|
|
3560
2976
|
import { createHash, generateKeyPairSync, sign, verify } from "crypto";
|
|
3561
|
-
import { existsSync as
|
|
3562
|
-
import { resolve as
|
|
2977
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
2978
|
+
import { resolve as resolve6 } from "path";
|
|
3563
2979
|
function generateIdentity(mindDir2) {
|
|
3564
|
-
const identityDir =
|
|
2980
|
+
const identityDir = resolve6(mindDir2, ".mind/identity");
|
|
3565
2981
|
mkdirSync4(identityDir, { recursive: true });
|
|
3566
2982
|
const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
|
|
3567
2983
|
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
3568
2984
|
privateKeyEncoding: { type: "pkcs8", format: "pem" }
|
|
3569
2985
|
});
|
|
3570
|
-
const privatePath =
|
|
3571
|
-
const publicPath =
|
|
2986
|
+
const privatePath = resolve6(identityDir, "private.pem");
|
|
2987
|
+
const publicPath = resolve6(identityDir, "public.pem");
|
|
3572
2988
|
writeFileSync4(privatePath, privateKey, { mode: 384 });
|
|
3573
2989
|
writeFileSync4(publicPath, publicKey, { mode: 420 });
|
|
3574
2990
|
const config2 = readVoluteConfig(mindDir2) ?? {};
|
|
@@ -3583,9 +2999,9 @@ function getPublicKey(mindDir2) {
|
|
|
3583
2999
|
const config2 = readVoluteConfig(mindDir2);
|
|
3584
3000
|
const relPath = config2?.identity?.publicKey;
|
|
3585
3001
|
if (!relPath) return null;
|
|
3586
|
-
const fullPath =
|
|
3587
|
-
if (!
|
|
3588
|
-
return
|
|
3002
|
+
const fullPath = resolve6(mindDir2, relPath);
|
|
3003
|
+
if (!existsSync4(fullPath)) return null;
|
|
3004
|
+
return readFileSync5(fullPath, "utf-8");
|
|
3589
3005
|
}
|
|
3590
3006
|
function getFingerprint(publicKeyPem) {
|
|
3591
3007
|
return createHash("sha256").update(publicKeyPem).digest("hex");
|
|
@@ -3632,16 +3048,16 @@ var keys_default = app10;
|
|
|
3632
3048
|
|
|
3633
3049
|
// packages/daemon/src/web/api/logs.ts
|
|
3634
3050
|
import { spawn as spawn2 } from "child_process";
|
|
3635
|
-
import { existsSync as
|
|
3636
|
-
import { resolve as
|
|
3051
|
+
import { existsSync as existsSync5 } from "fs";
|
|
3052
|
+
import { resolve as resolve7 } from "path";
|
|
3637
3053
|
import { Hono as Hono13 } from "hono";
|
|
3638
3054
|
import { streamSSE as streamSSE3 } from "hono/streaming";
|
|
3639
3055
|
var app11 = new Hono13().get("/:name/logs", async (c) => {
|
|
3640
3056
|
const name = c.req.param("name");
|
|
3641
3057
|
const entry = await findMind(name);
|
|
3642
3058
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3643
|
-
const logFile =
|
|
3644
|
-
if (!
|
|
3059
|
+
const logFile = resolve7(stateDir(name), "logs", "mind.log");
|
|
3060
|
+
if (!existsSync5(logFile)) {
|
|
3645
3061
|
return c.json({ error: "No log file found" }, 404);
|
|
3646
3062
|
}
|
|
3647
3063
|
return streamSSE3(c, async (stream) => {
|
|
@@ -3659,17 +3075,17 @@ var app11 = new Hono13().get("/:name/logs", async (c) => {
|
|
|
3659
3075
|
stream.onAbort(() => {
|
|
3660
3076
|
tail.kill();
|
|
3661
3077
|
});
|
|
3662
|
-
await new Promise((
|
|
3663
|
-
tail.on("exit",
|
|
3664
|
-
stream.onAbort(
|
|
3078
|
+
await new Promise((resolve17) => {
|
|
3079
|
+
tail.on("exit", resolve17);
|
|
3080
|
+
stream.onAbort(resolve17);
|
|
3665
3081
|
});
|
|
3666
3082
|
});
|
|
3667
3083
|
}).get("/:name/logs/tail", async (c) => {
|
|
3668
3084
|
const name = c.req.param("name");
|
|
3669
3085
|
const entry = await findMind(name);
|
|
3670
3086
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3671
|
-
const logFile =
|
|
3672
|
-
if (!
|
|
3087
|
+
const logFile = resolve7(stateDir(name), "logs", "mind.log");
|
|
3088
|
+
if (!existsSync5(logFile)) {
|
|
3673
3089
|
return c.json({ error: "No log file found" }, 404);
|
|
3674
3090
|
}
|
|
3675
3091
|
const nParam = parseInt(c.req.query("n") ?? "50", 10);
|
|
@@ -3679,8 +3095,8 @@ var app11 = new Hono13().get("/:name/logs", async (c) => {
|
|
|
3679
3095
|
tail.stdout.on("data", (data) => {
|
|
3680
3096
|
output += data.toString();
|
|
3681
3097
|
});
|
|
3682
|
-
await new Promise((
|
|
3683
|
-
tail.on("exit",
|
|
3098
|
+
await new Promise((resolve17) => {
|
|
3099
|
+
tail.on("exit", resolve17);
|
|
3684
3100
|
});
|
|
3685
3101
|
return c.text(output);
|
|
3686
3102
|
});
|
|
@@ -3770,33 +3186,33 @@ var mind_skills_default = app12;
|
|
|
3770
3186
|
// packages/daemon/src/web/api/minds.ts
|
|
3771
3187
|
import {
|
|
3772
3188
|
cpSync,
|
|
3773
|
-
existsSync as
|
|
3189
|
+
existsSync as existsSync7,
|
|
3774
3190
|
mkdirSync as mkdirSync6,
|
|
3775
3191
|
readdirSync as readdirSync2,
|
|
3776
|
-
readFileSync as
|
|
3192
|
+
readFileSync as readFileSync8,
|
|
3777
3193
|
rmSync as rmSync4,
|
|
3778
3194
|
writeFileSync as writeFileSync7
|
|
3779
3195
|
} from "fs";
|
|
3780
|
-
import { resolve as
|
|
3196
|
+
import { resolve as resolve10 } from "path";
|
|
3781
3197
|
import { zValidator as zValidator5 } from "@hono/zod-validator";
|
|
3782
3198
|
import { and as and4, desc as desc3, eq as eq5, sql as sql2 } from "drizzle-orm";
|
|
3783
3199
|
import { Hono as Hono15 } from "hono";
|
|
3784
3200
|
import { z as z5 } from "zod";
|
|
3785
3201
|
|
|
3786
|
-
// packages/daemon/src/lib/consolidate.ts
|
|
3787
|
-
import { readdirSync, readFileSync as
|
|
3788
|
-
import { resolve as
|
|
3202
|
+
// packages/daemon/src/lib/mind/consolidate.ts
|
|
3203
|
+
import { readdirSync, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
3204
|
+
import { resolve as resolve8 } from "path";
|
|
3789
3205
|
async function consolidateMemory(mindDir2) {
|
|
3790
|
-
const soulPath =
|
|
3791
|
-
const memoryPath =
|
|
3792
|
-
const memoryDir =
|
|
3793
|
-
const soul =
|
|
3206
|
+
const soulPath = resolve8(mindDir2, "home/SOUL.md");
|
|
3207
|
+
const memoryPath = resolve8(mindDir2, "home/MEMORY.md");
|
|
3208
|
+
const memoryDir = resolve8(mindDir2, "home/memory");
|
|
3209
|
+
const soul = readFileSync6(soulPath, "utf-8");
|
|
3794
3210
|
const logs = [];
|
|
3795
3211
|
try {
|
|
3796
3212
|
const files = readdirSync(memoryDir).filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).sort();
|
|
3797
3213
|
for (const filename of files) {
|
|
3798
3214
|
const date = filename.replace(".md", "");
|
|
3799
|
-
const content2 =
|
|
3215
|
+
const content2 = readFileSync6(resolve8(memoryDir, filename), "utf-8").trim();
|
|
3800
3216
|
if (content2) {
|
|
3801
3217
|
logs.push(`### ${date}
|
|
3802
3218
|
|
|
@@ -3854,13 +3270,71 @@ ${content2}`);
|
|
|
3854
3270
|
}
|
|
3855
3271
|
}
|
|
3856
3272
|
|
|
3857
|
-
// packages/daemon/src/lib/
|
|
3273
|
+
// packages/daemon/src/lib/mind/variant-cleanup.ts
|
|
3274
|
+
import { existsSync as existsSync6, rmSync as rmSync3 } from "fs";
|
|
3275
|
+
async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
|
|
3276
|
+
if (opts?.stop) {
|
|
3277
|
+
try {
|
|
3278
|
+
await getMindManager().stopMind(variantName);
|
|
3279
|
+
} catch (err) {
|
|
3280
|
+
logger_default.warn(`failed to stop variant ${variantName}`, logger_default.errorData(err));
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
const { findMind: findMind2 } = await import("./registry-KMELPC3X.js");
|
|
3284
|
+
const variantEntry = await findMind2(variantName);
|
|
3285
|
+
const branchName = variantEntry?.branch ?? variantName;
|
|
3286
|
+
if (existsSync6(variantPath)) {
|
|
3287
|
+
try {
|
|
3288
|
+
await gitExec(["worktree", "remove", "--force", variantPath], { cwd: projectRoot });
|
|
3289
|
+
} catch {
|
|
3290
|
+
rmSync3(variantPath, { recursive: true, force: true });
|
|
3291
|
+
try {
|
|
3292
|
+
await gitExec(["worktree", "prune"], { cwd: projectRoot });
|
|
3293
|
+
} catch (err) {
|
|
3294
|
+
logger_default.warn(`failed to prune worktrees for ${variantName}`, logger_default.errorData(err));
|
|
3295
|
+
}
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
try {
|
|
3299
|
+
await gitExec(["branch", "-D", branchName], { cwd: projectRoot });
|
|
3300
|
+
} catch (err) {
|
|
3301
|
+
logger_default.warn(`failed to delete branch ${branchName} for ${variantName}`, logger_default.errorData(err));
|
|
3302
|
+
}
|
|
3303
|
+
const baseName = variantEntry?.parent ?? variantName;
|
|
3304
|
+
try {
|
|
3305
|
+
await removeMind(variantName);
|
|
3306
|
+
} catch (err) {
|
|
3307
|
+
logger_default.warn(`failed to remove variant ${variantName} from DB`, logger_default.errorData(err));
|
|
3308
|
+
}
|
|
3309
|
+
try {
|
|
3310
|
+
chownMindDir(projectRoot, baseName);
|
|
3311
|
+
} catch (err) {
|
|
3312
|
+
logger_default.error(
|
|
3313
|
+
`failed to fix ownership during variant cleanup for ${variantName}`,
|
|
3314
|
+
logger_default.errorData(err)
|
|
3315
|
+
);
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
|
+
// packages/daemon/src/lib/mind/variants.ts
|
|
3320
|
+
var SAFE_BRANCH_RE = /^[a-zA-Z0-9._\-/]+$/;
|
|
3321
|
+
function validateBranchName(branch) {
|
|
3322
|
+
if (!SAFE_BRANCH_RE.test(branch)) {
|
|
3323
|
+
return `Invalid branch name: ${branch}. Only alphanumeric, '.', '_', '-', '/' allowed.`;
|
|
3324
|
+
}
|
|
3325
|
+
if (branch.includes("..")) {
|
|
3326
|
+
return `Invalid branch name: ${branch}. '..' not allowed.`;
|
|
3327
|
+
}
|
|
3328
|
+
return null;
|
|
3329
|
+
}
|
|
3330
|
+
|
|
3331
|
+
// packages/daemon/src/lib/template/convert-session.ts
|
|
3858
3332
|
import { randomUUID } from "crypto";
|
|
3859
|
-
import { mkdirSync as mkdirSync5, readFileSync as
|
|
3333
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
3860
3334
|
import { homedir } from "os";
|
|
3861
|
-
import { resolve as
|
|
3335
|
+
import { resolve as resolve9 } from "path";
|
|
3862
3336
|
function convertSession(opts) {
|
|
3863
|
-
const lines =
|
|
3337
|
+
const lines = readFileSync7(opts.sessionPath, "utf-8").trim().split("\n");
|
|
3864
3338
|
const sessionId = randomUUID();
|
|
3865
3339
|
const idMap = /* @__PURE__ */ new Map();
|
|
3866
3340
|
const messages = [];
|
|
@@ -3974,9 +3448,9 @@ function convertSession(opts) {
|
|
|
3974
3448
|
}
|
|
3975
3449
|
}
|
|
3976
3450
|
const projectId = opts.projectDir.replace(/\//g, "-");
|
|
3977
|
-
const sdkDir =
|
|
3451
|
+
const sdkDir = resolve9(homedir(), ".claude", "projects", projectId);
|
|
3978
3452
|
mkdirSync5(sdkDir, { recursive: true });
|
|
3979
|
-
const sdkPath =
|
|
3453
|
+
const sdkPath = resolve9(sdkDir, `${sessionId}.jsonl`);
|
|
3980
3454
|
writeFileSync6(sdkPath, `${sdkEvents.join("\n")}
|
|
3981
3455
|
`);
|
|
3982
3456
|
console.log(`Converted ${sdkEvents.length} messages \u2192 ${sdkPath}`);
|
|
@@ -4028,7 +3502,7 @@ function convertAssistantContent(content) {
|
|
|
4028
3502
|
return result;
|
|
4029
3503
|
}
|
|
4030
3504
|
|
|
4031
|
-
// packages/daemon/src/lib/health.ts
|
|
3505
|
+
// packages/daemon/src/lib/util/health.ts
|
|
4032
3506
|
async function checkHealth(port) {
|
|
4033
3507
|
try {
|
|
4034
3508
|
const res = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
@@ -4042,85 +3516,29 @@ async function checkHealth(port) {
|
|
|
4042
3516
|
}
|
|
4043
3517
|
}
|
|
4044
3518
|
|
|
4045
|
-
// packages/daemon/src/lib/variant-cleanup.ts
|
|
4046
|
-
import { existsSync as existsSync7, rmSync as rmSync3 } from "fs";
|
|
4047
|
-
async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
|
|
4048
|
-
if (opts?.stop) {
|
|
4049
|
-
try {
|
|
4050
|
-
await getMindManager().stopMind(variantName);
|
|
4051
|
-
} catch (err) {
|
|
4052
|
-
logger_default.warn(`failed to stop variant ${variantName}`, logger_default.errorData(err));
|
|
4053
|
-
}
|
|
4054
|
-
}
|
|
4055
|
-
const { findMind: findMind2 } = await import("./registry-GBSNW3HG.js");
|
|
4056
|
-
const variantEntry = await findMind2(variantName);
|
|
4057
|
-
const branchName = variantEntry?.branch ?? variantName;
|
|
4058
|
-
if (existsSync7(variantPath)) {
|
|
4059
|
-
try {
|
|
4060
|
-
await gitExec(["worktree", "remove", "--force", variantPath], { cwd: projectRoot });
|
|
4061
|
-
} catch {
|
|
4062
|
-
rmSync3(variantPath, { recursive: true, force: true });
|
|
4063
|
-
try {
|
|
4064
|
-
await gitExec(["worktree", "prune"], { cwd: projectRoot });
|
|
4065
|
-
} catch (err) {
|
|
4066
|
-
logger_default.warn(`failed to prune worktrees for ${variantName}`, logger_default.errorData(err));
|
|
4067
|
-
}
|
|
4068
|
-
}
|
|
4069
|
-
}
|
|
4070
|
-
try {
|
|
4071
|
-
await gitExec(["branch", "-D", branchName], { cwd: projectRoot });
|
|
4072
|
-
} catch (err) {
|
|
4073
|
-
logger_default.warn(`failed to delete branch ${branchName} for ${variantName}`, logger_default.errorData(err));
|
|
4074
|
-
}
|
|
4075
|
-
const baseName = variantEntry?.parent ?? variantName;
|
|
4076
|
-
try {
|
|
4077
|
-
await removeMind(variantName);
|
|
4078
|
-
} catch (err) {
|
|
4079
|
-
logger_default.warn(`failed to remove variant ${variantName} from DB`, logger_default.errorData(err));
|
|
4080
|
-
}
|
|
4081
|
-
try {
|
|
4082
|
-
chownMindDir(projectRoot, baseName);
|
|
4083
|
-
} catch (err) {
|
|
4084
|
-
logger_default.error(
|
|
4085
|
-
`failed to fix ownership during variant cleanup for ${variantName}`,
|
|
4086
|
-
logger_default.errorData(err)
|
|
4087
|
-
);
|
|
4088
|
-
}
|
|
4089
|
-
}
|
|
4090
|
-
|
|
4091
|
-
// packages/daemon/src/lib/variants.ts
|
|
4092
|
-
var SAFE_BRANCH_RE = /^[a-zA-Z0-9._\-/]+$/;
|
|
4093
|
-
function validateBranchName(branch) {
|
|
4094
|
-
if (!SAFE_BRANCH_RE.test(branch)) {
|
|
4095
|
-
return `Invalid branch name: ${branch}. Only alphanumeric, '.', '_', '-', '/' allowed.`;
|
|
4096
|
-
}
|
|
4097
|
-
if (branch.includes("..")) {
|
|
4098
|
-
return `Invalid branch name: ${branch}. '..' not allowed.`;
|
|
4099
|
-
}
|
|
4100
|
-
return null;
|
|
4101
|
-
}
|
|
4102
|
-
|
|
4103
3519
|
// packages/daemon/src/web/api/minds.ts
|
|
4104
3520
|
var SUBSTANTIVE_TYPES = /* @__PURE__ */ new Set(["thinking", "text", "tool_use", "tool_result", "outbound"]);
|
|
4105
|
-
|
|
3521
|
+
var _lastActiveCache = { map: /* @__PURE__ */ new Map(), ts: 0 };
|
|
3522
|
+
var _LAST_ACTIVE_TTL = 6e4;
|
|
3523
|
+
async function getMindStatus(name, port, registryRunning) {
|
|
4106
3524
|
const manager = getMindManager();
|
|
4107
3525
|
let status = "stopped";
|
|
4108
3526
|
try {
|
|
4109
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
3527
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TQP5ZJI5.js");
|
|
4110
3528
|
if (getSleepManagerIfReady2()?.isSleeping(name)) {
|
|
4111
3529
|
status = "sleeping";
|
|
4112
3530
|
}
|
|
4113
3531
|
} catch {
|
|
4114
3532
|
}
|
|
4115
|
-
if (status !== "sleeping" && manager.isRunning(name)) {
|
|
3533
|
+
if (status !== "sleeping" && registryRunning !== false && manager.isRunning(name)) {
|
|
4116
3534
|
const health = await checkHealth(port);
|
|
4117
3535
|
status = health.ok ? "running" : "starting";
|
|
4118
3536
|
}
|
|
4119
3537
|
const config2 = readVoluteConfig(mindDir(name));
|
|
4120
|
-
const
|
|
4121
|
-
for (const [, provider] of Object.entries(
|
|
3538
|
+
const channels2 = [];
|
|
3539
|
+
for (const [, provider] of Object.entries(PLATFORMS)) {
|
|
4122
3540
|
if (!provider.builtIn) continue;
|
|
4123
|
-
|
|
3541
|
+
channels2.push({
|
|
4124
3542
|
name: provider.name,
|
|
4125
3543
|
displayName: provider.displayName,
|
|
4126
3544
|
status: status === "running" ? "connected" : "disconnected"
|
|
@@ -4128,7 +3546,7 @@ async function getMindStatus(name, port) {
|
|
|
4128
3546
|
}
|
|
4129
3547
|
return {
|
|
4130
3548
|
status,
|
|
4131
|
-
channels,
|
|
3549
|
+
channels: channels2,
|
|
4132
3550
|
displayName: config2?.profile?.displayName,
|
|
4133
3551
|
description: config2?.profile?.description,
|
|
4134
3552
|
avatar: config2?.profile?.avatar
|
|
@@ -4152,7 +3570,7 @@ async function initTemplateBranch(projectRoot, composedDir, manifest, mindName,
|
|
|
4152
3570
|
await gitExec(["commit", "-m", "initial commit"], opts);
|
|
4153
3571
|
}
|
|
4154
3572
|
async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
4155
|
-
const tempWorktree =
|
|
3573
|
+
const tempWorktree = resolve10(projectRoot, ".variants", "_template_update");
|
|
4156
3574
|
let branchExists = false;
|
|
4157
3575
|
try {
|
|
4158
3576
|
await gitExec(["rev-parse", "--verify", TEMPLATE_BRANCH], { cwd: projectRoot });
|
|
@@ -4163,7 +3581,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4163
3581
|
await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
|
|
4164
3582
|
} catch {
|
|
4165
3583
|
}
|
|
4166
|
-
if (
|
|
3584
|
+
if (existsSync7(tempWorktree)) {
|
|
4167
3585
|
rmSync4(tempWorktree, { recursive: true, force: true });
|
|
4168
3586
|
}
|
|
4169
3587
|
const templatesRoot = findTemplatesRoot();
|
|
@@ -4184,15 +3602,15 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4184
3602
|
});
|
|
4185
3603
|
}
|
|
4186
3604
|
copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
|
|
4187
|
-
const initDir =
|
|
4188
|
-
if (
|
|
3605
|
+
const initDir = resolve10(tempWorktree, ".init");
|
|
3606
|
+
if (existsSync7(initDir)) {
|
|
4189
3607
|
rmSync4(initDir, { recursive: true, force: true });
|
|
4190
3608
|
}
|
|
4191
|
-
const homeDir =
|
|
4192
|
-
if (
|
|
3609
|
+
const homeDir = resolve10(tempWorktree, "home");
|
|
3610
|
+
if (existsSync7(homeDir)) {
|
|
4193
3611
|
for (const entry of readdirSync2(homeDir)) {
|
|
4194
3612
|
if (entry !== "VOLUTE.md") {
|
|
4195
|
-
rmSync4(
|
|
3613
|
+
rmSync4(resolve10(homeDir, entry), { recursive: true, force: true });
|
|
4196
3614
|
}
|
|
4197
3615
|
}
|
|
4198
3616
|
}
|
|
@@ -4207,7 +3625,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4207
3625
|
await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
|
|
4208
3626
|
} catch {
|
|
4209
3627
|
}
|
|
4210
|
-
if (
|
|
3628
|
+
if (existsSync7(tempWorktree)) {
|
|
4211
3629
|
rmSync4(tempWorktree, { recursive: true, force: true });
|
|
4212
3630
|
}
|
|
4213
3631
|
rmSync4(composedDir, { recursive: true, force: true });
|
|
@@ -4233,7 +3651,7 @@ async function mergeTemplateBranch(worktreeDir) {
|
|
|
4233
3651
|
async function npmInstallAsMind(cwd, mindName) {
|
|
4234
3652
|
if (isIsolationEnabled()) {
|
|
4235
3653
|
const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
|
|
4236
|
-
await exec(cmd, args, { cwd, env: { ...process.env, HOME:
|
|
3654
|
+
await exec(cmd, args, { cwd, env: { ...process.env, HOME: resolve10(cwd, "home") } });
|
|
4237
3655
|
} else {
|
|
4238
3656
|
await exec("npm", ["install"], { cwd });
|
|
4239
3657
|
}
|
|
@@ -4284,8 +3702,8 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
|
|
|
4284
3702
|
return { ok: true };
|
|
4285
3703
|
}
|
|
4286
3704
|
async function importFromArchive(c, tempDir, nameOverride, manifest) {
|
|
4287
|
-
const extractedMindDir =
|
|
4288
|
-
if (!
|
|
3705
|
+
const extractedMindDir = resolve10(tempDir, "mind");
|
|
3706
|
+
if (!existsSync7(extractedMindDir)) {
|
|
4289
3707
|
return c.json({ error: "Invalid archive: missing mind/ directory" }, 400);
|
|
4290
3708
|
}
|
|
4291
3709
|
if (!manifest?.includes || !manifest.name || !manifest.template) {
|
|
@@ -4303,7 +3721,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4303
3721
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
4304
3722
|
ensureVoluteHome();
|
|
4305
3723
|
const dest = mindDir(name);
|
|
4306
|
-
if (
|
|
3724
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4307
3725
|
try {
|
|
4308
3726
|
cpSync(extractedMindDir, dest, { recursive: true });
|
|
4309
3727
|
if (!manifest.includes.identity) {
|
|
@@ -4311,9 +3729,9 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4311
3729
|
}
|
|
4312
3730
|
const state = stateDir(name);
|
|
4313
3731
|
mkdirSync6(state, { recursive: true });
|
|
4314
|
-
const envJson =
|
|
4315
|
-
if (
|
|
4316
|
-
cpSync(envJson,
|
|
3732
|
+
const envJson = resolve10(tempDir, "state/env.json");
|
|
3733
|
+
if (existsSync7(envJson)) {
|
|
3734
|
+
cpSync(envJson, resolve10(state, "env.json"));
|
|
4317
3735
|
}
|
|
4318
3736
|
const port = await nextPort();
|
|
4319
3737
|
await addMind(name, port, manifest.stage, manifest.template);
|
|
@@ -4322,30 +3740,30 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4322
3740
|
} catch (err) {
|
|
4323
3741
|
logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
|
|
4324
3742
|
}
|
|
4325
|
-
const homeDir =
|
|
3743
|
+
const homeDir = resolve10(dest, "home");
|
|
4326
3744
|
ensureVoluteGroup();
|
|
4327
3745
|
createMindUser(name, homeDir);
|
|
4328
3746
|
chownMindDir(dest, name);
|
|
4329
3747
|
await npmInstallAsMind(dest, name);
|
|
4330
3748
|
await importHistoryFromArchive(name, tempDir);
|
|
4331
3749
|
importSessionsFromArchive(dest, tempDir);
|
|
4332
|
-
if (!
|
|
3750
|
+
if (!existsSync7(resolve10(dest, ".git"))) {
|
|
4333
3751
|
try {
|
|
4334
|
-
const env = isIsolationEnabled() ? { ...process.env, HOME:
|
|
3752
|
+
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dest, "home") } : void 0;
|
|
4335
3753
|
await gitExec(["init"], { cwd: dest, mindName: name, env });
|
|
4336
3754
|
await configureGitIdentity(name, { cwd: dest, mindName: name, env });
|
|
4337
3755
|
await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
|
|
4338
3756
|
await gitExec(["commit", "-m", "import from archive"], { cwd: dest, mindName: name, env });
|
|
4339
3757
|
} catch (err) {
|
|
4340
3758
|
logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
|
|
4341
|
-
rmSync4(
|
|
3759
|
+
rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
|
|
4342
3760
|
}
|
|
4343
3761
|
}
|
|
4344
3762
|
chownMindDir(dest, name);
|
|
4345
3763
|
rmSync4(tempDir, { recursive: true, force: true });
|
|
4346
3764
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
4347
3765
|
} catch (err) {
|
|
4348
|
-
if (
|
|
3766
|
+
if (existsSync7(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4349
3767
|
try {
|
|
4350
3768
|
await removeMind(name);
|
|
4351
3769
|
} catch (cleanupErr) {
|
|
@@ -4362,7 +3780,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4362
3780
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
4363
3781
|
ensureVoluteHome();
|
|
4364
3782
|
const dest = mindDir(name);
|
|
4365
|
-
if (
|
|
3783
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4366
3784
|
const templatesRoot = findTemplatesRoot();
|
|
4367
3785
|
const { composedDir, manifest: templateManifest } = composeTemplate(
|
|
4368
3786
|
templatesRoot,
|
|
@@ -4371,36 +3789,36 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4371
3789
|
try {
|
|
4372
3790
|
copyTemplateToDir(composedDir, dest, name, templateManifest);
|
|
4373
3791
|
applyInitFiles(dest);
|
|
4374
|
-
const extractedHome =
|
|
4375
|
-
if (
|
|
4376
|
-
cpSync(extractedHome,
|
|
3792
|
+
const extractedHome = resolve10(extractedMindDir, "home");
|
|
3793
|
+
if (existsSync7(extractedHome)) {
|
|
3794
|
+
cpSync(extractedHome, resolve10(dest, "home"), { recursive: true });
|
|
4377
3795
|
}
|
|
4378
|
-
const extractedMindInternal =
|
|
4379
|
-
if (
|
|
4380
|
-
cpSync(extractedMindInternal,
|
|
3796
|
+
const extractedMindInternal = resolve10(extractedMindDir, ".mind");
|
|
3797
|
+
if (existsSync7(extractedMindInternal)) {
|
|
3798
|
+
cpSync(extractedMindInternal, resolve10(dest, ".mind"), { recursive: true });
|
|
4381
3799
|
}
|
|
4382
|
-
const identityDir =
|
|
3800
|
+
const identityDir = resolve10(dest, ".mind/identity");
|
|
4383
3801
|
let publicKeyPem;
|
|
4384
|
-
if (!manifest.includes.identity || !
|
|
3802
|
+
if (!manifest.includes.identity || !existsSync7(resolve10(identityDir, "private.pem"))) {
|
|
4385
3803
|
({ publicKeyPem } = generateIdentity(dest));
|
|
4386
3804
|
} else {
|
|
4387
|
-
publicKeyPem =
|
|
3805
|
+
publicKeyPem = readFileSync8(resolve10(identityDir, "public.pem"), "utf-8");
|
|
4388
3806
|
}
|
|
4389
|
-
const promptsPath =
|
|
4390
|
-
if (!
|
|
3807
|
+
const promptsPath = resolve10(dest, "home/.config/prompts.json");
|
|
3808
|
+
if (!existsSync7(promptsPath)) {
|
|
4391
3809
|
const mindPrompts = await getMindPromptDefaults();
|
|
4392
3810
|
writeFileSync7(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
|
|
4393
3811
|
`);
|
|
4394
3812
|
}
|
|
4395
3813
|
const state = stateDir(name);
|
|
4396
3814
|
mkdirSync6(state, { recursive: true });
|
|
4397
|
-
const envJson =
|
|
4398
|
-
if (
|
|
4399
|
-
cpSync(envJson,
|
|
3815
|
+
const envJson = resolve10(tempDir, "state/env.json");
|
|
3816
|
+
if (existsSync7(envJson)) {
|
|
3817
|
+
cpSync(envJson, resolve10(state, "env.json"));
|
|
4400
3818
|
}
|
|
4401
3819
|
const port = await nextPort();
|
|
4402
3820
|
await addMind(name, port, manifest.stage, manifest.template);
|
|
4403
|
-
const homeDir =
|
|
3821
|
+
const homeDir = resolve10(dest, "home");
|
|
4404
3822
|
ensureVoluteGroup();
|
|
4405
3823
|
createMindUser(name, homeDir);
|
|
4406
3824
|
chownMindDir(dest, name);
|
|
@@ -4413,7 +3831,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4413
3831
|
await initTemplateBranch(dest, composedDir, templateManifest, name, env);
|
|
4414
3832
|
} catch (err) {
|
|
4415
3833
|
logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
|
|
4416
|
-
rmSync4(
|
|
3834
|
+
rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
|
|
4417
3835
|
gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
|
|
4418
3836
|
}
|
|
4419
3837
|
const skillSet = manifest.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions();
|
|
@@ -4443,7 +3861,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4443
3861
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
4444
3862
|
});
|
|
4445
3863
|
} catch (err) {
|
|
4446
|
-
if (
|
|
3864
|
+
if (existsSync7(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4447
3865
|
try {
|
|
4448
3866
|
await removeMind(name);
|
|
4449
3867
|
} catch (cleanupErr) {
|
|
@@ -4456,11 +3874,11 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4456
3874
|
}
|
|
4457
3875
|
}
|
|
4458
3876
|
async function importHistoryFromArchive(name, tempDir) {
|
|
4459
|
-
const historyJsonl =
|
|
4460
|
-
if (!
|
|
3877
|
+
const historyJsonl = resolve10(tempDir, "history.jsonl");
|
|
3878
|
+
if (!existsSync7(historyJsonl)) return;
|
|
4461
3879
|
try {
|
|
4462
3880
|
const db = await getDb();
|
|
4463
|
-
const lines =
|
|
3881
|
+
const lines = readFileSync8(historyJsonl, "utf-8").trim().split("\n");
|
|
4464
3882
|
let imported = 0;
|
|
4465
3883
|
let failed = 0;
|
|
4466
3884
|
for (const line of lines) {
|
|
@@ -4496,13 +3914,13 @@ async function importHistoryFromArchive(name, tempDir) {
|
|
|
4496
3914
|
}
|
|
4497
3915
|
}
|
|
4498
3916
|
function importSessionsFromArchive(dest, tempDir) {
|
|
4499
|
-
const sessionsDir =
|
|
4500
|
-
if (!
|
|
3917
|
+
const sessionsDir = resolve10(tempDir, "sessions");
|
|
3918
|
+
if (!existsSync7(sessionsDir)) return;
|
|
4501
3919
|
try {
|
|
4502
|
-
const destSessions =
|
|
3920
|
+
const destSessions = resolve10(dest, ".mind/sessions");
|
|
4503
3921
|
mkdirSync6(destSessions, { recursive: true });
|
|
4504
3922
|
for (const file of readdirSync2(sessionsDir)) {
|
|
4505
|
-
cpSync(
|
|
3923
|
+
cpSync(resolve10(sessionsDir, file), resolve10(destSessions, file));
|
|
4506
3924
|
}
|
|
4507
3925
|
} catch (err) {
|
|
4508
3926
|
logger_default.error("Failed to import sessions from archive", logger_default.errorData(err));
|
|
@@ -4537,7 +3955,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
|
|
|
4537
3955
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
4538
3956
|
ensureVoluteHome();
|
|
4539
3957
|
const dest = mindDir(name);
|
|
4540
|
-
if (
|
|
3958
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4541
3959
|
const templatesRoot = findTemplatesRoot();
|
|
4542
3960
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
4543
3961
|
try {
|
|
@@ -4545,7 +3963,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
|
|
|
4545
3963
|
applyInitFiles(dest);
|
|
4546
3964
|
const { publicKeyPem } = generateIdentity(dest);
|
|
4547
3965
|
{
|
|
4548
|
-
const { readGlobalConfig: readGlobal } = await import("./setup-
|
|
3966
|
+
const { readGlobalConfig: readGlobal } = await import("./setup-PF7JSFMO.js");
|
|
4549
3967
|
const mindDefaults = readGlobal().mindDefaults;
|
|
4550
3968
|
const config2 = readVoluteConfig(dest);
|
|
4551
3969
|
if (!config2) throw new Error("Failed to read volute.json after identity generation");
|
|
@@ -4582,9 +4000,9 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
|
|
|
4582
4000
|
}
|
|
4583
4001
|
writeVoluteConfig(dest, config2);
|
|
4584
4002
|
const modelId = body.model ?? cog?.model;
|
|
4585
|
-
const sdkConfigPath =
|
|
4003
|
+
const sdkConfigPath = resolve10(dest, "home/.config/config.json");
|
|
4586
4004
|
if (modelId || cog?.compaction) {
|
|
4587
|
-
const existing =
|
|
4005
|
+
const existing = existsSync7(sdkConfigPath) ? JSON.parse(readFileSync8(sdkConfigPath, "utf-8")) : {};
|
|
4588
4006
|
if (modelId) {
|
|
4589
4007
|
existing.model = template === "pi" ? qualifyModelId(modelId) : unqualifyModelId(modelId);
|
|
4590
4008
|
}
|
|
@@ -4597,7 +4015,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
|
|
|
4597
4015
|
}
|
|
4598
4016
|
const mindPrompts = await getMindPromptDefaults();
|
|
4599
4017
|
writeFileSync7(
|
|
4600
|
-
|
|
4018
|
+
resolve10(dest, "home/.config/prompts.json"),
|
|
4601
4019
|
`${JSON.stringify(mindPrompts, null, 2)}
|
|
4602
4020
|
`
|
|
4603
4021
|
);
|
|
@@ -4609,7 +4027,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
|
|
|
4609
4027
|
} catch (err) {
|
|
4610
4028
|
logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
|
|
4611
4029
|
}
|
|
4612
|
-
const homeDir =
|
|
4030
|
+
const homeDir = resolve10(dest, "home");
|
|
4613
4031
|
ensureVoluteGroup();
|
|
4614
4032
|
createMindUser(name, homeDir);
|
|
4615
4033
|
chownMindDir(dest, name);
|
|
@@ -4622,7 +4040,7 @@ var app13 = new Hono15().post("/", requireAdminOrSystem, zValidator5("json", cre
|
|
|
4622
4040
|
await initTemplateBranch(dest, composedDir, manifest, name, env);
|
|
4623
4041
|
} catch (err) {
|
|
4624
4042
|
logger_default.error(`git setup failed for ${name}`, logger_default.errorData(err));
|
|
4625
|
-
rmSync4(
|
|
4043
|
+
rmSync4(resolve10(dest, ".git"), { recursive: true, force: true });
|
|
4626
4044
|
gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
|
|
4627
4045
|
}
|
|
4628
4046
|
chownMindDir(dest, name);
|
|
@@ -4632,11 +4050,11 @@ The human who planted you described you as: "${body.description}"
|
|
|
4632
4050
|
` : "";
|
|
4633
4051
|
const seedSoulRaw = body.seedSoul ?? await getPrompt("seed_soul", { name, description: descLine });
|
|
4634
4052
|
const seedSoul = body.seedSoul ? substitute(seedSoulRaw, { name, description: descLine }) : seedSoulRaw;
|
|
4635
|
-
writeFileSync7(
|
|
4053
|
+
writeFileSync7(resolve10(dest, "home/SOUL.md"), seedSoul);
|
|
4636
4054
|
}
|
|
4637
4055
|
let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
|
|
4638
4056
|
if (body.stage === "seed" && !body.skills) {
|
|
4639
|
-
const { isImagegenEnabled } = await import("./setup-
|
|
4057
|
+
const { isImagegenEnabled } = await import("./setup-PF7JSFMO.js");
|
|
4640
4058
|
if (isImagegenEnabled()) {
|
|
4641
4059
|
skillSet = [...skillSet, "imagegen"];
|
|
4642
4060
|
}
|
|
@@ -4654,7 +4072,7 @@ The human who planted you described you as: "${body.description}"
|
|
|
4654
4072
|
try {
|
|
4655
4073
|
const spiritEntry = await findMind("volute");
|
|
4656
4074
|
if (spiritEntry) {
|
|
4657
|
-
const { spiritDir } = await import("./spirit-
|
|
4075
|
+
const { spiritDir } = await import("./spirit-SM6ARJ2N.js");
|
|
4658
4076
|
const sDir = spiritEntry.dir ?? spiritDir();
|
|
4659
4077
|
const spiritConfig = readVoluteConfig(sDir) ?? {};
|
|
4660
4078
|
const schedules = spiritConfig.schedules ?? [];
|
|
@@ -4669,7 +4087,7 @@ The human who planted you described you as: "${body.description}"
|
|
|
4669
4087
|
});
|
|
4670
4088
|
spiritConfig.schedules = schedules;
|
|
4671
4089
|
writeVoluteConfig(sDir, spiritConfig);
|
|
4672
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
4090
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-NTC74JYH.js");
|
|
4673
4091
|
getScheduler2().loadSchedules("volute", sDir);
|
|
4674
4092
|
}
|
|
4675
4093
|
}
|
|
@@ -4680,11 +4098,11 @@ The human who planted you described you as: "${body.description}"
|
|
|
4680
4098
|
if (body.stage !== "seed") {
|
|
4681
4099
|
const customSoul = await getPromptIfCustom("default_soul");
|
|
4682
4100
|
if (customSoul) {
|
|
4683
|
-
writeFileSync7(
|
|
4101
|
+
writeFileSync7(resolve10(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
|
|
4684
4102
|
}
|
|
4685
4103
|
const customMemory = await getPromptIfCustom("default_memory");
|
|
4686
4104
|
if (customMemory) {
|
|
4687
|
-
writeFileSync7(
|
|
4105
|
+
writeFileSync7(resolve10(dest, "home/MEMORY.md"), customMemory);
|
|
4688
4106
|
}
|
|
4689
4107
|
}
|
|
4690
4108
|
publishPublicKey(name, publicKeyPem).catch(
|
|
@@ -4713,7 +4131,7 @@ The human who planted you described you as: "${body.description}"
|
|
|
4713
4131
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
4714
4132
|
});
|
|
4715
4133
|
} catch (err) {
|
|
4716
|
-
if (
|
|
4134
|
+
if (existsSync7(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4717
4135
|
try {
|
|
4718
4136
|
await removeMind(name);
|
|
4719
4137
|
} catch {
|
|
@@ -4733,13 +4151,13 @@ The human who planted you described you as: "${body.description}"
|
|
|
4733
4151
|
return importFromArchive(c, body.archivePath, body.name, body.manifest);
|
|
4734
4152
|
}
|
|
4735
4153
|
const wsDir = body.workspacePath;
|
|
4736
|
-
if (!wsDir || !
|
|
4154
|
+
if (!wsDir || !existsSync7(resolve10(wsDir, "SOUL.md")) || !existsSync7(resolve10(wsDir, "IDENTITY.md"))) {
|
|
4737
4155
|
return c.json({ error: "Invalid workspace: missing SOUL.md or IDENTITY.md" }, 400);
|
|
4738
4156
|
}
|
|
4739
|
-
const soul =
|
|
4740
|
-
const identity =
|
|
4741
|
-
const userPath =
|
|
4742
|
-
const user =
|
|
4157
|
+
const soul = readFileSync8(resolve10(wsDir, "SOUL.md"), "utf-8");
|
|
4158
|
+
const identity = readFileSync8(resolve10(wsDir, "IDENTITY.md"), "utf-8");
|
|
4159
|
+
const userPath = resolve10(wsDir, "USER.md");
|
|
4160
|
+
const user = existsSync7(userPath) ? readFileSync8(userPath, "utf-8") : "";
|
|
4743
4161
|
const name = body.name ?? parseNameFromIdentity(identity) ?? "imported-mind";
|
|
4744
4162
|
const template = body.template ?? "claude";
|
|
4745
4163
|
const nameErr = validateMindName(name);
|
|
@@ -4759,33 +4177,33 @@ ${user.trimEnd()}
|
|
|
4759
4177
|
` : "";
|
|
4760
4178
|
ensureVoluteHome();
|
|
4761
4179
|
const dest = mindDir(name);
|
|
4762
|
-
if (
|
|
4180
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4763
4181
|
const templatesRoot = findTemplatesRoot();
|
|
4764
4182
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
4765
4183
|
try {
|
|
4766
4184
|
copyTemplateToDir(composedDir, dest, name, manifest);
|
|
4767
4185
|
applyInitFiles(dest);
|
|
4768
4186
|
const { publicKeyPem: importPublicKey } = generateIdentity(dest);
|
|
4769
|
-
writeFileSync7(
|
|
4770
|
-
const wsMemoryPath =
|
|
4771
|
-
const hasMemory =
|
|
4187
|
+
writeFileSync7(resolve10(dest, "home/SOUL.md"), mergedSoul);
|
|
4188
|
+
const wsMemoryPath = resolve10(wsDir, "MEMORY.md");
|
|
4189
|
+
const hasMemory = existsSync7(wsMemoryPath);
|
|
4772
4190
|
if (hasMemory) {
|
|
4773
|
-
const existingMemory =
|
|
4191
|
+
const existingMemory = readFileSync8(wsMemoryPath, "utf-8");
|
|
4774
4192
|
writeFileSync7(
|
|
4775
|
-
|
|
4193
|
+
resolve10(dest, "home/MEMORY.md"),
|
|
4776
4194
|
`${existingMemory.trimEnd()}${mergedMemoryExtra}`
|
|
4777
4195
|
);
|
|
4778
4196
|
} else if (user) {
|
|
4779
|
-
writeFileSync7(
|
|
4197
|
+
writeFileSync7(resolve10(dest, "home/MEMORY.md"), `${user.trimEnd()}
|
|
4780
4198
|
`);
|
|
4781
4199
|
}
|
|
4782
|
-
const wsMemoryDir =
|
|
4200
|
+
const wsMemoryDir = resolve10(wsDir, "memory");
|
|
4783
4201
|
let dailyLogCount = 0;
|
|
4784
|
-
if (
|
|
4785
|
-
const destMemoryDir =
|
|
4202
|
+
if (existsSync7(wsMemoryDir)) {
|
|
4203
|
+
const destMemoryDir = resolve10(dest, "home/memory");
|
|
4786
4204
|
const files = readdirSync2(wsMemoryDir).filter((f) => f.endsWith(".md"));
|
|
4787
4205
|
for (const file of files) {
|
|
4788
|
-
cpSync(
|
|
4206
|
+
cpSync(resolve10(wsMemoryDir, file), resolve10(destMemoryDir, file));
|
|
4789
4207
|
}
|
|
4790
4208
|
dailyLogCount = files.length;
|
|
4791
4209
|
}
|
|
@@ -4796,7 +4214,7 @@ ${user.trimEnd()}
|
|
|
4796
4214
|
} catch (err) {
|
|
4797
4215
|
logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
|
|
4798
4216
|
}
|
|
4799
|
-
const homeDir =
|
|
4217
|
+
const homeDir = resolve10(dest, "home");
|
|
4800
4218
|
ensureVoluteGroup();
|
|
4801
4219
|
createMindUser(name, homeDir);
|
|
4802
4220
|
chownMindDir(dest, name);
|
|
@@ -4804,20 +4222,20 @@ ${user.trimEnd()}
|
|
|
4804
4222
|
if (!hasMemory && dailyLogCount > 0) {
|
|
4805
4223
|
await consolidateMemory(dest);
|
|
4806
4224
|
}
|
|
4807
|
-
const env = isIsolationEnabled() ? { ...process.env, HOME:
|
|
4225
|
+
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dest, "home") } : void 0;
|
|
4808
4226
|
await gitExec(["init"], { cwd: dest, mindName: name, env });
|
|
4809
4227
|
await configureGitIdentity(name, { cwd: dest, mindName: name, env });
|
|
4810
4228
|
await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
|
|
4811
4229
|
await gitExec(["commit", "-m", "import from OpenClaw"], { cwd: dest, mindName: name, env });
|
|
4812
|
-
const sessionFile = body.sessionPath ?
|
|
4813
|
-
if (sessionFile &&
|
|
4230
|
+
const sessionFile = body.sessionPath ? resolve10(body.sessionPath) : findOpenClawSession(wsDir);
|
|
4231
|
+
if (sessionFile && existsSync7(sessionFile)) {
|
|
4814
4232
|
if (template === "pi") {
|
|
4815
4233
|
importPiSession(sessionFile, dest);
|
|
4816
4234
|
} else if (template === "claude") {
|
|
4817
4235
|
const sessionId = convertSession({ sessionPath: sessionFile, projectDir: dest });
|
|
4818
|
-
const mindRuntimeDir =
|
|
4236
|
+
const mindRuntimeDir = resolve10(dest, ".mind");
|
|
4819
4237
|
mkdirSync6(mindRuntimeDir, { recursive: true });
|
|
4820
|
-
writeFileSync7(
|
|
4238
|
+
writeFileSync7(resolve10(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
|
|
4821
4239
|
}
|
|
4822
4240
|
}
|
|
4823
4241
|
importOpenClawConnectors(name, dest);
|
|
@@ -4827,7 +4245,7 @@ ${user.trimEnd()}
|
|
|
4827
4245
|
);
|
|
4828
4246
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
4829
4247
|
} catch (err) {
|
|
4830
|
-
if (
|
|
4248
|
+
if (existsSync7(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4831
4249
|
try {
|
|
4832
4250
|
await removeMind(name);
|
|
4833
4251
|
} catch {
|
|
@@ -4838,20 +4256,27 @@ ${user.trimEnd()}
|
|
|
4838
4256
|
}
|
|
4839
4257
|
}).get("/", async (c) => {
|
|
4840
4258
|
const entries = await readRegistry();
|
|
4841
|
-
let lastActiveMap
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4259
|
+
let lastActiveMap;
|
|
4260
|
+
if (_lastActiveCache.ts > 0 && Date.now() - _lastActiveCache.ts < _LAST_ACTIVE_TTL) {
|
|
4261
|
+
lastActiveMap = _lastActiveCache.map;
|
|
4262
|
+
} else {
|
|
4263
|
+
lastActiveMap = /* @__PURE__ */ new Map();
|
|
4264
|
+
try {
|
|
4265
|
+
const db = await getDb();
|
|
4266
|
+
const lastActiveRows = await db.select({
|
|
4267
|
+
mind: mindHistory.mind,
|
|
4268
|
+
lastActiveAt: sql2`MAX(${mindHistory.created_at})`
|
|
4269
|
+
}).from(mindHistory).groupBy(mindHistory.mind);
|
|
4270
|
+
lastActiveMap = new Map(lastActiveRows.map((r) => [r.mind, r.lastActiveAt]));
|
|
4271
|
+
_lastActiveCache.map = lastActiveMap;
|
|
4272
|
+
_lastActiveCache.ts = Date.now();
|
|
4273
|
+
} catch {
|
|
4274
|
+
}
|
|
4850
4275
|
}
|
|
4851
4276
|
const minds = await Promise.all(
|
|
4852
4277
|
entries.map(async (entry) => {
|
|
4853
|
-
const mindStatus = await getMindStatus(entry.name, entry.port);
|
|
4854
|
-
const hasPages =
|
|
4278
|
+
const mindStatus = await getMindStatus(entry.name, entry.port, entry.running);
|
|
4279
|
+
const hasPages = existsSync7(resolve10(mindDir(entry.name), "home", "pages"));
|
|
4855
4280
|
return {
|
|
4856
4281
|
...entry,
|
|
4857
4282
|
...mindStatus,
|
|
@@ -4866,7 +4291,7 @@ ${user.trimEnd()}
|
|
|
4866
4291
|
const entry = await findMind(name);
|
|
4867
4292
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4868
4293
|
const dir = entry.dir ?? mindDir(entry.parent ?? name);
|
|
4869
|
-
if (!
|
|
4294
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4870
4295
|
const mindStatus = await getMindStatus(name, entry.port);
|
|
4871
4296
|
const variants = await findVariants(name);
|
|
4872
4297
|
const manager = getMindManager();
|
|
@@ -4880,7 +4305,7 @@ ${user.trimEnd()}
|
|
|
4880
4305
|
return { name: s.name, port: s.port, status: variantStatus };
|
|
4881
4306
|
})
|
|
4882
4307
|
);
|
|
4883
|
-
const hasPages =
|
|
4308
|
+
const hasPages = existsSync7(resolve10(mindDir(name), "home", "pages"));
|
|
4884
4309
|
return c.json({ ...entry, ...mindStatus, variants: variantStatuses, hasPages });
|
|
4885
4310
|
}).get("/:name/context", async (c) => {
|
|
4886
4311
|
const name = c.req.param("name");
|
|
@@ -4917,7 +4342,7 @@ ${user.trimEnd()}
|
|
|
4917
4342
|
if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
|
|
4918
4343
|
} else {
|
|
4919
4344
|
const dir = mindDir(name);
|
|
4920
|
-
if (!
|
|
4345
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4921
4346
|
}
|
|
4922
4347
|
if (getMindManager().isRunning(name)) {
|
|
4923
4348
|
return c.json({ error: "Mind already running" }, 409);
|
|
@@ -4938,7 +4363,7 @@ ${user.trimEnd()}
|
|
|
4938
4363
|
if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
|
|
4939
4364
|
} else {
|
|
4940
4365
|
const dir = mindDir(name);
|
|
4941
|
-
if (!
|
|
4366
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4942
4367
|
}
|
|
4943
4368
|
let context;
|
|
4944
4369
|
const contentType = c.req.header("content-type");
|
|
@@ -4953,7 +4378,7 @@ ${user.trimEnd()}
|
|
|
4953
4378
|
const manager = getMindManager();
|
|
4954
4379
|
try {
|
|
4955
4380
|
if (context?.type === "reload") {
|
|
4956
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4381
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TQP5ZJI5.js");
|
|
4957
4382
|
const sleepState = getSleepManagerIfReady2()?.getState(name);
|
|
4958
4383
|
if (sleepState?.sleeping) {
|
|
4959
4384
|
logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
|
|
@@ -4973,7 +4398,7 @@ ${user.trimEnd()}
|
|
|
4973
4398
|
const variantEntry = await findMind(mergeVariantName);
|
|
4974
4399
|
if (variantEntry && variantEntry.parent === baseName && variantEntry.dir && variantEntry.branch) {
|
|
4975
4400
|
const projectRoot = mindDir(baseName);
|
|
4976
|
-
if (
|
|
4401
|
+
if (existsSync7(variantEntry.dir)) {
|
|
4977
4402
|
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
4978
4403
|
if (status) {
|
|
4979
4404
|
try {
|
|
@@ -5014,10 +4439,9 @@ ${user.trimEnd()}
|
|
|
5014
4439
|
}
|
|
5015
4440
|
if (context?.type === "sprouted" && !entry.parent) {
|
|
5016
4441
|
try {
|
|
5017
|
-
const
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
await recordInbound(baseName, conv.channel, "system", "[seed has sprouted]");
|
|
4442
|
+
const mindConvs = await listConversationsForMind(baseName);
|
|
4443
|
+
for (const conv of mindConvs) {
|
|
4444
|
+
await recordInbound(baseName, "system", "system", "[seed has sprouted]");
|
|
5021
4445
|
await addMessage(conv.id, "assistant", "system", [
|
|
5022
4446
|
{ type: "text", text: "[seed has sprouted]" }
|
|
5023
4447
|
]);
|
|
@@ -5049,7 +4473,7 @@ ${user.trimEnd()}
|
|
|
5049
4473
|
const name = c.req.param("name");
|
|
5050
4474
|
const entry = await findMind(name);
|
|
5051
4475
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5052
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4476
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TQP5ZJI5.js");
|
|
5053
4477
|
const sm = getSleepManagerIfReady2();
|
|
5054
4478
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5055
4479
|
return c.json(sm.getState(name));
|
|
@@ -5057,7 +4481,7 @@ ${user.trimEnd()}
|
|
|
5057
4481
|
const name = c.req.param("name");
|
|
5058
4482
|
const entry = await findMind(name);
|
|
5059
4483
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5060
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4484
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TQP5ZJI5.js");
|
|
5061
4485
|
const sm = getSleepManagerIfReady2();
|
|
5062
4486
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5063
4487
|
if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
|
|
@@ -5077,7 +4501,7 @@ ${user.trimEnd()}
|
|
|
5077
4501
|
const name = c.req.param("name");
|
|
5078
4502
|
const entry = await findMind(name);
|
|
5079
4503
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5080
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4504
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TQP5ZJI5.js");
|
|
5081
4505
|
const sm = getSleepManagerIfReady2();
|
|
5082
4506
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5083
4507
|
const sleepState = sm.getState(name);
|
|
@@ -5092,7 +4516,7 @@ ${user.trimEnd()}
|
|
|
5092
4516
|
const name = c.req.param("name");
|
|
5093
4517
|
const entry = await findMind(name);
|
|
5094
4518
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5095
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4519
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-TQP5ZJI5.js");
|
|
5096
4520
|
const sm = getSleepManagerIfReady2();
|
|
5097
4521
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5098
4522
|
const flushed = await sm.flushQueuedMessages(name);
|
|
@@ -5110,7 +4534,7 @@ ${user.trimEnd()}
|
|
|
5110
4534
|
if (body.avatar !== void 0) profile.avatar = body.avatar;
|
|
5111
4535
|
config2.profile = profile;
|
|
5112
4536
|
writeVoluteConfig(dir, config2);
|
|
5113
|
-
const { syncMindProfile: syncMindProfile2 } = await import("./auth-
|
|
4537
|
+
const { syncMindProfile: syncMindProfile2 } = await import("./auth-2QOOPMBX.js");
|
|
5114
4538
|
await syncMindProfile2(name, profile);
|
|
5115
4539
|
broadcast({ type: "profile_updated", mind: name, summary: `${name} profile updated` });
|
|
5116
4540
|
return c.json({ ok: true });
|
|
@@ -5150,14 +4574,14 @@ ${user.trimEnd()}
|
|
|
5150
4574
|
return c.json({ output: "" });
|
|
5151
4575
|
}
|
|
5152
4576
|
const dir = entry.dir ?? mindDir(name);
|
|
5153
|
-
const soulPath =
|
|
5154
|
-
const memoryPath =
|
|
5155
|
-
const soulCustom =
|
|
5156
|
-
const memoryWritten =
|
|
4577
|
+
const soulPath = resolve10(dir, "home/SOUL.md");
|
|
4578
|
+
const memoryPath = resolve10(dir, "home/MEMORY.md");
|
|
4579
|
+
const soulCustom = existsSync7(soulPath) && !readFileSync8(soulPath, "utf-8").includes(ORIENTATION_MARKER);
|
|
4580
|
+
const memoryWritten = existsSync7(memoryPath) && readFileSync8(memoryPath, "utf-8").trim().length > 0;
|
|
5157
4581
|
const config2 = readVoluteConfig(dir);
|
|
5158
4582
|
const displayNameSet = !!config2?.profile?.displayName;
|
|
5159
4583
|
const avatarSet = !!config2?.profile?.avatar;
|
|
5160
|
-
const { isImagegenEnabled } = await import("./setup-
|
|
4584
|
+
const { isImagegenEnabled } = await import("./setup-PF7JSFMO.js");
|
|
5161
4585
|
const imagegenEnabled = isImagegenEnabled();
|
|
5162
4586
|
const done = [];
|
|
5163
4587
|
const remaining = [];
|
|
@@ -5195,7 +4619,7 @@ ${user.trimEnd()}
|
|
|
5195
4619
|
try {
|
|
5196
4620
|
const spiritEntry = await findMind("volute");
|
|
5197
4621
|
if (spiritEntry) {
|
|
5198
|
-
const { spiritDir } = await import("./spirit-
|
|
4622
|
+
const { spiritDir } = await import("./spirit-SM6ARJ2N.js");
|
|
5199
4623
|
const sDir = spiritEntry.dir ?? spiritDir();
|
|
5200
4624
|
const spiritConfig = readVoluteConfig(sDir);
|
|
5201
4625
|
if (spiritConfig?.schedules) {
|
|
@@ -5203,7 +4627,7 @@ ${user.trimEnd()}
|
|
|
5203
4627
|
spiritConfig.schedules = spiritConfig.schedules.filter((s) => s.id !== nurtureId);
|
|
5204
4628
|
if (spiritConfig.schedules.length === 0) spiritConfig.schedules = void 0;
|
|
5205
4629
|
writeVoluteConfig(sDir, spiritConfig);
|
|
5206
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
4630
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-NTC74JYH.js");
|
|
5207
4631
|
getScheduler2().loadSchedules("volute", sDir);
|
|
5208
4632
|
}
|
|
5209
4633
|
}
|
|
@@ -5229,11 +4653,12 @@ ${user.trimEnd()}
|
|
|
5229
4653
|
}
|
|
5230
4654
|
await removeMind(name);
|
|
5231
4655
|
await deleteMindUser2(name);
|
|
4656
|
+
invalidateMindUserCache(name);
|
|
5232
4657
|
const state = stateDir(name);
|
|
5233
|
-
if (
|
|
4658
|
+
if (existsSync7(state)) {
|
|
5234
4659
|
rmSync4(state, { recursive: true, force: true });
|
|
5235
4660
|
}
|
|
5236
|
-
if (force &&
|
|
4661
|
+
if (force && existsSync7(dir)) {
|
|
5237
4662
|
rmSync4(dir, { recursive: true, force: true });
|
|
5238
4663
|
deleteMindUser(name);
|
|
5239
4664
|
}
|
|
@@ -5248,7 +4673,7 @@ ${user.trimEnd()}
|
|
|
5248
4673
|
const entry = await findMind(mindName);
|
|
5249
4674
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5250
4675
|
const dir = mindDir(mindName);
|
|
5251
|
-
if (!
|
|
4676
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5252
4677
|
let body = {};
|
|
5253
4678
|
try {
|
|
5254
4679
|
body = await c.req.json();
|
|
@@ -5257,16 +4682,16 @@ ${user.trimEnd()}
|
|
|
5257
4682
|
const template = body.template ?? entry.template ?? "claude";
|
|
5258
4683
|
const UPGRADE_BRANCH = "upgrade";
|
|
5259
4684
|
const upgradeVariantName = `${mindName}-upgrade`;
|
|
5260
|
-
const worktreeDir =
|
|
4685
|
+
const worktreeDir = resolve10(dir, ".variants", UPGRADE_BRANCH);
|
|
5261
4686
|
if (body.abort) {
|
|
5262
|
-
if (!
|
|
4687
|
+
if (!existsSync7(worktreeDir)) {
|
|
5263
4688
|
return c.json({ error: "No upgrade in progress" }, 400);
|
|
5264
4689
|
}
|
|
5265
4690
|
try {
|
|
5266
4691
|
try {
|
|
5267
|
-
const gitDirContent =
|
|
4692
|
+
const gitDirContent = readFileSync8(resolve10(worktreeDir, ".git"), "utf-8").trim();
|
|
5268
4693
|
const gitDir = gitDirContent.replace("gitdir: ", "");
|
|
5269
|
-
if (
|
|
4694
|
+
if (existsSync7(resolve10(gitDir, "MERGE_HEAD"))) {
|
|
5270
4695
|
await gitExec(["merge", "--abort"], { cwd: worktreeDir });
|
|
5271
4696
|
}
|
|
5272
4697
|
} catch {
|
|
@@ -5285,7 +4710,7 @@ ${user.trimEnd()}
|
|
|
5285
4710
|
}
|
|
5286
4711
|
}
|
|
5287
4712
|
if (body.continue) {
|
|
5288
|
-
if (!
|
|
4713
|
+
if (!existsSync7(worktreeDir)) {
|
|
5289
4714
|
return c.json({ error: "No upgrade in progress" }, 400);
|
|
5290
4715
|
}
|
|
5291
4716
|
const status = await gitExec(["status", "--porcelain"], { cwd: worktreeDir });
|
|
@@ -5334,7 +4759,7 @@ ${user.trimEnd()}
|
|
|
5334
4759
|
}
|
|
5335
4760
|
}
|
|
5336
4761
|
if (body.accept) {
|
|
5337
|
-
if (
|
|
4762
|
+
if (existsSync7(worktreeDir)) {
|
|
5338
4763
|
try {
|
|
5339
4764
|
await cleanupVariant(upgradeVariantName, dir, worktreeDir, { stop: true });
|
|
5340
4765
|
} catch (err) {
|
|
@@ -5349,7 +4774,7 @@ ${user.trimEnd()}
|
|
|
5349
4774
|
}
|
|
5350
4775
|
if (body.diff) {
|
|
5351
4776
|
try {
|
|
5352
|
-
if (!
|
|
4777
|
+
if (!existsSync7(resolve10(dir, ".git"))) {
|
|
5353
4778
|
return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
|
|
5354
4779
|
}
|
|
5355
4780
|
await updateTemplateBranch(dir, template, mindName);
|
|
@@ -5367,22 +4792,22 @@ ${user.trimEnd()}
|
|
|
5367
4792
|
);
|
|
5368
4793
|
}
|
|
5369
4794
|
}
|
|
5370
|
-
if (
|
|
4795
|
+
if (existsSync7(worktreeDir)) {
|
|
5371
4796
|
return c.json(
|
|
5372
4797
|
{ error: "Upgrade variant already exists. Use continue or delete it first." },
|
|
5373
4798
|
409
|
|
5374
4799
|
);
|
|
5375
4800
|
}
|
|
5376
|
-
if (!
|
|
4801
|
+
if (!existsSync7(resolve10(dir, ".git"))) {
|
|
5377
4802
|
try {
|
|
5378
|
-
const env = isIsolationEnabled() ? { ...process.env, HOME:
|
|
4803
|
+
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve10(dir, "home") } : void 0;
|
|
5379
4804
|
await gitExec(["init"], { cwd: dir, mindName, env });
|
|
5380
4805
|
await configureGitIdentity(mindName, { cwd: dir, mindName, env });
|
|
5381
4806
|
await gitExec(["add", "-A"], { cwd: dir, mindName, env });
|
|
5382
4807
|
await gitExec(["commit", "-m", "initial commit"], { cwd: dir, mindName, env });
|
|
5383
4808
|
chownMindDir(dir, mindName);
|
|
5384
4809
|
} catch (err) {
|
|
5385
|
-
rmSync4(
|
|
4810
|
+
rmSync4(resolve10(dir, ".git"), { recursive: true, force: true });
|
|
5386
4811
|
return c.json(
|
|
5387
4812
|
{
|
|
5388
4813
|
error: `Git initialization failed: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -5397,8 +4822,8 @@ ${user.trimEnd()}
|
|
|
5397
4822
|
} catch {
|
|
5398
4823
|
}
|
|
5399
4824
|
await updateTemplateBranch(dir, template, mindName);
|
|
5400
|
-
const parentDir =
|
|
5401
|
-
if (!
|
|
4825
|
+
const parentDir = resolve10(dir, ".variants");
|
|
4826
|
+
if (!existsSync7(parentDir)) {
|
|
5402
4827
|
mkdirSync6(parentDir, { recursive: true });
|
|
5403
4828
|
}
|
|
5404
4829
|
await gitExec(["worktree", "add", "-b", UPGRADE_BRANCH, worktreeDir], { cwd: dir });
|
|
@@ -5527,22 +4952,22 @@ ${user.trimEnd()}
|
|
|
5527
4952
|
const entry = await findMind(name);
|
|
5528
4953
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5529
4954
|
const dir = entry.dir ?? mindDir(name);
|
|
5530
|
-
if (!
|
|
4955
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5531
4956
|
let config2 = readVoluteConfig(dir);
|
|
5532
4957
|
if (!config2 && entry.template === "pi") {
|
|
5533
|
-
const piConfigPath =
|
|
5534
|
-
if (
|
|
4958
|
+
const piConfigPath = resolve10(dir, "home/.config/config.json");
|
|
4959
|
+
if (existsSync7(piConfigPath)) {
|
|
5535
4960
|
try {
|
|
5536
|
-
config2 = JSON.parse(
|
|
4961
|
+
config2 = JSON.parse(readFileSync8(piConfigPath, "utf-8"));
|
|
5537
4962
|
} catch {
|
|
5538
4963
|
}
|
|
5539
4964
|
}
|
|
5540
4965
|
}
|
|
5541
4966
|
let templateConfig = {};
|
|
5542
|
-
const configJsonPath =
|
|
5543
|
-
if (
|
|
4967
|
+
const configJsonPath = resolve10(dir, "home/.config/config.json");
|
|
4968
|
+
if (existsSync7(configJsonPath)) {
|
|
5544
4969
|
try {
|
|
5545
|
-
templateConfig = JSON.parse(
|
|
4970
|
+
templateConfig = JSON.parse(readFileSync8(configJsonPath, "utf-8"));
|
|
5546
4971
|
} catch {
|
|
5547
4972
|
}
|
|
5548
4973
|
}
|
|
@@ -5596,7 +5021,7 @@ ${user.trimEnd()}
|
|
|
5596
5021
|
const entry = await findMind(name);
|
|
5597
5022
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5598
5023
|
const dir = entry.dir ?? mindDir(name);
|
|
5599
|
-
if (!
|
|
5024
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5600
5025
|
const body = c.req.valid("json");
|
|
5601
5026
|
const existing = readVoluteConfig(dir) ?? {};
|
|
5602
5027
|
if (body.model !== void 0) existing.model = body.model;
|
|
@@ -5627,11 +5052,11 @@ ${user.trimEnd()}
|
|
|
5627
5052
|
writeVoluteConfig(dir, existing);
|
|
5628
5053
|
const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.maxThinkingTokens !== void 0 || body.compaction !== void 0;
|
|
5629
5054
|
if (needsConfigJson) {
|
|
5630
|
-
const configJsonPath =
|
|
5055
|
+
const configJsonPath = resolve10(dir, "home/.config/config.json");
|
|
5631
5056
|
let templateConfig = {};
|
|
5632
|
-
if (
|
|
5057
|
+
if (existsSync7(configJsonPath)) {
|
|
5633
5058
|
try {
|
|
5634
|
-
templateConfig = JSON.parse(
|
|
5059
|
+
templateConfig = JSON.parse(readFileSync8(configJsonPath, "utf-8"));
|
|
5635
5060
|
} catch {
|
|
5636
5061
|
}
|
|
5637
5062
|
}
|
|
@@ -5699,7 +5124,7 @@ ${user.trimEnd()}
|
|
|
5699
5124
|
}
|
|
5700
5125
|
if (entry.mindType === "spirit" && body.model !== void 0) {
|
|
5701
5126
|
try {
|
|
5702
|
-
const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-
|
|
5127
|
+
const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-PF7JSFMO.js");
|
|
5703
5128
|
const globalConfig = readGlobalConfig2();
|
|
5704
5129
|
globalConfig.spiritModel = body.model;
|
|
5705
5130
|
writeGlobalConfig2(globalConfig);
|
|
@@ -5727,7 +5152,7 @@ ${user.trimEnd()}
|
|
|
5727
5152
|
if (!body.systemPrompt || !body.message) {
|
|
5728
5153
|
return c.json({ error: "systemPrompt and message required" }, 400);
|
|
5729
5154
|
}
|
|
5730
|
-
const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-
|
|
5155
|
+
const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-C2YNARGH.js");
|
|
5731
5156
|
if (!isAiConfigured()) {
|
|
5732
5157
|
return c.json({ error: "AI service not configured" }, 503);
|
|
5733
5158
|
}
|
|
@@ -5817,6 +5242,17 @@ ${user.trimEnd()}
|
|
|
5817
5242
|
metadata: body.metadata,
|
|
5818
5243
|
turnId: turnId ?? void 0
|
|
5819
5244
|
});
|
|
5245
|
+
if (body.type === "text" && body.channel && cleanContent) {
|
|
5246
|
+
echoTextToChannel(
|
|
5247
|
+
baseName,
|
|
5248
|
+
body.channel,
|
|
5249
|
+
cleanContent,
|
|
5250
|
+
turnId ?? void 0,
|
|
5251
|
+
insertedId
|
|
5252
|
+
).catch(
|
|
5253
|
+
(err) => logger_default.error(`echo-text failed for ${baseName} on ${body.channel}`, logger_default.errorData(err))
|
|
5254
|
+
);
|
|
5255
|
+
}
|
|
5820
5256
|
onMindEvent(baseName, body.type, body.channel);
|
|
5821
5257
|
if ((body.type === "text" || body.type === "outbound") && body.channel) {
|
|
5822
5258
|
const map = getTypingMap();
|
|
@@ -5885,7 +5321,7 @@ ${user.trimEnd()}
|
|
|
5885
5321
|
const stream = new ReadableStream({
|
|
5886
5322
|
start(controller) {
|
|
5887
5323
|
const encoder = new TextEncoder();
|
|
5888
|
-
const
|
|
5324
|
+
const send = (data) => {
|
|
5889
5325
|
controller.enqueue(encoder.encode(`data: ${data}
|
|
5890
5326
|
|
|
5891
5327
|
`));
|
|
@@ -5904,7 +5340,7 @@ ${user.trimEnd()}
|
|
|
5904
5340
|
if (sessionFilter && event.session !== sessionFilter) return;
|
|
5905
5341
|
if (channelFilter && event.channel !== channelFilter) return;
|
|
5906
5342
|
try {
|
|
5907
|
-
|
|
5343
|
+
send(JSON.stringify(event));
|
|
5908
5344
|
} catch {
|
|
5909
5345
|
clearInterval(pingInterval);
|
|
5910
5346
|
unsubscribe?.();
|
|
@@ -6187,15 +5623,14 @@ var prompts_default = app14;
|
|
|
6187
5623
|
import { CronExpressionParser } from "cron-parser";
|
|
6188
5624
|
import { Hono as Hono17 } from "hono";
|
|
6189
5625
|
var slog2 = logger_default.child("schedules");
|
|
6190
|
-
function readSchedules(
|
|
6191
|
-
return readVoluteConfig(
|
|
5626
|
+
function readSchedules(dir) {
|
|
5627
|
+
return readVoluteConfig(dir)?.schedules ?? [];
|
|
6192
5628
|
}
|
|
6193
|
-
function writeSchedules(name, schedules) {
|
|
6194
|
-
const dir = mindDir(name);
|
|
5629
|
+
function writeSchedules(name, dir, schedules) {
|
|
6195
5630
|
const config2 = readVoluteConfig(dir) ?? {};
|
|
6196
5631
|
config2.schedules = schedules.length > 0 ? schedules : void 0;
|
|
6197
5632
|
writeVoluteConfig(dir, config2);
|
|
6198
|
-
getScheduler().loadSchedules(name);
|
|
5633
|
+
getScheduler().loadSchedules(name, dir);
|
|
6199
5634
|
getSleepManagerIfReady()?.invalidateSleepConfig(name);
|
|
6200
5635
|
fireWebhook({
|
|
6201
5636
|
event: "schedule_changed",
|
|
@@ -6205,11 +5640,13 @@ function writeSchedules(name, schedules) {
|
|
|
6205
5640
|
}
|
|
6206
5641
|
var app15 = new Hono17().get("/:name/clock/status", async (c) => {
|
|
6207
5642
|
const name = c.req.param("name");
|
|
6208
|
-
|
|
5643
|
+
const entry = await findMind(name);
|
|
5644
|
+
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5645
|
+
const dir = entry.dir ?? mindDir(name);
|
|
6209
5646
|
const sleepManager = getSleepManagerIfReady();
|
|
6210
5647
|
const sleepState = sleepManager?.getState(name) ?? null;
|
|
6211
5648
|
const sleepConfig = sleepManager?.getSleepConfig(name) ?? null;
|
|
6212
|
-
const schedules = readSchedules(
|
|
5649
|
+
const schedules = readSchedules(dir);
|
|
6213
5650
|
const now = /* @__PURE__ */ new Date();
|
|
6214
5651
|
const upcoming = [];
|
|
6215
5652
|
const previous = [];
|
|
@@ -6262,8 +5699,9 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
|
|
|
6262
5699
|
return c.json({ sleep: sleepState, sleepConfig, schedules, upcoming, previous });
|
|
6263
5700
|
}).get("/:name/sleep/config", async (c) => {
|
|
6264
5701
|
const name = c.req.param("name");
|
|
6265
|
-
|
|
6266
|
-
|
|
5702
|
+
const entry = await findMind(name);
|
|
5703
|
+
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5704
|
+
const config2 = readVoluteConfig(entry.dir ?? mindDir(name));
|
|
6267
5705
|
return c.json(config2?.sleep ?? { enabled: false });
|
|
6268
5706
|
}).put("/:name/sleep/config", requireSelf(), async (c) => {
|
|
6269
5707
|
const name = c.req.param("name");
|
|
@@ -6281,7 +5719,7 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
|
|
|
6281
5719
|
}
|
|
6282
5720
|
}
|
|
6283
5721
|
}
|
|
6284
|
-
const dir = mindDir(name);
|
|
5722
|
+
const dir = entry.dir ?? mindDir(name);
|
|
6285
5723
|
const config2 = readVoluteConfig(dir) ?? {};
|
|
6286
5724
|
const sleep = config2.sleep ?? {};
|
|
6287
5725
|
if (body.enabled !== void 0) sleep.enabled = body.enabled;
|
|
@@ -6293,8 +5731,9 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
|
|
|
6293
5731
|
return c.json({ ok: true });
|
|
6294
5732
|
}).get("/:name/schedules", async (c) => {
|
|
6295
5733
|
const name = c.req.param("name");
|
|
6296
|
-
|
|
6297
|
-
return c.json(
|
|
5734
|
+
const entry = await findMind(name);
|
|
5735
|
+
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5736
|
+
return c.json(readSchedules(entry.dir ?? mindDir(name)));
|
|
6298
5737
|
}).post("/:name/schedules", requireSelf(), async (c) => {
|
|
6299
5738
|
const name = c.req.param("name");
|
|
6300
5739
|
const entry = await findMind(name);
|
|
@@ -6335,7 +5774,8 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
|
|
|
6335
5774
|
400
|
|
6336
5775
|
);
|
|
6337
5776
|
}
|
|
6338
|
-
const
|
|
5777
|
+
const dir = entry.dir ?? mindDir(name);
|
|
5778
|
+
const schedules = readSchedules(dir);
|
|
6339
5779
|
const id = body.id;
|
|
6340
5780
|
if (schedules.some((s) => s.id === id)) {
|
|
6341
5781
|
return c.json({ error: `Schedule "${id}" already exists` }, 409);
|
|
@@ -6348,13 +5788,15 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
|
|
|
6348
5788
|
if (body.channel) schedule.channel = body.channel;
|
|
6349
5789
|
if (body.whileSleeping) schedule.whileSleeping = body.whileSleeping;
|
|
6350
5790
|
schedules.push(schedule);
|
|
6351
|
-
writeSchedules(name, schedules);
|
|
5791
|
+
writeSchedules(name, dir, schedules);
|
|
6352
5792
|
return c.json({ ok: true, id }, 201);
|
|
6353
5793
|
}).put("/:name/schedules/:id", requireSelf(), async (c) => {
|
|
6354
5794
|
const name = c.req.param("name");
|
|
6355
5795
|
const id = c.req.param("id");
|
|
6356
|
-
|
|
6357
|
-
|
|
5796
|
+
const entry = await findMind(name);
|
|
5797
|
+
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5798
|
+
const dir = entry.dir ?? mindDir(name);
|
|
5799
|
+
const schedules = readSchedules(dir);
|
|
6358
5800
|
const idx = schedules.findIndex((s) => s.id === id);
|
|
6359
5801
|
if (idx === -1) return c.json({ error: "Schedule not found" }, 404);
|
|
6360
5802
|
const body = await c.req.json();
|
|
@@ -6397,18 +5839,20 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
|
|
|
6397
5839
|
if (body.channel !== void 0) schedules[idx].channel = body.channel || void 0;
|
|
6398
5840
|
if (body.whileSleeping !== void 0)
|
|
6399
5841
|
schedules[idx].whileSleeping = body.whileSleeping || void 0;
|
|
6400
|
-
writeSchedules(name, schedules);
|
|
5842
|
+
writeSchedules(name, dir, schedules);
|
|
6401
5843
|
return c.json({ ok: true });
|
|
6402
5844
|
}).delete("/:name/schedules/:id", requireSelf(), async (c) => {
|
|
6403
5845
|
const name = c.req.param("name");
|
|
6404
5846
|
const id = c.req.param("id");
|
|
6405
|
-
|
|
6406
|
-
|
|
5847
|
+
const entry = await findMind(name);
|
|
5848
|
+
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5849
|
+
const dir = entry.dir ?? mindDir(name);
|
|
5850
|
+
const schedules = readSchedules(dir);
|
|
6407
5851
|
const filtered = schedules.filter((s) => s.id !== id);
|
|
6408
5852
|
if (filtered.length === schedules.length) {
|
|
6409
5853
|
return c.json({ error: "Schedule not found" }, 404);
|
|
6410
5854
|
}
|
|
6411
|
-
writeSchedules(name, filtered);
|
|
5855
|
+
writeSchedules(name, dir, filtered);
|
|
6412
5856
|
return c.json({ ok: true });
|
|
6413
5857
|
}).post("/:name/webhook/:event", async (c) => {
|
|
6414
5858
|
const name = c.req.param("name");
|
|
@@ -6418,7 +5862,7 @@ var app15 = new Hono17().get("/:name/clock/status", async (c) => {
|
|
|
6418
5862
|
const body = await c.req.text();
|
|
6419
5863
|
const message = `[webhook: ${event}] ${body}`;
|
|
6420
5864
|
try {
|
|
6421
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
5865
|
+
const { sendSystemMessage } = await import("./system-chat-NNXYCSVL.js");
|
|
6422
5866
|
await sendSystemMessage(name, message);
|
|
6423
5867
|
return c.json({ ok: true });
|
|
6424
5868
|
} catch (err) {
|
|
@@ -6431,14 +5875,14 @@ var schedules_default = app15;
|
|
|
6431
5875
|
// packages/daemon/src/web/api/setup.ts
|
|
6432
5876
|
import { mkdirSync as mkdirSync7 } from "fs";
|
|
6433
5877
|
import { homedir as homedir2 } from "os";
|
|
6434
|
-
import { resolve as
|
|
5878
|
+
import { resolve as resolve11 } from "path";
|
|
6435
5879
|
import { Hono as Hono18 } from "hono";
|
|
6436
5880
|
import { setCookie as setCookie2 } from "hono/cookie";
|
|
6437
5881
|
var DEFAULT_API_URL2 = "https://volute.systems";
|
|
6438
5882
|
var setup = new Hono18();
|
|
6439
5883
|
function writeSetupConfig(systemName, description) {
|
|
6440
|
-
const configHome = process.env.VOLUTE_HOME ??
|
|
6441
|
-
const mindsDir =
|
|
5884
|
+
const configHome = process.env.VOLUTE_HOME ?? resolve11(homedir2(), ".volute");
|
|
5885
|
+
const mindsDir = resolve11(configHome, "minds");
|
|
6442
5886
|
mkdirSync7(configHome, { recursive: true });
|
|
6443
5887
|
mkdirSync7(mindsDir, { recursive: true });
|
|
6444
5888
|
const existingConfig = readGlobalConfig();
|
|
@@ -6452,7 +5896,8 @@ function writeSetupConfig(systemName, description) {
|
|
|
6452
5896
|
...existingConfig,
|
|
6453
5897
|
name: systemName,
|
|
6454
5898
|
description: description || existingConfig.description,
|
|
6455
|
-
setup: setupConfig
|
|
5899
|
+
setup: setupConfig,
|
|
5900
|
+
setupCompleted: false
|
|
6456
5901
|
};
|
|
6457
5902
|
writeGlobalConfig(config2);
|
|
6458
5903
|
return config2;
|
|
@@ -6471,7 +5916,7 @@ setup.get("/status", async (c) => {
|
|
|
6471
5916
|
let hasAccount = false;
|
|
6472
5917
|
if (hasSystem) {
|
|
6473
5918
|
try {
|
|
6474
|
-
const { listUsersByType: listUsersByType2 } = await import("./auth-
|
|
5919
|
+
const { listUsersByType: listUsersByType2 } = await import("./auth-2QOOPMBX.js");
|
|
6475
5920
|
const brains = await listUsersByType2("brain");
|
|
6476
5921
|
hasAccount = brains.length > 0;
|
|
6477
5922
|
} catch (err) {
|
|
@@ -6660,7 +6105,7 @@ setup.post("/account", async (c) => {
|
|
|
6660
6105
|
}
|
|
6661
6106
|
}
|
|
6662
6107
|
try {
|
|
6663
|
-
const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-
|
|
6108
|
+
const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-2QOOPMBX.js");
|
|
6664
6109
|
const user = await createUser2(body.username.trim(), body.password);
|
|
6665
6110
|
if (body.displayName?.trim()) {
|
|
6666
6111
|
await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
|
|
@@ -6706,7 +6151,7 @@ setup.post("/models", async (c) => {
|
|
|
6706
6151
|
return c.json({ error: "Spirit model is required" }, 400);
|
|
6707
6152
|
}
|
|
6708
6153
|
try {
|
|
6709
|
-
const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-
|
|
6154
|
+
const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-C2YNARGH.js");
|
|
6710
6155
|
setEnabledModels3(body.models);
|
|
6711
6156
|
const config2 = readGlobalConfig();
|
|
6712
6157
|
config2.spiritModel = body.spiritModel.trim();
|
|
@@ -6724,8 +6169,8 @@ setup.post("/complete", async (c) => {
|
|
|
6724
6169
|
return c.json({ error: "Setup already complete" }, 400);
|
|
6725
6170
|
}
|
|
6726
6171
|
try {
|
|
6727
|
-
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-
|
|
6728
|
-
const { startSpiritFull } = await import("./mind-service-
|
|
6172
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-SM6ARJ2N.js");
|
|
6173
|
+
const { startSpiritFull } = await import("./mind-service-UDXF5WC2.js");
|
|
6729
6174
|
await ensureSpiritProject();
|
|
6730
6175
|
await syncSpiritTemplate();
|
|
6731
6176
|
const warnings = [];
|
|
@@ -6741,19 +6186,18 @@ setup.post("/complete", async (c) => {
|
|
|
6741
6186
|
}
|
|
6742
6187
|
let spiritConversationId;
|
|
6743
6188
|
try {
|
|
6744
|
-
const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-
|
|
6745
|
-
const { createConversation:
|
|
6189
|
+
const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-2QOOPMBX.js");
|
|
6190
|
+
const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-G6YRSABR.js");
|
|
6746
6191
|
const spiritUser = await getOrCreateMindUser2("volute");
|
|
6747
6192
|
const brains = await listUsersByType2("brain");
|
|
6748
6193
|
const admin2 = brains.find((u) => u.role === "admin");
|
|
6749
6194
|
if (admin2) {
|
|
6750
|
-
const existing = await findDMConversation2(
|
|
6195
|
+
const existing = await findDMConversation2([admin2.id, spiritUser.id]);
|
|
6751
6196
|
if (existing) {
|
|
6752
6197
|
spiritConversationId = existing;
|
|
6753
6198
|
} else {
|
|
6754
|
-
const conv = await
|
|
6755
|
-
participantIds: [admin2.id, spiritUser.id]
|
|
6756
|
-
title: "Volute"
|
|
6199
|
+
const conv = await createConversation2({
|
|
6200
|
+
participantIds: [admin2.id, spiritUser.id]
|
|
6757
6201
|
});
|
|
6758
6202
|
spiritConversationId = conv.id;
|
|
6759
6203
|
}
|
|
@@ -6765,9 +6209,9 @@ setup.post("/complete", async (c) => {
|
|
|
6765
6209
|
logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
|
|
6766
6210
|
if (spiritConversationId && spiritStarted) {
|
|
6767
6211
|
try {
|
|
6768
|
-
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-
|
|
6769
|
-
const { listUsersByType:
|
|
6770
|
-
const admins = await
|
|
6212
|
+
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-N2V5APCS.js");
|
|
6213
|
+
const { listUsersByType: listUsers2 } = await import("./auth-2QOOPMBX.js");
|
|
6214
|
+
const admins = await listUsers2("brain");
|
|
6771
6215
|
const admin2 = admins.find((u) => u.role === "admin");
|
|
6772
6216
|
const adminName = admin2?.display_name || admin2?.username || "the admin";
|
|
6773
6217
|
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.`;
|
|
@@ -6803,9 +6247,9 @@ setup.post("/complete", async (c) => {
|
|
|
6803
6247
|
var setup_default = setup;
|
|
6804
6248
|
|
|
6805
6249
|
// packages/daemon/src/web/api/skills.ts
|
|
6806
|
-
import { existsSync as
|
|
6250
|
+
import { existsSync as existsSync8, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync5 } from "fs";
|
|
6807
6251
|
import { tmpdir } from "os";
|
|
6808
|
-
import { join, resolve as
|
|
6252
|
+
import { join, resolve as resolve12 } from "path";
|
|
6809
6253
|
import AdmZip from "adm-zip";
|
|
6810
6254
|
import { Hono as Hono19 } from "hono";
|
|
6811
6255
|
var app16 = new Hono19().get("/", async (c) => {
|
|
@@ -6881,19 +6325,19 @@ var app16 = new Hono19().get("/", async (c) => {
|
|
|
6881
6325
|
try {
|
|
6882
6326
|
const zip = new AdmZip(buffer2);
|
|
6883
6327
|
for (const entry of zip.getEntries()) {
|
|
6884
|
-
const target =
|
|
6328
|
+
const target = resolve12(tmpDir, entry.entryName);
|
|
6885
6329
|
if (!target.startsWith(tmpDir)) {
|
|
6886
6330
|
return c.json({ error: "Invalid zip: paths must not escape archive" }, 400);
|
|
6887
6331
|
}
|
|
6888
6332
|
}
|
|
6889
6333
|
zip.extractAllTo(tmpDir, true);
|
|
6890
6334
|
let skillDir = null;
|
|
6891
|
-
if (
|
|
6335
|
+
if (existsSync8(join(tmpDir, "SKILL.md"))) {
|
|
6892
6336
|
skillDir = tmpDir;
|
|
6893
6337
|
} else {
|
|
6894
6338
|
const entries = readdirSync3(tmpDir, { withFileTypes: true }).filter((e) => e.isDirectory());
|
|
6895
6339
|
for (const entry of entries) {
|
|
6896
|
-
if (
|
|
6340
|
+
if (existsSync8(join(tmpDir, entry.name, "SKILL.md"))) {
|
|
6897
6341
|
skillDir = join(tmpDir, entry.name);
|
|
6898
6342
|
break;
|
|
6899
6343
|
}
|
|
@@ -6988,7 +6432,6 @@ import { zValidator as zValidator8 } from "@hono/zod-validator";
|
|
|
6988
6432
|
import { Hono as Hono22 } from "hono";
|
|
6989
6433
|
import { z as z8 } from "zod";
|
|
6990
6434
|
var createSchema = z8.object({
|
|
6991
|
-
title: z8.string().optional(),
|
|
6992
6435
|
participantNames: z8.array(z8.string()).min(1)
|
|
6993
6436
|
});
|
|
6994
6437
|
var app19 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
|
|
@@ -7045,10 +6488,17 @@ var app19 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
|
|
|
7045
6488
|
if (participantIds.size > 2) {
|
|
7046
6489
|
return c.json({ error: "Use channels for multi-participant conversations" }, 400);
|
|
7047
6490
|
}
|
|
7048
|
-
const
|
|
6491
|
+
const ids = [...participantIds];
|
|
6492
|
+
if (ids.length === 2) {
|
|
6493
|
+
const existingId = await findDMConversation(ids);
|
|
6494
|
+
if (existingId) {
|
|
6495
|
+
const existing = await getConversation(existingId);
|
|
6496
|
+
if (existing) return c.json(existing);
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6499
|
+
const conv = await createConversation({
|
|
7049
6500
|
userId: user.id !== 0 ? user.id : void 0,
|
|
7050
|
-
|
|
7051
|
-
participantIds: [...participantIds]
|
|
6501
|
+
participantIds: ids
|
|
7052
6502
|
});
|
|
7053
6503
|
return c.json(conv, 201);
|
|
7054
6504
|
}).post("/:id/read", async (c) => {
|
|
@@ -7217,8 +6667,8 @@ var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
|
|
|
7217
6667
|
});
|
|
7218
6668
|
}, 15e3);
|
|
7219
6669
|
cleanups.push(() => clearInterval(keepAlive));
|
|
7220
|
-
await new Promise((
|
|
7221
|
-
stream.onAbort(() =>
|
|
6670
|
+
await new Promise((resolve17) => {
|
|
6671
|
+
stream.onAbort(() => resolve17());
|
|
7222
6672
|
});
|
|
7223
6673
|
} finally {
|
|
7224
6674
|
for (const cleanup of cleanups) {
|
|
@@ -7233,16 +6683,16 @@ var app20 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
|
|
|
7233
6683
|
var events_default = app20;
|
|
7234
6684
|
|
|
7235
6685
|
// packages/daemon/src/web/api/variants.ts
|
|
7236
|
-
import { existsSync as
|
|
7237
|
-
import { resolve as
|
|
6686
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8 } from "fs";
|
|
6687
|
+
import { resolve as resolve14 } from "path";
|
|
7238
6688
|
import { Hono as Hono24 } from "hono";
|
|
7239
6689
|
|
|
7240
|
-
// packages/daemon/src/lib/spawn-server.ts
|
|
6690
|
+
// packages/daemon/src/lib/mind/spawn-server.ts
|
|
7241
6691
|
import { spawn as spawn4 } from "child_process";
|
|
7242
|
-
import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as
|
|
7243
|
-
import { resolve as
|
|
6692
|
+
import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync9 } from "fs";
|
|
6693
|
+
import { resolve as resolve13 } from "path";
|
|
7244
6694
|
function tsxBin(cwd) {
|
|
7245
|
-
return
|
|
6695
|
+
return resolve13(cwd, "node_modules", ".bin", "tsx");
|
|
7246
6696
|
}
|
|
7247
6697
|
function spawnServer(cwd, port, options) {
|
|
7248
6698
|
if (options?.detached) {
|
|
@@ -7255,31 +6705,31 @@ function spawnAttached(cwd, port) {
|
|
|
7255
6705
|
cwd,
|
|
7256
6706
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7257
6707
|
});
|
|
7258
|
-
return new Promise((
|
|
7259
|
-
const timeout = setTimeout(() =>
|
|
6708
|
+
return new Promise((resolve17) => {
|
|
6709
|
+
const timeout = setTimeout(() => resolve17(null), 3e4);
|
|
7260
6710
|
function checkOutput(data) {
|
|
7261
6711
|
const match = data.toString().match(/listening on :(\d+)/);
|
|
7262
6712
|
if (match) {
|
|
7263
6713
|
clearTimeout(timeout);
|
|
7264
|
-
|
|
6714
|
+
resolve17({ child, actualPort: parseInt(match[1], 10) });
|
|
7265
6715
|
}
|
|
7266
6716
|
}
|
|
7267
6717
|
child.stdout?.on("data", checkOutput);
|
|
7268
6718
|
child.stderr?.on("data", checkOutput);
|
|
7269
6719
|
child.on("error", () => {
|
|
7270
6720
|
clearTimeout(timeout);
|
|
7271
|
-
|
|
6721
|
+
resolve17(null);
|
|
7272
6722
|
});
|
|
7273
6723
|
child.on("exit", () => {
|
|
7274
6724
|
clearTimeout(timeout);
|
|
7275
|
-
|
|
6725
|
+
resolve17(null);
|
|
7276
6726
|
});
|
|
7277
6727
|
});
|
|
7278
6728
|
}
|
|
7279
6729
|
function spawnDetached(cwd, port, logDir) {
|
|
7280
|
-
const logsDir = logDir ??
|
|
6730
|
+
const logsDir = logDir ?? resolve13(cwd, ".mind", "logs");
|
|
7281
6731
|
mkdirSync8(logsDir, { recursive: true });
|
|
7282
|
-
const logPath =
|
|
6732
|
+
const logPath = resolve13(logsDir, "mind.log");
|
|
7283
6733
|
const logFd = openSync(logPath, "a");
|
|
7284
6734
|
const child = spawn4(tsxBin(cwd), ["src/server.ts", "--port", String(port)], {
|
|
7285
6735
|
cwd,
|
|
@@ -7299,7 +6749,7 @@ function spawnDetached(cwd, port, logDir) {
|
|
|
7299
6749
|
}
|
|
7300
6750
|
const interval = setInterval(() => {
|
|
7301
6751
|
try {
|
|
7302
|
-
const content =
|
|
6752
|
+
const content = readFileSync9(logPath, "utf-8");
|
|
7303
6753
|
const match = content.match(/listening on :(\d+)/);
|
|
7304
6754
|
if (match) {
|
|
7305
6755
|
finish({ child, actualPort: parseInt(match[1], 10) });
|
|
@@ -7313,7 +6763,7 @@ function spawnDetached(cwd, port, logDir) {
|
|
|
7313
6763
|
});
|
|
7314
6764
|
}
|
|
7315
6765
|
|
|
7316
|
-
// packages/daemon/src/lib/verify.ts
|
|
6766
|
+
// packages/daemon/src/lib/mind/verify.ts
|
|
7317
6767
|
async function verify2(port) {
|
|
7318
6768
|
const health = await checkHealth(port);
|
|
7319
6769
|
if (!health.ok) {
|
|
@@ -7395,11 +6845,11 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
|
|
|
7395
6845
|
return c.json({ error: `Name already in use: ${variantName}` }, 409);
|
|
7396
6846
|
}
|
|
7397
6847
|
const projectRoot = mindDir(mindName);
|
|
7398
|
-
const variantDir =
|
|
7399
|
-
if (
|
|
6848
|
+
const variantDir = resolve14(projectRoot, ".variants", variantName);
|
|
6849
|
+
if (existsSync9(variantDir)) {
|
|
7400
6850
|
return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
|
|
7401
6851
|
}
|
|
7402
|
-
mkdirSync9(
|
|
6852
|
+
mkdirSync9(resolve14(projectRoot, ".variants"), { recursive: true });
|
|
7403
6853
|
try {
|
|
7404
6854
|
await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
|
|
7405
6855
|
} catch (e) {
|
|
@@ -7412,7 +6862,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
|
|
|
7412
6862
|
const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
|
|
7413
6863
|
await exec(cmd, args, {
|
|
7414
6864
|
cwd: variantDir,
|
|
7415
|
-
env: { ...process.env, HOME:
|
|
6865
|
+
env: { ...process.env, HOME: resolve14(variantDir, "home") }
|
|
7416
6866
|
});
|
|
7417
6867
|
} else {
|
|
7418
6868
|
await exec("npm", ["install"], { cwd: variantDir });
|
|
@@ -7422,7 +6872,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
|
|
|
7422
6872
|
return c.json({ error: `npm install failed: ${msg}` }, 500);
|
|
7423
6873
|
}
|
|
7424
6874
|
if (body.soul) {
|
|
7425
|
-
writeFileSync8(
|
|
6875
|
+
writeFileSync8(resolve14(variantDir, "home/SOUL.md"), body.soul);
|
|
7426
6876
|
}
|
|
7427
6877
|
const variantPort = body.port ?? await nextPort();
|
|
7428
6878
|
await addVariant(variantName, mindName, variantPort, variantDir, variantName);
|
|
@@ -7457,7 +6907,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
|
|
|
7457
6907
|
} catch {
|
|
7458
6908
|
}
|
|
7459
6909
|
const projectRoot = mindDir(mindName);
|
|
7460
|
-
if (
|
|
6910
|
+
if (existsSync9(variantEntry.dir)) {
|
|
7461
6911
|
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
7462
6912
|
if (status) {
|
|
7463
6913
|
try {
|
|
@@ -7517,8 +6967,8 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
|
|
|
7517
6967
|
await cleanupVariant(variantName, projectRoot, variantEntry.dir);
|
|
7518
6968
|
if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
|
|
7519
6969
|
try {
|
|
7520
|
-
const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-
|
|
7521
|
-
const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-
|
|
6970
|
+
const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-SSIBEEYK.js");
|
|
6971
|
+
const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-KMELPC3X.js");
|
|
7522
6972
|
const tmpl = parentEntry.template ?? "claude";
|
|
7523
6973
|
await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
|
|
7524
6974
|
} catch (err) {
|
|
@@ -7531,7 +6981,7 @@ var app21 = new Hono24().get("/:name/variants", async (c) => {
|
|
|
7531
6981
|
const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
|
|
7532
6982
|
await exec(cmd, args, {
|
|
7533
6983
|
cwd: projectRoot,
|
|
7534
|
-
env: { ...process.env, HOME:
|
|
6984
|
+
env: { ...process.env, HOME: resolve14(projectRoot, "home") }
|
|
7535
6985
|
});
|
|
7536
6986
|
} else {
|
|
7537
6987
|
await exec("npm", ["install"], { cwd: projectRoot });
|
|
@@ -7579,17 +7029,23 @@ var variants_default = app21;
|
|
|
7579
7029
|
import { zValidator as zValidator9 } from "@hono/zod-validator";
|
|
7580
7030
|
import { Hono as Hono25 } from "hono";
|
|
7581
7031
|
import { z as z9 } from "zod";
|
|
7032
|
+
var channelSettingsSchema = z9.object({
|
|
7033
|
+
description: z9.string().nullable().optional(),
|
|
7034
|
+
rules: z9.string().nullable().optional(),
|
|
7035
|
+
charLimit: z9.number().int().positive().nullable().optional(),
|
|
7036
|
+
private: z9.boolean().optional()
|
|
7037
|
+
});
|
|
7582
7038
|
var createSchema2 = z9.object({
|
|
7583
7039
|
name: z9.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
|
|
7584
|
-
});
|
|
7040
|
+
}).merge(channelSettingsSchema);
|
|
7585
7041
|
var inviteSchema = z9.object({
|
|
7586
7042
|
username: z9.string().min(1)
|
|
7587
7043
|
});
|
|
7588
7044
|
var app22 = new Hono25().get("/", async (c) => {
|
|
7589
7045
|
const user = c.get("user");
|
|
7590
|
-
const
|
|
7046
|
+
const channels2 = await listChannels();
|
|
7591
7047
|
const results = await Promise.all(
|
|
7592
|
-
|
|
7048
|
+
channels2.map(async (ch) => {
|
|
7593
7049
|
const participants = await getParticipants(ch.id);
|
|
7594
7050
|
const isMember = participants.some((p) => p.userId === user.id);
|
|
7595
7051
|
return { ...ch, participantCount: participants.length, isMember };
|
|
@@ -7600,8 +7056,9 @@ var app22 = new Hono25().get("/", async (c) => {
|
|
|
7600
7056
|
const user = c.get("user");
|
|
7601
7057
|
const body = c.req.valid("json");
|
|
7602
7058
|
try {
|
|
7603
|
-
const
|
|
7604
|
-
|
|
7059
|
+
const { name, ...settings } = body;
|
|
7060
|
+
const ch = await createChannel(name, user.id, settings);
|
|
7061
|
+
return c.json({ ...ch, channel_name: name }, 201);
|
|
7605
7062
|
} catch (err) {
|
|
7606
7063
|
const cause = err instanceof Error ? err.cause : null;
|
|
7607
7064
|
if (cause && /UNIQUE/i.test(cause.extendedCode ?? cause.message ?? "")) {
|
|
@@ -7613,8 +7070,24 @@ var app22 = new Hono25().get("/", async (c) => {
|
|
|
7613
7070
|
const name = c.req.param("name");
|
|
7614
7071
|
const ch = await getChannelByName(name);
|
|
7615
7072
|
if (!ch) return c.json({ error: "Channel not found" }, 404);
|
|
7616
|
-
const participants = await
|
|
7617
|
-
|
|
7073
|
+
const [participants, settings] = await Promise.all([
|
|
7074
|
+
getParticipants(ch.id),
|
|
7075
|
+
getChannelSettings(name)
|
|
7076
|
+
]);
|
|
7077
|
+
return c.json({
|
|
7078
|
+
...ch,
|
|
7079
|
+
channel_name: name,
|
|
7080
|
+
participants,
|
|
7081
|
+
settings: formatChannelSettings(settings)
|
|
7082
|
+
});
|
|
7083
|
+
}).patch("/:name", zValidator9("json", channelSettingsSchema), async (c) => {
|
|
7084
|
+
const name = c.req.param("name");
|
|
7085
|
+
const body = c.req.valid("json");
|
|
7086
|
+
const ch = await getChannelByName(name);
|
|
7087
|
+
if (!ch) return c.json({ error: "Channel not found" }, 404);
|
|
7088
|
+
await updateChannelSettings(name, body);
|
|
7089
|
+
const settings = await getChannelSettings(name);
|
|
7090
|
+
return c.json({ ...ch, channel_name: name, settings: formatChannelSettings(settings) });
|
|
7618
7091
|
}).post("/:name/join", async (c) => {
|
|
7619
7092
|
const name = c.req.param("name");
|
|
7620
7093
|
const user = c.get("user");
|
|
@@ -7662,90 +7135,15 @@ import { zValidator as zValidator10 } from "@hono/zod-validator";
|
|
|
7662
7135
|
import { Hono as Hono26 } from "hono";
|
|
7663
7136
|
import { streamSSE as streamSSE5 } from "hono/streaming";
|
|
7664
7137
|
import { z as z10 } from "zod";
|
|
7665
|
-
|
|
7666
|
-
// packages/daemon/src/lib/bridge-outbound.ts
|
|
7667
|
-
function extractContent(contentBlocks) {
|
|
7668
|
-
const text = contentBlocks.filter((b) => b.type === "text").map((b) => b.text).join("\n");
|
|
7669
|
-
const images = contentBlocks.filter((b) => b.type === "image").map((b) => ({ media_type: b.media_type, data: b.data }));
|
|
7670
|
-
return { text, images };
|
|
7671
|
-
}
|
|
7672
|
-
async function routeOutboundBridge(conversationId, senderName, contentBlocks) {
|
|
7673
|
-
try {
|
|
7674
|
-
const conv = await getConversation(conversationId);
|
|
7675
|
-
if (!conv) return;
|
|
7676
|
-
if (conv.type === "channel" && conv.name) {
|
|
7677
|
-
await routeChannelOutbound(conv.name, senderName, contentBlocks);
|
|
7678
|
-
} else if (conv.type === "dm") {
|
|
7679
|
-
await routeDMOutbound(conversationId, senderName, contentBlocks);
|
|
7680
|
-
}
|
|
7681
|
-
} catch (err) {
|
|
7682
|
-
logger_default.error(`bridge outbound failed for conversation ${conversationId}`, logger_default.errorData(err));
|
|
7683
|
-
}
|
|
7684
|
-
}
|
|
7685
|
-
async function routeChannelOutbound(channelName, senderName, contentBlocks) {
|
|
7686
|
-
const bridgeInfo = findBridgeForChannel(channelName);
|
|
7687
|
-
if (!bridgeInfo) return;
|
|
7688
|
-
const driver = getChannelDriver(bridgeInfo.platform);
|
|
7689
|
-
if (!driver) {
|
|
7690
|
-
logger_default.warn(`no channel driver for bridge platform: ${bridgeInfo.platform}`);
|
|
7691
|
-
return;
|
|
7692
|
-
}
|
|
7693
|
-
const { text, images } = extractContent(contentBlocks);
|
|
7694
|
-
if (!text) return;
|
|
7695
|
-
const env = readEnv(sharedEnvPath());
|
|
7696
|
-
env.VOLUTE_SENDER = senderName;
|
|
7697
|
-
await driver.send(env, bridgeInfo.externalChannel, text, images.length > 0 ? images : void 0);
|
|
7698
|
-
logger_default.debug(`bridge outbound: sent to ${bridgeInfo.platform}:${bridgeInfo.externalChannel}`);
|
|
7699
|
-
}
|
|
7700
|
-
async function routeDMOutbound(conversationId, senderName, contentBlocks) {
|
|
7701
|
-
const participants = await getParticipants(conversationId);
|
|
7702
|
-
const puppets = participants.filter((p) => p.userType === "puppet");
|
|
7703
|
-
if (puppets.length === 0) return;
|
|
7704
|
-
const { text, images } = extractContent(contentBlocks);
|
|
7705
|
-
if (!text) return;
|
|
7706
|
-
for (const puppet of puppets) {
|
|
7707
|
-
const colonIdx = puppet.username.indexOf(":");
|
|
7708
|
-
if (colonIdx === -1) {
|
|
7709
|
-
logger_default.warn(
|
|
7710
|
-
`puppet user ${puppet.username} has malformed username (expected platform:id format)`
|
|
7711
|
-
);
|
|
7712
|
-
continue;
|
|
7713
|
-
}
|
|
7714
|
-
const platform = puppet.username.slice(0, colonIdx);
|
|
7715
|
-
const externalUserId = puppet.username.slice(colonIdx + 1);
|
|
7716
|
-
const bridgeConfig = getBridgeConfig(platform);
|
|
7717
|
-
if (!bridgeConfig?.enabled) continue;
|
|
7718
|
-
const driver = getChannelDriver(platform);
|
|
7719
|
-
if (!driver?.createConversation) {
|
|
7720
|
-
logger_default.warn(`no channel driver with DM support for bridge platform: ${platform}`);
|
|
7721
|
-
continue;
|
|
7722
|
-
}
|
|
7723
|
-
try {
|
|
7724
|
-
const env = readEnv(sharedEnvPath());
|
|
7725
|
-
env.VOLUTE_SENDER = senderName;
|
|
7726
|
-
env.VOLUTE_MIND = senderName;
|
|
7727
|
-
env.VOLUTE_MIND_DIR = mindDir(senderName);
|
|
7728
|
-
const slug = await driver.createConversation(env, [externalUserId]);
|
|
7729
|
-
await driver.send(env, slug, text, images.length > 0 ? images : void 0);
|
|
7730
|
-
logger_default.debug(`bridge outbound DM: sent to ${platform}:${externalUserId}`);
|
|
7731
|
-
} catch (err) {
|
|
7732
|
-
logger_default.error(`bridge outbound DM failed for puppet ${puppet.username}`, logger_default.errorData(err));
|
|
7733
|
-
}
|
|
7734
|
-
}
|
|
7735
|
-
}
|
|
7736
|
-
|
|
7737
|
-
// packages/daemon/src/web/api/volute/chat.ts
|
|
7738
7138
|
async function fanOutToMinds(opts) {
|
|
7739
|
-
const participants =
|
|
7139
|
+
const participants = opts.participants;
|
|
7740
7140
|
const mindParticipants = participants.filter(
|
|
7741
7141
|
(p) => p.userType === "mind" || p.userType === "system"
|
|
7742
7142
|
);
|
|
7743
7143
|
const participantNames = participants.map((p) => p.username);
|
|
7744
7144
|
const isDM = opts.isDM ?? participants.length === 2;
|
|
7745
|
-
const
|
|
7746
|
-
const
|
|
7747
|
-
const manager = getMindManager2();
|
|
7748
|
-
const sm = getSleepManagerIfReady2();
|
|
7145
|
+
const manager = getMindManager();
|
|
7146
|
+
const sm = getSleepManagerIfReady();
|
|
7749
7147
|
const targetMinds = mindParticipants.map((ap) => {
|
|
7750
7148
|
const key = opts.targetName ? opts.targetName(ap.username) : ap.username;
|
|
7751
7149
|
if (manager.isRunning(key) || sm?.isSleeping(ap.username)) return ap.username;
|
|
@@ -7755,7 +7153,6 @@ async function fanOutToMinds(opts) {
|
|
|
7755
7153
|
return buildVoluteSlug({
|
|
7756
7154
|
participants,
|
|
7757
7155
|
mindUsername,
|
|
7758
|
-
convTitle: opts.convTitle,
|
|
7759
7156
|
conversationId: opts.conversationId,
|
|
7760
7157
|
...opts.slugExtra
|
|
7761
7158
|
});
|
|
@@ -7868,17 +7265,14 @@ var unifiedChatApp = new Hono26().post(
|
|
|
7868
7265
|
}
|
|
7869
7266
|
participantIds.push(mindUser.id);
|
|
7870
7267
|
if (participantIds.length === 2) {
|
|
7871
|
-
const existing = await findDMConversation(
|
|
7268
|
+
const existing = await findDMConversation(participantIds);
|
|
7872
7269
|
if (existing) {
|
|
7873
7270
|
conversationId = existing;
|
|
7874
7271
|
}
|
|
7875
7272
|
}
|
|
7876
7273
|
if (!conversationId) {
|
|
7877
|
-
const
|
|
7878
|
-
const title = [...participantNames].join(", ");
|
|
7879
|
-
const conv2 = await createConversation(baseName, "volute", {
|
|
7274
|
+
const conv2 = await createConversation({
|
|
7880
7275
|
userId: user.id !== 0 ? user.id : void 0,
|
|
7881
|
-
title,
|
|
7882
7276
|
participantIds
|
|
7883
7277
|
});
|
|
7884
7278
|
conversationId = conv2.id;
|
|
@@ -7891,14 +7285,14 @@ var unifiedChatApp = new Hono26().post(
|
|
|
7891
7285
|
}
|
|
7892
7286
|
const conv = await getConversation(conversationId);
|
|
7893
7287
|
if (!conv) return c.json({ error: "Conversation not found" }, 404);
|
|
7894
|
-
const
|
|
7288
|
+
const convName = conv.type === "channel" ? await getChannelName(conversationId) : null;
|
|
7289
|
+
const participants = await getParticipants(conversationId);
|
|
7895
7290
|
const fileNotifications = [];
|
|
7896
7291
|
if (body.files && body.files.length > 0) {
|
|
7897
7292
|
let fileTargets;
|
|
7898
7293
|
if (baseName) {
|
|
7899
7294
|
fileTargets = [baseName];
|
|
7900
7295
|
} else {
|
|
7901
|
-
const participants = await getParticipants(conversationId);
|
|
7902
7296
|
fileTargets = participants.filter((p) => p.userType === "mind" && p.username !== senderName).map((p) => p.username);
|
|
7903
7297
|
}
|
|
7904
7298
|
const { notifications, error } = stageFilesForMinds(body.files, fileTargets, senderName);
|
|
@@ -7915,6 +7309,25 @@ var unifiedChatApp = new Hono26().post(
|
|
|
7915
7309
|
contentBlocks.push({ type: "image", media_type: img.media_type, data: img.data });
|
|
7916
7310
|
}
|
|
7917
7311
|
}
|
|
7312
|
+
if (senderIsMind && conv.type === "channel" && convName) {
|
|
7313
|
+
try {
|
|
7314
|
+
const chSettings = await getChannelSettings(convName);
|
|
7315
|
+
if (chSettings?.char_limit) {
|
|
7316
|
+
for (const block of contentBlocks) {
|
|
7317
|
+
if (block.type === "text" && block.text.length > chSettings.char_limit) {
|
|
7318
|
+
return c.json(
|
|
7319
|
+
{
|
|
7320
|
+
error: `Message exceeds channel character limit (${chSettings.char_limit}). Shorten your message and try again.`
|
|
7321
|
+
},
|
|
7322
|
+
400
|
|
7323
|
+
);
|
|
7324
|
+
}
|
|
7325
|
+
}
|
|
7326
|
+
}
|
|
7327
|
+
} catch (err) {
|
|
7328
|
+
logger_default.warn("failed to look up channel char_limit, skipping enforcement", logger_default.errorData(err));
|
|
7329
|
+
}
|
|
7330
|
+
}
|
|
7918
7331
|
const message = await addMessage(conversationId, "user", senderName, contentBlocks);
|
|
7919
7332
|
let outboundId;
|
|
7920
7333
|
if (senderIsMind) {
|
|
@@ -7922,12 +7335,11 @@ var unifiedChatApp = new Hono26().post(
|
|
|
7922
7335
|
logger_default.warn("outbound bridge routing failed", logger_default.errorData(err));
|
|
7923
7336
|
});
|
|
7924
7337
|
const channel = buildVoluteSlug({
|
|
7925
|
-
participants
|
|
7338
|
+
participants,
|
|
7926
7339
|
mindUsername: senderName,
|
|
7927
|
-
convTitle,
|
|
7928
7340
|
conversationId,
|
|
7929
7341
|
convType: conv.type,
|
|
7930
|
-
convName
|
|
7342
|
+
convName
|
|
7931
7343
|
});
|
|
7932
7344
|
try {
|
|
7933
7345
|
outboundId = await recordOutbound(senderName, channel, extractTextContent(contentBlocks), {
|
|
@@ -7942,15 +7354,14 @@ var unifiedChatApp = new Hono26().post(
|
|
|
7942
7354
|
conversationId,
|
|
7943
7355
|
contentBlocks,
|
|
7944
7356
|
senderName,
|
|
7945
|
-
|
|
7357
|
+
participants,
|
|
7946
7358
|
isDM,
|
|
7947
|
-
slugExtra: { convType: conv.type, convName
|
|
7359
|
+
slugExtra: { convType: conv.type, convName },
|
|
7948
7360
|
// Variant-aware targeting: when targetMind is a variant, route to the variant name
|
|
7949
7361
|
targetName: baseName ? (username) => username === baseName ? variantName : username : void 0
|
|
7950
7362
|
});
|
|
7951
7363
|
const systemReplyTarget = baseName ?? senderName;
|
|
7952
7364
|
if (senderIsMind && body.message) {
|
|
7953
|
-
const participants = await getParticipants(conversationId);
|
|
7954
7365
|
const hasSystemUser = participants.some((p) => p.userType === "system");
|
|
7955
7366
|
if (hasSystemUser) {
|
|
7956
7367
|
generateSystemReply(conversationId, systemReplyTarget, body.message).catch(
|
|
@@ -7978,11 +7389,11 @@ var app23 = new Hono26().get("/:name/conversations/:id/events", async (c) => {
|
|
|
7978
7389
|
if (!stream.aborted) console.error("[chat] SSE ping error:", err);
|
|
7979
7390
|
});
|
|
7980
7391
|
}, 15e3);
|
|
7981
|
-
await new Promise((
|
|
7392
|
+
await new Promise((resolve17) => {
|
|
7982
7393
|
stream.onAbort(() => {
|
|
7983
7394
|
unsubscribe();
|
|
7984
7395
|
clearInterval(keepAlive);
|
|
7985
|
-
|
|
7396
|
+
resolve17();
|
|
7986
7397
|
});
|
|
7987
7398
|
});
|
|
7988
7399
|
});
|
|
@@ -7994,7 +7405,6 @@ import { zValidator as zValidator11 } from "@hono/zod-validator";
|
|
|
7994
7405
|
import { Hono as Hono27 } from "hono";
|
|
7995
7406
|
import { z as z11 } from "zod";
|
|
7996
7407
|
var createConvSchema = z11.object({
|
|
7997
|
-
title: z11.string().optional(),
|
|
7998
7408
|
participantIds: z11.array(z11.number()).optional(),
|
|
7999
7409
|
participantNames: z11.array(z11.string()).optional()
|
|
8000
7410
|
});
|
|
@@ -8006,8 +7416,7 @@ var app24 = new Hono27().get("/:name/conversations", async (c) => {
|
|
|
8006
7416
|
const mindUser = await getOrCreateMindUser(name);
|
|
8007
7417
|
lookupId = mindUser.id;
|
|
8008
7418
|
}
|
|
8009
|
-
const
|
|
8010
|
-
const convs = all.filter((c2) => c2.mind_name === name || c2.type === "channel");
|
|
7419
|
+
const convs = await listConversationsForUser(lookupId);
|
|
8011
7420
|
return c.json(convs);
|
|
8012
7421
|
}).post("/:name/conversations", zValidator11("json", createConvSchema), async (c) => {
|
|
8013
7422
|
const name = c.req.param("name");
|
|
@@ -8055,20 +7464,15 @@ var app24 = new Hono27().get("/:name/conversations", async (c) => {
|
|
|
8055
7464
|
return c.json({ error: "Use channels for multi-participant conversations" }, 400);
|
|
8056
7465
|
}
|
|
8057
7466
|
if (participantIds.length === 2) {
|
|
8058
|
-
const existingId = await findDMConversation(
|
|
7467
|
+
const existingId = await findDMConversation(participantIds);
|
|
8059
7468
|
if (existingId) {
|
|
8060
7469
|
const conv2 = await getConversation(existingId);
|
|
8061
7470
|
if (conv2) return c.json(conv2);
|
|
8062
7471
|
console.warn(`[conversations] DM conversation ${existingId} found but not retrievable`);
|
|
8063
7472
|
}
|
|
8064
7473
|
}
|
|
8065
|
-
|
|
8066
|
-
if (!title && body.participantNames?.length) {
|
|
8067
|
-
title = body.participantNames.join(", ");
|
|
8068
|
-
}
|
|
8069
|
-
const conv = await createConversation(name, "volute", {
|
|
7474
|
+
const conv = await createConversation({
|
|
8070
7475
|
userId: user.id !== 0 ? user.id : void 0,
|
|
8071
|
-
title,
|
|
8072
7476
|
participantIds
|
|
8073
7477
|
});
|
|
8074
7478
|
return c.json(conv, 201);
|
|
@@ -8146,10 +7550,11 @@ app25.use(
|
|
|
8146
7550
|
credentials: false
|
|
8147
7551
|
})
|
|
8148
7552
|
);
|
|
7553
|
+
var csrfMiddleware = csrf();
|
|
8149
7554
|
app25.use("/api/*", async (c, next) => {
|
|
8150
7555
|
const auth = c.req.header("Authorization");
|
|
8151
7556
|
if (auth?.startsWith("Bearer ") && auth.length > 7) return next();
|
|
8152
|
-
return
|
|
7557
|
+
return csrfMiddleware(c, next);
|
|
8153
7558
|
});
|
|
8154
7559
|
app25.get("/api/health", (c) => {
|
|
8155
7560
|
let version = "unknown";
|
|
@@ -8198,10 +7603,10 @@ app25.route("/api/conversations", conversations_default);
|
|
|
8198
7603
|
var app_default = app25;
|
|
8199
7604
|
|
|
8200
7605
|
// packages/daemon/src/web/server.ts
|
|
8201
|
-
import { existsSync as
|
|
7606
|
+
import { existsSync as existsSync10 } from "fs";
|
|
8202
7607
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
8203
7608
|
import { createServer as createHttpsServer } from "https";
|
|
8204
|
-
import { dirname as dirname2, extname as extname3, resolve as
|
|
7609
|
+
import { dirname as dirname2, extname as extname3, resolve as resolve15 } from "path";
|
|
8205
7610
|
import { serve } from "@hono/node-server";
|
|
8206
7611
|
var MIME_TYPES2 = {
|
|
8207
7612
|
".html": "text/html",
|
|
@@ -8220,8 +7625,8 @@ async function startServer({
|
|
|
8220
7625
|
let assetsDir = "";
|
|
8221
7626
|
let searchDir = dirname2(new URL(import.meta.url).pathname);
|
|
8222
7627
|
for (let i = 0; i < 5; i++) {
|
|
8223
|
-
const candidate =
|
|
8224
|
-
if (
|
|
7628
|
+
const candidate = resolve15(searchDir, "dist", "web-assets");
|
|
7629
|
+
if (existsSync10(candidate)) {
|
|
8225
7630
|
assetsDir = candidate;
|
|
8226
7631
|
break;
|
|
8227
7632
|
}
|
|
@@ -8231,20 +7636,24 @@ async function startServer({
|
|
|
8231
7636
|
app_default.get("*", async (c) => {
|
|
8232
7637
|
const urlPath = new URL(c.req.url).pathname;
|
|
8233
7638
|
if (urlPath.startsWith("/api/") || urlPath.startsWith("/ext/")) return c.notFound();
|
|
8234
|
-
const filePath =
|
|
7639
|
+
const filePath = resolve15(assetsDir, urlPath.slice(1));
|
|
8235
7640
|
if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
|
|
8236
7641
|
const s = await stat2(filePath).catch(() => null);
|
|
8237
7642
|
if (s?.isFile()) {
|
|
8238
7643
|
const ext = extname3(filePath);
|
|
8239
7644
|
const mime = MIME_TYPES2[ext] || "application/octet-stream";
|
|
8240
7645
|
const body = await readFile2(filePath);
|
|
8241
|
-
|
|
7646
|
+
const basename = filePath.slice(filePath.lastIndexOf("/") + 1);
|
|
7647
|
+
const nameWithoutExt = basename.slice(0, basename.lastIndexOf("."));
|
|
7648
|
+
const isHashed = /[-.][\da-f]{8,}$/.test(nameWithoutExt);
|
|
7649
|
+
const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
|
|
7650
|
+
return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
|
|
8242
7651
|
}
|
|
8243
|
-
const indexPath =
|
|
7652
|
+
const indexPath = resolve15(assetsDir, "index.html");
|
|
8244
7653
|
const indexStat = await stat2(indexPath).catch(() => null);
|
|
8245
7654
|
if (indexStat?.isFile()) {
|
|
8246
7655
|
const body = await readFile2(indexPath, "utf-8");
|
|
8247
|
-
return c.html(body);
|
|
7656
|
+
return c.html(body, 200, { "Cache-Control": "no-cache" });
|
|
8248
7657
|
}
|
|
8249
7658
|
return c.text("Not found", 404);
|
|
8250
7659
|
});
|
|
@@ -8257,10 +7666,10 @@ async function startServer({
|
|
|
8257
7666
|
createServer: createHttpsServer,
|
|
8258
7667
|
serverOptions: { key: tls.key, cert: tls.cert }
|
|
8259
7668
|
});
|
|
8260
|
-
await new Promise((
|
|
7669
|
+
await new Promise((resolve17, reject) => {
|
|
8261
7670
|
server2.on("listening", () => {
|
|
8262
7671
|
logger_default.info("Volute UI running (https)", { hostname, port });
|
|
8263
|
-
|
|
7672
|
+
resolve17();
|
|
8264
7673
|
});
|
|
8265
7674
|
server2.on("error", (err) => {
|
|
8266
7675
|
reject(err);
|
|
@@ -8268,13 +7677,13 @@ async function startServer({
|
|
|
8268
7677
|
});
|
|
8269
7678
|
const internalPort = port + 1;
|
|
8270
7679
|
const internalServer = serve({ fetch: app_default.fetch, port: internalPort, hostname: "127.0.0.1" });
|
|
8271
|
-
await new Promise((
|
|
7680
|
+
await new Promise((resolve17, reject) => {
|
|
8272
7681
|
internalServer.on("listening", () => {
|
|
8273
7682
|
logger_default.info("Volute API running (http, internal)", {
|
|
8274
7683
|
hostname: "127.0.0.1",
|
|
8275
7684
|
port: internalPort
|
|
8276
7685
|
});
|
|
8277
|
-
|
|
7686
|
+
resolve17();
|
|
8278
7687
|
});
|
|
8279
7688
|
internalServer.on("error", (err) => {
|
|
8280
7689
|
reject(err);
|
|
@@ -8283,10 +7692,10 @@ async function startServer({
|
|
|
8283
7692
|
return { server: server2, internalPort };
|
|
8284
7693
|
}
|
|
8285
7694
|
const server = serve({ fetch: app_default.fetch, port, hostname });
|
|
8286
|
-
await new Promise((
|
|
7695
|
+
await new Promise((resolve17, reject) => {
|
|
8287
7696
|
server.on("listening", () => {
|
|
8288
7697
|
logger_default.info("Volute API running (http)", { hostname, port });
|
|
8289
|
-
|
|
7698
|
+
resolve17();
|
|
8290
7699
|
});
|
|
8291
7700
|
server.on("error", (err) => {
|
|
8292
7701
|
reject(err);
|
|
@@ -8297,7 +7706,7 @@ async function startServer({
|
|
|
8297
7706
|
|
|
8298
7707
|
// packages/daemon/src/daemon.ts
|
|
8299
7708
|
if (!process.env.VOLUTE_HOME) {
|
|
8300
|
-
process.env.VOLUTE_HOME =
|
|
7709
|
+
process.env.VOLUTE_HOME = resolve16(homedir3(), ".volute");
|
|
8301
7710
|
}
|
|
8302
7711
|
if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
|
|
8303
7712
|
process.env.TZ = process.env.VOLUTE_TIMEZONE;
|
|
@@ -8308,7 +7717,7 @@ async function startDaemon(opts) {
|
|
|
8308
7717
|
const home = voluteHome();
|
|
8309
7718
|
const systemDir = voluteSystemDir();
|
|
8310
7719
|
if (!opts.foreground) {
|
|
8311
|
-
const rotatingLog = new RotatingLog(
|
|
7720
|
+
const rotatingLog = new RotatingLog(resolve16(systemDir, "daemon.log"));
|
|
8312
7721
|
logger_default.setOutput((line) => rotatingLog.write(`${line}
|
|
8313
7722
|
`));
|
|
8314
7723
|
const write = (...args) => rotatingLog.write(`${format(...args)}
|
|
@@ -8318,22 +7727,22 @@ async function startDaemon(opts) {
|
|
|
8318
7727
|
console.warn = write;
|
|
8319
7728
|
console.info = write;
|
|
8320
7729
|
}
|
|
8321
|
-
const DAEMON_PID_PATH =
|
|
8322
|
-
const DAEMON_JSON_PATH =
|
|
7730
|
+
const DAEMON_PID_PATH = resolve16(systemDir, "daemon.pid");
|
|
7731
|
+
const DAEMON_JSON_PATH = resolve16(systemDir, "daemon.json");
|
|
8323
7732
|
mkdirSync10(home, { recursive: true });
|
|
8324
7733
|
ensureSystemDir();
|
|
8325
|
-
const { migrateSetupCompleted } = await import("./setup-
|
|
7734
|
+
const { migrateSetupCompleted } = await import("./setup-PF7JSFMO.js");
|
|
8326
7735
|
migrateSetupCompleted();
|
|
8327
|
-
await (await import("./db-
|
|
7736
|
+
await (await import("./db-CBOCDYVA.js")).getDb();
|
|
8328
7737
|
try {
|
|
8329
7738
|
const { eq: eq7, and: and5 } = await import("drizzle-orm");
|
|
8330
|
-
const { users: users2 } = await import("./schema-
|
|
8331
|
-
const db = await (await import("./db-
|
|
7739
|
+
const { users: users2 } = await import("./schema-K575EBPE.js");
|
|
7740
|
+
const db = await (await import("./db-CBOCDYVA.js")).getDb();
|
|
8332
7741
|
await db.update(users2).set({ role: "system" }).where(and5(eq7(users2.user_type, "system"), eq7(users2.role, "user")));
|
|
8333
7742
|
} catch (err) {
|
|
8334
7743
|
logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
|
|
8335
7744
|
}
|
|
8336
|
-
const { initSandbox } = await import("./sandbox-
|
|
7745
|
+
const { initSandbox } = await import("./sandbox-PQYEICEF.js");
|
|
8337
7746
|
await initSandbox();
|
|
8338
7747
|
try {
|
|
8339
7748
|
await syncBuiltinSkills();
|
|
@@ -8360,7 +7769,7 @@ async function startDaemon(opts) {
|
|
|
8360
7769
|
logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
|
|
8361
7770
|
}
|
|
8362
7771
|
try {
|
|
8363
|
-
const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-
|
|
7772
|
+
const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-2QOOPMBX.js");
|
|
8364
7773
|
await getOrCreateSystemUser2();
|
|
8365
7774
|
} catch (err) {
|
|
8366
7775
|
logger_default.warn(
|
|
@@ -8371,7 +7780,7 @@ async function startDaemon(opts) {
|
|
|
8371
7780
|
const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes(32).toString("hex");
|
|
8372
7781
|
let tls;
|
|
8373
7782
|
if (opts.tailscale) {
|
|
8374
|
-
const { getTailscaleTls } = await import("./tailscale-
|
|
7783
|
+
const { getTailscaleTls } = await import("./tailscale-LTYNKIPZ.js");
|
|
8375
7784
|
const tlsConfig = await getTailscaleTls();
|
|
8376
7785
|
tls = { key: tlsConfig.key, cert: tlsConfig.cert };
|
|
8377
7786
|
logger_default.info("Tailscale HTTPS enabled", { hostname: tlsConfig.hostname });
|
|
@@ -8444,10 +7853,10 @@ async function startDaemon(opts) {
|
|
|
8444
7853
|
await Promise.all(workers);
|
|
8445
7854
|
}
|
|
8446
7855
|
try {
|
|
8447
|
-
const { isSetupComplete: isSetupComplete2 } = await import("./setup-
|
|
7856
|
+
const { isSetupComplete: isSetupComplete2 } = await import("./setup-PF7JSFMO.js");
|
|
8448
7857
|
if (isSetupComplete2()) {
|
|
8449
|
-
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-
|
|
8450
|
-
const { startSpiritFull } = await import("./mind-service-
|
|
7858
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-SM6ARJ2N.js");
|
|
7859
|
+
const { startSpiritFull } = await import("./mind-service-UDXF5WC2.js");
|
|
8451
7860
|
await ensureSpiritProject();
|
|
8452
7861
|
await syncSpiritTemplate();
|
|
8453
7862
|
const spiritEntry = await findMind("volute");
|
|
@@ -8464,7 +7873,7 @@ async function startDaemon(opts) {
|
|
|
8464
7873
|
bridgeManager.startBridges(daemonPort).catch((err) => {
|
|
8465
7874
|
logger_default.warn("failed to start bridges", logger_default.errorData(err));
|
|
8466
7875
|
});
|
|
8467
|
-
import("./cloud-sync-
|
|
7876
|
+
import("./cloud-sync-OIX576NA.js").then(
|
|
8468
7877
|
({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
|
|
8469
7878
|
logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
|
|
8470
7879
|
})
|
|
@@ -8472,7 +7881,7 @@ async function startDaemon(opts) {
|
|
|
8472
7881
|
logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
|
|
8473
7882
|
});
|
|
8474
7883
|
try {
|
|
8475
|
-
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-
|
|
7884
|
+
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-CSE4NBYM.js");
|
|
8476
7885
|
backfillTemplateHashes();
|
|
8477
7886
|
notifyVersionUpdate().catch((err) => {
|
|
8478
7887
|
logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
|
|
@@ -8493,13 +7902,13 @@ async function startDaemon(opts) {
|
|
|
8493
7902
|
logger_default.info(`running on ${hostname}:${port}, pid ${myPid}`);
|
|
8494
7903
|
function cleanup() {
|
|
8495
7904
|
try {
|
|
8496
|
-
if (
|
|
7905
|
+
if (readFileSync10(DAEMON_PID_PATH, "utf-8").trim() === myPid) {
|
|
8497
7906
|
unlinkSync2(DAEMON_PID_PATH);
|
|
8498
7907
|
}
|
|
8499
7908
|
} catch {
|
|
8500
7909
|
}
|
|
8501
7910
|
try {
|
|
8502
|
-
const data = JSON.parse(
|
|
7911
|
+
const data = JSON.parse(readFileSync10(DAEMON_JSON_PATH, "utf-8"));
|
|
8503
7912
|
if (data.token === token) {
|
|
8504
7913
|
unlinkSync2(DAEMON_JSON_PATH);
|
|
8505
7914
|
}
|