volute 0.48.0 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -328
- package/dist/{activity-events-MIOK3IOU.js → activity-events-GJJAI2WT.js} +4 -4
- package/dist/{ai-service-643TNFPH.js → ai-service-A7FS7EC3.js} +5 -5
- package/dist/{archive-6Z4GFQPH.js → archive-7E3YE6VF.js} +3 -3
- package/dist/{auth-A4VGHADI.js → auth-ABYLOEZ7.js} +5 -5
- package/dist/{avatar-image-Y45R7LW5.js → avatar-image-6ATV2IOZ.js} +4 -4
- package/dist/{backup-UDH4GMSW.js → backup-XYAMT4CU.js} +15 -15
- package/dist/{chat-X43VYHH2.js → chat-OGXAEXMV.js} +2 -2
- package/dist/{chunk-LTLFOSA4.js → chunk-3B427GUK.js} +3 -3
- package/dist/{chunk-XVBSFLM7.js → chunk-4B62E4CG.js} +2 -2
- package/dist/{chunk-ODDGGLM6.js → chunk-4DSGN4FL.js} +3 -3
- package/dist/{chunk-PJVPDY2Z.js → chunk-6HGEZJDH.js} +2 -2
- package/dist/{chunk-MJRXFUMS.js → chunk-DAIIMBLB.js} +3 -3
- package/dist/{chunk-DGGZVZTM.js → chunk-DVN6DNMI.js} +1 -1
- package/dist/chunk-EADX54RG.js +113 -0
- package/dist/{chunk-EIQDZC43.js → chunk-EFT2OALG.js} +6 -2
- package/dist/{chunk-OQJMTHEH.js → chunk-EG5LSKHU.js} +2 -2
- package/dist/{chunk-WQ46E33M.js → chunk-FBBS4BVR.js} +2 -2
- package/dist/{chunk-HUNDXZBZ.js → chunk-GWVFDUNB.js} +45 -14
- package/dist/{chunk-FJ2MZ5PH.js → chunk-HCYQRME2.js} +2 -2
- package/dist/{chunk-T4VS7UDW.js → chunk-IH5TKXX6.js} +9 -9
- package/dist/{chunk-Q7HOAVFR.js → chunk-JBIFXB6I.js} +4 -4
- package/dist/{chunk-WARH6GIV.js → chunk-JCBPU57A.js} +12 -10
- package/dist/{chunk-VZRA5TYO.js → chunk-JCWB2ITW.js} +2 -2
- package/dist/{chunk-MOERAQXH.js → chunk-JPGHSXSV.js} +18 -25
- package/dist/{chunk-USD45JKR.js → chunk-K3JOLGWF.js} +7 -7
- package/dist/{chunk-3YUBFTDN.js → chunk-KHCKZ36O.js} +1 -1
- package/dist/{chunk-7KRIHYLR.js → chunk-L27YYONJ.js} +2 -2
- package/dist/{chunk-SZJCJVXV.js → chunk-MG3Z34YE.js} +2 -2
- package/dist/{chunk-5KXCM5AW.js → chunk-NJHN6IRB.js} +9 -1
- package/dist/{chunk-2OIYNHWO.js → chunk-NOIAHMJB.js} +1 -1
- package/dist/{chunk-2MJ7EOMT.js → chunk-P4LHVRNE.js} +1 -0
- package/dist/{chunk-IJPMIEVE.js → chunk-PY24ZL62.js} +1 -1
- package/dist/{chunk-VB2QXUJQ.js → chunk-QQBOI3QA.js} +202 -117
- package/dist/{chunk-T2TP6ZC6.js → chunk-QUSMYGNQ.js} +6 -0
- package/dist/{chunk-WW6C3PLV.js → chunk-RSBL3FAD.js} +39 -6
- package/dist/{chunk-YKA7DCVW.js → chunk-SX72DOO3.js} +1 -1
- package/dist/{chunk-4FCL4DVZ.js → chunk-TXJL36ZQ.js} +2 -2
- package/dist/{chunk-HNGFKPNS.js → chunk-VIUH5CHQ.js} +55 -23
- package/dist/{chunk-HPGN6XRT.js → chunk-VNRSXEBF.js} +4 -4
- package/dist/{chunk-IYCV34IU.js → chunk-XTEKINWG.js} +3 -3
- package/dist/{chunk-YNBXEQAP.js → chunk-YIJGKHIS.js} +3 -3
- package/dist/{chunk-MTRMQFCQ.js → chunk-ZX46PGCC.js} +2 -2
- package/dist/cli.js +20 -20
- package/dist/{clock-CNRF6F7T.js → clock-6JZL2FS6.js} +2 -2
- package/dist/{cloud-sync-WHKCB4CD.js → cloud-sync-VFDTNNCA.js} +20 -20
- package/dist/{conversations-C7IKYSHD.js → conversations-TUM5PJJ4.js} +5 -5
- package/dist/{create-GJKHABJB.js → create-Z5FSDNVZ.js} +1 -1
- package/dist/{daemon-restart-7KUHVZIN.js → daemon-restart-54L4B6AQ.js} +7 -7
- package/dist/daemon.js +647 -410
- package/dist/{db-FO6LXYCW.js → db-F6UMFRYD.js} +2 -2
- package/dist/delivery-manager-RBXBPVWM.js +36 -0
- package/dist/{delivery-router-3QFG2ZEX.js → delivery-router-VUOL5YSA.js} +8 -6
- package/dist/{down-G6IADJXV.js → down-6X7KX7BZ.js} +5 -5
- package/dist/echo-text-B6NZ5FGE.js +36 -0
- package/dist/{env-6TGPO5WG.js → env-KUL4XKN2.js} +3 -3
- package/dist/{exec-QIFYZG4C.js → exec-FBXA3CM4.js} +3 -3
- package/dist/{export-C2K3NIRD.js → export-TNBPDH77.js} +3 -3
- package/dist/{extensions-GEKF47A4.js → extensions-AWNO3SZF.js} +20 -20
- package/dist/{files-LXQSQOFG.js → files-BVBRJJ2P.js} +3 -3
- package/dist/{import-SX3ZXHB4.js → import-ZUNKMCKC.js} +7 -7
- package/dist/{isolation-MCT4ZYLT.js → isolation-OPCZQRTH.js} +3 -3
- package/dist/{login-CL4IT2ED.js → login-KAKNFCW5.js} +6 -6
- package/dist/{logout-HZYJCYCA.js → logout-RLT62RQP.js} +2 -2
- package/dist/message-delivery-ABPV76EA.js +42 -0
- package/dist/{mind-46AOK373.js → mind-IF6CGMFW.js} +12 -12
- package/dist/{mind-activity-tracker-YVZPC4A5.js → mind-activity-tracker-YMMERB6B.js} +5 -5
- package/dist/mind-service-42GDO4KH.js +44 -0
- package/dist/{mind-sleep-DV7KP255.js → mind-sleep-VBV7YRSU.js} +2 -2
- package/dist/{notices-2KU5NTRY.js → notices-N6BCGHFV.js} +4 -4
- package/dist/{package-RTN2PS7O.js → package-PD67VPHB.js} +5 -4
- package/dist/prompts-MDHDLWEX.js +24 -0
- package/dist/{registry-UMMDRPRM.js → registry-3ELJPUGJ.js} +6 -2
- package/dist/{sandbox-5VQ454XP.js → sandbox-XPYA7UIF.js} +5 -5
- package/dist/scheduler-K7Y7Z7FQ.js +34 -0
- package/dist/{schema-VEVO7HG6.js → schema-6YONVTKZ.js} +1 -1
- package/dist/{seed-F2HXZQU4.js → seed-NQED7PSX.js} +1 -1
- package/dist/{seed-cmd-MLCTGSX5.js → seed-cmd-QF3F2G4S.js} +2 -2
- package/dist/{seed-create-KQ7OILWB.js → seed-create-XOO4N2OE.js} +3 -3
- package/dist/{seed-readiness-RBPGOLSZ.js → seed-readiness-3LRYASA4.js} +5 -5
- package/dist/{seed-sprout-HVYCFJLA.js → seed-sprout-HSBBGSS2.js} +11 -11
- package/dist/{send-TD2X5U3K.js → send-IHRJYNXA.js} +6 -6
- package/dist/{service-CVZMQYK6.js → service-YCOPCTSZ.js} +4 -4
- package/dist/{service-install-VCRMFWX5.js → service-install-Y46OTF55.js} +5 -5
- package/dist/{setup-AE4CVUC4.js → setup-F4TE64YI.js} +7 -7
- package/dist/{setup-5ECWTYKG.js → setup-TCN7VH5U.js} +5 -3
- package/dist/skills/volute-mind/SKILL.md +3 -3
- package/dist/skills/volute-mind/references/routing.md +6 -5
- package/dist/skills/volute-mind/references/variants.md +48 -14
- package/dist/{skills-B3SVDCEB.js → skills-NN5UZCUU.js} +8 -6
- package/dist/sleep-manager-DSPXFHGX.js +38 -0
- package/dist/spirit-SSJMYC6A.js +31 -0
- package/dist/{split-SKZ4Y2D6.js → split-JF2VWTXA.js} +4 -1
- package/dist/{sprout-KQ43BWZJ.js → sprout-AXA2SECQ.js} +1 -1
- package/dist/{status-F4PGREUU.js → status-VJGXMQ4L.js} +5 -5
- package/dist/system-chat-M2XOBKEM.js +40 -0
- package/dist/{systems-JJNGQHAO.js → systems-5MH2ELQE.js} +2 -2
- package/dist/{tailscale-MCLY5GYE.js → tailscale-AMMVKDXB.js} +3 -3
- package/dist/{template-staleness-EMQORSGG.js → template-staleness-HKGCTS3H.js} +4 -4
- package/dist/{turn-tracker-KLPV3PAU.js → turn-tracker-JQ2YUUY2.js} +7 -7
- package/dist/{up-RVGDE6CQ.js → up-SDLTLPAO.js} +6 -6
- package/dist/{update-OXQEGGXD.js → update-WEA4N2TR.js} +5 -5
- package/dist/{update-check-266R4ZSY.js → update-check-DZOTONII.js} +3 -3
- package/dist/variant-cleanup-P4MBNLJD.js +33 -0
- package/dist/{version-notify-73YURTFR.js → version-notify-WFA5XB5A.js} +23 -23
- package/dist/web-assets/assets/index-BostMFoR.css +1 -0
- package/dist/web-assets/assets/index-CKlqUkyG.js +92 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0013_variant_purpose.sql +3 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +5 -4
- package/templates/_base/.init/.local/hooks/startup-context.ts +19 -2
- package/templates/_base/home/VOLUTE.md +13 -1
- package/templates/_base/src/lib/daemon-client.ts +27 -7
- package/templates/claude/src/agent.ts +1 -1
- package/templates/claude/src/lib/hooks/identity-reload.ts +12 -3
- package/templates/pi/src/lib/event-handler.ts +47 -6
- package/dist/delivery-manager-HZTT5SJR.js +0 -36
- package/dist/echo-text-H3SH337Q.js +0 -36
- package/dist/message-delivery-GPQ5SE5N.js +0 -40
- package/dist/mind-service-2ARGJNKP.js +0 -44
- package/dist/scheduler-I7JZCT47.js +0 -34
- package/dist/sleep-manager-Z27R3WTW.js +0 -38
- package/dist/spirit-WXS3HCLN.js +0 -25
- package/dist/system-chat-63ABFF6V.js +0 -40
- package/dist/web-assets/assets/index-WdZ60R6c.css +0 -1
- package/dist/web-assets/assets/index-taX6Ezfa.js +0 -92
- package/dist/{env-C7Z55QCJ.js → env-ZYMSCB7B.js} +5 -5
- package/dist/{login-ARRZ4ORJ.js → login-LKNLCJPA.js} +3 -3
- package/dist/{mind-contacts-GV7XYL5D.js → mind-contacts-BKUFPUCU.js} +6 -6
- package/dist/{mind-history-TTGA5BHZ.js → mind-history-WI5OI3BW.js} +4 -4
- package/dist/{register-42VBJKTP.js → register-TWQDKQRT.js} +3 -3
- package/dist/{restart-YYEGZJDD.js → restart-5F5QDBOG.js} +4 -4
- package/dist/{skill-UUM4JZRF.js → skill-4CYJLYVY.js} +4 -4
- package/dist/{src-WLJE73NP.js → src-ZN4LXMPI.js} +3 -3
- package/dist/{start-O6UKK7BG.js → start-BTVMTP3K.js} +3 -3
- package/dist/{stop-UBX6X5RA.js → stop-YORESK4U.js} +4 -4
package/dist/daemon.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
readBackupState,
|
|
7
7
|
resticVersion,
|
|
8
8
|
runBackup
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-JBIFXB6I.js";
|
|
10
10
|
import {
|
|
11
11
|
acceptPending,
|
|
12
12
|
formatFileSize,
|
|
@@ -14,16 +14,22 @@ import {
|
|
|
14
14
|
rejectPending,
|
|
15
15
|
stageFile,
|
|
16
16
|
validateFilePath
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-NOIAHMJB.js";
|
|
18
18
|
import {
|
|
19
19
|
findOpenClawSession,
|
|
20
20
|
importOpenClawConnectors,
|
|
21
21
|
importPiSession,
|
|
22
22
|
parseNameFromIdentity
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-EG5LSKHU.js";
|
|
24
|
+
import {
|
|
25
|
+
isHomeOnlyArchive
|
|
26
|
+
} from "./chunk-KHCKZ36O.js";
|
|
27
|
+
import {
|
|
28
|
+
cleanupVariant
|
|
29
|
+
} from "./chunk-EADX54RG.js";
|
|
24
30
|
import {
|
|
25
31
|
isTemplateStale
|
|
26
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-L27YYONJ.js";
|
|
27
33
|
import {
|
|
28
34
|
computeTemplateHash
|
|
29
35
|
} from "./chunk-C3KLHJDB.js";
|
|
@@ -31,17 +37,14 @@ import {
|
|
|
31
37
|
checkForUpdate,
|
|
32
38
|
checkForUpdateCached,
|
|
33
39
|
getCurrentVersion
|
|
34
|
-
} from "./chunk-
|
|
35
|
-
import {
|
|
36
|
-
isHomeOnlyArchive
|
|
37
|
-
} from "./chunk-3YUBFTDN.js";
|
|
40
|
+
} from "./chunk-SX72DOO3.js";
|
|
38
41
|
import {
|
|
39
42
|
PLATFORMS,
|
|
40
43
|
echoTextToChannel,
|
|
41
44
|
fixModelEscapes,
|
|
42
45
|
getPlatformDriver,
|
|
43
46
|
routeOutboundBridge
|
|
44
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-IH5TKXX6.js";
|
|
45
48
|
import {
|
|
46
49
|
getBridgeConfig,
|
|
47
50
|
readBridgesConfig,
|
|
@@ -50,7 +53,7 @@ import {
|
|
|
50
53
|
resolveChannelMapping,
|
|
51
54
|
setBridgeConfig,
|
|
52
55
|
setChannelMapping
|
|
53
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-MG3Z34YE.js";
|
|
54
57
|
import {
|
|
55
58
|
MindStartupError,
|
|
56
59
|
RestartTracker,
|
|
@@ -66,6 +69,7 @@ import {
|
|
|
66
69
|
deleteSession,
|
|
67
70
|
deleteSystemsConfig,
|
|
68
71
|
deliverMessage,
|
|
72
|
+
deliverSproutedNotice,
|
|
69
73
|
ensureSystemChannel,
|
|
70
74
|
formatHoldNotice,
|
|
71
75
|
generateSystemFallbackReply,
|
|
@@ -91,26 +95,29 @@ import {
|
|
|
91
95
|
invalidateSessionCache,
|
|
92
96
|
isConversationId,
|
|
93
97
|
joinSystemChannel,
|
|
98
|
+
joinSystemChannelForMind,
|
|
94
99
|
linkToolResultToTurn,
|
|
95
100
|
loadAllExtensions,
|
|
96
101
|
notifyExtensionsDaemonStart,
|
|
97
102
|
notifyExtensionsDaemonStop,
|
|
98
103
|
publishTypingForChannels,
|
|
99
104
|
readSystemsConfig,
|
|
100
|
-
recordInbound,
|
|
101
105
|
recordOutbound,
|
|
102
106
|
requireAdmin,
|
|
103
107
|
requireAdminOrSystem,
|
|
104
108
|
requireSelf,
|
|
109
|
+
sendSystemMessage,
|
|
110
|
+
sendSystemMessageDirect,
|
|
105
111
|
setExtensionEnabled,
|
|
106
112
|
shouldGenerateSystemFallback,
|
|
107
113
|
startMindFull,
|
|
108
114
|
stopMindFull,
|
|
109
115
|
syncProviderToMinds,
|
|
116
|
+
tryGetMindManager,
|
|
110
117
|
uninstallNpmExtension,
|
|
111
118
|
writeSystemsConfig
|
|
112
|
-
} from "./chunk-
|
|
113
|
-
import "./chunk-
|
|
119
|
+
} from "./chunk-QQBOI3QA.js";
|
|
120
|
+
import "./chunk-VIUH5CHQ.js";
|
|
114
121
|
import {
|
|
115
122
|
applyInitFiles,
|
|
116
123
|
applyTemplateHomeFiles,
|
|
@@ -120,6 +127,9 @@ import {
|
|
|
120
127
|
isKnownTemplate,
|
|
121
128
|
listFiles
|
|
122
129
|
} from "./chunk-RRZ4RQQU.js";
|
|
130
|
+
import {
|
|
131
|
+
extractTextContent
|
|
132
|
+
} from "./chunk-EFT2OALG.js";
|
|
123
133
|
import {
|
|
124
134
|
assignSession,
|
|
125
135
|
completeOrphanedTurns,
|
|
@@ -138,15 +148,7 @@ import {
|
|
|
138
148
|
takeErrored,
|
|
139
149
|
trackToolUse,
|
|
140
150
|
utcDateTimeStr
|
|
141
|
-
} from "./chunk-
|
|
142
|
-
import {
|
|
143
|
-
PROMPT_DEFAULTS,
|
|
144
|
-
PROMPT_KEYS,
|
|
145
|
-
getMindPromptDefaults,
|
|
146
|
-
getPrompt,
|
|
147
|
-
getPromptIfCustom,
|
|
148
|
-
substitute
|
|
149
|
-
} from "./chunk-MOERAQXH.js";
|
|
151
|
+
} from "./chunk-K3JOLGWF.js";
|
|
150
152
|
import {
|
|
151
153
|
SEED_SKILLS,
|
|
152
154
|
STANDARD_SKILLS,
|
|
@@ -160,6 +162,7 @@ import {
|
|
|
160
162
|
listFilesRecursive,
|
|
161
163
|
listMindSkills,
|
|
162
164
|
listSharedSkills,
|
|
165
|
+
migrateSkillsToTemplate,
|
|
163
166
|
mindSkillsDir,
|
|
164
167
|
publishSkill,
|
|
165
168
|
removeSharedSkill,
|
|
@@ -167,7 +170,7 @@ import {
|
|
|
167
170
|
syncBuiltinSkills,
|
|
168
171
|
uninstallSkill,
|
|
169
172
|
updateSkill
|
|
170
|
-
} from "./chunk-
|
|
173
|
+
} from "./chunk-GWVFDUNB.js";
|
|
171
174
|
import {
|
|
172
175
|
approveUser,
|
|
173
176
|
changePassword,
|
|
@@ -186,7 +189,7 @@ import {
|
|
|
186
189
|
syncMindProfile,
|
|
187
190
|
updateUserProfile,
|
|
188
191
|
verifyUser
|
|
189
|
-
} from "./chunk-
|
|
192
|
+
} from "./chunk-4DSGN4FL.js";
|
|
190
193
|
import {
|
|
191
194
|
addMessage,
|
|
192
195
|
createChannel,
|
|
@@ -219,11 +222,19 @@ import {
|
|
|
219
222
|
setConversationPrivate,
|
|
220
223
|
subscribe as subscribe2,
|
|
221
224
|
updateChannelSettings
|
|
222
|
-
} from "./chunk-
|
|
225
|
+
} from "./chunk-VNRSXEBF.js";
|
|
226
|
+
import {
|
|
227
|
+
PROMPT_DEFAULTS,
|
|
228
|
+
PROMPT_KEYS,
|
|
229
|
+
getMindPromptDefaults,
|
|
230
|
+
getPrompt,
|
|
231
|
+
getPromptIfCustom,
|
|
232
|
+
substitute
|
|
233
|
+
} from "./chunk-JPGHSXSV.js";
|
|
223
234
|
import {
|
|
224
235
|
isSandboxEnabled,
|
|
225
236
|
wrapForSandbox
|
|
226
|
-
} from "./chunk-
|
|
237
|
+
} from "./chunk-JCWB2ITW.js";
|
|
227
238
|
import {
|
|
228
239
|
clearDeliveredNotices,
|
|
229
240
|
drainNotices,
|
|
@@ -231,15 +242,15 @@ import {
|
|
|
231
242
|
latestFailureNotice,
|
|
232
243
|
latestNotice,
|
|
233
244
|
recordNotice
|
|
234
|
-
} from "./chunk-
|
|
245
|
+
} from "./chunk-XTEKINWG.js";
|
|
235
246
|
import {
|
|
236
247
|
getActiveMinds,
|
|
237
248
|
onMindEvent,
|
|
238
249
|
stopAll
|
|
239
|
-
} from "./chunk-
|
|
250
|
+
} from "./chunk-ZX46PGCC.js";
|
|
240
251
|
import {
|
|
241
252
|
normalizeAvatar
|
|
242
|
-
} from "./chunk-
|
|
253
|
+
} from "./chunk-FBBS4BVR.js";
|
|
243
254
|
import {
|
|
244
255
|
safeResolveWithinBase
|
|
245
256
|
} from "./chunk-DW4TRDOZ.js";
|
|
@@ -247,10 +258,7 @@ import {
|
|
|
247
258
|
readVoluteConfig,
|
|
248
259
|
writeVoluteConfig
|
|
249
260
|
} from "./chunk-WCFSBH33.js";
|
|
250
|
-
import
|
|
251
|
-
extractTextContent
|
|
252
|
-
} from "./chunk-EIQDZC43.js";
|
|
253
|
-
import "./chunk-FJ2MZ5PH.js";
|
|
261
|
+
import "./chunk-HCYQRME2.js";
|
|
254
262
|
import {
|
|
255
263
|
chownMindDir,
|
|
256
264
|
createMindUser,
|
|
@@ -261,14 +269,14 @@ import {
|
|
|
261
269
|
isIsolationEnabled,
|
|
262
270
|
resolveVoluteBin,
|
|
263
271
|
wrapForIsolation
|
|
264
|
-
} from "./chunk-
|
|
272
|
+
} from "./chunk-DVN6DNMI.js";
|
|
265
273
|
import {
|
|
266
274
|
loadMergedEnv,
|
|
267
275
|
mindEnvPath,
|
|
268
276
|
readEnv,
|
|
269
277
|
sharedEnvPath,
|
|
270
278
|
writeEnv
|
|
271
|
-
} from "./chunk-
|
|
279
|
+
} from "./chunk-PY24ZL62.js";
|
|
272
280
|
import {
|
|
273
281
|
addCustomModel,
|
|
274
282
|
aiCompleteUtility,
|
|
@@ -291,23 +299,23 @@ import {
|
|
|
291
299
|
setProviderRefreshHook,
|
|
292
300
|
setUtilityModel,
|
|
293
301
|
unqualifyModelId
|
|
294
|
-
} from "./chunk-
|
|
302
|
+
} from "./chunk-YIJGKHIS.js";
|
|
295
303
|
import {
|
|
296
304
|
isSetupComplete,
|
|
297
305
|
readGlobalConfig,
|
|
298
306
|
writeGlobalConfig
|
|
299
|
-
} from "./chunk-
|
|
307
|
+
} from "./chunk-NJHN6IRB.js";
|
|
300
308
|
import {
|
|
301
309
|
broadcast,
|
|
302
310
|
getEventsSince,
|
|
303
311
|
nextEventId,
|
|
304
312
|
publish,
|
|
305
313
|
subscribe
|
|
306
|
-
} from "./chunk-
|
|
314
|
+
} from "./chunk-3B427GUK.js";
|
|
307
315
|
import {
|
|
308
316
|
logBuffer,
|
|
309
317
|
logger_default
|
|
310
|
-
} from "./chunk-
|
|
318
|
+
} from "./chunk-QUSMYGNQ.js";
|
|
311
319
|
import {
|
|
312
320
|
buildVoluteSlug
|
|
313
321
|
} from "./chunk-LGNUFVMR.js";
|
|
@@ -315,6 +323,7 @@ import {
|
|
|
315
323
|
SPIRIT_NAME,
|
|
316
324
|
addMind,
|
|
317
325
|
addVariant,
|
|
326
|
+
countCappedMinds,
|
|
318
327
|
daemonLoopback,
|
|
319
328
|
ensureSystemDir,
|
|
320
329
|
ensureVoluteHome,
|
|
@@ -337,7 +346,7 @@ import {
|
|
|
337
346
|
validateMindName,
|
|
338
347
|
voluteHome,
|
|
339
348
|
voluteSystemDir
|
|
340
|
-
} from "./chunk-
|
|
349
|
+
} from "./chunk-RSBL3FAD.js";
|
|
341
350
|
import {
|
|
342
351
|
activity,
|
|
343
352
|
channels,
|
|
@@ -348,14 +357,14 @@ import {
|
|
|
348
357
|
systemPrompts,
|
|
349
358
|
turns,
|
|
350
359
|
users
|
|
351
|
-
} from "./chunk-
|
|
360
|
+
} from "./chunk-P4LHVRNE.js";
|
|
352
361
|
import "./chunk-K3NQKI34.js";
|
|
353
362
|
|
|
354
363
|
// packages/daemon/src/daemon.ts
|
|
355
364
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
356
|
-
import { chmodSync, mkdirSync as mkdirSync10, readFileSync as
|
|
365
|
+
import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync12, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
|
|
357
366
|
import { homedir as homedir3 } from "os";
|
|
358
|
-
import { resolve as
|
|
367
|
+
import { resolve as resolve18 } from "path";
|
|
359
368
|
import { format } from "util";
|
|
360
369
|
|
|
361
370
|
// packages/daemon/src/lib/daemon/backup-manager.ts
|
|
@@ -467,8 +476,8 @@ var BackupManager = class {
|
|
|
467
476
|
blog.error("failed to publish backup-failure activity", logger_default.errorData(pubErr));
|
|
468
477
|
}
|
|
469
478
|
try {
|
|
470
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
471
|
-
await
|
|
479
|
+
const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-M2XOBKEM.js");
|
|
480
|
+
await sendSystemMessage2(
|
|
472
481
|
SPIRIT_NAME,
|
|
473
482
|
`${summary}
|
|
474
483
|
|
|
@@ -693,8 +702,8 @@ var BridgeManager = class {
|
|
|
693
702
|
if (!tracked) return;
|
|
694
703
|
this.stopping.add(platform);
|
|
695
704
|
this.bridges.delete(platform);
|
|
696
|
-
await new Promise((
|
|
697
|
-
tracked.child.on("exit", () =>
|
|
705
|
+
await new Promise((resolve19) => {
|
|
706
|
+
tracked.child.on("exit", () => resolve19());
|
|
698
707
|
try {
|
|
699
708
|
if (tracked.child.pid) {
|
|
700
709
|
process.kill(-tracked.child.pid, "SIGTERM");
|
|
@@ -705,7 +714,7 @@ var BridgeManager = class {
|
|
|
705
714
|
if (err instanceof Error && err.code !== "ESRCH") {
|
|
706
715
|
blog2.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
|
|
707
716
|
}
|
|
708
|
-
|
|
717
|
+
resolve19();
|
|
709
718
|
}
|
|
710
719
|
setTimeout(() => {
|
|
711
720
|
try {
|
|
@@ -716,7 +725,7 @@ var BridgeManager = class {
|
|
|
716
725
|
}
|
|
717
726
|
} catch {
|
|
718
727
|
}
|
|
719
|
-
|
|
728
|
+
resolve19();
|
|
720
729
|
}, 5e3);
|
|
721
730
|
});
|
|
722
731
|
this.stopping.delete(platform);
|
|
@@ -1056,10 +1065,10 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1056
1065
|
stream.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
|
|
1057
1066
|
});
|
|
1058
1067
|
});
|
|
1059
|
-
await new Promise((
|
|
1068
|
+
await new Promise((resolve19) => {
|
|
1060
1069
|
stream.onAbort(() => {
|
|
1061
1070
|
unsubscribe();
|
|
1062
|
-
|
|
1071
|
+
resolve19();
|
|
1063
1072
|
});
|
|
1064
1073
|
});
|
|
1065
1074
|
});
|
|
@@ -1072,13 +1081,34 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1072
1081
|
name: globalConfig.name ?? null,
|
|
1073
1082
|
timezone
|
|
1074
1083
|
});
|
|
1075
|
-
}).put("/info", requireAdmin, zValidator("json", z.object({ name: z.string() })), (c) => {
|
|
1084
|
+
}).put("/info", requireAdmin, zValidator("json", z.object({ name: z.string() })), async (c) => {
|
|
1076
1085
|
const { name } = c.req.valid("json");
|
|
1077
1086
|
const config2 = readGlobalConfig();
|
|
1087
|
+
const previousName = config2.name;
|
|
1078
1088
|
config2.name = name.trim() || void 0;
|
|
1079
1089
|
writeGlobalConfig(config2);
|
|
1090
|
+
if (config2.name !== previousName) {
|
|
1091
|
+
const { notifySpiritSystemChange } = await import("./spirit-SSJMYC6A.js");
|
|
1092
|
+
await notifySpiritSystemChange();
|
|
1093
|
+
}
|
|
1080
1094
|
return c.json({ name: config2.name ?? null });
|
|
1081
|
-
}).
|
|
1095
|
+
}).get("/max-minds", requireAdmin, async (c) => {
|
|
1096
|
+
return c.json({
|
|
1097
|
+
maxMinds: readGlobalConfig().maxMinds ?? null,
|
|
1098
|
+
count: await countCappedMinds()
|
|
1099
|
+
});
|
|
1100
|
+
}).put(
|
|
1101
|
+
"/max-minds",
|
|
1102
|
+
requireAdmin,
|
|
1103
|
+
zValidator("json", z.object({ maxMinds: z.number().int().positive().nullable() })),
|
|
1104
|
+
async (c) => {
|
|
1105
|
+
const { maxMinds } = c.req.valid("json");
|
|
1106
|
+
const config2 = readGlobalConfig();
|
|
1107
|
+
config2.maxMinds = maxMinds ?? void 0;
|
|
1108
|
+
writeGlobalConfig(config2);
|
|
1109
|
+
return c.json({ maxMinds: maxMinds ?? null, count: await countCappedMinds() });
|
|
1110
|
+
}
|
|
1111
|
+
).post(
|
|
1082
1112
|
"/register",
|
|
1083
1113
|
requireAdmin,
|
|
1084
1114
|
zValidator("json", z.object({ name: z.string().min(1) })),
|
|
@@ -1408,8 +1438,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1408
1438
|
createdAt: Date.now()
|
|
1409
1439
|
};
|
|
1410
1440
|
oauthFlows.set(flowId, flow);
|
|
1411
|
-
const promptPromise = needsManualCode ? new Promise((
|
|
1412
|
-
flow.resolveCode =
|
|
1441
|
+
const promptPromise = needsManualCode ? new Promise((resolve19) => {
|
|
1442
|
+
flow.resolveCode = resolve19;
|
|
1413
1443
|
}) : void 0;
|
|
1414
1444
|
oauthProvider.login({
|
|
1415
1445
|
onAuth: (info) => {
|
|
@@ -1448,7 +1478,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1448
1478
|
existing.error = err instanceof Error ? err.message : String(err);
|
|
1449
1479
|
}
|
|
1450
1480
|
});
|
|
1451
|
-
await new Promise((
|
|
1481
|
+
await new Promise((resolve19) => setTimeout(resolve19, 2e3));
|
|
1452
1482
|
const state = oauthFlows.get(flowId);
|
|
1453
1483
|
return c.json({
|
|
1454
1484
|
flowId,
|
|
@@ -1706,8 +1736,8 @@ var app2 = new Hono2().get("/events", async (c) => {
|
|
|
1706
1736
|
});
|
|
1707
1737
|
}, 15e3);
|
|
1708
1738
|
cleanups.push(() => clearInterval(keepAlive));
|
|
1709
|
-
await new Promise((
|
|
1710
|
-
stream.onAbort(() =>
|
|
1739
|
+
await new Promise((resolve19) => {
|
|
1740
|
+
stream.onAbort(() => resolve19());
|
|
1711
1741
|
});
|
|
1712
1742
|
} finally {
|
|
1713
1743
|
for (const cleanup of cleanups) {
|
|
@@ -2278,7 +2308,7 @@ var app4 = new Hono5().post("/:platform/inbound", zValidator4("json", inboundSch
|
|
|
2278
2308
|
}
|
|
2279
2309
|
const participants = await getParticipants(channel.id);
|
|
2280
2310
|
if (!participants.some((p) => p.userId === puppet.id)) {
|
|
2281
|
-
const { addParticipant } = await import("./conversations-
|
|
2311
|
+
const { addParticipant } = await import("./conversations-TUM5PJJ4.js");
|
|
2282
2312
|
await addParticipant(channel.id, puppet.id);
|
|
2283
2313
|
}
|
|
2284
2314
|
const contentBlocks = body.content;
|
|
@@ -2562,8 +2592,8 @@ async function notifyMind(mindName, message) {
|
|
|
2562
2592
|
const entry = await findMind(mindName);
|
|
2563
2593
|
if (!entry) return;
|
|
2564
2594
|
try {
|
|
2565
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
2566
|
-
await
|
|
2595
|
+
const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-M2XOBKEM.js");
|
|
2596
|
+
await sendSystemMessage2(mindName, message);
|
|
2567
2597
|
} catch (err) {
|
|
2568
2598
|
logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
|
|
2569
2599
|
}
|
|
@@ -3394,9 +3424,9 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
|
|
|
3394
3424
|
stream.onAbort(() => {
|
|
3395
3425
|
tail.kill();
|
|
3396
3426
|
});
|
|
3397
|
-
await new Promise((
|
|
3398
|
-
tail.on("exit",
|
|
3399
|
-
stream.onAbort(
|
|
3427
|
+
await new Promise((resolve19) => {
|
|
3428
|
+
tail.on("exit", resolve19);
|
|
3429
|
+
stream.onAbort(resolve19);
|
|
3400
3430
|
});
|
|
3401
3431
|
});
|
|
3402
3432
|
}).get("/:name/logs/tail", requireSelf(), async (c) => {
|
|
@@ -3414,8 +3444,8 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
|
|
|
3414
3444
|
tail.stdout.on("data", (data) => {
|
|
3415
3445
|
output += data.toString();
|
|
3416
3446
|
});
|
|
3417
|
-
await new Promise((
|
|
3418
|
-
tail.on("exit",
|
|
3447
|
+
await new Promise((resolve19) => {
|
|
3448
|
+
tail.on("exit", resolve19);
|
|
3419
3449
|
});
|
|
3420
3450
|
return c.text(output);
|
|
3421
3451
|
});
|
|
@@ -3508,11 +3538,11 @@ var mind_skills_default = app12;
|
|
|
3508
3538
|
// packages/daemon/src/web/api/minds.ts
|
|
3509
3539
|
import {
|
|
3510
3540
|
cpSync,
|
|
3511
|
-
existsSync as
|
|
3541
|
+
existsSync as existsSync7,
|
|
3512
3542
|
mkdirSync as mkdirSync6,
|
|
3513
3543
|
readdirSync as readdirSync2,
|
|
3514
3544
|
readFileSync as readFileSync9,
|
|
3515
|
-
rmSync as
|
|
3545
|
+
rmSync as rmSync3,
|
|
3516
3546
|
writeFileSync as writeFileSync8
|
|
3517
3547
|
} from "fs";
|
|
3518
3548
|
import { relative, resolve as resolve11 } from "path";
|
|
@@ -3997,62 +4027,97 @@ function deriveThinkingLevel(config2) {
|
|
|
3997
4027
|
return null;
|
|
3998
4028
|
}
|
|
3999
4029
|
|
|
4000
|
-
// packages/daemon/src/lib/mind/
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
if (
|
|
4004
|
-
|
|
4005
|
-
await getMindManager().stopMind(variantName);
|
|
4006
|
-
} catch (err) {
|
|
4007
|
-
logger_default.warn(`failed to stop variant ${variantName}`, logger_default.errorData(err));
|
|
4008
|
-
}
|
|
4030
|
+
// packages/daemon/src/lib/mind/variants.ts
|
|
4031
|
+
var SAFE_BRANCH_RE = /^[a-zA-Z0-9._\-/]+$/;
|
|
4032
|
+
function validateBranchName(branch) {
|
|
4033
|
+
if (!SAFE_BRANCH_RE.test(branch)) {
|
|
4034
|
+
return `Invalid branch name: ${branch}. Only alphanumeric, '.', '_', '-', '/' allowed.`;
|
|
4009
4035
|
}
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
const branchName = variantEntry?.branch ?? variantName;
|
|
4013
|
-
if (existsSync7(variantPath)) {
|
|
4014
|
-
try {
|
|
4015
|
-
await gitExec(["worktree", "remove", "--force", variantPath], { cwd: projectRoot });
|
|
4016
|
-
} catch {
|
|
4017
|
-
rmSync3(variantPath, { recursive: true, force: true });
|
|
4018
|
-
try {
|
|
4019
|
-
await gitExec(["worktree", "prune"], { cwd: projectRoot });
|
|
4020
|
-
} catch (err) {
|
|
4021
|
-
logger_default.warn(`failed to prune worktrees for ${variantName}`, logger_default.errorData(err));
|
|
4022
|
-
}
|
|
4023
|
-
}
|
|
4036
|
+
if (branch.includes("..")) {
|
|
4037
|
+
return `Invalid branch name: ${branch}. '..' not allowed.`;
|
|
4024
4038
|
}
|
|
4039
|
+
return null;
|
|
4040
|
+
}
|
|
4041
|
+
var MERGE_EXCLUDED_PATHS = ["home/MEMORY.md", "home/memory/journal/"];
|
|
4042
|
+
var MAX_DELTA_CHARS = 12e3;
|
|
4043
|
+
async function mergeVariantExcludingMemory(projectRoot, variantBranch) {
|
|
4044
|
+
const opts = { cwd: projectRoot };
|
|
4045
|
+
let memoryDelta = "";
|
|
4025
4046
|
try {
|
|
4026
|
-
await gitExec(["
|
|
4047
|
+
const base = (await gitExec(["merge-base", "HEAD", variantBranch], opts)).trim();
|
|
4048
|
+
memoryDelta = (await gitExec(["diff", `${base}..${variantBranch}`, "--", ...MERGE_EXCLUDED_PATHS], opts)).trim();
|
|
4027
4049
|
} catch (err) {
|
|
4028
|
-
logger_default.
|
|
4050
|
+
logger_default.error(
|
|
4051
|
+
`variant join: failed to compute memory delta for ${variantBranch}`,
|
|
4052
|
+
logger_default.errorData(err)
|
|
4053
|
+
);
|
|
4054
|
+
memoryDelta = `(journal delta unavailable \u2014 ${err instanceof Error ? err.message : String(err)})`;
|
|
4029
4055
|
}
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
} catch (err) {
|
|
4034
|
-
logger_default.warn(`failed to remove variant ${variantName} from DB`, logger_default.errorData(err));
|
|
4056
|
+
if (memoryDelta.length > MAX_DELTA_CHARS) {
|
|
4057
|
+
memoryDelta = `${memoryDelta.slice(0, MAX_DELTA_CHARS)}
|
|
4058
|
+
\u2026 (delta truncated)`;
|
|
4035
4059
|
}
|
|
4036
4060
|
try {
|
|
4037
|
-
await
|
|
4061
|
+
await gitExec(["merge", "--no-ff", "--no-commit", variantBranch], opts).catch(() => {
|
|
4062
|
+
});
|
|
4063
|
+
await gitExec(["reset", "-q", "HEAD", "--", ...MERGE_EXCLUDED_PATHS], opts);
|
|
4064
|
+
for (const path of MERGE_EXCLUDED_PATHS) {
|
|
4065
|
+
await gitExec(["checkout", "--", path], opts).catch(() => {
|
|
4066
|
+
});
|
|
4067
|
+
}
|
|
4068
|
+
await gitExec(["clean", "-fdq", "--", ...MERGE_EXCLUDED_PATHS], opts);
|
|
4069
|
+
await assertExcludedPathsRestored(opts);
|
|
4070
|
+
if (await mergeInProgress(opts)) {
|
|
4071
|
+
await gitExec(["commit", "--no-edit"], opts);
|
|
4072
|
+
}
|
|
4038
4073
|
} catch (err) {
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4074
|
+
const conflicts = await listConflicts(opts);
|
|
4075
|
+
const abortFailed = await gitExec(["merge", "--abort"], opts).then(
|
|
4076
|
+
() => false,
|
|
4077
|
+
() => true
|
|
4078
|
+
);
|
|
4079
|
+
throw new VariantMergeError(
|
|
4080
|
+
`variant join aborted: ${err instanceof Error ? err.message : String(err)}`,
|
|
4081
|
+
conflicts,
|
|
4082
|
+
abortFailed
|
|
4042
4083
|
);
|
|
4043
4084
|
}
|
|
4085
|
+
return memoryDelta;
|
|
4044
4086
|
}
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4087
|
+
var VariantMergeError = class extends Error {
|
|
4088
|
+
constructor(message, conflicts, abortFailed = false) {
|
|
4089
|
+
super(message);
|
|
4090
|
+
this.conflicts = conflicts;
|
|
4091
|
+
this.abortFailed = abortFailed;
|
|
4092
|
+
this.name = "VariantMergeError";
|
|
4051
4093
|
}
|
|
4052
|
-
|
|
4053
|
-
|
|
4094
|
+
};
|
|
4095
|
+
async function mergeInProgress(opts) {
|
|
4096
|
+
return gitExec(["rev-parse", "-q", "--verify", "MERGE_HEAD"], opts).then(
|
|
4097
|
+
() => true,
|
|
4098
|
+
() => false
|
|
4099
|
+
);
|
|
4100
|
+
}
|
|
4101
|
+
async function listConflicts(opts) {
|
|
4102
|
+
try {
|
|
4103
|
+
const out = (await gitExec(["diff", "--name-only", "--diff-filter=U"], opts)).trim();
|
|
4104
|
+
return out ? out.split("\n") : [];
|
|
4105
|
+
} catch {
|
|
4106
|
+
return [];
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
async function assertExcludedPathsRestored(opts) {
|
|
4110
|
+
await gitExec(["diff", "--cached", "--quiet", "HEAD", "--", ...MERGE_EXCLUDED_PATHS], opts);
|
|
4111
|
+
await gitExec(["diff", "--quiet", "HEAD", "--", ...MERGE_EXCLUDED_PATHS], opts);
|
|
4112
|
+
const untracked = (await gitExec(
|
|
4113
|
+
["ls-files", "--others", "--exclude-standard", "--", ...MERGE_EXCLUDED_PATHS],
|
|
4114
|
+
opts
|
|
4115
|
+
)).trim();
|
|
4116
|
+
if (untracked) {
|
|
4117
|
+
throw new Error(
|
|
4118
|
+
`untracked memory files remain after restore: ${untracked.replace(/\n/g, ", ")}`
|
|
4119
|
+
);
|
|
4054
4120
|
}
|
|
4055
|
-
return null;
|
|
4056
4121
|
}
|
|
4057
4122
|
|
|
4058
4123
|
// packages/daemon/src/lib/template/convert-session.ts
|
|
@@ -4237,7 +4302,7 @@ async function getMindStatus(name, port, registryRunning) {
|
|
|
4237
4302
|
let status = "stopped";
|
|
4238
4303
|
let wakeAt = null;
|
|
4239
4304
|
try {
|
|
4240
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4305
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-DSPXFHGX.js");
|
|
4241
4306
|
const sleepManager = getSleepManagerIfReady2();
|
|
4242
4307
|
if (sleepManager?.isSleeping(name)) {
|
|
4243
4308
|
status = "sleeping";
|
|
@@ -4324,8 +4389,8 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4324
4389
|
await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
|
|
4325
4390
|
} catch {
|
|
4326
4391
|
}
|
|
4327
|
-
if (
|
|
4328
|
-
|
|
4392
|
+
if (existsSync7(tempWorktree)) {
|
|
4393
|
+
rmSync3(tempWorktree, { recursive: true, force: true });
|
|
4329
4394
|
}
|
|
4330
4395
|
const templatesRoot = findTemplatesRoot();
|
|
4331
4396
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
@@ -4346,14 +4411,14 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4346
4411
|
}
|
|
4347
4412
|
copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
|
|
4348
4413
|
const initDir = resolve11(tempWorktree, ".init");
|
|
4349
|
-
if (
|
|
4350
|
-
|
|
4414
|
+
if (existsSync7(initDir)) {
|
|
4415
|
+
rmSync3(initDir, { recursive: true, force: true });
|
|
4351
4416
|
}
|
|
4352
4417
|
const homeDir = resolve11(tempWorktree, "home");
|
|
4353
|
-
if (
|
|
4418
|
+
if (existsSync7(homeDir)) {
|
|
4354
4419
|
for (const entry of readdirSync2(homeDir)) {
|
|
4355
4420
|
if (entry !== "VOLUTE.md") {
|
|
4356
|
-
|
|
4421
|
+
rmSync3(resolve11(homeDir, entry), { recursive: true, force: true });
|
|
4357
4422
|
}
|
|
4358
4423
|
}
|
|
4359
4424
|
}
|
|
@@ -4368,10 +4433,10 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4368
4433
|
await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
|
|
4369
4434
|
} catch {
|
|
4370
4435
|
}
|
|
4371
|
-
if (
|
|
4372
|
-
|
|
4436
|
+
if (existsSync7(tempWorktree)) {
|
|
4437
|
+
rmSync3(tempWorktree, { recursive: true, force: true });
|
|
4373
4438
|
}
|
|
4374
|
-
|
|
4439
|
+
rmSync3(composedDir, { recursive: true, force: true });
|
|
4375
4440
|
}
|
|
4376
4441
|
}
|
|
4377
4442
|
async function mergeTemplateBranch(worktreeDir) {
|
|
@@ -4420,6 +4485,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
|
|
|
4420
4485
|
if (templateChanged) {
|
|
4421
4486
|
try {
|
|
4422
4487
|
applyTemplateHomeFiles(resolve11(dir, "home"), template);
|
|
4488
|
+
const migratedSkills = migrateSkillsToTemplate(dir, oldTemplate, template);
|
|
4423
4489
|
await gitExec(["add", "home/"], { cwd: dir });
|
|
4424
4490
|
try {
|
|
4425
4491
|
await gitExec(["diff", "--cached", "--quiet"], { cwd: dir });
|
|
@@ -4429,7 +4495,8 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
|
|
|
4429
4495
|
});
|
|
4430
4496
|
}
|
|
4431
4497
|
await chownMindDir(dir, mindName);
|
|
4432
|
-
|
|
4498
|
+
const skillNote = migratedSkills.length > 0 ? ` Migrated skills to the ${template} skills dir: ${migratedSkills.join(", ")}.` : "";
|
|
4499
|
+
switchWarning = `Switched ${oldTemplate}\u2192${template}: config reset to ${template} defaults, mechanics doc replaced, conversation starts fresh (sessions aren't portable across runtimes).${skillNote}`;
|
|
4433
4500
|
} catch (err) {
|
|
4434
4501
|
logger_default.warn(`failed to swap template home files for ${mindName}`, logger_default.errorData(err));
|
|
4435
4502
|
return {
|
|
@@ -4470,7 +4537,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
|
|
|
4470
4537
|
}
|
|
4471
4538
|
async function importFromArchive(c, tempDir, nameOverride, manifest) {
|
|
4472
4539
|
const extractedMindDir = resolve11(tempDir, "mind");
|
|
4473
|
-
if (!
|
|
4540
|
+
if (!existsSync7(extractedMindDir)) {
|
|
4474
4541
|
return c.json({ error: "Invalid archive: missing mind/ directory" }, 400);
|
|
4475
4542
|
}
|
|
4476
4543
|
if (!manifest?.includes || !manifest.name || !manifest.template) {
|
|
@@ -4488,7 +4555,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4488
4555
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
4489
4556
|
ensureVoluteHome();
|
|
4490
4557
|
const dest = mindDir(name);
|
|
4491
|
-
if (
|
|
4558
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4492
4559
|
try {
|
|
4493
4560
|
cpSync(extractedMindDir, dest, { recursive: true });
|
|
4494
4561
|
if (!manifest.includes.identity) {
|
|
@@ -4497,7 +4564,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4497
4564
|
const state = stateDir(name);
|
|
4498
4565
|
mkdirSync6(state, { recursive: true });
|
|
4499
4566
|
const envJson = resolve11(tempDir, "state/env.json");
|
|
4500
|
-
if (
|
|
4567
|
+
if (existsSync7(envJson)) {
|
|
4501
4568
|
cpSync(envJson, resolve11(state, "env.json"));
|
|
4502
4569
|
}
|
|
4503
4570
|
const port = await nextPort();
|
|
@@ -4514,7 +4581,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4514
4581
|
await npmInstallAsMind(dest, name);
|
|
4515
4582
|
await importHistoryFromArchive(name, tempDir);
|
|
4516
4583
|
importSessionsFromArchive(dest, tempDir);
|
|
4517
|
-
if (!
|
|
4584
|
+
if (!existsSync7(resolve11(dest, ".git"))) {
|
|
4518
4585
|
try {
|
|
4519
4586
|
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
|
|
4520
4587
|
await gitExec(["init"], { cwd: dest, mindName: name, env });
|
|
@@ -4523,20 +4590,20 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4523
4590
|
await gitExec(["commit", "-m", "import from archive"], { cwd: dest, mindName: name, env });
|
|
4524
4591
|
} catch (err) {
|
|
4525
4592
|
logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
|
|
4526
|
-
|
|
4593
|
+
rmSync3(resolve11(dest, ".git"), { recursive: true, force: true });
|
|
4527
4594
|
}
|
|
4528
4595
|
}
|
|
4529
4596
|
await chownMindDir(dest, name);
|
|
4530
|
-
|
|
4597
|
+
rmSync3(tempDir, { recursive: true, force: true });
|
|
4531
4598
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
4532
4599
|
} catch (err) {
|
|
4533
|
-
if (
|
|
4600
|
+
if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
|
|
4534
4601
|
try {
|
|
4535
4602
|
await removeMind(name);
|
|
4536
4603
|
} catch (cleanupErr) {
|
|
4537
4604
|
logger_default.error(`Failed to clean up registry for ${name}`, logger_default.errorData(cleanupErr));
|
|
4538
4605
|
}
|
|
4539
|
-
|
|
4606
|
+
rmSync3(tempDir, { recursive: true, force: true });
|
|
4540
4607
|
return c.json({ error: err instanceof Error ? err.message : "Failed to import mind" }, 500);
|
|
4541
4608
|
}
|
|
4542
4609
|
}
|
|
@@ -4547,7 +4614,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4547
4614
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
4548
4615
|
ensureVoluteHome();
|
|
4549
4616
|
const dest = mindDir(name);
|
|
4550
|
-
if (
|
|
4617
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4551
4618
|
const templatesRoot = findTemplatesRoot();
|
|
4552
4619
|
const { composedDir, manifest: templateManifest } = composeTemplate(
|
|
4553
4620
|
templatesRoot,
|
|
@@ -4557,22 +4624,22 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4557
4624
|
copyTemplateToDir(composedDir, dest, name, templateManifest);
|
|
4558
4625
|
applyInitFiles(dest);
|
|
4559
4626
|
const extractedHome = resolve11(extractedMindDir, "home");
|
|
4560
|
-
if (
|
|
4627
|
+
if (existsSync7(extractedHome)) {
|
|
4561
4628
|
cpSync(extractedHome, resolve11(dest, "home"), { recursive: true });
|
|
4562
4629
|
}
|
|
4563
4630
|
const extractedMindInternal = resolve11(extractedMindDir, ".mind");
|
|
4564
|
-
if (
|
|
4631
|
+
if (existsSync7(extractedMindInternal)) {
|
|
4565
4632
|
cpSync(extractedMindInternal, resolve11(dest, ".mind"), { recursive: true });
|
|
4566
4633
|
}
|
|
4567
4634
|
const identityDir = resolve11(dest, ".mind/identity");
|
|
4568
4635
|
let publicKeyPem;
|
|
4569
|
-
if (!manifest.includes.identity || !
|
|
4636
|
+
if (!manifest.includes.identity || !existsSync7(resolve11(identityDir, "private.pem"))) {
|
|
4570
4637
|
({ publicKeyPem } = generateIdentity(dest));
|
|
4571
4638
|
} else {
|
|
4572
4639
|
publicKeyPem = readFileSync9(resolve11(identityDir, "public.pem"), "utf-8");
|
|
4573
4640
|
}
|
|
4574
4641
|
const promptsPath = resolve11(dest, "home/.config/prompts.json");
|
|
4575
|
-
if (!
|
|
4642
|
+
if (!existsSync7(promptsPath)) {
|
|
4576
4643
|
const mindPrompts = await getMindPromptDefaults();
|
|
4577
4644
|
writeFileSync8(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
|
|
4578
4645
|
`);
|
|
@@ -4580,7 +4647,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4580
4647
|
const state = stateDir(name);
|
|
4581
4648
|
mkdirSync6(state, { recursive: true });
|
|
4582
4649
|
const envJson = resolve11(tempDir, "state/env.json");
|
|
4583
|
-
if (
|
|
4650
|
+
if (existsSync7(envJson)) {
|
|
4584
4651
|
cpSync(envJson, resolve11(state, "env.json"));
|
|
4585
4652
|
}
|
|
4586
4653
|
const port = await nextPort();
|
|
@@ -4598,7 +4665,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4598
4665
|
await initTemplateBranch(dest, composedDir, templateManifest, name, env);
|
|
4599
4666
|
} catch (err) {
|
|
4600
4667
|
logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
|
|
4601
|
-
|
|
4668
|
+
rmSync3(resolve11(dest, ".git"), { recursive: true, force: true });
|
|
4602
4669
|
gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
|
|
4603
4670
|
}
|
|
4604
4671
|
const skillSet = manifest.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions();
|
|
@@ -4617,7 +4684,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4617
4684
|
publishPublicKey(name, publicKeyPem).catch(
|
|
4618
4685
|
(err) => logger_default.warn(`failed to publish key for ${name}`, { error: err.message })
|
|
4619
4686
|
);
|
|
4620
|
-
|
|
4687
|
+
rmSync3(tempDir, { recursive: true, force: true });
|
|
4621
4688
|
return c.json({
|
|
4622
4689
|
ok: true,
|
|
4623
4690
|
name,
|
|
@@ -4628,21 +4695,21 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4628
4695
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
4629
4696
|
});
|
|
4630
4697
|
} catch (err) {
|
|
4631
|
-
if (
|
|
4698
|
+
if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
|
|
4632
4699
|
try {
|
|
4633
4700
|
await removeMind(name);
|
|
4634
4701
|
} catch (cleanupErr) {
|
|
4635
4702
|
logger_default.error(`Failed to clean up registry for ${name}`, logger_default.errorData(cleanupErr));
|
|
4636
4703
|
}
|
|
4637
|
-
|
|
4704
|
+
rmSync3(tempDir, { recursive: true, force: true });
|
|
4638
4705
|
return c.json({ error: err instanceof Error ? err.message : "Failed to import mind" }, 500);
|
|
4639
4706
|
} finally {
|
|
4640
|
-
|
|
4707
|
+
rmSync3(composedDir, { recursive: true, force: true });
|
|
4641
4708
|
}
|
|
4642
4709
|
}
|
|
4643
4710
|
async function importHistoryFromArchive(name, tempDir) {
|
|
4644
4711
|
const historyJsonl = resolve11(tempDir, "history.jsonl");
|
|
4645
|
-
if (!
|
|
4712
|
+
if (!existsSync7(historyJsonl)) return;
|
|
4646
4713
|
try {
|
|
4647
4714
|
const db = await getDb();
|
|
4648
4715
|
const lines = readFileSync9(historyJsonl, "utf-8").trim().split("\n");
|
|
@@ -4682,7 +4749,7 @@ async function importHistoryFromArchive(name, tempDir) {
|
|
|
4682
4749
|
}
|
|
4683
4750
|
function importSessionsFromArchive(dest, tempDir) {
|
|
4684
4751
|
const sessionsDir = resolve11(tempDir, "sessions");
|
|
4685
|
-
if (!
|
|
4752
|
+
if (!existsSync7(sessionsDir)) return;
|
|
4686
4753
|
try {
|
|
4687
4754
|
const destSessions = resolve11(dest, ".mind/sessions");
|
|
4688
4755
|
mkdirSync6(destSessions, { recursive: true });
|
|
@@ -4752,9 +4819,14 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
4752
4819
|
const nameErr = validateMindName(name);
|
|
4753
4820
|
if (nameErr) return c.json({ error: nameErr }, 400);
|
|
4754
4821
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
4822
|
+
{
|
|
4823
|
+
const { mindLimitError, readGlobalConfig: readGlobalConfig2 } = await import("./setup-TCN7VH5U.js");
|
|
4824
|
+
const limitError = mindLimitError(await countCappedMinds(), readGlobalConfig2().maxMinds);
|
|
4825
|
+
if (limitError) return c.json({ error: limitError }, 409);
|
|
4826
|
+
}
|
|
4755
4827
|
ensureVoluteHome();
|
|
4756
4828
|
const dest = mindDir(name);
|
|
4757
|
-
if (
|
|
4829
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4758
4830
|
const templatesRoot = findTemplatesRoot();
|
|
4759
4831
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
4760
4832
|
try {
|
|
@@ -4763,7 +4835,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
4763
4835
|
const { publicKeyPem } = generateIdentity(dest);
|
|
4764
4836
|
let effectiveModel = body.model;
|
|
4765
4837
|
{
|
|
4766
|
-
const { readGlobalConfig: readGlobal } = await import("./setup-
|
|
4838
|
+
const { readGlobalConfig: readGlobal } = await import("./setup-TCN7VH5U.js");
|
|
4767
4839
|
const mindDefaults = readGlobal().mindDefaults;
|
|
4768
4840
|
const config2 = readVoluteConfig(dest);
|
|
4769
4841
|
if (!config2) throw new Error("Failed to read volute.json after identity generation");
|
|
@@ -4793,7 +4865,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
4793
4865
|
effectiveModel = modelId ? qualifyModelId(modelId) : void 0;
|
|
4794
4866
|
const sdkConfigPath = resolve11(dest, "home/.config/config.json");
|
|
4795
4867
|
if (modelId || cog?.compaction) {
|
|
4796
|
-
const existing =
|
|
4868
|
+
const existing = existsSync7(sdkConfigPath) ? JSON.parse(readFileSync9(sdkConfigPath, "utf-8")) : {};
|
|
4797
4869
|
if (modelId) {
|
|
4798
4870
|
existing.model = template === "pi" ? qualifyModelId(modelId) : unqualifyModelId(modelId);
|
|
4799
4871
|
}
|
|
@@ -4831,7 +4903,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
4831
4903
|
await initTemplateBranch(dest, composedDir, manifest, name, env);
|
|
4832
4904
|
} catch (err) {
|
|
4833
4905
|
logger_default.error(`git setup failed for ${name}`, logger_default.errorData(err));
|
|
4834
|
-
|
|
4906
|
+
rmSync3(resolve11(dest, ".git"), { recursive: true, force: true });
|
|
4835
4907
|
gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
|
|
4836
4908
|
}
|
|
4837
4909
|
if (body.stage === "seed") {
|
|
@@ -4844,7 +4916,7 @@ Your creator described you as: "${body.description}"
|
|
|
4844
4916
|
}
|
|
4845
4917
|
let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
|
|
4846
4918
|
if (body.stage === "seed" && !body.skills) {
|
|
4847
|
-
const { isImagegenEnabled } = await import("./setup-
|
|
4919
|
+
const { isImagegenEnabled } = await import("./setup-TCN7VH5U.js");
|
|
4848
4920
|
if (isImagegenEnabled()) {
|
|
4849
4921
|
skillSet = [...skillSet, "imagegen"];
|
|
4850
4922
|
}
|
|
@@ -4865,7 +4937,7 @@ Your creator described you as: "${body.description}"
|
|
|
4865
4937
|
try {
|
|
4866
4938
|
const spiritEntry = await findMind("volute");
|
|
4867
4939
|
if (spiritEntry) {
|
|
4868
|
-
const { spiritDir } = await import("./spirit-
|
|
4940
|
+
const { spiritDir } = await import("./spirit-SSJMYC6A.js");
|
|
4869
4941
|
const sDir = spiritEntry.dir ?? spiritDir();
|
|
4870
4942
|
const spiritConfig = readVoluteConfig(sDir) ?? {};
|
|
4871
4943
|
const schedules = spiritConfig.schedules ?? [];
|
|
@@ -4880,7 +4952,7 @@ Your creator described you as: "${body.description}"
|
|
|
4880
4952
|
});
|
|
4881
4953
|
spiritConfig.schedules = schedules;
|
|
4882
4954
|
writeVoluteConfig(sDir, spiritConfig);
|
|
4883
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
4955
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-K7Y7Z7FQ.js");
|
|
4884
4956
|
getScheduler2().loadSchedules("volute", sDir);
|
|
4885
4957
|
}
|
|
4886
4958
|
}
|
|
@@ -4934,14 +5006,14 @@ Your creator described you as: "${body.description}"
|
|
|
4934
5006
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
4935
5007
|
});
|
|
4936
5008
|
} catch (err) {
|
|
4937
|
-
if (
|
|
5009
|
+
if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
|
|
4938
5010
|
try {
|
|
4939
5011
|
await removeMind(name);
|
|
4940
5012
|
} catch {
|
|
4941
5013
|
}
|
|
4942
5014
|
return c.json({ error: err instanceof Error ? err.message : "Failed to create mind" }, 500);
|
|
4943
5015
|
} finally {
|
|
4944
|
-
|
|
5016
|
+
rmSync3(composedDir, { recursive: true, force: true });
|
|
4945
5017
|
}
|
|
4946
5018
|
}).post("/import", requireAdmin, async (c) => {
|
|
4947
5019
|
let body;
|
|
@@ -4954,13 +5026,13 @@ Your creator described you as: "${body.description}"
|
|
|
4954
5026
|
return importFromArchive(c, body.archivePath, body.name, body.manifest);
|
|
4955
5027
|
}
|
|
4956
5028
|
const wsDir = body.workspacePath;
|
|
4957
|
-
if (!wsDir || !
|
|
5029
|
+
if (!wsDir || !existsSync7(resolve11(wsDir, "SOUL.md")) || !existsSync7(resolve11(wsDir, "IDENTITY.md"))) {
|
|
4958
5030
|
return c.json({ error: "Invalid workspace: missing SOUL.md or IDENTITY.md" }, 400);
|
|
4959
5031
|
}
|
|
4960
5032
|
const soul = readFileSync9(resolve11(wsDir, "SOUL.md"), "utf-8");
|
|
4961
5033
|
const identity = readFileSync9(resolve11(wsDir, "IDENTITY.md"), "utf-8");
|
|
4962
5034
|
const userPath = resolve11(wsDir, "USER.md");
|
|
4963
|
-
const user =
|
|
5035
|
+
const user = existsSync7(userPath) ? readFileSync9(userPath, "utf-8") : "";
|
|
4964
5036
|
const name = body.name ?? parseNameFromIdentity(identity) ?? "imported-mind";
|
|
4965
5037
|
const template = body.template ?? "claude";
|
|
4966
5038
|
const nameErr = validateMindName(name);
|
|
@@ -4980,7 +5052,7 @@ ${user.trimEnd()}
|
|
|
4980
5052
|
` : "";
|
|
4981
5053
|
ensureVoluteHome();
|
|
4982
5054
|
const dest = mindDir(name);
|
|
4983
|
-
if (
|
|
5055
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4984
5056
|
const templatesRoot = findTemplatesRoot();
|
|
4985
5057
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
4986
5058
|
try {
|
|
@@ -4989,7 +5061,7 @@ ${user.trimEnd()}
|
|
|
4989
5061
|
const { publicKeyPem: importPublicKey } = generateIdentity(dest);
|
|
4990
5062
|
writeFileSync8(resolve11(dest, "home/SOUL.md"), mergedSoul);
|
|
4991
5063
|
const wsMemoryPath = resolve11(wsDir, "MEMORY.md");
|
|
4992
|
-
const hasMemory =
|
|
5064
|
+
const hasMemory = existsSync7(wsMemoryPath);
|
|
4993
5065
|
if (hasMemory) {
|
|
4994
5066
|
const existingMemory = readFileSync9(wsMemoryPath, "utf-8");
|
|
4995
5067
|
writeFileSync8(
|
|
@@ -5002,7 +5074,7 @@ ${user.trimEnd()}
|
|
|
5002
5074
|
}
|
|
5003
5075
|
const wsMemoryDir = resolve11(wsDir, "memory");
|
|
5004
5076
|
let dailyLogCount = 0;
|
|
5005
|
-
if (
|
|
5077
|
+
if (existsSync7(wsMemoryDir)) {
|
|
5006
5078
|
const destMemoryDir = resolve11(dest, "home/memory");
|
|
5007
5079
|
const files = readdirSync2(wsMemoryDir).filter((f) => f.endsWith(".md"));
|
|
5008
5080
|
for (const file of files) {
|
|
@@ -5031,7 +5103,7 @@ ${user.trimEnd()}
|
|
|
5031
5103
|
await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
|
|
5032
5104
|
await gitExec(["commit", "-m", "import from OpenClaw"], { cwd: dest, mindName: name, env });
|
|
5033
5105
|
const sessionFile = body.sessionPath ? resolve11(body.sessionPath) : findOpenClawSession(wsDir);
|
|
5034
|
-
if (sessionFile &&
|
|
5106
|
+
if (sessionFile && existsSync7(sessionFile)) {
|
|
5035
5107
|
if (template === "pi") {
|
|
5036
5108
|
importPiSession(sessionFile, dest);
|
|
5037
5109
|
} else if (template === "claude") {
|
|
@@ -5048,14 +5120,14 @@ ${user.trimEnd()}
|
|
|
5048
5120
|
);
|
|
5049
5121
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
5050
5122
|
} catch (err) {
|
|
5051
|
-
if (
|
|
5123
|
+
if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
|
|
5052
5124
|
try {
|
|
5053
5125
|
await removeMind(name);
|
|
5054
5126
|
} catch {
|
|
5055
5127
|
}
|
|
5056
5128
|
return c.json({ error: err instanceof Error ? err.message : "Failed to import mind" }, 500);
|
|
5057
5129
|
} finally {
|
|
5058
|
-
|
|
5130
|
+
rmSync3(composedDir, { recursive: true, force: true });
|
|
5059
5131
|
}
|
|
5060
5132
|
}).get("/", async (c) => {
|
|
5061
5133
|
const entries = await readRegistry();
|
|
@@ -5080,7 +5152,7 @@ ${user.trimEnd()}
|
|
|
5080
5152
|
const minds = await Promise.all(
|
|
5081
5153
|
entries.map(async (entry) => {
|
|
5082
5154
|
const mindStatus = await getMindStatus(entry.name, entry.port, entry.running);
|
|
5083
|
-
const hasPages =
|
|
5155
|
+
const hasPages = existsSync7(resolve11(mindDir(entry.name), "home", "pages"));
|
|
5084
5156
|
const lastActiveAt = lastActiveMap.get(entry.name) ?? null;
|
|
5085
5157
|
if (!privileged) return toPublicMind(entry, mindStatus, { hasPages, lastActiveAt });
|
|
5086
5158
|
return {
|
|
@@ -5098,9 +5170,9 @@ ${user.trimEnd()}
|
|
|
5098
5170
|
const entry = await findMind(name);
|
|
5099
5171
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5100
5172
|
const dir = entry.dir ?? mindDir(entry.parent ?? name);
|
|
5101
|
-
if (!
|
|
5173
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5102
5174
|
const mindStatus = await getMindStatus(name, entry.port);
|
|
5103
|
-
const hasPages =
|
|
5175
|
+
const hasPages = existsSync7(resolve11(mindDir(name), "home", "pages"));
|
|
5104
5176
|
if (!isPrivileged(c)) {
|
|
5105
5177
|
return c.json(toPublicMind(entry, mindStatus, { hasPages }));
|
|
5106
5178
|
}
|
|
@@ -5137,11 +5209,11 @@ ${user.trimEnd()}
|
|
|
5137
5209
|
const entry = await findMind(name);
|
|
5138
5210
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5139
5211
|
const targetPort = entry.port;
|
|
5212
|
+
const projectDir = entry.dir ?? mindDir(name);
|
|
5140
5213
|
if (entry.parent) {
|
|
5141
5214
|
if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
|
|
5142
|
-
} else {
|
|
5143
|
-
|
|
5144
|
-
if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5215
|
+
} else if (!existsSync7(projectDir)) {
|
|
5216
|
+
return c.json({ error: "Mind directory missing" }, 404);
|
|
5145
5217
|
}
|
|
5146
5218
|
if (getMindManager().isRunning(name)) {
|
|
5147
5219
|
return c.json({ error: "Mind already running" }, 409);
|
|
@@ -5158,11 +5230,11 @@ ${user.trimEnd()}
|
|
|
5158
5230
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5159
5231
|
const baseName = entry.parent ?? name;
|
|
5160
5232
|
const targetPort = entry.port;
|
|
5233
|
+
const projectDir = entry.dir ?? mindDir(name);
|
|
5161
5234
|
if (entry.parent) {
|
|
5162
5235
|
if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
|
|
5163
|
-
} else {
|
|
5164
|
-
|
|
5165
|
-
if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5236
|
+
} else if (!existsSync7(projectDir)) {
|
|
5237
|
+
return c.json({ error: "Mind directory missing" }, 404);
|
|
5166
5238
|
}
|
|
5167
5239
|
let context;
|
|
5168
5240
|
const contentType = c.req.header("content-type");
|
|
@@ -5177,7 +5249,7 @@ ${user.trimEnd()}
|
|
|
5177
5249
|
const manager = getMindManager();
|
|
5178
5250
|
try {
|
|
5179
5251
|
if (context?.type === "reload") {
|
|
5180
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5252
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-DSPXFHGX.js");
|
|
5181
5253
|
const sleepState = getSleepManagerIfReady2()?.getState(name);
|
|
5182
5254
|
if (sleepState?.sleeping) {
|
|
5183
5255
|
logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
|
|
@@ -5197,7 +5269,7 @@ ${user.trimEnd()}
|
|
|
5197
5269
|
const variantEntry = await findMind(mergeVariantName);
|
|
5198
5270
|
if (variantEntry && variantEntry.parent === baseName && variantEntry.dir && variantEntry.branch) {
|
|
5199
5271
|
const projectRoot = mindDir(baseName);
|
|
5200
|
-
if (
|
|
5272
|
+
if (existsSync7(variantEntry.dir)) {
|
|
5201
5273
|
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
5202
5274
|
if (status) {
|
|
5203
5275
|
try {
|
|
@@ -5224,7 +5296,8 @@ ${user.trimEnd()}
|
|
|
5224
5296
|
logger_default.error(`failed to auto-commit main worktree for ${baseName}`, logger_default.errorData(e));
|
|
5225
5297
|
}
|
|
5226
5298
|
}
|
|
5227
|
-
await
|
|
5299
|
+
const memoryDelta = await mergeVariantExcludingMemory(projectRoot, variantEntry.branch);
|
|
5300
|
+
if (memoryDelta && context) context.memoryDelta = memoryDelta;
|
|
5228
5301
|
await cleanupVariant(mergeVariantName, projectRoot, variantEntry.dir);
|
|
5229
5302
|
try {
|
|
5230
5303
|
await npmInstallAsMind(projectRoot, baseName);
|
|
@@ -5238,18 +5311,12 @@ ${user.trimEnd()}
|
|
|
5238
5311
|
}
|
|
5239
5312
|
if (context?.type === "sprouted" && !entry.parent) {
|
|
5240
5313
|
try {
|
|
5241
|
-
|
|
5242
|
-
for (const conv of mindConvs) {
|
|
5243
|
-
await recordInbound(baseName, "system", "system", "[seed has sprouted]");
|
|
5244
|
-
await addMessage(conv.id, "assistant", "system", [
|
|
5245
|
-
{ type: "text", text: "[seed has sprouted]" }
|
|
5246
|
-
]);
|
|
5247
|
-
}
|
|
5314
|
+
await deliverSproutedNotice(baseName);
|
|
5248
5315
|
} catch (err) {
|
|
5249
5316
|
logger_default.error(`failed to inject sprouted message for ${baseName}`, logger_default.errorData(err));
|
|
5250
5317
|
}
|
|
5251
5318
|
}
|
|
5252
|
-
const repoDir =
|
|
5319
|
+
const repoDir = projectDir;
|
|
5253
5320
|
try {
|
|
5254
5321
|
await startMindFull(name);
|
|
5255
5322
|
} catch (startErr) {
|
|
@@ -5304,7 +5371,7 @@ ${user.trimEnd()}
|
|
|
5304
5371
|
const name = c.req.param("name");
|
|
5305
5372
|
const entry = await findMind(name);
|
|
5306
5373
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5307
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5374
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-DSPXFHGX.js");
|
|
5308
5375
|
const sm = getSleepManagerIfReady2();
|
|
5309
5376
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5310
5377
|
return c.json(sm.getState(name));
|
|
@@ -5312,7 +5379,7 @@ ${user.trimEnd()}
|
|
|
5312
5379
|
const name = c.req.param("name");
|
|
5313
5380
|
const entry = await findMind(name);
|
|
5314
5381
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5315
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5382
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-DSPXFHGX.js");
|
|
5316
5383
|
const sm = getSleepManagerIfReady2();
|
|
5317
5384
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5318
5385
|
if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
|
|
@@ -5332,7 +5399,7 @@ ${user.trimEnd()}
|
|
|
5332
5399
|
const name = c.req.param("name");
|
|
5333
5400
|
const entry = await findMind(name);
|
|
5334
5401
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5335
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5402
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-DSPXFHGX.js");
|
|
5336
5403
|
const sm = getSleepManagerIfReady2();
|
|
5337
5404
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5338
5405
|
const sleepState = sm.getState(name);
|
|
@@ -5347,7 +5414,7 @@ ${user.trimEnd()}
|
|
|
5347
5414
|
const name = c.req.param("name");
|
|
5348
5415
|
const entry = await findMind(name);
|
|
5349
5416
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5350
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5417
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-DSPXFHGX.js");
|
|
5351
5418
|
const sm = getSleepManagerIfReady2();
|
|
5352
5419
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5353
5420
|
const flushed = await sm.flushQueuedMessages(name);
|
|
@@ -5368,14 +5435,14 @@ ${user.trimEnd()}
|
|
|
5368
5435
|
if (!avatarPath) {
|
|
5369
5436
|
return c.json({ error: "Avatar path must be inside the mind's home directory" }, 400);
|
|
5370
5437
|
}
|
|
5371
|
-
if (!
|
|
5438
|
+
if (!existsSync7(avatarPath)) {
|
|
5372
5439
|
return c.json({ error: `Avatar file not found: ${relative(homeDir, avatarPath)}` }, 400);
|
|
5373
5440
|
}
|
|
5374
5441
|
profile.avatar = relative(homeDir, avatarPath);
|
|
5375
5442
|
}
|
|
5376
5443
|
config2.profile = profile;
|
|
5377
5444
|
writeVoluteConfig(dir, config2);
|
|
5378
|
-
const { syncMindProfile: syncMindProfile2 } = await import("./auth-
|
|
5445
|
+
const { syncMindProfile: syncMindProfile2 } = await import("./auth-ABYLOEZ7.js");
|
|
5379
5446
|
await syncMindProfile2(name, profile);
|
|
5380
5447
|
broadcast({ type: "profile_updated", mind: name, summary: `${name} profile updated` });
|
|
5381
5448
|
return c.json({ ok: true });
|
|
@@ -5414,7 +5481,7 @@ ${user.trimEnd()}
|
|
|
5414
5481
|
return c.json({ output: "" });
|
|
5415
5482
|
}
|
|
5416
5483
|
const dir = entry.dir ?? mindDir(name);
|
|
5417
|
-
const { evaluateSeedChecklist } = await import("./seed-readiness-
|
|
5484
|
+
const { evaluateSeedChecklist } = await import("./seed-readiness-3LRYASA4.js");
|
|
5418
5485
|
const checklist = evaluateSeedChecklist(dir);
|
|
5419
5486
|
const done = [];
|
|
5420
5487
|
const remaining = [];
|
|
@@ -5449,10 +5516,13 @@ ${user.trimEnd()}
|
|
|
5449
5516
|
return c.json({ error: `Mind is not a seed (stage: ${entry.stage})` }, 409);
|
|
5450
5517
|
}
|
|
5451
5518
|
await setMindStage(name, "sprouted");
|
|
5519
|
+
await joinSystemChannelForMind(name).catch(
|
|
5520
|
+
(err) => logger_default.warn(`failed to join #system on sprout for ${name}`, logger_default.errorData(err))
|
|
5521
|
+
);
|
|
5452
5522
|
try {
|
|
5453
5523
|
const sproutedDir = entry.dir ?? mindDir(name);
|
|
5454
5524
|
if (setupDefaultDreaming(sproutedDir).schedulesChanged) {
|
|
5455
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
5525
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-K7Y7Z7FQ.js");
|
|
5456
5526
|
getScheduler2().loadSchedules(name, sproutedDir);
|
|
5457
5527
|
}
|
|
5458
5528
|
} catch (err) {
|
|
@@ -5461,7 +5531,7 @@ ${user.trimEnd()}
|
|
|
5461
5531
|
try {
|
|
5462
5532
|
const spiritEntry = await findMind("volute");
|
|
5463
5533
|
if (spiritEntry) {
|
|
5464
|
-
const { firstWeekSchedules, spiritDir } = await import("./spirit-
|
|
5534
|
+
const { firstWeekSchedules, spiritDir } = await import("./spirit-SSJMYC6A.js");
|
|
5465
5535
|
const sDir = spiritEntry.dir ?? spiritDir();
|
|
5466
5536
|
const spiritConfig = readVoluteConfig(sDir);
|
|
5467
5537
|
if (spiritConfig) {
|
|
@@ -5475,7 +5545,7 @@ ${user.trimEnd()}
|
|
|
5475
5545
|
spiritConfig.schedules = schedules;
|
|
5476
5546
|
writeVoluteConfig(sDir, spiritConfig);
|
|
5477
5547
|
try {
|
|
5478
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
5548
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-K7Y7Z7FQ.js");
|
|
5479
5549
|
getScheduler2().loadSchedules("volute", sDir);
|
|
5480
5550
|
} catch (err) {
|
|
5481
5551
|
logger_default.warn(
|
|
@@ -5513,11 +5583,11 @@ ${user.trimEnd()}
|
|
|
5513
5583
|
await deleteMindUser2(name);
|
|
5514
5584
|
invalidateMindUserCache(name);
|
|
5515
5585
|
const state = stateDir(name);
|
|
5516
|
-
if (
|
|
5517
|
-
|
|
5586
|
+
if (existsSync7(state)) {
|
|
5587
|
+
rmSync3(state, { recursive: true, force: true });
|
|
5518
5588
|
}
|
|
5519
|
-
if (force &&
|
|
5520
|
-
|
|
5589
|
+
if (force && existsSync7(dir)) {
|
|
5590
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
5521
5591
|
deleteMindUser(name);
|
|
5522
5592
|
}
|
|
5523
5593
|
fireWebhook({
|
|
@@ -5531,7 +5601,7 @@ ${user.trimEnd()}
|
|
|
5531
5601
|
const entry = await findMind(mindName);
|
|
5532
5602
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5533
5603
|
const dir = mindDir(mindName);
|
|
5534
|
-
if (!
|
|
5604
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5535
5605
|
let body = {};
|
|
5536
5606
|
try {
|
|
5537
5607
|
body = await c.req.json();
|
|
@@ -5546,14 +5616,14 @@ ${user.trimEnd()}
|
|
|
5546
5616
|
const upgradeVariantName = `${mindName}-upgrade`;
|
|
5547
5617
|
const worktreeDir = resolve11(dir, ".variants", UPGRADE_BRANCH);
|
|
5548
5618
|
if (body.abort) {
|
|
5549
|
-
if (!
|
|
5619
|
+
if (!existsSync7(worktreeDir)) {
|
|
5550
5620
|
return c.json({ error: "No upgrade in progress" }, 400);
|
|
5551
5621
|
}
|
|
5552
5622
|
try {
|
|
5553
5623
|
try {
|
|
5554
5624
|
const gitDirContent = readFileSync9(resolve11(worktreeDir, ".git"), "utf-8").trim();
|
|
5555
5625
|
const gitDir = gitDirContent.replace("gitdir: ", "");
|
|
5556
|
-
if (
|
|
5626
|
+
if (existsSync7(resolve11(gitDir, "MERGE_HEAD"))) {
|
|
5557
5627
|
await gitExec(["merge", "--abort"], { cwd: worktreeDir });
|
|
5558
5628
|
}
|
|
5559
5629
|
} catch {
|
|
@@ -5572,7 +5642,7 @@ ${user.trimEnd()}
|
|
|
5572
5642
|
}
|
|
5573
5643
|
}
|
|
5574
5644
|
if (body.continue) {
|
|
5575
|
-
if (!
|
|
5645
|
+
if (!existsSync7(worktreeDir)) {
|
|
5576
5646
|
return c.json({ error: "No upgrade in progress" }, 400);
|
|
5577
5647
|
}
|
|
5578
5648
|
const status = await gitExec(["status", "--porcelain"], { cwd: worktreeDir });
|
|
@@ -5622,7 +5692,7 @@ ${user.trimEnd()}
|
|
|
5622
5692
|
}
|
|
5623
5693
|
}
|
|
5624
5694
|
if (body.accept) {
|
|
5625
|
-
if (
|
|
5695
|
+
if (existsSync7(worktreeDir)) {
|
|
5626
5696
|
try {
|
|
5627
5697
|
await cleanupVariant(upgradeVariantName, dir, worktreeDir, { stop: true });
|
|
5628
5698
|
} catch (err) {
|
|
@@ -5637,7 +5707,7 @@ ${user.trimEnd()}
|
|
|
5637
5707
|
}
|
|
5638
5708
|
if (body.diff) {
|
|
5639
5709
|
try {
|
|
5640
|
-
if (!
|
|
5710
|
+
if (!existsSync7(resolve11(dir, ".git"))) {
|
|
5641
5711
|
return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
|
|
5642
5712
|
}
|
|
5643
5713
|
await updateTemplateBranch(dir, template, mindName);
|
|
@@ -5655,13 +5725,13 @@ ${user.trimEnd()}
|
|
|
5655
5725
|
);
|
|
5656
5726
|
}
|
|
5657
5727
|
}
|
|
5658
|
-
if (
|
|
5728
|
+
if (existsSync7(worktreeDir)) {
|
|
5659
5729
|
return c.json(
|
|
5660
5730
|
{ error: "Upgrade variant already exists. Use continue or delete it first." },
|
|
5661
5731
|
409
|
|
5662
5732
|
);
|
|
5663
5733
|
}
|
|
5664
|
-
if (!
|
|
5734
|
+
if (!existsSync7(resolve11(dir, ".git"))) {
|
|
5665
5735
|
try {
|
|
5666
5736
|
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dir, "home") } : void 0;
|
|
5667
5737
|
await gitExec(["init"], { cwd: dir, mindName, env });
|
|
@@ -5670,7 +5740,7 @@ ${user.trimEnd()}
|
|
|
5670
5740
|
await gitExec(["commit", "-m", "initial commit"], { cwd: dir, mindName, env });
|
|
5671
5741
|
await chownMindDir(dir, mindName);
|
|
5672
5742
|
} catch (err) {
|
|
5673
|
-
|
|
5743
|
+
rmSync3(resolve11(dir, ".git"), { recursive: true, force: true });
|
|
5674
5744
|
return c.json(
|
|
5675
5745
|
{
|
|
5676
5746
|
error: `Git initialization failed: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -5686,7 +5756,7 @@ ${user.trimEnd()}
|
|
|
5686
5756
|
}
|
|
5687
5757
|
await updateTemplateBranch(dir, template, mindName);
|
|
5688
5758
|
const parentDir = resolve11(dir, ".variants");
|
|
5689
|
-
if (!
|
|
5759
|
+
if (!existsSync7(parentDir)) {
|
|
5690
5760
|
mkdirSync6(parentDir, { recursive: true });
|
|
5691
5761
|
}
|
|
5692
5762
|
await gitExec(["worktree", "add", "-b", UPGRADE_BRANCH, worktreeDir], { cwd: dir });
|
|
@@ -5816,11 +5886,11 @@ ${user.trimEnd()}
|
|
|
5816
5886
|
const entry = await findMind(name);
|
|
5817
5887
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5818
5888
|
const dir = entry.dir ?? mindDir(name);
|
|
5819
|
-
if (!
|
|
5889
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5820
5890
|
let config2 = readVoluteConfig(dir);
|
|
5821
5891
|
if (!config2 && entry.template === "pi") {
|
|
5822
5892
|
const piConfigPath = resolve11(dir, "home/.config/config.json");
|
|
5823
|
-
if (
|
|
5893
|
+
if (existsSync7(piConfigPath)) {
|
|
5824
5894
|
try {
|
|
5825
5895
|
config2 = JSON.parse(readFileSync9(piConfigPath, "utf-8"));
|
|
5826
5896
|
} catch {
|
|
@@ -5829,7 +5899,7 @@ ${user.trimEnd()}
|
|
|
5829
5899
|
}
|
|
5830
5900
|
let templateConfig = {};
|
|
5831
5901
|
const configJsonPath = resolve11(dir, "home/.config/config.json");
|
|
5832
|
-
if (
|
|
5902
|
+
if (existsSync7(configJsonPath)) {
|
|
5833
5903
|
try {
|
|
5834
5904
|
templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
|
|
5835
5905
|
} catch {
|
|
@@ -5871,7 +5941,7 @@ ${user.trimEnd()}
|
|
|
5871
5941
|
const entry = await findMind(name);
|
|
5872
5942
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5873
5943
|
const dir = entry.dir ?? mindDir(name);
|
|
5874
|
-
if (!
|
|
5944
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5875
5945
|
const body = c.req.valid("json");
|
|
5876
5946
|
const existing = readVoluteConfig(dir) ?? {};
|
|
5877
5947
|
if (body.model !== void 0) existing.model = body.model;
|
|
@@ -5897,14 +5967,14 @@ ${user.trimEnd()}
|
|
|
5897
5967
|
}
|
|
5898
5968
|
writeVoluteConfig(dir, existing);
|
|
5899
5969
|
if (body.unescapeNewlines !== void 0) {
|
|
5900
|
-
const { clearEchoTextCache } = await import("./echo-text-
|
|
5970
|
+
const { clearEchoTextCache } = await import("./echo-text-B6NZ5FGE.js");
|
|
5901
5971
|
clearEchoTextCache(name);
|
|
5902
5972
|
}
|
|
5903
5973
|
const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.compaction !== void 0;
|
|
5904
5974
|
if (needsConfigJson) {
|
|
5905
5975
|
const configJsonPath = resolve11(dir, "home/.config/config.json");
|
|
5906
5976
|
let templateConfig = {};
|
|
5907
|
-
if (
|
|
5977
|
+
if (existsSync7(configJsonPath)) {
|
|
5908
5978
|
try {
|
|
5909
5979
|
templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
|
|
5910
5980
|
} catch {
|
|
@@ -5934,7 +6004,7 @@ ${user.trimEnd()}
|
|
|
5934
6004
|
}
|
|
5935
6005
|
if (entry.mindType === "spirit" && body.model !== void 0) {
|
|
5936
6006
|
try {
|
|
5937
|
-
const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-
|
|
6007
|
+
const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-TCN7VH5U.js");
|
|
5938
6008
|
const globalConfig = readGlobalConfig2();
|
|
5939
6009
|
globalConfig.spiritModel = body.model;
|
|
5940
6010
|
writeGlobalConfig2(globalConfig);
|
|
@@ -5977,7 +6047,7 @@ ${user.trimEnd()}
|
|
|
5977
6047
|
if (!body.systemPrompt || !body.message) {
|
|
5978
6048
|
return c.json({ error: "systemPrompt and message required" }, 400);
|
|
5979
6049
|
}
|
|
5980
|
-
const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-
|
|
6050
|
+
const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-A7FS7EC3.js");
|
|
5981
6051
|
if (!isAiConfigured()) {
|
|
5982
6052
|
return c.json({ error: "AI service not configured" }, 503);
|
|
5983
6053
|
}
|
|
@@ -6452,7 +6522,8 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
|
|
|
6452
6522
|
const schedules = readSchedules(dir);
|
|
6453
6523
|
const now = /* @__PURE__ */ new Date();
|
|
6454
6524
|
const { upcoming, previous } = computeClockEvents(schedules, sleepState, sleepConfig, now);
|
|
6455
|
-
|
|
6525
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
6526
|
+
return c.json({ sleep: sleepState, sleepConfig, schedules, upcoming, previous, timezone });
|
|
6456
6527
|
}).get("/:name/sleep/config", requireSelf(), async (c) => {
|
|
6457
6528
|
const name = c.req.param("name");
|
|
6458
6529
|
const entry = await findMind(name);
|
|
@@ -6639,8 +6710,8 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
|
|
|
6639
6710
|
const body = await c.req.text();
|
|
6640
6711
|
const message = `[webhook: ${event}] ${body}`;
|
|
6641
6712
|
try {
|
|
6642
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
6643
|
-
await
|
|
6713
|
+
const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-M2XOBKEM.js");
|
|
6714
|
+
await sendSystemMessage2(name, message);
|
|
6644
6715
|
return c.json({ ok: true });
|
|
6645
6716
|
} catch (err) {
|
|
6646
6717
|
slog2.warn(`webhook delivery failed for ${name}`, logger_default.errorData(err));
|
|
@@ -6693,7 +6764,7 @@ setup.get("/status", async (c) => {
|
|
|
6693
6764
|
let hasAccount = false;
|
|
6694
6765
|
if (hasSystem) {
|
|
6695
6766
|
try {
|
|
6696
|
-
const { listUsersByType: listUsersByType2 } = await import("./auth-
|
|
6767
|
+
const { listUsersByType: listUsersByType2 } = await import("./auth-ABYLOEZ7.js");
|
|
6697
6768
|
const brains = await listUsersByType2("brain");
|
|
6698
6769
|
hasAccount = brains.length > 0;
|
|
6699
6770
|
} catch (err) {
|
|
@@ -6904,7 +6975,7 @@ setup.post("/account", async (c) => {
|
|
|
6904
6975
|
}
|
|
6905
6976
|
}
|
|
6906
6977
|
try {
|
|
6907
|
-
const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-
|
|
6978
|
+
const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-ABYLOEZ7.js");
|
|
6908
6979
|
const user = await createUser2(body.username.trim(), body.password);
|
|
6909
6980
|
if (body.displayName?.trim()) {
|
|
6910
6981
|
await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
|
|
@@ -6950,7 +7021,7 @@ setup.post("/models", async (c) => {
|
|
|
6950
7021
|
return c.json({ error: "Spirit model is required" }, 400);
|
|
6951
7022
|
}
|
|
6952
7023
|
try {
|
|
6953
|
-
const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-
|
|
7024
|
+
const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-A7FS7EC3.js");
|
|
6954
7025
|
setEnabledModels3(body.models);
|
|
6955
7026
|
const config2 = readGlobalConfig();
|
|
6956
7027
|
config2.spiritModel = body.spiritModel.trim();
|
|
@@ -6968,15 +7039,15 @@ setup.post("/complete", async (c) => {
|
|
|
6968
7039
|
return c.json({ error: "Setup already complete" }, 400);
|
|
6969
7040
|
}
|
|
6970
7041
|
try {
|
|
6971
|
-
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-
|
|
6972
|
-
const { startSpiritFull } = await import("./mind-service-
|
|
7042
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-SSJMYC6A.js");
|
|
7043
|
+
const { startSpiritFull } = await import("./mind-service-42GDO4KH.js");
|
|
6973
7044
|
await ensureSpiritProject();
|
|
6974
7045
|
await syncSpiritTemplate();
|
|
6975
7046
|
const warnings = [];
|
|
6976
7047
|
const config2 = readGlobalConfig();
|
|
6977
7048
|
if (config2.setup?.service && config2.setup?.type === "local") {
|
|
6978
7049
|
try {
|
|
6979
|
-
const { installUserService } = await import("./service-install-
|
|
7050
|
+
const { installUserService } = await import("./service-install-Y46OTF55.js");
|
|
6980
7051
|
const installed = await installUserService(config2.port, config2.hostname);
|
|
6981
7052
|
if (!installed) {
|
|
6982
7053
|
warnings.push("Service installation is not supported on this platform.");
|
|
@@ -7005,8 +7076,8 @@ setup.post("/complete", async (c) => {
|
|
|
7005
7076
|
}
|
|
7006
7077
|
let spiritConversationId;
|
|
7007
7078
|
try {
|
|
7008
|
-
const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-
|
|
7009
|
-
const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-
|
|
7079
|
+
const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-ABYLOEZ7.js");
|
|
7080
|
+
const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-TUM5PJJ4.js");
|
|
7010
7081
|
const spiritUser = await getOrCreateMindUser2("volute");
|
|
7011
7082
|
const brains = await listUsersByType2("brain");
|
|
7012
7083
|
const admin2 = brains.find((u) => u.role === "admin");
|
|
@@ -7028,8 +7099,8 @@ setup.post("/complete", async (c) => {
|
|
|
7028
7099
|
logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
|
|
7029
7100
|
if (spiritConversationId && spiritStarted) {
|
|
7030
7101
|
try {
|
|
7031
|
-
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-
|
|
7032
|
-
const { listUsersByType: listUsers2 } = await import("./auth-
|
|
7102
|
+
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-ABPV76EA.js");
|
|
7103
|
+
const { listUsersByType: listUsers2 } = await import("./auth-ABYLOEZ7.js");
|
|
7033
7104
|
const admins = await listUsers2("brain");
|
|
7034
7105
|
const admin2 = admins.find((u) => u.role === "admin");
|
|
7035
7106
|
if (admin2) {
|
|
@@ -7068,7 +7139,7 @@ setup.post("/complete", async (c) => {
|
|
|
7068
7139
|
var setup_default = setup;
|
|
7069
7140
|
|
|
7070
7141
|
// packages/daemon/src/web/api/skills.ts
|
|
7071
|
-
import { existsSync as
|
|
7142
|
+
import { existsSync as existsSync8, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync4 } from "fs";
|
|
7072
7143
|
import { tmpdir } from "os";
|
|
7073
7144
|
import { join, resolve as resolve13 } from "path";
|
|
7074
7145
|
import AdmZip from "adm-zip";
|
|
@@ -7153,12 +7224,12 @@ var app16 = new Hono20().get("/", async (c) => {
|
|
|
7153
7224
|
}
|
|
7154
7225
|
zip.extractAllTo(tmpDir, true);
|
|
7155
7226
|
let skillDir = null;
|
|
7156
|
-
if (
|
|
7227
|
+
if (existsSync8(join(tmpDir, "SKILL.md"))) {
|
|
7157
7228
|
skillDir = tmpDir;
|
|
7158
7229
|
} else {
|
|
7159
7230
|
const entries = readdirSync3(tmpDir, { withFileTypes: true }).filter((e) => e.isDirectory());
|
|
7160
7231
|
for (const entry of entries) {
|
|
7161
|
-
if (
|
|
7232
|
+
if (existsSync8(join(tmpDir, entry.name, "SKILL.md"))) {
|
|
7162
7233
|
skillDir = join(tmpDir, entry.name);
|
|
7163
7234
|
break;
|
|
7164
7235
|
}
|
|
@@ -7175,7 +7246,7 @@ var app16 = new Hono20().get("/", async (c) => {
|
|
|
7175
7246
|
}
|
|
7176
7247
|
throw e;
|
|
7177
7248
|
} finally {
|
|
7178
|
-
|
|
7249
|
+
rmSync4(tmpDir, { recursive: true, force: true });
|
|
7179
7250
|
}
|
|
7180
7251
|
}).get("/:id", async (c) => {
|
|
7181
7252
|
const id = c.req.param("id");
|
|
@@ -7472,8 +7543,8 @@ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
|
|
|
7472
7543
|
});
|
|
7473
7544
|
}, 15e3);
|
|
7474
7545
|
cleanups.push(() => clearInterval(keepAlive));
|
|
7475
|
-
await new Promise((
|
|
7476
|
-
stream.onAbort(() =>
|
|
7546
|
+
await new Promise((resolve19) => {
|
|
7547
|
+
stream.onAbort(() => resolve19());
|
|
7477
7548
|
});
|
|
7478
7549
|
} finally {
|
|
7479
7550
|
for (const cleanup of cleanups) {
|
|
@@ -7489,13 +7560,102 @@ var events_default = app20;
|
|
|
7489
7560
|
|
|
7490
7561
|
// packages/daemon/src/web/api/variants.ts
|
|
7491
7562
|
import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
7492
|
-
import { resolve as
|
|
7563
|
+
import { resolve as resolve16 } from "path";
|
|
7493
7564
|
import { Hono as Hono25 } from "hono";
|
|
7494
7565
|
|
|
7566
|
+
// packages/daemon/src/lib/mind/farewell.ts
|
|
7567
|
+
import { existsSync as existsSync9, readFileSync as readFileSync10, rmSync as rmSync5 } from "fs";
|
|
7568
|
+
import { resolve as resolve14 } from "path";
|
|
7569
|
+
var flog = logger_default.child("farewell");
|
|
7570
|
+
var FAREWELL_RELPATH = ".mind/farewell.md";
|
|
7571
|
+
var FAREWELL_MIND_PATH = "../.mind/farewell.md";
|
|
7572
|
+
var FAREWELL_TIMEOUT_MS = 12e4;
|
|
7573
|
+
function farewellPath(variantDir) {
|
|
7574
|
+
return resolve14(variantDir, FAREWELL_RELPATH);
|
|
7575
|
+
}
|
|
7576
|
+
function readFarewell(variantDir) {
|
|
7577
|
+
const path = farewellPath(variantDir);
|
|
7578
|
+
if (!existsSync9(path)) return void 0;
|
|
7579
|
+
try {
|
|
7580
|
+
const text = readFileSync10(path, "utf-8").trim();
|
|
7581
|
+
return text || void 0;
|
|
7582
|
+
} catch (err) {
|
|
7583
|
+
flog.warn(`failed to read farewell note at ${path}`, logger_default.errorData(err));
|
|
7584
|
+
return void 0;
|
|
7585
|
+
}
|
|
7586
|
+
}
|
|
7587
|
+
function waitForFarewell(name, variantDir, timeoutMs) {
|
|
7588
|
+
let settle;
|
|
7589
|
+
const done = new Promise((resolvePromise) => {
|
|
7590
|
+
settle = resolvePromise;
|
|
7591
|
+
});
|
|
7592
|
+
const cleanup = () => {
|
|
7593
|
+
clearTimeout(timeout);
|
|
7594
|
+
unsub();
|
|
7595
|
+
settle();
|
|
7596
|
+
};
|
|
7597
|
+
const timeout = setTimeout(cleanup, timeoutMs);
|
|
7598
|
+
const unsub = subscribe((event) => {
|
|
7599
|
+
if (event.mind !== name) return;
|
|
7600
|
+
if (event.type !== "mind_done" && event.type !== "mind_idle") return;
|
|
7601
|
+
if (existsSync9(farewellPath(variantDir))) cleanup();
|
|
7602
|
+
});
|
|
7603
|
+
return { done, cancel: cleanup };
|
|
7604
|
+
}
|
|
7605
|
+
async function runFarewellTurn(opts) {
|
|
7606
|
+
const { variantName, parentName, variantDir, port, running } = opts;
|
|
7607
|
+
const timeoutMs = opts.timeoutMs ?? FAREWELL_TIMEOUT_MS;
|
|
7608
|
+
if (!running) return readFarewell(variantDir);
|
|
7609
|
+
try {
|
|
7610
|
+
rmSync5(farewellPath(variantDir), { force: true });
|
|
7611
|
+
} catch (err) {
|
|
7612
|
+
flog.warn(`failed to clear stale farewell note for ${variantName}`, logger_default.errorData(err));
|
|
7613
|
+
}
|
|
7614
|
+
const message = await getPrompt("farewell_message", {
|
|
7615
|
+
parent: parentName,
|
|
7616
|
+
path: FAREWELL_MIND_PATH
|
|
7617
|
+
});
|
|
7618
|
+
let conversationId;
|
|
7619
|
+
try {
|
|
7620
|
+
const result = await sendSystemMessageDirect(variantName, message);
|
|
7621
|
+
conversationId = result.conversationId;
|
|
7622
|
+
} catch (err) {
|
|
7623
|
+
flog.error(`failed to persist farewell message for ${variantName}`, logger_default.errorData(err));
|
|
7624
|
+
}
|
|
7625
|
+
const waiter = waitForFarewell(variantName, variantDir, timeoutMs);
|
|
7626
|
+
let delivered = false;
|
|
7627
|
+
try {
|
|
7628
|
+
const res = await fetch(`http://127.0.0.1:${port}/message`, {
|
|
7629
|
+
method: "POST",
|
|
7630
|
+
headers: { "Content-Type": "application/json" },
|
|
7631
|
+
body: JSON.stringify({
|
|
7632
|
+
content: [{ type: "text", text: message }],
|
|
7633
|
+
channel: "@volute",
|
|
7634
|
+
sender: "volute",
|
|
7635
|
+
isDM: true,
|
|
7636
|
+
participants: ["volute", variantName],
|
|
7637
|
+
participantCount: 2,
|
|
7638
|
+
...conversationId ? { conversationId } : {}
|
|
7639
|
+
}),
|
|
7640
|
+
signal: AbortSignal.timeout(1e4)
|
|
7641
|
+
});
|
|
7642
|
+
if (res.ok) delivered = true;
|
|
7643
|
+
else flog.warn(`farewell delivery to ${variantName} returned HTTP ${res.status}`);
|
|
7644
|
+
} catch (err) {
|
|
7645
|
+
flog.warn(`failed to deliver farewell message to ${variantName}`, logger_default.errorData(err));
|
|
7646
|
+
}
|
|
7647
|
+
if (delivered) {
|
|
7648
|
+
await waiter.done;
|
|
7649
|
+
} else {
|
|
7650
|
+
waiter.cancel();
|
|
7651
|
+
}
|
|
7652
|
+
return readFarewell(variantDir);
|
|
7653
|
+
}
|
|
7654
|
+
|
|
7495
7655
|
// packages/daemon/src/lib/mind/spawn-server.ts
|
|
7496
7656
|
import { spawn as spawn4 } from "child_process";
|
|
7497
|
-
import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as
|
|
7498
|
-
import { resolve as
|
|
7657
|
+
import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync11, statSync as statSync3 } from "fs";
|
|
7658
|
+
import { resolve as resolve15 } from "path";
|
|
7499
7659
|
async function spawnServer(cwd, port, options) {
|
|
7500
7660
|
let cmd = process.env.VOLUTE_NODE_PATH ?? process.execPath;
|
|
7501
7661
|
let args = ["--import", "tsx", "src/server.ts", "--port", String(port)];
|
|
@@ -7516,31 +7676,36 @@ function spawnAttached(cmd, args, cwd) {
|
|
|
7516
7676
|
cwd,
|
|
7517
7677
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7518
7678
|
});
|
|
7519
|
-
return new Promise((
|
|
7520
|
-
const timeout = setTimeout(() =>
|
|
7679
|
+
return new Promise((resolve19) => {
|
|
7680
|
+
const timeout = setTimeout(() => resolve19(null), 3e4);
|
|
7521
7681
|
function checkOutput(data) {
|
|
7522
7682
|
const match = data.toString().match(/listening on :(\d+)/);
|
|
7523
7683
|
if (match) {
|
|
7524
7684
|
clearTimeout(timeout);
|
|
7525
|
-
|
|
7685
|
+
resolve19({ child, actualPort: parseInt(match[1], 10) });
|
|
7526
7686
|
}
|
|
7527
7687
|
}
|
|
7528
7688
|
child.stdout?.on("data", checkOutput);
|
|
7529
7689
|
child.stderr?.on("data", checkOutput);
|
|
7530
7690
|
child.on("error", () => {
|
|
7531
7691
|
clearTimeout(timeout);
|
|
7532
|
-
|
|
7692
|
+
resolve19(null);
|
|
7533
7693
|
});
|
|
7534
7694
|
child.on("exit", () => {
|
|
7535
7695
|
clearTimeout(timeout);
|
|
7536
|
-
|
|
7696
|
+
resolve19(null);
|
|
7537
7697
|
});
|
|
7538
7698
|
});
|
|
7539
7699
|
}
|
|
7540
7700
|
function spawnDetached(cmd, args, cwd, logDir) {
|
|
7541
|
-
const logsDir = logDir ??
|
|
7701
|
+
const logsDir = logDir ?? resolve15(cwd, ".mind", "logs");
|
|
7542
7702
|
mkdirSync8(logsDir, { recursive: true });
|
|
7543
|
-
const logPath =
|
|
7703
|
+
const logPath = resolve15(logsDir, "mind.log");
|
|
7704
|
+
let startOffset = 0;
|
|
7705
|
+
try {
|
|
7706
|
+
startOffset = statSync3(logPath).size;
|
|
7707
|
+
} catch {
|
|
7708
|
+
}
|
|
7544
7709
|
const logFd = openSync(logPath, "a");
|
|
7545
7710
|
const child = spawn4(cmd, args, {
|
|
7546
7711
|
cwd,
|
|
@@ -7560,7 +7725,7 @@ function spawnDetached(cmd, args, cwd, logDir) {
|
|
|
7560
7725
|
}
|
|
7561
7726
|
const interval = setInterval(() => {
|
|
7562
7727
|
try {
|
|
7563
|
-
const content =
|
|
7728
|
+
const content = readFileSync11(logPath).subarray(startOffset).toString("utf-8");
|
|
7564
7729
|
const match = content.match(/listening on :(\d+)/);
|
|
7565
7730
|
if (match) {
|
|
7566
7731
|
finish({ child, actualPort: parseInt(match[1], 10) });
|
|
@@ -7612,6 +7777,19 @@ async function verify2(port) {
|
|
|
7612
7777
|
}
|
|
7613
7778
|
|
|
7614
7779
|
// packages/daemon/src/web/api/variants.ts
|
|
7780
|
+
async function establishVariantDialogue(parent, variant, purpose) {
|
|
7781
|
+
const parentUser = await getOrCreateMindUser(parent);
|
|
7782
|
+
const variantUser = await getOrCreateMindUser(variant);
|
|
7783
|
+
const existing = await findDMConversation([parentUser.id, variantUser.id]);
|
|
7784
|
+
if (!existing) {
|
|
7785
|
+
await createConversation({ participantIds: [parentUser.id, variantUser.id] });
|
|
7786
|
+
}
|
|
7787
|
+
const purposeLine = purpose ? ` Its purpose: ${purpose}.` : "";
|
|
7788
|
+
await sendSystemMessage(
|
|
7789
|
+
parent,
|
|
7790
|
+
`You've split off a variant, ${variant} \u2014 a parallel version of you exploring on its own.${purposeLine} Reach it at @${variant} to check in on how the experiment is going, and merge its work back with \`volute mind join ${variant}\` when you're ready.`
|
|
7791
|
+
);
|
|
7792
|
+
}
|
|
7615
7793
|
var app21 = new Hono25().get("/:name/variants", async (c) => {
|
|
7616
7794
|
const name = c.req.param("name");
|
|
7617
7795
|
const entry = await findMind(name);
|
|
@@ -7655,56 +7833,105 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
7655
7833
|
}
|
|
7656
7834
|
const variantName = body.name;
|
|
7657
7835
|
if (!variantName) return c.json({ error: "Variant name required" }, 400);
|
|
7836
|
+
const purpose = body.purpose?.trim() || void 0;
|
|
7658
7837
|
const err = validateBranchName(variantName);
|
|
7659
7838
|
if (err) return c.json({ error: err }, 400);
|
|
7660
7839
|
if (await findMind(variantName)) {
|
|
7661
7840
|
return c.json({ error: `Name already in use: ${variantName}` }, 409);
|
|
7662
7841
|
}
|
|
7663
7842
|
const projectRoot = entry.dir ?? mindDir(mindName);
|
|
7664
|
-
const variantDir =
|
|
7843
|
+
const variantDir = resolve16(projectRoot, ".variants", variantName);
|
|
7665
7844
|
if (existsSync10(variantDir)) {
|
|
7666
7845
|
return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
|
|
7667
7846
|
}
|
|
7668
|
-
mkdirSync9(
|
|
7847
|
+
mkdirSync9(resolve16(projectRoot, ".variants"), { recursive: true });
|
|
7669
7848
|
try {
|
|
7670
7849
|
await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
|
|
7671
7850
|
} catch (e) {
|
|
7672
7851
|
const msg = e instanceof Error ? e.message : String(e);
|
|
7673
|
-
|
|
7852
|
+
let error = `Failed to create worktree: ${msg}`;
|
|
7853
|
+
try {
|
|
7854
|
+
await chownMindDir(projectRoot, mindName);
|
|
7855
|
+
} catch (err2) {
|
|
7856
|
+
logger_default.warn(
|
|
7857
|
+
`failed to restore ownership after worktree-add failure for ${mindName}`,
|
|
7858
|
+
logger_default.errorData(err2)
|
|
7859
|
+
);
|
|
7860
|
+
error += ` Restoring mind ownership also failed: ${err2 instanceof Error ? err2.message : String(err2)}`;
|
|
7861
|
+
}
|
|
7862
|
+
return c.json({ error }, 500);
|
|
7863
|
+
}
|
|
7864
|
+
const rollbackSplit = async () => {
|
|
7865
|
+
try {
|
|
7866
|
+
await cleanupVariant(variantName, projectRoot, variantDir, { stop: true });
|
|
7867
|
+
} catch (err2) {
|
|
7868
|
+
logger_default.warn(`failed to roll back split of ${variantName}`, logger_default.errorData(err2));
|
|
7869
|
+
}
|
|
7870
|
+
try {
|
|
7871
|
+
await chownMindDir(projectRoot, mindName);
|
|
7872
|
+
} catch (err2) {
|
|
7873
|
+
logger_default.warn(
|
|
7874
|
+
`failed to restore ${mindName} ownership after split rollback`,
|
|
7875
|
+
logger_default.errorData(err2)
|
|
7876
|
+
);
|
|
7877
|
+
}
|
|
7878
|
+
};
|
|
7879
|
+
try {
|
|
7880
|
+
await chownMindDir(projectRoot, mindName);
|
|
7881
|
+
} catch (e) {
|
|
7882
|
+
await rollbackSplit();
|
|
7883
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
7884
|
+
return c.json({ error: `Failed to prepare variant ownership: ${msg}` }, 500);
|
|
7674
7885
|
}
|
|
7675
|
-
await chownMindDir(projectRoot, mindName);
|
|
7676
7886
|
try {
|
|
7677
7887
|
if (isIsolationEnabled()) {
|
|
7678
7888
|
const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
|
|
7679
7889
|
await exec(cmd, args, {
|
|
7680
7890
|
cwd: variantDir,
|
|
7681
|
-
env: { ...process.env, HOME:
|
|
7891
|
+
env: { ...process.env, HOME: resolve16(variantDir, "home") }
|
|
7682
7892
|
});
|
|
7683
7893
|
} else {
|
|
7684
7894
|
await exec("npm", ["install"], { cwd: variantDir });
|
|
7685
7895
|
}
|
|
7686
7896
|
} catch (e) {
|
|
7897
|
+
await rollbackSplit();
|
|
7687
7898
|
const msg = e instanceof Error ? e.message : String(e);
|
|
7688
7899
|
return c.json({ error: `npm install failed: ${msg}` }, 500);
|
|
7689
7900
|
}
|
|
7690
7901
|
if (body.soul) {
|
|
7691
|
-
writeFileSync9(
|
|
7902
|
+
writeFileSync9(resolve16(variantDir, "home/SOUL.md"), body.soul);
|
|
7692
7903
|
}
|
|
7693
7904
|
const variantPort = body.port ?? await nextPort();
|
|
7694
|
-
|
|
7905
|
+
try {
|
|
7906
|
+
await addVariant(variantName, mindName, variantPort, variantDir, variantName, purpose);
|
|
7907
|
+
} catch (e) {
|
|
7908
|
+
await rollbackSplit();
|
|
7909
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
7910
|
+
return c.json({ error: `Failed to register variant: ${msg}` }, 500);
|
|
7911
|
+
}
|
|
7912
|
+
const manager = getMindManager();
|
|
7913
|
+
manager.setPendingContext(variantName, { type: "split", parent: mindName, purpose });
|
|
7695
7914
|
if (!body.noStart) {
|
|
7696
7915
|
try {
|
|
7697
|
-
const manager = getMindManager();
|
|
7698
|
-
manager.setPendingContext(variantName, { type: "split", parent: mindName });
|
|
7699
7916
|
await manager.startMind(variantName);
|
|
7700
7917
|
} catch (e) {
|
|
7918
|
+
await rollbackSplit();
|
|
7701
7919
|
const msg = e instanceof Error ? e.message : String(e);
|
|
7702
7920
|
return c.json({ error: `Variant created but failed to start: ${msg}` }, 500);
|
|
7703
7921
|
}
|
|
7704
7922
|
}
|
|
7923
|
+
await establishVariantDialogue(mindName, variantName, purpose).catch(
|
|
7924
|
+
(e) => logger_default.error(`failed to establish variant dialogue for ${variantName}`, logger_default.errorData(e))
|
|
7925
|
+
);
|
|
7705
7926
|
return c.json({
|
|
7706
7927
|
ok: true,
|
|
7707
|
-
variant: {
|
|
7928
|
+
variant: {
|
|
7929
|
+
name: variantName,
|
|
7930
|
+
branch: variantName,
|
|
7931
|
+
path: variantDir,
|
|
7932
|
+
port: variantPort,
|
|
7933
|
+
...purpose && { purpose }
|
|
7934
|
+
}
|
|
7708
7935
|
});
|
|
7709
7936
|
}).post("/:name/variants/:variant/merge", requireSelf(), async (c) => {
|
|
7710
7937
|
const mindName = c.req.param("name");
|
|
@@ -7725,146 +7952,150 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
7725
7952
|
} catch {
|
|
7726
7953
|
}
|
|
7727
7954
|
const projectRoot = parentEntry.dir ?? mindDir(mindName);
|
|
7728
|
-
|
|
7729
|
-
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
7730
|
-
if (status) {
|
|
7731
|
-
try {
|
|
7732
|
-
await gitExec(["add", "-A"], { cwd: variantEntry.dir });
|
|
7733
|
-
await gitExec(["commit", "-m", "Auto-commit uncommitted changes before merge"], {
|
|
7734
|
-
cwd: variantEntry.dir
|
|
7735
|
-
});
|
|
7736
|
-
} catch (_e) {
|
|
7737
|
-
return c.json(
|
|
7738
|
-
{
|
|
7739
|
-
error: "Failed to auto-commit variant changes. Commit or stash manually before merging."
|
|
7740
|
-
},
|
|
7741
|
-
500
|
|
7742
|
-
);
|
|
7743
|
-
}
|
|
7744
|
-
}
|
|
7745
|
-
}
|
|
7746
|
-
if (!body.skipVerify) {
|
|
7747
|
-
const result = await spawnServer(variantEntry.dir, 0, {
|
|
7748
|
-
detached: true,
|
|
7749
|
-
mindName: variantName,
|
|
7750
|
-
template: variantEntry.template
|
|
7751
|
-
});
|
|
7752
|
-
if (!result) {
|
|
7753
|
-
return c.json(
|
|
7754
|
-
{ error: "Failed to start server for verification. Use skipVerify to skip." },
|
|
7755
|
-
500
|
|
7756
|
-
);
|
|
7757
|
-
}
|
|
7758
|
-
const verified = await verify2(result.actualPort);
|
|
7759
|
-
try {
|
|
7760
|
-
process.kill(-result.child.pid, "SIGTERM");
|
|
7761
|
-
} catch {
|
|
7762
|
-
}
|
|
7763
|
-
if (!verified) {
|
|
7764
|
-
return c.json(
|
|
7765
|
-
{ error: "Verification failed. Fix issues or use skipVerify to proceed." },
|
|
7766
|
-
500
|
|
7767
|
-
);
|
|
7768
|
-
}
|
|
7769
|
-
}
|
|
7770
|
-
const mainStatus = (await gitExec(["status", "--porcelain"], { cwd: projectRoot })).trim();
|
|
7771
|
-
if (mainStatus) {
|
|
7772
|
-
try {
|
|
7773
|
-
await gitExec(["add", "-A"], { cwd: projectRoot });
|
|
7774
|
-
await gitExec(["commit", "-m", "Auto-commit uncommitted changes before merge"], {
|
|
7775
|
-
cwd: projectRoot
|
|
7776
|
-
});
|
|
7777
|
-
} catch (_e) {
|
|
7778
|
-
return c.json(
|
|
7779
|
-
{ error: "Failed to auto-commit main changes. Commit or stash manually before merging." },
|
|
7780
|
-
500
|
|
7781
|
-
);
|
|
7782
|
-
}
|
|
7783
|
-
}
|
|
7784
|
-
try {
|
|
7785
|
-
await gitExec(["merge", variantEntry.branch], { cwd: projectRoot });
|
|
7786
|
-
} catch (_e) {
|
|
7787
|
-
let conflicts = [];
|
|
7788
|
-
try {
|
|
7789
|
-
const out = (await gitExec(["diff", "--name-only", "--diff-filter=U"], { cwd: projectRoot })).trim();
|
|
7790
|
-
conflicts = out ? out.split("\n") : [];
|
|
7791
|
-
} catch (err) {
|
|
7792
|
-
logger_default.warn(`failed to list merge conflicts for ${mindName}`, logger_default.errorData(err));
|
|
7793
|
-
}
|
|
7794
|
-
try {
|
|
7795
|
-
await gitExec(["merge", "--abort"], { cwd: projectRoot });
|
|
7796
|
-
} catch (err) {
|
|
7797
|
-
logger_default.warn(`failed to abort merge for ${mindName}`, logger_default.errorData(err));
|
|
7798
|
-
}
|
|
7955
|
+
const failAfterGitWrite = async (message, extra) => {
|
|
7799
7956
|
try {
|
|
7800
7957
|
await chownMindDir(projectRoot, mindName);
|
|
7801
7958
|
} catch (err) {
|
|
7802
7959
|
logger_default.warn(
|
|
7803
|
-
`failed to restore ownership
|
|
7960
|
+
`failed to restore ownership for ${mindName} after merge failure`,
|
|
7804
7961
|
logger_default.errorData(err)
|
|
7805
7962
|
);
|
|
7806
7963
|
return c.json(
|
|
7807
7964
|
{
|
|
7808
|
-
error:
|
|
7809
|
-
|
|
7965
|
+
error: `${message} Restoring mind ownership also failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
7966
|
+
...extra
|
|
7810
7967
|
},
|
|
7811
7968
|
500
|
|
7812
7969
|
);
|
|
7813
7970
|
}
|
|
7814
|
-
return c.json(
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7971
|
+
return c.json({ error: message, ...extra }, 500);
|
|
7972
|
+
};
|
|
7973
|
+
let farewell;
|
|
7974
|
+
try {
|
|
7975
|
+
farewell = await runFarewellTurn({
|
|
7976
|
+
variantName,
|
|
7977
|
+
parentName: mindName,
|
|
7978
|
+
variantDir: variantEntry.dir,
|
|
7979
|
+
port: variantEntry.port,
|
|
7980
|
+
running: tryGetMindManager()?.isRunning(variantName) ?? false
|
|
7981
|
+
});
|
|
7982
|
+
} catch (err) {
|
|
7983
|
+
logger_default.warn(`farewell turn failed for ${variantName}`, logger_default.errorData(err));
|
|
7821
7984
|
}
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7985
|
+
try {
|
|
7986
|
+
if (existsSync10(variantEntry.dir)) {
|
|
7987
|
+
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
7988
|
+
if (status) {
|
|
7989
|
+
try {
|
|
7990
|
+
await gitExec(["add", "-A"], { cwd: variantEntry.dir });
|
|
7991
|
+
await gitExec(["commit", "-m", "Auto-commit uncommitted changes before merge"], {
|
|
7992
|
+
cwd: variantEntry.dir
|
|
7993
|
+
});
|
|
7994
|
+
} catch (_e) {
|
|
7995
|
+
return failAfterGitWrite(
|
|
7996
|
+
"Failed to auto-commit variant changes. Commit or stash manually before merging."
|
|
7997
|
+
);
|
|
7998
|
+
}
|
|
7999
|
+
}
|
|
8000
|
+
}
|
|
8001
|
+
if (!body.skipVerify) {
|
|
8002
|
+
const result = await spawnServer(variantEntry.dir, 0, {
|
|
8003
|
+
detached: true,
|
|
8004
|
+
mindName: variantName,
|
|
8005
|
+
template: variantEntry.template
|
|
8006
|
+
});
|
|
8007
|
+
if (!result) {
|
|
8008
|
+
return failAfterGitWrite(
|
|
8009
|
+
"Failed to start server for verification. Use skipVerify to skip."
|
|
8010
|
+
);
|
|
8011
|
+
}
|
|
8012
|
+
const verified = await verify2(result.actualPort);
|
|
8013
|
+
try {
|
|
8014
|
+
process.kill(-result.child.pid, "SIGTERM");
|
|
8015
|
+
} catch {
|
|
8016
|
+
}
|
|
8017
|
+
if (!verified) {
|
|
8018
|
+
return failAfterGitWrite("Verification failed. Fix issues or use skipVerify to proceed.");
|
|
8019
|
+
}
|
|
8020
|
+
}
|
|
8021
|
+
const mainStatus = (await gitExec(["status", "--porcelain"], { cwd: projectRoot })).trim();
|
|
8022
|
+
if (mainStatus) {
|
|
8023
|
+
try {
|
|
8024
|
+
await gitExec(["add", "-A"], { cwd: projectRoot });
|
|
8025
|
+
await gitExec(["commit", "-m", "Auto-commit uncommitted changes before merge"], {
|
|
8026
|
+
cwd: projectRoot
|
|
8027
|
+
});
|
|
8028
|
+
} catch (_e) {
|
|
8029
|
+
return failAfterGitWrite(
|
|
8030
|
+
"Failed to auto-commit main changes. Commit or stash manually before merging."
|
|
8031
|
+
);
|
|
8032
|
+
}
|
|
8033
|
+
}
|
|
8034
|
+
let memoryDelta = "";
|
|
7825
8035
|
try {
|
|
7826
|
-
|
|
7827
|
-
const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-UMMDRPRM.js");
|
|
7828
|
-
const tmpl = parentEntry.template ?? "claude";
|
|
7829
|
-
await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
|
|
8036
|
+
memoryDelta = await mergeVariantExcludingMemory(projectRoot, variantEntry.branch);
|
|
7830
8037
|
} catch (err) {
|
|
7831
|
-
|
|
8038
|
+
if (!(err instanceof VariantMergeError)) throw err;
|
|
8039
|
+
return failAfterGitWrite(
|
|
8040
|
+
err.abortFailed ? "Merge failed and the abort did not complete \u2014 the parent worktree may be left mid-merge with conflict markers; manual cleanup may be needed." : "Merge failed. Resolve conflicts in the variant and retry the join.",
|
|
8041
|
+
{ conflicts: err.conflicts }
|
|
8042
|
+
);
|
|
7832
8043
|
}
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
})
|
|
7842
|
-
|
|
7843
|
-
|
|
8044
|
+
await cleanupVariant(variantName, projectRoot, variantEntry.dir, { stop: true });
|
|
8045
|
+
await chownMindDir(projectRoot, mindName);
|
|
8046
|
+
if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
|
|
8047
|
+
try {
|
|
8048
|
+
const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-GSOUARW4.js");
|
|
8049
|
+
const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-3ELJPUGJ.js");
|
|
8050
|
+
const tmpl = parentEntry.template ?? "claude";
|
|
8051
|
+
await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
|
|
8052
|
+
} catch (err) {
|
|
8053
|
+
logger_default.warn(`failed to update template hash for ${mindName}`, logger_default.errorData(err));
|
|
8054
|
+
}
|
|
7844
8055
|
}
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
8056
|
+
let restartWarning;
|
|
8057
|
+
try {
|
|
8058
|
+
if (isIsolationEnabled()) {
|
|
8059
|
+
const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
|
|
8060
|
+
await exec(cmd, args, {
|
|
8061
|
+
cwd: projectRoot,
|
|
8062
|
+
env: { ...process.env, HOME: resolve16(projectRoot, "home") }
|
|
8063
|
+
});
|
|
8064
|
+
} else {
|
|
8065
|
+
await exec("npm", ["install"], { cwd: projectRoot });
|
|
8066
|
+
}
|
|
8067
|
+
} catch (err) {
|
|
8068
|
+
logger_default.warn(`npm install failed after merge for ${mindName}`, logger_default.errorData(err));
|
|
8069
|
+
restartWarning = `npm install failed after merge \u2014 mind may have stale dependencies`;
|
|
8070
|
+
}
|
|
8071
|
+
const manager = getMindManager();
|
|
8072
|
+
const justification = body.justification?.trim() || variantEntry.purpose;
|
|
8073
|
+
const context = {
|
|
8074
|
+
type: "merged",
|
|
8075
|
+
name: variantName,
|
|
8076
|
+
...body.summary && { summary: body.summary },
|
|
8077
|
+
...justification && { justification },
|
|
8078
|
+
...body.memory && { memory: body.memory },
|
|
8079
|
+
...memoryDelta && { memoryDelta },
|
|
8080
|
+
...farewell && { farewell }
|
|
8081
|
+
};
|
|
8082
|
+
try {
|
|
8083
|
+
if (manager.isRunning(mindName)) {
|
|
8084
|
+
await manager.stopMind(mindName);
|
|
8085
|
+
}
|
|
8086
|
+
manager.setPendingContext(mindName, context);
|
|
8087
|
+
await manager.startMind(mindName);
|
|
8088
|
+
} catch (e) {
|
|
8089
|
+
restartWarning = `Merge succeeded but mind restart failed: ${e instanceof Error ? e.message : String(e)}`;
|
|
8090
|
+
logger_default.warn(restartWarning);
|
|
7860
8091
|
}
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
8092
|
+
return c.json({ ok: true, ...restartWarning && { warning: restartWarning } });
|
|
8093
|
+
} catch (err) {
|
|
8094
|
+
logger_default.error(`variant join failed for ${mindName}`, logger_default.errorData(err));
|
|
8095
|
+
return await failAfterGitWrite(
|
|
8096
|
+
`Variant join failed: ${err instanceof Error ? err.message : String(err)}`
|
|
8097
|
+
);
|
|
7866
8098
|
}
|
|
7867
|
-
return c.json({ ok: true, ...restartWarning && { warning: restartWarning } });
|
|
7868
8099
|
}).delete("/:name/variants/:variant", requireSelf(), async (c) => {
|
|
7869
8100
|
const mindName = c.req.param("name");
|
|
7870
8101
|
const variantName = c.req.param("variant");
|
|
@@ -8285,11 +8516,11 @@ var app23 = new Hono27().get("/:name/conversations/:id/events", async (c) => {
|
|
|
8285
8516
|
if (!stream.aborted) console.error("[chat] SSE ping error:", err);
|
|
8286
8517
|
});
|
|
8287
8518
|
}, 15e3);
|
|
8288
|
-
await new Promise((
|
|
8519
|
+
await new Promise((resolve19) => {
|
|
8289
8520
|
stream.onAbort(() => {
|
|
8290
8521
|
unsubscribe();
|
|
8291
8522
|
clearInterval(keepAlive);
|
|
8292
|
-
|
|
8523
|
+
resolve19();
|
|
8293
8524
|
});
|
|
8294
8525
|
});
|
|
8295
8526
|
});
|
|
@@ -8506,7 +8737,7 @@ var app_default = app25;
|
|
|
8506
8737
|
import { existsSync as existsSync11 } from "fs";
|
|
8507
8738
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
8508
8739
|
import { createServer as createHttpsServer } from "https";
|
|
8509
|
-
import { dirname as dirname2, extname as extname3, resolve as
|
|
8740
|
+
import { dirname as dirname2, extname as extname3, resolve as resolve17 } from "path";
|
|
8510
8741
|
import { serve } from "@hono/node-server";
|
|
8511
8742
|
var MIME_TYPES2 = {
|
|
8512
8743
|
".html": "text/html",
|
|
@@ -8525,7 +8756,7 @@ async function startServer({
|
|
|
8525
8756
|
let assetsDir = "";
|
|
8526
8757
|
let searchDir = dirname2(new URL(import.meta.url).pathname);
|
|
8527
8758
|
for (let i = 0; i < 5; i++) {
|
|
8528
|
-
const candidate =
|
|
8759
|
+
const candidate = resolve17(searchDir, "dist", "web-assets");
|
|
8529
8760
|
if (existsSync11(candidate)) {
|
|
8530
8761
|
assetsDir = candidate;
|
|
8531
8762
|
break;
|
|
@@ -8536,7 +8767,7 @@ async function startServer({
|
|
|
8536
8767
|
app_default.get("*", async (c) => {
|
|
8537
8768
|
const urlPath = new URL(c.req.url).pathname;
|
|
8538
8769
|
if (urlPath.startsWith("/api/") || urlPath.startsWith("/ext/")) return c.notFound();
|
|
8539
|
-
const filePath =
|
|
8770
|
+
const filePath = resolve17(assetsDir, urlPath.slice(1));
|
|
8540
8771
|
if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
|
|
8541
8772
|
const s = await stat2(filePath).catch(() => null);
|
|
8542
8773
|
if (s?.isFile()) {
|
|
@@ -8549,7 +8780,7 @@ async function startServer({
|
|
|
8549
8780
|
const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
|
|
8550
8781
|
return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
|
|
8551
8782
|
}
|
|
8552
|
-
const indexPath =
|
|
8783
|
+
const indexPath = resolve17(assetsDir, "index.html");
|
|
8553
8784
|
const indexStat = await stat2(indexPath).catch(() => null);
|
|
8554
8785
|
if (indexStat?.isFile()) {
|
|
8555
8786
|
const body = await readFile2(indexPath, "utf-8");
|
|
@@ -8566,10 +8797,10 @@ async function startServer({
|
|
|
8566
8797
|
createServer: createHttpsServer,
|
|
8567
8798
|
serverOptions: { key: tls.key, cert: tls.cert }
|
|
8568
8799
|
});
|
|
8569
|
-
await new Promise((
|
|
8800
|
+
await new Promise((resolve19, reject) => {
|
|
8570
8801
|
server2.on("listening", () => {
|
|
8571
8802
|
logger_default.info("Volute UI running (https)", { hostname, port });
|
|
8572
|
-
|
|
8803
|
+
resolve19();
|
|
8573
8804
|
});
|
|
8574
8805
|
server2.on("error", (err) => {
|
|
8575
8806
|
reject(err);
|
|
@@ -8577,13 +8808,13 @@ async function startServer({
|
|
|
8577
8808
|
});
|
|
8578
8809
|
const internalPort = port + 1;
|
|
8579
8810
|
const internalServer = serve({ fetch: app_default.fetch, port: internalPort, hostname: "127.0.0.1" });
|
|
8580
|
-
await new Promise((
|
|
8811
|
+
await new Promise((resolve19, reject) => {
|
|
8581
8812
|
internalServer.on("listening", () => {
|
|
8582
8813
|
logger_default.info("Volute API running (http, internal)", {
|
|
8583
8814
|
hostname: "127.0.0.1",
|
|
8584
8815
|
port: internalPort
|
|
8585
8816
|
});
|
|
8586
|
-
|
|
8817
|
+
resolve19();
|
|
8587
8818
|
});
|
|
8588
8819
|
internalServer.on("error", (err) => {
|
|
8589
8820
|
reject(err);
|
|
@@ -8592,10 +8823,10 @@ async function startServer({
|
|
|
8592
8823
|
return { server: server2, internalPort };
|
|
8593
8824
|
}
|
|
8594
8825
|
const server = serve({ fetch: app_default.fetch, port, hostname });
|
|
8595
|
-
await new Promise((
|
|
8826
|
+
await new Promise((resolve19, reject) => {
|
|
8596
8827
|
server.on("listening", () => {
|
|
8597
8828
|
logger_default.info("Volute API running (http)", { hostname, port });
|
|
8598
|
-
|
|
8829
|
+
resolve19();
|
|
8599
8830
|
});
|
|
8600
8831
|
server.on("error", (err) => {
|
|
8601
8832
|
reject(err);
|
|
@@ -8606,17 +8837,17 @@ async function startServer({
|
|
|
8606
8837
|
|
|
8607
8838
|
// packages/daemon/src/daemon.ts
|
|
8608
8839
|
if (!process.env.VOLUTE_HOME) {
|
|
8609
|
-
process.env.VOLUTE_HOME =
|
|
8840
|
+
process.env.VOLUTE_HOME = resolve18(homedir3(), ".volute");
|
|
8610
8841
|
}
|
|
8611
8842
|
if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
|
|
8612
8843
|
process.env.TZ = process.env.VOLUTE_TIMEZONE;
|
|
8613
8844
|
}
|
|
8614
8845
|
function writeDaemonConfig(systemDir, config2, token) {
|
|
8615
|
-
const configPath =
|
|
8846
|
+
const configPath = resolve18(systemDir, "daemon.json");
|
|
8616
8847
|
writeFileSync10(configPath, `${JSON.stringify(config2, null, 2)}
|
|
8617
8848
|
`, { mode: 420 });
|
|
8618
8849
|
chmodSync(configPath, 420);
|
|
8619
|
-
const tokenPath =
|
|
8850
|
+
const tokenPath = resolve18(systemDir, "daemon-token");
|
|
8620
8851
|
writeFileSync10(tokenPath, `${token}
|
|
8621
8852
|
`, { mode: 384 });
|
|
8622
8853
|
chmodSync(tokenPath, 384);
|
|
@@ -8627,7 +8858,7 @@ async function startDaemon(opts) {
|
|
|
8627
8858
|
const home = voluteHome();
|
|
8628
8859
|
const systemDir = voluteSystemDir();
|
|
8629
8860
|
if (!opts.foreground) {
|
|
8630
|
-
const rotatingLog = new RotatingLog(
|
|
8861
|
+
const rotatingLog = new RotatingLog(resolve18(systemDir, "daemon.log"));
|
|
8631
8862
|
logger_default.setOutput((line) => rotatingLog.write(`${line}
|
|
8632
8863
|
`));
|
|
8633
8864
|
const write = (...args) => rotatingLog.write(`${format(...args)}
|
|
@@ -8637,32 +8868,32 @@ async function startDaemon(opts) {
|
|
|
8637
8868
|
console.warn = write;
|
|
8638
8869
|
console.info = write;
|
|
8639
8870
|
}
|
|
8640
|
-
const DAEMON_PID_PATH =
|
|
8641
|
-
const DAEMON_JSON_PATH =
|
|
8642
|
-
const DAEMON_TOKEN_PATH =
|
|
8871
|
+
const DAEMON_PID_PATH = resolve18(systemDir, "daemon.pid");
|
|
8872
|
+
const DAEMON_JSON_PATH = resolve18(systemDir, "daemon.json");
|
|
8873
|
+
const DAEMON_TOKEN_PATH = resolve18(systemDir, "daemon-token");
|
|
8643
8874
|
mkdirSync10(home, { recursive: true });
|
|
8644
8875
|
ensureSystemDir();
|
|
8645
|
-
const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-
|
|
8876
|
+
const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-TCN7VH5U.js");
|
|
8646
8877
|
migrateConfigSecrets();
|
|
8647
8878
|
migrateSetupCompleted();
|
|
8648
|
-
const { migrateAiModelQualification } = await import("./ai-service-
|
|
8879
|
+
const { migrateAiModelQualification } = await import("./ai-service-A7FS7EC3.js");
|
|
8649
8880
|
migrateAiModelQualification();
|
|
8650
|
-
await (await import("./db-
|
|
8881
|
+
await (await import("./db-F6UMFRYD.js")).getDb();
|
|
8651
8882
|
try {
|
|
8652
8883
|
const { eq: eq8, and: and6 } = await import("drizzle-orm");
|
|
8653
|
-
const { users: users2 } = await import("./schema-
|
|
8654
|
-
const db = await (await import("./db-
|
|
8884
|
+
const { users: users2 } = await import("./schema-6YONVTKZ.js");
|
|
8885
|
+
const db = await (await import("./db-F6UMFRYD.js")).getDb();
|
|
8655
8886
|
await db.update(users2).set({ role: "system" }).where(and6(eq8(users2.user_type, "system"), eq8(users2.role, "user")));
|
|
8656
8887
|
} catch (err) {
|
|
8657
8888
|
logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
|
|
8658
8889
|
}
|
|
8659
8890
|
try {
|
|
8660
|
-
const { migrateAvatarSizes } = await import("./avatar-image-
|
|
8891
|
+
const { migrateAvatarSizes } = await import("./avatar-image-6ATV2IOZ.js");
|
|
8661
8892
|
await migrateAvatarSizes();
|
|
8662
8893
|
} catch (err) {
|
|
8663
8894
|
logger_default.warn("avatar size migration failed", logger_default.errorData(err));
|
|
8664
8895
|
}
|
|
8665
|
-
const { initSandbox } = await import("./sandbox-
|
|
8896
|
+
const { initSandbox } = await import("./sandbox-XPYA7UIF.js");
|
|
8666
8897
|
await initSandbox();
|
|
8667
8898
|
try {
|
|
8668
8899
|
await syncBuiltinSkills();
|
|
@@ -8694,7 +8925,7 @@ async function startDaemon(opts) {
|
|
|
8694
8925
|
logger_default.warn("failed to backfill minds into #system", logger_default.errorData(err));
|
|
8695
8926
|
}
|
|
8696
8927
|
try {
|
|
8697
|
-
const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-
|
|
8928
|
+
const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-ABYLOEZ7.js");
|
|
8698
8929
|
await getOrCreateSystemUser2();
|
|
8699
8930
|
} catch (err) {
|
|
8700
8931
|
logger_default.warn(
|
|
@@ -8703,12 +8934,12 @@ async function startDaemon(opts) {
|
|
|
8703
8934
|
);
|
|
8704
8935
|
}
|
|
8705
8936
|
const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes3(32).toString("hex");
|
|
8706
|
-
const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-
|
|
8937
|
+
const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-TCN7VH5U.js");
|
|
8707
8938
|
const globalCfg = readGlobalConfig2();
|
|
8708
8939
|
let tls;
|
|
8709
8940
|
if (opts.tailscale || globalCfg.tailscale) {
|
|
8710
8941
|
try {
|
|
8711
|
-
const { getTailscaleTls } = await import("./tailscale-
|
|
8942
|
+
const { getTailscaleTls } = await import("./tailscale-AMMVKDXB.js");
|
|
8712
8943
|
const tlsConfig = await getTailscaleTls();
|
|
8713
8944
|
tls = { key: tlsConfig.key, cert: tlsConfig.cert };
|
|
8714
8945
|
logger_default.info("Tailscale HTTPS enabled", { hostname: tlsConfig.hostname });
|
|
@@ -8759,6 +8990,12 @@ async function startDaemon(opts) {
|
|
|
8759
8990
|
const unsubscribeWebhook = initWebhook();
|
|
8760
8991
|
const orphanedTurns = await completeOrphanedTurns();
|
|
8761
8992
|
summarizeOrphanedTurns(orphanedTurns);
|
|
8993
|
+
try {
|
|
8994
|
+
const { reconcileVariants } = await import("./variant-cleanup-P4MBNLJD.js");
|
|
8995
|
+
await reconcileVariants();
|
|
8996
|
+
} catch (err) {
|
|
8997
|
+
logger_default.error("failed to reconcile variants", logger_default.errorData(err));
|
|
8998
|
+
}
|
|
8762
8999
|
const allMinds = await readAllMinds();
|
|
8763
9000
|
const runningEntries = allMinds.filter((e) => e.running && e.mindType !== "spirit");
|
|
8764
9001
|
{
|
|
@@ -8788,14 +9025,14 @@ async function startDaemon(opts) {
|
|
|
8788
9025
|
await Promise.all(workers);
|
|
8789
9026
|
}
|
|
8790
9027
|
try {
|
|
8791
|
-
const { isSetupComplete: isSetupComplete2 } = await import("./setup-
|
|
9028
|
+
const { isSetupComplete: isSetupComplete2 } = await import("./setup-TCN7VH5U.js");
|
|
8792
9029
|
if (isSetupComplete2()) {
|
|
8793
|
-
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-
|
|
8794
|
-
const { startSpiritFull } = await import("./mind-service-
|
|
9030
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-SSJMYC6A.js");
|
|
9031
|
+
const { startSpiritFull } = await import("./mind-service-42GDO4KH.js");
|
|
8795
9032
|
await ensureSpiritProject();
|
|
8796
9033
|
const spiritEntry = await findMind(SPIRIT_NAME);
|
|
8797
9034
|
if (spiritEntry?.dir) {
|
|
8798
|
-
const { registerMindDir } = await import("./delivery-router-
|
|
9035
|
+
const { registerMindDir } = await import("./delivery-router-VUOL5YSA.js");
|
|
8799
9036
|
registerMindDir(SPIRIT_NAME, spiritEntry.dir);
|
|
8800
9037
|
}
|
|
8801
9038
|
await syncSpiritTemplate();
|
|
@@ -8812,7 +9049,7 @@ async function startDaemon(opts) {
|
|
|
8812
9049
|
bridgeManager.startBridges(daemonPort).catch((err) => {
|
|
8813
9050
|
logger_default.warn("failed to start bridges", logger_default.errorData(err));
|
|
8814
9051
|
});
|
|
8815
|
-
import("./cloud-sync-
|
|
9052
|
+
import("./cloud-sync-VFDTNNCA.js").then(
|
|
8816
9053
|
({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
|
|
8817
9054
|
logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
|
|
8818
9055
|
})
|
|
@@ -8820,7 +9057,7 @@ async function startDaemon(opts) {
|
|
|
8820
9057
|
logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
|
|
8821
9058
|
});
|
|
8822
9059
|
try {
|
|
8823
|
-
const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-
|
|
9060
|
+
const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-WFA5XB5A.js");
|
|
8824
9061
|
backfillTemplateHashes().then(() => warnStaleTemplates()).catch((err) => {
|
|
8825
9062
|
logger_default.warn("failed to check template staleness", logger_default.errorData(err));
|
|
8826
9063
|
});
|
|
@@ -8850,13 +9087,13 @@ async function startDaemon(opts) {
|
|
|
8850
9087
|
logger_default.info(`running on ${hostname}:${port}, pid ${myPid}`);
|
|
8851
9088
|
function cleanup() {
|
|
8852
9089
|
try {
|
|
8853
|
-
if (
|
|
9090
|
+
if (readFileSync12(DAEMON_PID_PATH, "utf-8").trim() === myPid) {
|
|
8854
9091
|
unlinkSync2(DAEMON_PID_PATH);
|
|
8855
9092
|
}
|
|
8856
9093
|
} catch {
|
|
8857
9094
|
}
|
|
8858
9095
|
try {
|
|
8859
|
-
if (
|
|
9096
|
+
if (readFileSync12(DAEMON_TOKEN_PATH, "utf-8").trim() === token) {
|
|
8860
9097
|
unlinkSync2(DAEMON_TOKEN_PATH);
|
|
8861
9098
|
try {
|
|
8862
9099
|
unlinkSync2(DAEMON_JSON_PATH);
|