volute 0.52.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{accept-5NK5XJB5.js → accept-RSDIVJL6.js} +3 -0
- package/dist/auto-upgrade-HEVZKPTF.js +46 -0
- package/dist/{backup-YVGV2ZNM.js → backup-QRNX6RK7.js} +10 -10
- package/dist/channels-CKCY64TD.js +203 -0
- package/dist/{chat-VAZ25KVT.js → chat-ZUGNL5GS.js} +5 -5
- package/dist/chunk-3LHUXY3E.js +102 -0
- package/dist/{chunk-SW2U6HRB.js → chunk-444RR3YF.js} +21 -4
- package/dist/{chunk-YVR6EHWL.js → chunk-56IT2ZXF.js} +160 -18
- package/dist/chunk-5RBEEAKW.js +58 -0
- package/dist/{chunk-OXWUEU5V.js → chunk-5U5GLZSD.js} +2 -2
- package/dist/{chunk-G7A5LEVI.js → chunk-7XKPG66D.js} +5 -5
- package/dist/{chunk-R772ET2M.js → chunk-AAPNU7GA.js} +4 -0
- package/dist/{chunk-XRWUQPCA.js → chunk-ATZF2RNJ.js} +25 -3
- package/dist/{chunk-6NLW72HP.js → chunk-CKPAVQNK.js} +1 -1
- package/dist/{chunk-JHKBALS2.js → chunk-CLCHOXLR.js} +1 -1
- package/dist/{chunk-DMK5ASKV.js → chunk-F6D766VQ.js} +6 -2
- package/dist/{chunk-AXFLY5GU.js → chunk-HKGYZVWN.js} +16 -1
- package/dist/{chunk-ZEZQNP2G.js → chunk-LGXVGIWN.js} +103 -25
- package/dist/{chunk-CW7BQKF6.js → chunk-LKUGUQUW.js} +3 -3
- package/dist/{chunk-FXWBFDQR.js → chunk-OAYY3WF3.js} +59 -12
- package/dist/{chunk-ITK6HV47.js → chunk-OGPVJ53N.js} +14 -6
- package/dist/{chunk-M77B73VV.js → chunk-OIOW3FPT.js} +7 -2
- package/dist/chunk-OT5SXF7L.js +904 -0
- package/dist/{chunk-EDR47UE2.js → chunk-OYF25B62.js} +1 -1
- package/dist/{chunk-RPPTGPYF.js → chunk-PPSN2MLC.js} +2 -2
- package/dist/{chunk-K2F237KS.js → chunk-RGHF3OK5.js} +154 -18
- package/dist/{chunk-RU74YG46.js → chunk-VDUCLVZI.js} +338 -30
- package/dist/{chunk-724DVYHU.js → chunk-WHL6PKYP.js} +10 -10
- package/dist/{chunk-EEOMA4DX.js → chunk-WZZCA23D.js} +2 -1
- package/dist/{chunk-UDZLPR34.js → chunk-YSRYCS3N.js} +13 -8
- package/dist/{chunk-5N32EN4O.js → chunk-Z4Q6TQWL.js} +1 -1
- package/dist/{chunk-VPOMJMV6.js → chunk-ZNHL5KQJ.js} +1 -1
- package/dist/cli.js +17 -17
- package/dist/{clock-ZT5YT6HA.js → clock-X7V3C7NL.js} +2 -2
- package/dist/{cloud-sync-H7EWZASD.js → cloud-sync-52YNJRMR.js} +12 -11
- package/dist/{daemon-restart-4FWUA5JF.js → daemon-restart-QWHN5VMU.js} +4 -4
- package/dist/daemon.js +538 -782
- package/dist/{db-IPXRJUI7.js → db-I4EH5SLF.js} +3 -1
- package/dist/{delivery-manager-VYXVKUMP.js → delivery-manager-7R2YIQ2W.js} +13 -7
- package/dist/delivery-notices-RZQ6GONP.js +18 -0
- package/dist/{delivery-router-RHANNTAC.js → delivery-router-QS4NLJR6.js} +3 -1
- package/dist/{down-QSNEMTTX.js → down-UN2EDX2Y.js} +3 -3
- package/dist/{echo-text-PEEV7FQU.js → echo-text-73CYQRL7.js} +14 -13
- package/dist/{exec-ABD3DYA2.js → exec-Z34TTUO3.js} +1 -1
- package/dist/{extensions-N6L5NYTK.js → extensions-QT65JGV6.js} +22 -11
- package/dist/{files-BRY5RRIM.js → files-PCKBQHAY.js} +2 -1
- package/dist/{isolation-GVV2IBAU.js → isolation-UQPDO34R.js} +1 -1
- package/dist/{message-delivery-7URC52ME.js → message-delivery-TRKT4T2P.js} +16 -13
- package/dist/migrate-name-placeholder-C7NCNLWF.js +37 -0
- package/dist/{mind-NEXGT3KE.js → mind-CT6ANXK4.js} +11 -11
- package/dist/{mind-contacts-QYU4TPEA.js → mind-contacts-PEXCDRXA.js} +6 -6
- package/dist/{mind-history-OGNR4L7W.js → mind-history-RZMMCHMX.js} +83 -11
- package/dist/{mind-list-SYRA7CH5.js → mind-list-7KBLPLES.js} +1 -1
- package/dist/{mind-service-E26ZQXDS.js → mind-service-7EFIJ3ZA.js} +12 -11
- package/dist/{mind-sleep-LZAFBDZD.js → mind-sleep-24HV4RCA.js} +2 -2
- package/dist/{mind-status-Z2LQFA6F.js → mind-status-4YW4PHMO.js} +15 -0
- package/dist/{package-2W2XKSIP.js → package-F6S5NHY2.js} +4 -4
- package/dist/{prompts-NBO3HRK3.js → prompts-JECJIFPQ.js} +1 -1
- package/dist/{reject-TWB4QJHG.js → reject-4NFLXKRN.js} +6 -2
- package/dist/{scheduler-JTTWZDYU.js → scheduler-73Q4MQ7Y.js} +8 -6
- package/dist/{seed-64XEHRUP.js → seed-DRKAP3XV.js} +1 -1
- package/dist/{seed-cmd-UEL2QB3Q.js → seed-cmd-6IMTO3LG.js} +2 -2
- package/dist/{seed-create-4JRQDPGA.js → seed-create-VNLDYRFK.js} +1 -1
- package/dist/{seed-readiness-DYOVCYHN.js → seed-readiness-H5TTPAQH.js} +2 -2
- package/dist/{seed-sprout-NIDIOJXT.js → seed-sprout-PPGYGK4G.js} +5 -5
- package/dist/{send-2YKOZJJ5.js → send-UXUQKO4N.js} +37 -22
- package/dist/{service-XQPMZAGI.js → service-T4P5W6RS.js} +2 -2
- package/dist/{service-install-2EWD7KXD.js → service-install-R4SNYUVO.js} +3 -3
- package/dist/{setup-4IX6PCD3.js → setup-YUAQMDVZ.js} +4 -4
- package/dist/skills/dreaming/SKILL.md +2 -2
- package/dist/skills/dreaming/references/INSTALL.md +1 -1
- package/dist/skills/memory/SKILL.md +47 -43
- package/dist/skills/tending/SKILL.md +2 -0
- package/dist/skills/volute-mind/references/integrations.md +3 -2
- package/dist/skills/volute-mind/references/routing.md +18 -5
- package/dist/{skills-MPUALV3S.js → skills-GMQ5UIIW.js} +2 -2
- package/dist/{sleep-manager-OFP2GFXF.js → sleep-manager-KHI65FEX.js} +12 -11
- package/dist/{spirit-4ECYIVGE.js → spirit-Q5VGFWUI.js} +19 -3
- package/dist/{spirit-availability-Y54Y3675.js → spirit-availability-G5FMWKRH.js} +13 -12
- package/dist/{sprout-GJMZFRGZ.js → sprout-PMTRL7QN.js} +1 -1
- package/dist/{src-LCSOQY6Z.js → src-3FIW7DLH.js} +241 -87
- package/dist/src-H3UCOP6B.js +516 -0
- package/dist/{src-HGNE2XG4.js → src-LTTQVN2Z.js} +1 -1
- package/dist/{status-MWLE3RVC.js → status-LCKTTIWS.js} +2 -2
- package/dist/{system-events-V43HDA3T.js → system-events-Q7IVZ5T4.js} +5 -1
- package/dist/{systems-VDRUZXNF.js → systems-HL7SGSW7.js} +2 -2
- package/dist/{turn-tracker-C5PVIC3B.js → turn-tracker-HZDPMSCC.js} +4 -2
- package/dist/{up-H6LJZDRK.js → up-XZDSJVMU.js} +3 -3
- package/dist/{update-CIWI2JYA.js → update-ILCPVNDD.js} +2 -2
- package/dist/{upgrade-LIE46UBB.js → upgrade-XY2J7NWZ.js} +9 -1
- package/dist/{variant-cleanup-STC6B5HR.js → variant-cleanup-QHGGY7ND.js} +8 -6
- package/dist/{version-notify-LBVHH5YV.js → version-notify-VNVFX6UP.js} +22 -7
- package/dist/web-assets/assets/{index-B_eYTa3R.js → index-CwtxGwe_.js} +16 -16
- package/dist/web-assets/assets/index-DhM1yYRN.css +1 -0
- package/dist/web-assets/index.html +2 -2
- package/package.json +4 -4
- package/packages/extensions/intentions/dist/ui/assets/index-3FneLCKR.css +1 -0
- package/packages/extensions/intentions/dist/ui/assets/index-CQz4aceM.js +67 -0
- package/packages/extensions/{plan → intentions}/dist/ui/index.html +3 -3
- package/packages/extensions/intentions/skills/intention-review/SKILL.md +38 -0
- package/packages/extensions/intentions/skills/intentions/SKILL.md +49 -0
- package/packages/extensions/intentions/skills/intentions/scripts/intentions-hook.sh +45 -0
- package/packages/extensions/pages/skills/commons-gardening/SKILL.md +50 -0
- package/packages/extensions/pages/skills/pages/SKILL.md +18 -13
- package/templates/_base/.init/.config/prompts.json +3 -3
- package/templates/{pi → _base}/.init/.config/routes.json +1 -0
- package/templates/_base/.init/memory/dreams/.gitkeep +0 -0
- package/templates/_base/home/.config/routes.json +1 -1
- package/templates/_base/home/VOLUTE.md +1 -1
- package/templates/_base/src/lib/codex-session-seed.ts +463 -0
- package/templates/_base/src/lib/context-breakdown.ts +11 -3
- package/templates/_base/src/lib/daemon-client.ts +35 -0
- package/templates/_base/src/lib/pi-session-seed.ts +434 -0
- package/templates/_base/src/lib/routing.ts +2 -2
- package/templates/_base/src/lib/seed-note.ts +78 -0
- package/templates/_base/src/lib/session-seed.ts +375 -0
- package/templates/_base/src/lib/startup.ts +112 -6
- package/templates/claude/.init/CLAUDE.md +7 -3
- package/templates/claude/src/agent.ts +295 -101
- package/templates/claude/src/lib/hooks/pre-compact.ts +30 -5
- package/templates/claude/src/lib/message-channel.ts +43 -15
- package/templates/claude/src/lib/recover.ts +69 -0
- package/templates/claude/src/lib/stream-consumer.ts +33 -2
- package/templates/claude/src/server.ts +2 -1
- package/templates/claude/volute-template.json +1 -1
- package/templates/codex/.init/AGENTS.md +7 -3
- package/templates/codex/src/agent.ts +256 -39
- package/templates/codex/src/server.ts +2 -1
- package/templates/codex/volute-template.json +1 -1
- package/templates/pi/.init/MINDS.md +7 -3
- package/templates/pi/src/agent.ts +269 -43
- package/templates/pi/src/lib/event-handler.ts +11 -0
- package/templates/pi/src/lib/mechanics-doc.ts +30 -0
- package/templates/pi/src/server.ts +5 -1
- package/templates/pi/volute-template.json +1 -1
- package/dist/channels-FSAHOQWI.js +0 -90
- package/dist/skills/plan-coordinator/SKILL.md +0 -60
- package/dist/src-UDMJZ6MH.js +0 -426
- package/dist/web-assets/assets/index-DhZrzddW.css +0 -1
- package/packages/extensions/plan/dist/ui/assets/index-B8s8wxyt.js +0 -67
- package/packages/extensions/plan/dist/ui/assets/index-jIkrt-vI.css +0 -1
- package/packages/extensions/plan/skills/plan/SKILL.md +0 -43
- package/packages/extensions/plan/skills/plan/scripts/plan-hook.sh +0 -37
- package/templates/claude/.init/.config/routes.json +0 -11
- package/templates/codex/.init/.config/routes.json +0 -11
- package/dist/{env-IBW2QI6K.js → env-7AZFBPWX.js} +5 -5
- package/dist/{login-RJJTCVR3.js → login-4NUS72Z5.js} +3 -3
- package/dist/{login-SB5OENMV.js → login-57MMYILL.js} +4 -4
- package/dist/{register-OX4HRSGC.js → register-WNCSOTAU.js} +3 -3
- package/dist/{restart-AGEGNSYQ.js → restart-B4GNMVF2.js} +4 -4
- package/dist/{skill-B5OJEQUA.js → skill-QYTBUDNQ.js} +4 -4
- package/dist/{start-MUMNFR52.js → start-BDHJVOVX.js} +3 -3
- package/dist/{stop-EKERNYTX.js → stop-45QYSGYS.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-OYF25B62.js";
|
|
10
10
|
import {
|
|
11
11
|
acceptPending,
|
|
12
12
|
formatFileSize,
|
|
@@ -14,23 +14,43 @@ import {
|
|
|
14
14
|
rejectPending,
|
|
15
15
|
stageFile,
|
|
16
16
|
validateFilePath
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-F6D766VQ.js";
|
|
18
|
+
import {
|
|
19
|
+
getMemoryStatus
|
|
20
|
+
} from "./chunk-5RBEEAKW.js";
|
|
18
21
|
import {
|
|
19
22
|
findOpenClawSession,
|
|
20
23
|
importOpenClawConnectors,
|
|
21
24
|
importPiSession,
|
|
22
25
|
parseNameFromIdentity
|
|
23
26
|
} from "./chunk-I7U5EEZC.js";
|
|
27
|
+
import {
|
|
28
|
+
checkForUpdate,
|
|
29
|
+
checkForUpdateCached,
|
|
30
|
+
getCurrentVersion
|
|
31
|
+
} from "./chunk-LAUCO2HC.js";
|
|
24
32
|
import {
|
|
25
33
|
SPIRIT_NOTICE_PREFIX,
|
|
26
34
|
ensureSpiritAvailable
|
|
27
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-LKUGUQUW.js";
|
|
28
36
|
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
TEMPLATE_BRANCH,
|
|
38
|
+
UpgradeInProgressError,
|
|
39
|
+
VariantMergeError,
|
|
40
|
+
abortUpgrade,
|
|
41
|
+
configureGitIdentity,
|
|
42
|
+
continueUpgrade,
|
|
43
|
+
findUnresolvedHomeFiles,
|
|
44
|
+
formatUnresolvedHomeFilesMessage,
|
|
45
|
+
getUpgradeBlocked,
|
|
46
|
+
mergeVariantExcludingMemory,
|
|
47
|
+
npmInstallAsMind,
|
|
48
|
+
npmInstallNeeded,
|
|
49
|
+
runUpgrade,
|
|
50
|
+
upgradeDiff,
|
|
51
|
+
upgradeInProgress,
|
|
52
|
+
validateBranchName
|
|
53
|
+
} from "./chunk-OT5SXF7L.js";
|
|
34
54
|
import {
|
|
35
55
|
isTemplateStale
|
|
36
56
|
} from "./chunk-CV6BNGFK.js";
|
|
@@ -39,19 +59,20 @@ import {
|
|
|
39
59
|
} from "./chunk-HTRSSOHY.js";
|
|
40
60
|
import {
|
|
41
61
|
cleanupVariant
|
|
42
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-OGPVJ53N.js";
|
|
43
63
|
import {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
64
|
+
isHomeOnlyArchive
|
|
65
|
+
} from "./chunk-FLIEXG2T.js";
|
|
66
|
+
import {
|
|
67
|
+
evaluateSeedChecklist
|
|
68
|
+
} from "./chunk-CLCHOXLR.js";
|
|
48
69
|
import {
|
|
49
70
|
PLATFORMS,
|
|
50
71
|
echoTextToChannel,
|
|
51
72
|
fixModelEscapes,
|
|
52
73
|
getPlatformDriver,
|
|
53
74
|
routeOutboundBridge
|
|
54
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-ATZF2RNJ.js";
|
|
55
76
|
import {
|
|
56
77
|
getBridgeConfig,
|
|
57
78
|
readBridgesConfig,
|
|
@@ -94,6 +115,7 @@ import {
|
|
|
94
115
|
loadAllExtensions,
|
|
95
116
|
notifyExtensionsDaemonStart,
|
|
96
117
|
notifyExtensionsDaemonStop,
|
|
118
|
+
notifyExtensionsSpiritReady,
|
|
97
119
|
readSystemsConfig,
|
|
98
120
|
recordOutbound,
|
|
99
121
|
requireAdmin,
|
|
@@ -104,12 +126,12 @@ import {
|
|
|
104
126
|
startMindFull,
|
|
105
127
|
stopMindFull,
|
|
106
128
|
uninstallNpmExtension,
|
|
129
|
+
willGateMessage,
|
|
107
130
|
writeSystemsConfig
|
|
108
|
-
} from "./chunk-
|
|
109
|
-
import "./chunk-
|
|
131
|
+
} from "./chunk-LGXVGIWN.js";
|
|
132
|
+
import "./chunk-RGHF3OK5.js";
|
|
110
133
|
import {
|
|
111
134
|
applyInitFiles,
|
|
112
|
-
applyTemplateHomeFiles,
|
|
113
135
|
composeTemplate,
|
|
114
136
|
copyTemplateToDir,
|
|
115
137
|
findTemplatesRoot,
|
|
@@ -119,8 +141,12 @@ import {
|
|
|
119
141
|
import {
|
|
120
142
|
getScheduler,
|
|
121
143
|
initScheduler
|
|
122
|
-
} from "./chunk-
|
|
144
|
+
} from "./chunk-444RR3YF.js";
|
|
145
|
+
import {
|
|
146
|
+
recordDeliveryFailure
|
|
147
|
+
} from "./chunk-3LHUXY3E.js";
|
|
123
148
|
import {
|
|
149
|
+
UnknownChannelError,
|
|
124
150
|
checkStaleSend,
|
|
125
151
|
formatHoldNotice,
|
|
126
152
|
getDeliveryManager,
|
|
@@ -128,7 +154,7 @@ import {
|
|
|
128
154
|
initDeliveryManager,
|
|
129
155
|
isConversationId,
|
|
130
156
|
publishTypingForChannels
|
|
131
|
-
} from "./chunk-
|
|
157
|
+
} from "./chunk-VDUCLVZI.js";
|
|
132
158
|
import {
|
|
133
159
|
MindStartupError,
|
|
134
160
|
RestartTracker,
|
|
@@ -138,10 +164,10 @@ import {
|
|
|
138
164
|
initMindManager,
|
|
139
165
|
syncProviderToMinds,
|
|
140
166
|
tryGetMindManager
|
|
141
|
-
} from "./chunk-
|
|
167
|
+
} from "./chunk-WHL6PKYP.js";
|
|
142
168
|
import {
|
|
143
169
|
extractTextContent
|
|
144
|
-
} from "./chunk-
|
|
170
|
+
} from "./chunk-YSRYCS3N.js";
|
|
145
171
|
import {
|
|
146
172
|
SYSTEM_MIND,
|
|
147
173
|
assignSession,
|
|
@@ -155,13 +181,15 @@ import {
|
|
|
155
181
|
initSummarizer,
|
|
156
182
|
isoWeekKeyForDateStr,
|
|
157
183
|
markErrored,
|
|
184
|
+
parseDbTimestamp,
|
|
158
185
|
parseUtcDateTime,
|
|
159
186
|
summarizeOrphanedTurns,
|
|
160
187
|
summarizeTurn,
|
|
188
|
+
supersedeTurnSummary,
|
|
161
189
|
takeErrored,
|
|
162
190
|
trackToolUse,
|
|
163
191
|
utcDateTimeStr
|
|
164
|
-
} from "./chunk-
|
|
192
|
+
} from "./chunk-56IT2ZXF.js";
|
|
165
193
|
import {
|
|
166
194
|
SEED_SKILLS,
|
|
167
195
|
STANDARD_SKILLS,
|
|
@@ -175,7 +203,6 @@ import {
|
|
|
175
203
|
listFilesRecursive,
|
|
176
204
|
listMindSkills,
|
|
177
205
|
listSharedSkills,
|
|
178
|
-
migrateSkillsToTemplate,
|
|
179
206
|
mindSkillsDir,
|
|
180
207
|
publishSkill,
|
|
181
208
|
removeSharedSkill,
|
|
@@ -183,7 +210,7 @@ import {
|
|
|
183
210
|
syncBuiltinSkills,
|
|
184
211
|
uninstallSkill,
|
|
185
212
|
updateSkill
|
|
186
|
-
} from "./chunk-
|
|
213
|
+
} from "./chunk-PPSN2MLC.js";
|
|
187
214
|
import {
|
|
188
215
|
approveUser,
|
|
189
216
|
changePassword,
|
|
@@ -207,6 +234,7 @@ import {
|
|
|
207
234
|
withSenderDisplayNames
|
|
208
235
|
} from "./chunk-7LT3YZUR.js";
|
|
209
236
|
import {
|
|
237
|
+
MIND_LEVEL_THREAD,
|
|
210
238
|
captureReflection,
|
|
211
239
|
cleanExpiredEvents,
|
|
212
240
|
clearDeliveredEvents,
|
|
@@ -219,7 +247,7 @@ import {
|
|
|
219
247
|
listEvents,
|
|
220
248
|
parseMeta,
|
|
221
249
|
recordNotice
|
|
222
|
-
} from "./chunk-
|
|
250
|
+
} from "./chunk-HKGYZVWN.js";
|
|
223
251
|
import {
|
|
224
252
|
publish as publish2,
|
|
225
253
|
subscribe as subscribe2,
|
|
@@ -232,7 +260,7 @@ import {
|
|
|
232
260
|
getPrompt,
|
|
233
261
|
getPromptIfCustom,
|
|
234
262
|
substitute
|
|
235
|
-
} from "./chunk-
|
|
263
|
+
} from "./chunk-OAYY3WF3.js";
|
|
236
264
|
import {
|
|
237
265
|
isSandboxEnabled,
|
|
238
266
|
wrapForSandbox
|
|
@@ -295,7 +323,7 @@ import {
|
|
|
295
323
|
readVoluteConfig,
|
|
296
324
|
writeVoluteConfig
|
|
297
325
|
} from "./chunk-WCFSBH33.js";
|
|
298
|
-
import "./chunk-
|
|
326
|
+
import "./chunk-CKPAVQNK.js";
|
|
299
327
|
import {
|
|
300
328
|
chownMindDir,
|
|
301
329
|
chownMindFile,
|
|
@@ -307,7 +335,7 @@ import {
|
|
|
307
335
|
isIsolationEnabled,
|
|
308
336
|
resolveVoluteBin,
|
|
309
337
|
wrapForIsolation
|
|
310
|
-
} from "./chunk-
|
|
338
|
+
} from "./chunk-OIOW3FPT.js";
|
|
311
339
|
import {
|
|
312
340
|
loadMergedEnv,
|
|
313
341
|
mindEnvPath,
|
|
@@ -372,7 +400,6 @@ import {
|
|
|
372
400
|
resolveMindDir,
|
|
373
401
|
setMindRunning,
|
|
374
402
|
setMindStage,
|
|
375
|
-
setMindTemplate,
|
|
376
403
|
setMindTemplateHash,
|
|
377
404
|
stateDir,
|
|
378
405
|
validateMindName,
|
|
@@ -397,9 +424,9 @@ import "./chunk-K3NQKI34.js";
|
|
|
397
424
|
|
|
398
425
|
// packages/daemon/src/daemon.ts
|
|
399
426
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
400
|
-
import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync12, unlinkSync as unlinkSync2, writeFileSync as
|
|
427
|
+
import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync12, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "fs";
|
|
401
428
|
import { homedir as homedir3 } from "os";
|
|
402
|
-
import { resolve as
|
|
429
|
+
import { resolve as resolve18 } from "path";
|
|
403
430
|
import { format } from "util";
|
|
404
431
|
|
|
405
432
|
// packages/daemon/src/lib/daemon/backup-manager.ts
|
|
@@ -510,7 +537,7 @@ var BackupManager = class {
|
|
|
510
537
|
} catch (pubErr) {
|
|
511
538
|
blog.error("failed to publish backup-failure activity", logger_default.errorData(pubErr));
|
|
512
539
|
}
|
|
513
|
-
const { deliverEvent: deliverEvent2 } = await import("./system-events-
|
|
540
|
+
const { deliverEvent: deliverEvent2 } = await import("./system-events-Q7IVZ5T4.js");
|
|
514
541
|
await deliverEvent2(getSpiritName(), {
|
|
515
542
|
type: "notice",
|
|
516
543
|
meta: { subtype: "backup" },
|
|
@@ -734,8 +761,8 @@ var BridgeManager = class {
|
|
|
734
761
|
if (!tracked) return;
|
|
735
762
|
this.stopping.add(platform);
|
|
736
763
|
this.bridges.delete(platform);
|
|
737
|
-
await new Promise((
|
|
738
|
-
tracked.child.on("exit", () =>
|
|
764
|
+
await new Promise((resolve19) => {
|
|
765
|
+
tracked.child.on("exit", () => resolve19());
|
|
739
766
|
try {
|
|
740
767
|
if (tracked.child.pid) {
|
|
741
768
|
process.kill(-tracked.child.pid, "SIGTERM");
|
|
@@ -746,7 +773,7 @@ var BridgeManager = class {
|
|
|
746
773
|
if (err instanceof Error && err.code !== "ESRCH") {
|
|
747
774
|
blog2.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
|
|
748
775
|
}
|
|
749
|
-
|
|
776
|
+
resolve19();
|
|
750
777
|
}
|
|
751
778
|
setTimeout(() => {
|
|
752
779
|
try {
|
|
@@ -757,7 +784,7 @@ var BridgeManager = class {
|
|
|
757
784
|
}
|
|
758
785
|
} catch {
|
|
759
786
|
}
|
|
760
|
-
|
|
787
|
+
resolve19();
|
|
761
788
|
}, 5e3);
|
|
762
789
|
});
|
|
763
790
|
this.stopping.delete(platform);
|
|
@@ -1434,10 +1461,10 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1434
1461
|
stream.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
|
|
1435
1462
|
});
|
|
1436
1463
|
});
|
|
1437
|
-
await new Promise((
|
|
1464
|
+
await new Promise((resolve19) => {
|
|
1438
1465
|
stream.onAbort(() => {
|
|
1439
1466
|
unsubscribe();
|
|
1440
|
-
|
|
1467
|
+
resolve19();
|
|
1441
1468
|
});
|
|
1442
1469
|
});
|
|
1443
1470
|
});
|
|
@@ -1462,7 +1489,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1462
1489
|
config2.name = name.trim() || void 0;
|
|
1463
1490
|
writeGlobalConfig(config2);
|
|
1464
1491
|
if (config2.name !== previousName) {
|
|
1465
|
-
const { notifySpiritSystemChange } = await import("./spirit-
|
|
1492
|
+
const { notifySpiritSystemChange } = await import("./spirit-Q5VGFWUI.js");
|
|
1466
1493
|
await notifySpiritSystemChange();
|
|
1467
1494
|
}
|
|
1468
1495
|
return c.json({ name: config2.name ?? null });
|
|
@@ -1821,8 +1848,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1821
1848
|
createdAt: Date.now()
|
|
1822
1849
|
};
|
|
1823
1850
|
oauthFlows.set(flowId, flow);
|
|
1824
|
-
const promptPromise = needsManualCode ? new Promise((
|
|
1825
|
-
flow.resolveCode =
|
|
1851
|
+
const promptPromise = needsManualCode ? new Promise((resolve19) => {
|
|
1852
|
+
flow.resolveCode = resolve19;
|
|
1826
1853
|
}) : void 0;
|
|
1827
1854
|
oauthProvider.login({
|
|
1828
1855
|
onAuth: (info) => {
|
|
@@ -1861,7 +1888,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1861
1888
|
existing.error = err instanceof Error ? err.message : String(err);
|
|
1862
1889
|
}
|
|
1863
1890
|
});
|
|
1864
|
-
await new Promise((
|
|
1891
|
+
await new Promise((resolve19) => setTimeout(resolve19, 2e3));
|
|
1865
1892
|
const state = oauthFlows.get(flowId);
|
|
1866
1893
|
return c.json({
|
|
1867
1894
|
flowId,
|
|
@@ -2122,8 +2149,8 @@ var app2 = new Hono2().get("/events", async (c) => {
|
|
|
2122
2149
|
});
|
|
2123
2150
|
}, 15e3);
|
|
2124
2151
|
cleanups.push(() => clearInterval(keepAlive));
|
|
2125
|
-
await new Promise((
|
|
2126
|
-
stream.onAbort(() =>
|
|
2152
|
+
await new Promise((resolve19) => {
|
|
2153
|
+
stream.onAbort(() => resolve19());
|
|
2127
2154
|
});
|
|
2128
2155
|
} finally {
|
|
2129
2156
|
for (const cleanup of cleanups) {
|
|
@@ -2674,6 +2701,21 @@ async function fanOutToMinds(opts) {
|
|
|
2674
2701
|
const manager = getMindManager();
|
|
2675
2702
|
const sm = getSleepManagerIfReady();
|
|
2676
2703
|
const registeredMinds = new Set((await readAllMinds()).map((m) => m.name));
|
|
2704
|
+
const senderIsMind = registeredMinds.has(opts.senderName);
|
|
2705
|
+
let senderCtx;
|
|
2706
|
+
const reportFailure = (reason) => {
|
|
2707
|
+
if (!senderIsMind) return;
|
|
2708
|
+
senderCtx ??= getBaseName(opts.senderName).then((base) => ({
|
|
2709
|
+
base,
|
|
2710
|
+
channel: buildVoluteSlug({
|
|
2711
|
+
participants,
|
|
2712
|
+
mindUsername: base,
|
|
2713
|
+
conversationId: opts.conversationId,
|
|
2714
|
+
...opts.slugExtra
|
|
2715
|
+
})
|
|
2716
|
+
}));
|
|
2717
|
+
senderCtx.then(({ base, channel }) => recordDeliveryFailure({ mind: base, channel, reason })).catch((err) => logger_default.warn("fan-out: failed to report send failure", logger_default.errorData(err)));
|
|
2718
|
+
};
|
|
2677
2719
|
const targetMinds = mindParticipants.map((ap) => {
|
|
2678
2720
|
const key = opts.targetName ? opts.targetName(ap.username) : ap.username;
|
|
2679
2721
|
if (manager.isRunning(key) || sm?.isSleeping(ap.username)) return ap.username;
|
|
@@ -2682,21 +2724,46 @@ async function fanOutToMinds(opts) {
|
|
|
2682
2724
|
logger_default.warn(
|
|
2683
2725
|
`fan-out: skipping ${ap.username} (not running) for conversation ${opts.conversationId}`
|
|
2684
2726
|
);
|
|
2727
|
+
reportFailure(`${ap.username} is not running`);
|
|
2728
|
+
} else if (ap.userType === "mind") {
|
|
2729
|
+
logger_default.info(
|
|
2730
|
+
`fan-out: skipping ${ap.username} (no registry row \u2014 external mind or stale participant) for conversation ${opts.conversationId}`
|
|
2731
|
+
);
|
|
2685
2732
|
}
|
|
2686
2733
|
if (ap.userType === "system") {
|
|
2687
|
-
import("./spirit-availability-
|
|
2734
|
+
import("./spirit-availability-G5FMWKRH.js").then(({ ensureSpiritAvailable: ensureSpiritAvailable2 }) => ensureSpiritAvailable2()).catch((err) => logger_default.warn("fan-out: on-demand spirit start failed", logger_default.errorData(err)));
|
|
2688
2735
|
}
|
|
2689
2736
|
}
|
|
2690
2737
|
return null;
|
|
2691
2738
|
}).filter((n) => n !== null && n !== opts.senderName);
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2739
|
+
const targets = targetMinds.map((mindName) => ({
|
|
2740
|
+
mindName,
|
|
2741
|
+
target: opts.targetName ? opts.targetName(mindName) : mindName,
|
|
2742
|
+
channel: buildVoluteSlug({
|
|
2695
2743
|
participants,
|
|
2696
2744
|
mindUsername: mindName,
|
|
2697
2745
|
conversationId: opts.conversationId,
|
|
2698
2746
|
...opts.slugExtra
|
|
2699
|
-
})
|
|
2747
|
+
})
|
|
2748
|
+
}));
|
|
2749
|
+
const gatedRecipients = (await Promise.all(
|
|
2750
|
+
targets.map(async ({ mindName, target, channel }) => {
|
|
2751
|
+
if (sm?.isSleeping(mindName)) return null;
|
|
2752
|
+
try {
|
|
2753
|
+
const gated = await willGateMessage(target, {
|
|
2754
|
+
channel,
|
|
2755
|
+
sender: opts.senderName,
|
|
2756
|
+
isDM,
|
|
2757
|
+
participantCount: participants.length
|
|
2758
|
+
});
|
|
2759
|
+
return gated ? mindName : null;
|
|
2760
|
+
} catch (err) {
|
|
2761
|
+
logger_default.warn(`fan-out: will-gate check failed for ${target}`, logger_default.errorData(err));
|
|
2762
|
+
return null;
|
|
2763
|
+
}
|
|
2764
|
+
})
|
|
2765
|
+
)).filter((n) => n !== null);
|
|
2766
|
+
for (const { mindName, target, channel } of targets) {
|
|
2700
2767
|
const typingMap = getTypingMap();
|
|
2701
2768
|
const currentlyTyping = typingMap.get(channel).filter((name) => participantNames.includes(name));
|
|
2702
2769
|
deliverMessage(target, {
|
|
@@ -2708,10 +2775,20 @@ async function fanOutToMinds(opts) {
|
|
|
2708
2775
|
participantCount: participants.length,
|
|
2709
2776
|
isDM,
|
|
2710
2777
|
...currentlyTyping.length > 0 ? { typing: currentlyTyping } : {}
|
|
2711
|
-
}).
|
|
2712
|
-
|
|
2713
|
-
|
|
2778
|
+
}).then(
|
|
2779
|
+
(ok) => {
|
|
2780
|
+
if (!ok) {
|
|
2781
|
+
logger_default.warn(`fan-out delivery failed for ${target} (message not delivered)`);
|
|
2782
|
+
reportFailure(`the delivery to ${mindName} failed`);
|
|
2783
|
+
}
|
|
2784
|
+
},
|
|
2785
|
+
(err) => {
|
|
2786
|
+
logger_default.warn(`fan-out delivery failed for ${target}`, logger_default.errorData(err));
|
|
2787
|
+
reportFailure(`the delivery to ${mindName} failed`);
|
|
2788
|
+
}
|
|
2789
|
+
);
|
|
2714
2790
|
}
|
|
2791
|
+
return { gatedRecipients };
|
|
2715
2792
|
}
|
|
2716
2793
|
|
|
2717
2794
|
// packages/daemon/src/web/api/bridges.ts
|
|
@@ -3069,12 +3146,18 @@ import { resolve as resolve4 } from "path";
|
|
|
3069
3146
|
import { Hono as Hono10 } from "hono";
|
|
3070
3147
|
async function notifyMind(mindName, message) {
|
|
3071
3148
|
const entry = await findMind(mindName);
|
|
3072
|
-
if (!entry) return;
|
|
3073
|
-
try {
|
|
3074
|
-
const { deliverEvent: deliverEvent2 } = await import("./system-events-
|
|
3075
|
-
await deliverEvent2(mindName, { type: "file-share", body: message });
|
|
3149
|
+
if (!entry) return false;
|
|
3150
|
+
try {
|
|
3151
|
+
const { deliverEvent: deliverEvent2 } = await import("./system-events-Q7IVZ5T4.js");
|
|
3152
|
+
const result = await deliverEvent2(mindName, { type: "file-share", body: message });
|
|
3153
|
+
if (result.delivered) return true;
|
|
3154
|
+
if (result.id == null) return false;
|
|
3155
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-KHI65FEX.js");
|
|
3156
|
+
const { getBaseName: getBaseName2 } = await import("./registry-TRC2HJXR.js");
|
|
3157
|
+
return getSleepManagerIfReady2()?.isSleeping(await getBaseName2(mindName)) ?? false;
|
|
3076
3158
|
} catch (err) {
|
|
3077
3159
|
logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
|
|
3160
|
+
return false;
|
|
3078
3161
|
}
|
|
3079
3162
|
}
|
|
3080
3163
|
var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
|
|
@@ -3115,11 +3198,11 @@ var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
|
|
|
3115
3198
|
const filename = body.filePath;
|
|
3116
3199
|
const sizeStr = formatFileSize(content.length);
|
|
3117
3200
|
const { id } = stageFile(body.targetMind, senderName, filename, content, body.filePath);
|
|
3118
|
-
await notifyMind(
|
|
3201
|
+
const notified = await notifyMind(
|
|
3119
3202
|
body.targetMind,
|
|
3120
3203
|
`[file] ${senderName} sent ${filename} (${sizeStr}) \u2014 run: volute chat accept ${id}`
|
|
3121
3204
|
);
|
|
3122
|
-
return c.json({ status: "pending", id }, 200);
|
|
3205
|
+
return c.json({ status: "pending", id, notified }, 200);
|
|
3123
3206
|
}).get("/:name/files/pending", requireSelf(), async (c) => {
|
|
3124
3207
|
const name = c.req.param("name");
|
|
3125
3208
|
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
@@ -3144,8 +3227,8 @@ var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
|
|
|
3144
3227
|
}
|
|
3145
3228
|
return c.json({ error: `Failed to accept file: ${message}` }, 500);
|
|
3146
3229
|
}
|
|
3147
|
-
await notifyMind(result.sender, `[file] ${name} accepted ${result.filename}`);
|
|
3148
|
-
return c.json({ ok: true, destPath: result.destPath });
|
|
3230
|
+
const notified = await notifyMind(result.sender, `[file] ${name} accepted ${result.filename}`);
|
|
3231
|
+
return c.json({ ok: true, destPath: result.destPath, notified });
|
|
3149
3232
|
}).post("/:name/files/reject", requireSelf(), async (c) => {
|
|
3150
3233
|
const name = c.req.param("name");
|
|
3151
3234
|
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
@@ -3161,8 +3244,8 @@ var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
|
|
|
3161
3244
|
}
|
|
3162
3245
|
return c.json({ error: `Failed to reject file: ${message}` }, 500);
|
|
3163
3246
|
}
|
|
3164
|
-
await notifyMind(result.sender, `[file] ${name} rejected ${result.filename}`);
|
|
3165
|
-
return c.json({ ok: true });
|
|
3247
|
+
const notified = await notifyMind(result.sender, `[file] ${name} rejected ${result.filename}`);
|
|
3248
|
+
return c.json({ ok: true, notified });
|
|
3166
3249
|
}).post("/:name/files/stage", requireSelf(), async (c) => {
|
|
3167
3250
|
const receiverName = c.req.param("name");
|
|
3168
3251
|
const receiverEntry = await findMind(receiverName);
|
|
@@ -3185,11 +3268,11 @@ var app8 = new Hono10().post("/:name/files/send", requireSelf(), async (c) => {
|
|
|
3185
3268
|
}
|
|
3186
3269
|
const sizeStr = formatFileSize(content.length);
|
|
3187
3270
|
const { id } = stageFile(receiverName, body.sender, body.filename, content, body.filename);
|
|
3188
|
-
await notifyMind(
|
|
3271
|
+
const notified = await notifyMind(
|
|
3189
3272
|
receiverName,
|
|
3190
3273
|
`[file] ${body.sender} sent ${body.filename} (${sizeStr}) \u2014 run: volute chat accept ${id}`
|
|
3191
3274
|
);
|
|
3192
|
-
return c.json({ status: "pending", id }, 200);
|
|
3275
|
+
return c.json({ status: "pending", id, notified }, 200);
|
|
3193
3276
|
});
|
|
3194
3277
|
var file_sharing_default = app8;
|
|
3195
3278
|
|
|
@@ -4042,9 +4125,9 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
|
|
|
4042
4125
|
stream.onAbort(() => {
|
|
4043
4126
|
tail.kill();
|
|
4044
4127
|
});
|
|
4045
|
-
await new Promise((
|
|
4046
|
-
tail.on("exit",
|
|
4047
|
-
stream.onAbort(
|
|
4128
|
+
await new Promise((resolve19) => {
|
|
4129
|
+
tail.on("exit", resolve19);
|
|
4130
|
+
stream.onAbort(resolve19);
|
|
4048
4131
|
});
|
|
4049
4132
|
});
|
|
4050
4133
|
}).get("/:name/logs/tail", requireSelf(), async (c) => {
|
|
@@ -4062,8 +4145,8 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
|
|
|
4062
4145
|
tail.stdout.on("data", (data) => {
|
|
4063
4146
|
output += data.toString();
|
|
4064
4147
|
});
|
|
4065
|
-
await new Promise((
|
|
4066
|
-
tail.on("exit",
|
|
4148
|
+
await new Promise((resolve19) => {
|
|
4149
|
+
tail.on("exit", resolve19);
|
|
4067
4150
|
});
|
|
4068
4151
|
return c.text(output);
|
|
4069
4152
|
});
|
|
@@ -4156,14 +4239,14 @@ var mind_skills_default = app12;
|
|
|
4156
4239
|
// packages/daemon/src/web/api/minds.ts
|
|
4157
4240
|
import {
|
|
4158
4241
|
cpSync,
|
|
4159
|
-
existsSync as
|
|
4242
|
+
existsSync as existsSync7,
|
|
4160
4243
|
mkdirSync as mkdirSync6,
|
|
4161
4244
|
readdirSync as readdirSync2,
|
|
4162
4245
|
readFileSync as readFileSync9,
|
|
4163
4246
|
rmSync as rmSync3,
|
|
4164
4247
|
writeFileSync as writeFileSync8
|
|
4165
4248
|
} from "fs";
|
|
4166
|
-
import { relative, resolve as
|
|
4249
|
+
import { relative, resolve as resolve11 } from "path";
|
|
4167
4250
|
import { zValidator as zValidator6 } from "@hono/zod-validator";
|
|
4168
4251
|
import { and as and5, desc as desc3, eq as eq5, sql as sql3 } from "drizzle-orm";
|
|
4169
4252
|
import { Hono as Hono16 } from "hono";
|
|
@@ -4606,49 +4689,6 @@ async function commitSrcChanges(dir, mindName) {
|
|
|
4606
4689
|
glog.info(`committed known-good src changes (${dir})`);
|
|
4607
4690
|
}
|
|
4608
4691
|
|
|
4609
|
-
// packages/daemon/src/lib/mind/npm-install.ts
|
|
4610
|
-
import { existsSync as existsSync7 } from "fs";
|
|
4611
|
-
import { resolve as resolve10 } from "path";
|
|
4612
|
-
var NPM_INSTALL_ARGS = [
|
|
4613
|
-
"install",
|
|
4614
|
-
"--no-audit",
|
|
4615
|
-
"--no-fund",
|
|
4616
|
-
"--prefer-offline",
|
|
4617
|
-
"--loglevel=error"
|
|
4618
|
-
];
|
|
4619
|
-
function lowPriorityArgv(cmd, args, ionice) {
|
|
4620
|
-
return ionice ? ["ionice", ["-c2", "-n7", "nice", "-n19", cmd, ...args]] : ["nice", ["-n19", cmd, ...args]];
|
|
4621
|
-
}
|
|
4622
|
-
function hasIonice() {
|
|
4623
|
-
return process.platform === "linux" && (existsSync7("/usr/bin/ionice") || existsSync7("/bin/ionice"));
|
|
4624
|
-
}
|
|
4625
|
-
async function npmInstallAsMind(cwd, mindName) {
|
|
4626
|
-
const [cmd, args] = lowPriorityArgv("npm", NPM_INSTALL_ARGS, hasIonice());
|
|
4627
|
-
if (isIsolationEnabled()) {
|
|
4628
|
-
const [wrappedCmd, wrappedArgs] = await wrapForIsolation(cmd, args, mindName);
|
|
4629
|
-
await exec(wrappedCmd, wrappedArgs, {
|
|
4630
|
-
cwd,
|
|
4631
|
-
env: { ...process.env, HOME: resolve10(cwd, "home") }
|
|
4632
|
-
});
|
|
4633
|
-
} else {
|
|
4634
|
-
await exec(cmd, args, { cwd });
|
|
4635
|
-
}
|
|
4636
|
-
}
|
|
4637
|
-
async function depsChangedSince(dir, fromRef) {
|
|
4638
|
-
try {
|
|
4639
|
-
await gitExec(["diff", "--quiet", fromRef, "HEAD", "--", "package.json", "package-lock.json"], {
|
|
4640
|
-
cwd: dir
|
|
4641
|
-
});
|
|
4642
|
-
return false;
|
|
4643
|
-
} catch {
|
|
4644
|
-
return true;
|
|
4645
|
-
}
|
|
4646
|
-
}
|
|
4647
|
-
async function npmInstallNeeded(dir, preMergeRef) {
|
|
4648
|
-
if (!existsSync7(resolve10(dir, "node_modules"))) return true;
|
|
4649
|
-
return depsChangedSince(dir, preMergeRef);
|
|
4650
|
-
}
|
|
4651
|
-
|
|
4652
4692
|
// packages/daemon/src/lib/mind/thinking-config.ts
|
|
4653
4693
|
var CLAUDE_EFFORT = {
|
|
4654
4694
|
minimal: "low",
|
|
@@ -4690,150 +4730,6 @@ function deriveThinkingLevel(config2) {
|
|
|
4690
4730
|
return null;
|
|
4691
4731
|
}
|
|
4692
4732
|
|
|
4693
|
-
// packages/daemon/src/lib/mind/variants.ts
|
|
4694
|
-
import { statSync as statSync3 } from "fs";
|
|
4695
|
-
import { resolve as resolve11 } from "path";
|
|
4696
|
-
var SAFE_BRANCH_RE = /^[a-zA-Z0-9._\-/]+$/;
|
|
4697
|
-
function validateBranchName(branch) {
|
|
4698
|
-
if (!SAFE_BRANCH_RE.test(branch)) {
|
|
4699
|
-
return `Invalid branch name: ${branch}. Only alphanumeric, '.', '_', '-', '/' allowed.`;
|
|
4700
|
-
}
|
|
4701
|
-
if (branch.includes("..")) {
|
|
4702
|
-
return `Invalid branch name: ${branch}. '..' not allowed.`;
|
|
4703
|
-
}
|
|
4704
|
-
return null;
|
|
4705
|
-
}
|
|
4706
|
-
var MERGE_EXCLUDED_PATHS = ["home/MEMORY.md", "home/memory/journal/"];
|
|
4707
|
-
var MAX_DELTA_CHARS = 12e3;
|
|
4708
|
-
var NEVER_REPORT_PREFIXES = ["home/.claude/", "home/.pi/", "home/.agents/"];
|
|
4709
|
-
var MAX_LISTED_UNRESOLVED_FILES = 20;
|
|
4710
|
-
async function findUnresolvedHomeFiles(cwd) {
|
|
4711
|
-
const raw = await gitExec(
|
|
4712
|
-
["ls-files", "--others", "--ignored", "--exclude-standard", "-z", "--", "home"],
|
|
4713
|
-
{ cwd }
|
|
4714
|
-
);
|
|
4715
|
-
const allPaths = raw.split("\0").filter((path) => path && !NEVER_REPORT_PREFIXES.some((prefix) => path.startsWith(prefix)));
|
|
4716
|
-
const files = [];
|
|
4717
|
-
let totalBytes = 0;
|
|
4718
|
-
for (const path of allPaths) {
|
|
4719
|
-
let bytes = -1;
|
|
4720
|
-
try {
|
|
4721
|
-
bytes = statSync3(resolve11(cwd, path)).size;
|
|
4722
|
-
} catch {
|
|
4723
|
-
}
|
|
4724
|
-
if (bytes > 0) totalBytes += bytes;
|
|
4725
|
-
if (files.length < MAX_LISTED_UNRESOLVED_FILES) files.push({ path, bytes });
|
|
4726
|
-
}
|
|
4727
|
-
return { files, totalCount: allPaths.length, totalBytes };
|
|
4728
|
-
}
|
|
4729
|
-
function formatBytes(bytes) {
|
|
4730
|
-
if (bytes < 0) return "size unknown";
|
|
4731
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
4732
|
-
const units = ["KB", "MB", "GB", "TB"];
|
|
4733
|
-
let value = bytes / 1024;
|
|
4734
|
-
for (const unit of units) {
|
|
4735
|
-
if (value < 1024) return `${value.toFixed(1)} ${unit}`;
|
|
4736
|
-
value /= 1024;
|
|
4737
|
-
}
|
|
4738
|
-
return `${value.toFixed(1)} PB`;
|
|
4739
|
-
}
|
|
4740
|
-
function formatUnresolvedHomeFilesMessage(variantName, result) {
|
|
4741
|
-
const lines = result.files.map(
|
|
4742
|
-
(f) => ` - ${f.path.replace(/^home\//, "")} (${formatBytes(f.bytes)})`
|
|
4743
|
-
);
|
|
4744
|
-
const remaining = result.totalCount - result.files.length;
|
|
4745
|
-
if (remaining > 0) lines.push(` ...and ${remaining} more`);
|
|
4746
|
-
return `Cannot join variant "${variantName}": it has ${result.totalCount} untracked file${result.totalCount === 1 ? "" : "s"} under home/ that .gitignore is hiding from git \u2014 never committed, and joining would destroy them when the variant is cleaned up (total: ${formatBytes(result.totalBytes)}):
|
|
4747
|
-
|
|
4748
|
-
${lines.join("\n")}
|
|
4749
|
-
|
|
4750
|
-
Before retrying the join, resolve each file in the variant \u2014 one of:
|
|
4751
|
-
1. Track it: git add -f -- <path> (then commit it, or let auto-commit pick it up next turn)
|
|
4752
|
-
2. Copy it out of home/ to somewhere safe, then delete it
|
|
4753
|
-
3. Delete it if it's disposable
|
|
4754
|
-
|
|
4755
|
-
Once resolved, retry the join. To join anyway and discard everything listed above, pass discardUnresolved: true.`;
|
|
4756
|
-
}
|
|
4757
|
-
async function mergeVariantExcludingMemory(projectRoot, variantBranch) {
|
|
4758
|
-
const opts = { cwd: projectRoot };
|
|
4759
|
-
let memoryDelta = "";
|
|
4760
|
-
try {
|
|
4761
|
-
const base = (await gitExec(["merge-base", "HEAD", variantBranch], opts)).trim();
|
|
4762
|
-
memoryDelta = (await gitExec(["diff", `${base}..${variantBranch}`, "--", ...MERGE_EXCLUDED_PATHS], opts)).trim();
|
|
4763
|
-
} catch (err) {
|
|
4764
|
-
logger_default.error(
|
|
4765
|
-
`variant join: failed to compute memory delta for ${variantBranch}`,
|
|
4766
|
-
logger_default.errorData(err)
|
|
4767
|
-
);
|
|
4768
|
-
memoryDelta = `(journal delta unavailable \u2014 ${err instanceof Error ? err.message : String(err)})`;
|
|
4769
|
-
}
|
|
4770
|
-
if (memoryDelta.length > MAX_DELTA_CHARS) {
|
|
4771
|
-
memoryDelta = `${memoryDelta.slice(0, MAX_DELTA_CHARS)}
|
|
4772
|
-
\u2026 (delta truncated)`;
|
|
4773
|
-
}
|
|
4774
|
-
try {
|
|
4775
|
-
await gitExec(["merge", "--no-ff", "--no-commit", variantBranch], opts).catch(() => {
|
|
4776
|
-
});
|
|
4777
|
-
await gitExec(["reset", "-q", "HEAD", "--", ...MERGE_EXCLUDED_PATHS], opts);
|
|
4778
|
-
for (const path of MERGE_EXCLUDED_PATHS) {
|
|
4779
|
-
await gitExec(["checkout", "--", path], opts).catch(() => {
|
|
4780
|
-
});
|
|
4781
|
-
}
|
|
4782
|
-
await gitExec(["clean", "-fdq", "--", ...MERGE_EXCLUDED_PATHS], opts);
|
|
4783
|
-
await assertExcludedPathsRestored(opts);
|
|
4784
|
-
if (await mergeInProgress(opts)) {
|
|
4785
|
-
await gitExec(["commit", "--no-edit"], opts);
|
|
4786
|
-
}
|
|
4787
|
-
} catch (err) {
|
|
4788
|
-
const conflicts = await listConflicts(opts);
|
|
4789
|
-
const abortFailed = await gitExec(["merge", "--abort"], opts).then(
|
|
4790
|
-
() => false,
|
|
4791
|
-
() => true
|
|
4792
|
-
);
|
|
4793
|
-
throw new VariantMergeError(
|
|
4794
|
-
`variant join aborted: ${err instanceof Error ? err.message : String(err)}`,
|
|
4795
|
-
conflicts,
|
|
4796
|
-
abortFailed
|
|
4797
|
-
);
|
|
4798
|
-
}
|
|
4799
|
-
return memoryDelta;
|
|
4800
|
-
}
|
|
4801
|
-
var VariantMergeError = class extends Error {
|
|
4802
|
-
constructor(message, conflicts, abortFailed = false) {
|
|
4803
|
-
super(message);
|
|
4804
|
-
this.conflicts = conflicts;
|
|
4805
|
-
this.abortFailed = abortFailed;
|
|
4806
|
-
this.name = "VariantMergeError";
|
|
4807
|
-
}
|
|
4808
|
-
};
|
|
4809
|
-
async function mergeInProgress(opts) {
|
|
4810
|
-
return gitExec(["rev-parse", "-q", "--verify", "MERGE_HEAD"], opts).then(
|
|
4811
|
-
() => true,
|
|
4812
|
-
() => false
|
|
4813
|
-
);
|
|
4814
|
-
}
|
|
4815
|
-
async function listConflicts(opts) {
|
|
4816
|
-
try {
|
|
4817
|
-
const out = (await gitExec(["diff", "--name-only", "--diff-filter=U"], opts)).trim();
|
|
4818
|
-
return out ? out.split("\n") : [];
|
|
4819
|
-
} catch {
|
|
4820
|
-
return [];
|
|
4821
|
-
}
|
|
4822
|
-
}
|
|
4823
|
-
async function assertExcludedPathsRestored(opts) {
|
|
4824
|
-
await gitExec(["diff", "--cached", "--quiet", "HEAD", "--", ...MERGE_EXCLUDED_PATHS], opts);
|
|
4825
|
-
await gitExec(["diff", "--quiet", "HEAD", "--", ...MERGE_EXCLUDED_PATHS], opts);
|
|
4826
|
-
const untracked = (await gitExec(
|
|
4827
|
-
["ls-files", "--others", "--exclude-standard", "--", ...MERGE_EXCLUDED_PATHS],
|
|
4828
|
-
opts
|
|
4829
|
-
)).trim();
|
|
4830
|
-
if (untracked) {
|
|
4831
|
-
throw new Error(
|
|
4832
|
-
`untracked memory files remain after restore: ${untracked.replace(/\n/g, ", ")}`
|
|
4833
|
-
);
|
|
4834
|
-
}
|
|
4835
|
-
}
|
|
4836
|
-
|
|
4837
4733
|
// packages/daemon/src/lib/services/imagegen-jobs.ts
|
|
4838
4734
|
import { mkdir, writeFile } from "fs/promises";
|
|
4839
4735
|
import { dirname as dirname2 } from "path";
|
|
@@ -4956,7 +4852,7 @@ async function waitForImagegenJob(mind, id, timeoutMs) {
|
|
|
4956
4852
|
import { randomUUID } from "crypto";
|
|
4957
4853
|
import { mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
4958
4854
|
import { homedir } from "os";
|
|
4959
|
-
import { resolve as
|
|
4855
|
+
import { resolve as resolve10 } from "path";
|
|
4960
4856
|
function convertSession(opts) {
|
|
4961
4857
|
const lines = readFileSync8(opts.sessionPath, "utf-8").trim().split("\n");
|
|
4962
4858
|
const sessionId = randomUUID();
|
|
@@ -5072,9 +4968,9 @@ function convertSession(opts) {
|
|
|
5072
4968
|
}
|
|
5073
4969
|
}
|
|
5074
4970
|
const projectId = opts.projectDir.replace(/\//g, "-");
|
|
5075
|
-
const sdkDir =
|
|
4971
|
+
const sdkDir = resolve10(homedir(), ".claude", "projects", projectId);
|
|
5076
4972
|
mkdirSync5(sdkDir, { recursive: true });
|
|
5077
|
-
const sdkPath =
|
|
4973
|
+
const sdkPath = resolve10(sdkDir, `${sessionId}.jsonl`);
|
|
5078
4974
|
writeFileSync7(sdkPath, `${sdkEvents.join("\n")}
|
|
5079
4975
|
`);
|
|
5080
4976
|
console.log(`Converted ${sdkEvents.length} messages \u2192 ${sdkPath}`);
|
|
@@ -5126,12 +5022,6 @@ function convertAssistantContent(content) {
|
|
|
5126
5022
|
return result;
|
|
5127
5023
|
}
|
|
5128
5024
|
|
|
5129
|
-
// packages/daemon/src/lib/util/time.ts
|
|
5130
|
-
function parseDbTimestamp(ts) {
|
|
5131
|
-
if (/[zZ]$|[+-]\d\d:?\d\d$/.test(ts)) return new Date(ts);
|
|
5132
|
-
return /* @__PURE__ */ new Date(`${ts.replace(" ", "T")}Z`);
|
|
5133
|
-
}
|
|
5134
|
-
|
|
5135
5025
|
// packages/daemon/src/web/api/minds.ts
|
|
5136
5026
|
var _lastActiveCache = { map: /* @__PURE__ */ new Map(), ts: 0 };
|
|
5137
5027
|
var _LAST_ACTIVE_TTL = 6e4;
|
|
@@ -5141,7 +5031,7 @@ async function getMindStatus(name, port, registryRunning, seed) {
|
|
|
5141
5031
|
let status = "stopped";
|
|
5142
5032
|
let wakeAt = null;
|
|
5143
5033
|
try {
|
|
5144
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5034
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-KHI65FEX.js");
|
|
5145
5035
|
const sleepManager = getSleepManagerIfReady2();
|
|
5146
5036
|
if (sleepManager?.isSleeping(name)) {
|
|
5147
5037
|
status = "sleeping";
|
|
@@ -5167,10 +5057,12 @@ async function getMindStatus(name, port, registryRunning, seed) {
|
|
|
5167
5057
|
}
|
|
5168
5058
|
const lastError = await latestFailureEvent(name);
|
|
5169
5059
|
const seedChecklist = seed?.stage === "seed" ? evaluateSeedChecklist(seed.dir ?? mindDir(name)) : void 0;
|
|
5060
|
+
const memory = getMemoryStatus(seed?.dir ?? mindDir(name));
|
|
5170
5061
|
return {
|
|
5171
5062
|
status,
|
|
5172
5063
|
wakeAt,
|
|
5173
5064
|
lastError,
|
|
5065
|
+
memory,
|
|
5174
5066
|
channels: channels2,
|
|
5175
5067
|
displayName: config2?.profile?.displayName,
|
|
5176
5068
|
description: config2?.profile?.description,
|
|
@@ -5193,6 +5085,7 @@ function toPublicMind(entry, status, extras) {
|
|
|
5193
5085
|
// Kind/reason/at only — `detail` can embed the raw error string (unknown
|
|
5194
5086
|
// classifications), which is mind-private (served behind requireSelf).
|
|
5195
5087
|
lastError: status.lastError ? { kind: status.lastError.kind, reason: status.lastError.reason, at: status.lastError.at } : null,
|
|
5088
|
+
memory: status.memory,
|
|
5196
5089
|
channels: status.channels,
|
|
5197
5090
|
displayName: status.displayName,
|
|
5198
5091
|
description: status.description,
|
|
@@ -5202,13 +5095,6 @@ function toPublicMind(entry, status, extras) {
|
|
|
5202
5095
|
lastActiveAt: extras.lastActiveAt ?? null
|
|
5203
5096
|
};
|
|
5204
5097
|
}
|
|
5205
|
-
var TEMPLATE_BRANCH = "volute/template";
|
|
5206
|
-
async function configureGitIdentity(mindName, opts) {
|
|
5207
|
-
const systemsConfig = readSystemsConfig();
|
|
5208
|
-
const system = systemsConfig?.system ?? "local";
|
|
5209
|
-
await gitExec(["config", "user.name", mindName], opts);
|
|
5210
|
-
await gitExec(["config", "user.email", `${mindName}.${system}@volute.systems`], opts);
|
|
5211
|
-
}
|
|
5212
5098
|
async function initTemplateBranch(projectRoot, composedDir, manifest, mindName, env) {
|
|
5213
5099
|
const templateFiles = listFiles(composedDir).filter((f) => !f.startsWith(".init/") && !f.startsWith(".init\\")).filter((f) => !f.startsWith("home/") && !f.startsWith("home\\") || f === "home/VOLUTE.md").map((f) => manifest.rename[f] ?? f);
|
|
5214
5100
|
const opts = { cwd: projectRoot, mindName, env };
|
|
@@ -5219,164 +5105,9 @@ async function initTemplateBranch(projectRoot, composedDir, manifest, mindName,
|
|
|
5219
5105
|
await gitExec(["add", "-A"], opts);
|
|
5220
5106
|
await gitExec(["commit", "-m", "initial commit"], opts);
|
|
5221
5107
|
}
|
|
5222
|
-
async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
5223
|
-
const tempWorktree = resolve13(projectRoot, ".variants", "_template_update");
|
|
5224
|
-
let branchExists = false;
|
|
5225
|
-
try {
|
|
5226
|
-
await gitExec(["rev-parse", "--verify", TEMPLATE_BRANCH], { cwd: projectRoot });
|
|
5227
|
-
branchExists = true;
|
|
5228
|
-
} catch {
|
|
5229
|
-
}
|
|
5230
|
-
try {
|
|
5231
|
-
await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
|
|
5232
|
-
} catch {
|
|
5233
|
-
}
|
|
5234
|
-
if (existsSync8(tempWorktree)) {
|
|
5235
|
-
rmSync3(tempWorktree, { recursive: true, force: true });
|
|
5236
|
-
}
|
|
5237
|
-
const templatesRoot = findTemplatesRoot();
|
|
5238
|
-
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
5239
|
-
try {
|
|
5240
|
-
if (branchExists) {
|
|
5241
|
-
await gitExec(["worktree", "add", tempWorktree, TEMPLATE_BRANCH], {
|
|
5242
|
-
cwd: projectRoot
|
|
5243
|
-
});
|
|
5244
|
-
} else {
|
|
5245
|
-
await gitExec(["worktree", "add", "--detach", tempWorktree], { cwd: projectRoot });
|
|
5246
|
-
await gitExec(["checkout", "--orphan", TEMPLATE_BRANCH], { cwd: tempWorktree });
|
|
5247
|
-
await gitExec(["rm", "-rf", "--cached", "."], { cwd: tempWorktree });
|
|
5248
|
-
await gitExec(["clean", "-fd"], { cwd: tempWorktree });
|
|
5249
|
-
}
|
|
5250
|
-
if (branchExists) {
|
|
5251
|
-
await gitExec(["rm", "-rf", "."], { cwd: tempWorktree }).catch(() => {
|
|
5252
|
-
});
|
|
5253
|
-
}
|
|
5254
|
-
copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
|
|
5255
|
-
const initDir = resolve13(tempWorktree, ".init");
|
|
5256
|
-
if (existsSync8(initDir)) {
|
|
5257
|
-
rmSync3(initDir, { recursive: true, force: true });
|
|
5258
|
-
}
|
|
5259
|
-
const homeDir = resolve13(tempWorktree, "home");
|
|
5260
|
-
if (existsSync8(homeDir)) {
|
|
5261
|
-
for (const entry of readdirSync2(homeDir)) {
|
|
5262
|
-
if (entry !== "VOLUTE.md") {
|
|
5263
|
-
rmSync3(resolve13(homeDir, entry), { recursive: true, force: true });
|
|
5264
|
-
}
|
|
5265
|
-
}
|
|
5266
|
-
}
|
|
5267
|
-
await gitExec(["add", "-A"], { cwd: tempWorktree });
|
|
5268
|
-
try {
|
|
5269
|
-
await gitExec(["diff", "--cached", "--quiet"], { cwd: tempWorktree });
|
|
5270
|
-
} catch {
|
|
5271
|
-
await gitExec(["commit", "-m", "template update"], { cwd: tempWorktree });
|
|
5272
|
-
}
|
|
5273
|
-
} finally {
|
|
5274
|
-
try {
|
|
5275
|
-
await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
|
|
5276
|
-
} catch {
|
|
5277
|
-
}
|
|
5278
|
-
if (existsSync8(tempWorktree)) {
|
|
5279
|
-
rmSync3(tempWorktree, { recursive: true, force: true });
|
|
5280
|
-
}
|
|
5281
|
-
rmSync3(composedDir, { recursive: true, force: true });
|
|
5282
|
-
}
|
|
5283
|
-
}
|
|
5284
|
-
async function mergeTemplateBranch(worktreeDir) {
|
|
5285
|
-
try {
|
|
5286
|
-
await gitExec(
|
|
5287
|
-
["merge", TEMPLATE_BRANCH, "--allow-unrelated-histories", "-m", "merge template update"],
|
|
5288
|
-
{ cwd: worktreeDir }
|
|
5289
|
-
);
|
|
5290
|
-
return false;
|
|
5291
|
-
} catch (e) {
|
|
5292
|
-
try {
|
|
5293
|
-
const status = await gitExec(["status", "--porcelain"], { cwd: worktreeDir });
|
|
5294
|
-
const hasConflictMarkers = status.split("\n").some((line) => line.startsWith("UU") || line.startsWith("AA"));
|
|
5295
|
-
if (hasConflictMarkers) return true;
|
|
5296
|
-
} catch {
|
|
5297
|
-
}
|
|
5298
|
-
throw e;
|
|
5299
|
-
}
|
|
5300
|
-
}
|
|
5301
|
-
async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariantName, upgradeBranch, template, oldTemplate) {
|
|
5302
|
-
const templateChanged = template !== oldTemplate;
|
|
5303
|
-
const mainStatus = (await gitExec(["status", "--porcelain"], { cwd: dir })).trim();
|
|
5304
|
-
if (mainStatus) {
|
|
5305
|
-
await gitExec(["add", "-A"], { cwd: dir });
|
|
5306
|
-
await gitExec(["commit", "-m", "Auto-commit before upgrade merge"], { cwd: dir });
|
|
5307
|
-
}
|
|
5308
|
-
const preMergeHead = (await gitExec(["rev-parse", "HEAD"], { cwd: dir })).trim();
|
|
5309
|
-
await gitExec(["merge", upgradeBranch], { cwd: dir });
|
|
5310
|
-
try {
|
|
5311
|
-
await cleanupVariant(upgradeVariantName, mindName, dir, worktreeDir);
|
|
5312
|
-
} catch (err) {
|
|
5313
|
-
logger_default.warn(`failed to clean up upgrade worktree for ${mindName}`, logger_default.errorData(err));
|
|
5314
|
-
}
|
|
5315
|
-
try {
|
|
5316
|
-
await gitExec(["branch", "-D", upgradeBranch], { cwd: dir });
|
|
5317
|
-
} catch {
|
|
5318
|
-
}
|
|
5319
|
-
let switchWarning;
|
|
5320
|
-
if (templateChanged) {
|
|
5321
|
-
try {
|
|
5322
|
-
applyTemplateHomeFiles(resolve13(dir, "home"), template);
|
|
5323
|
-
const migratedSkills = migrateSkillsToTemplate(dir, oldTemplate, template);
|
|
5324
|
-
await gitExec(["add", "home/"], { cwd: dir });
|
|
5325
|
-
try {
|
|
5326
|
-
await gitExec(["diff", "--cached", "--quiet"], { cwd: dir });
|
|
5327
|
-
} catch {
|
|
5328
|
-
await gitExec(["commit", "-m", `swap template-owned home files for ${template}`], {
|
|
5329
|
-
cwd: dir
|
|
5330
|
-
});
|
|
5331
|
-
}
|
|
5332
|
-
await chownMindDir(dir, mindName);
|
|
5333
|
-
const skillNote = migratedSkills.length > 0 ? ` Migrated skills to the ${template} skills dir: ${migratedSkills.join(", ")}.` : "";
|
|
5334
|
-
switchWarning = `Switched ${oldTemplate}\u2192${template}: config reset to ${template} defaults, mechanics doc replaced, conversation starts fresh (sessions aren't portable across runtimes).${skillNote}`;
|
|
5335
|
-
} catch (err) {
|
|
5336
|
-
logger_default.warn(`failed to swap template home files for ${mindName}`, logger_default.errorData(err));
|
|
5337
|
-
return {
|
|
5338
|
-
ok: true,
|
|
5339
|
-
warning: `Upgrade merged but template switch ${oldTemplate}\u2192${template} failed: ${err instanceof Error ? err.message : String(err)}. The mind is still registered as ${oldTemplate}; re-run the switch or fix home/ manually.`
|
|
5340
|
-
};
|
|
5341
|
-
}
|
|
5342
|
-
}
|
|
5343
|
-
try {
|
|
5344
|
-
await setMindTemplateHash(mindName, computeTemplateHash(template));
|
|
5345
|
-
await setMindTemplate(mindName, template);
|
|
5346
|
-
} catch (err) {
|
|
5347
|
-
logger_default.warn(`failed to update template for ${mindName}`, logger_default.errorData(err));
|
|
5348
|
-
}
|
|
5349
|
-
if (await npmInstallNeeded(dir, preMergeHead)) {
|
|
5350
|
-
try {
|
|
5351
|
-
await npmInstallAsMind(dir, mindName);
|
|
5352
|
-
} catch (err) {
|
|
5353
|
-
logger_default.warn(`npm install failed after upgrade merge for ${mindName}`, logger_default.errorData(err));
|
|
5354
|
-
return {
|
|
5355
|
-
ok: true,
|
|
5356
|
-
warning: `Upgrade merged but npm install failed: ${err instanceof Error ? err.message : String(err)}. You may need to run npm install manually.`
|
|
5357
|
-
};
|
|
5358
|
-
}
|
|
5359
|
-
} else {
|
|
5360
|
-
logger_default.info(`skipping npm install for ${mindName} \u2014 dependencies unchanged by upgrade`);
|
|
5361
|
-
}
|
|
5362
|
-
const manager = getMindManager();
|
|
5363
|
-
try {
|
|
5364
|
-
if (manager.isRunning(mindName)) {
|
|
5365
|
-
await manager.stopMind(mindName);
|
|
5366
|
-
}
|
|
5367
|
-
manager.setPendingContext(mindName, { type: "upgraded" });
|
|
5368
|
-
await manager.startMind(mindName, { healthTimeoutMs: 12e4 });
|
|
5369
|
-
} catch (e) {
|
|
5370
|
-
return {
|
|
5371
|
-
ok: true,
|
|
5372
|
-
warning: `Upgrade merged but mind restart failed: ${e instanceof Error ? e.message : String(e)}`
|
|
5373
|
-
};
|
|
5374
|
-
}
|
|
5375
|
-
return { ok: true, warning: switchWarning };
|
|
5376
|
-
}
|
|
5377
5108
|
async function importFromArchive(c, tempDir, nameOverride, manifest) {
|
|
5378
|
-
const extractedMindDir =
|
|
5379
|
-
if (!
|
|
5109
|
+
const extractedMindDir = resolve11(tempDir, "mind");
|
|
5110
|
+
if (!existsSync7(extractedMindDir)) {
|
|
5380
5111
|
return c.json({ error: "Invalid archive: missing mind/ directory" }, 400);
|
|
5381
5112
|
}
|
|
5382
5113
|
if (!manifest?.includes || !manifest.name || !manifest.template) {
|
|
@@ -5394,7 +5125,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
5394
5125
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
5395
5126
|
ensureVoluteHome();
|
|
5396
5127
|
const dest = mindDir(name);
|
|
5397
|
-
if (
|
|
5128
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
5398
5129
|
try {
|
|
5399
5130
|
cpSync(extractedMindDir, dest, { recursive: true });
|
|
5400
5131
|
if (!manifest.includes.identity) {
|
|
@@ -5402,9 +5133,9 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
5402
5133
|
}
|
|
5403
5134
|
const state = stateDir(name);
|
|
5404
5135
|
mkdirSync6(state, { recursive: true });
|
|
5405
|
-
const envJson =
|
|
5406
|
-
if (
|
|
5407
|
-
cpSync(envJson,
|
|
5136
|
+
const envJson = resolve11(tempDir, "state/env.json");
|
|
5137
|
+
if (existsSync7(envJson)) {
|
|
5138
|
+
cpSync(envJson, resolve11(state, "env.json"));
|
|
5408
5139
|
}
|
|
5409
5140
|
const port = await nextPort();
|
|
5410
5141
|
await addMind(name, port, manifest.stage, manifest.template);
|
|
@@ -5413,30 +5144,30 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
5413
5144
|
} catch (err) {
|
|
5414
5145
|
logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
|
|
5415
5146
|
}
|
|
5416
|
-
const homeDir =
|
|
5147
|
+
const homeDir = resolve11(dest, "home");
|
|
5417
5148
|
ensureVoluteGroup();
|
|
5418
5149
|
createMindUser(name, homeDir);
|
|
5419
5150
|
await chownMindDir(dest, name);
|
|
5420
5151
|
await npmInstallAsMind(dest, name);
|
|
5421
5152
|
await importHistoryFromArchive(name, tempDir);
|
|
5422
5153
|
importSessionsFromArchive(dest, tempDir);
|
|
5423
|
-
if (!
|
|
5154
|
+
if (!existsSync7(resolve11(dest, ".git"))) {
|
|
5424
5155
|
try {
|
|
5425
|
-
const env = isIsolationEnabled() ? { ...process.env, HOME:
|
|
5156
|
+
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
|
|
5426
5157
|
await gitExec(["init"], { cwd: dest, mindName: name, env });
|
|
5427
5158
|
await configureGitIdentity(name, { cwd: dest, mindName: name, env });
|
|
5428
5159
|
await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
|
|
5429
5160
|
await gitExec(["commit", "-m", "import from archive"], { cwd: dest, mindName: name, env });
|
|
5430
5161
|
} catch (err) {
|
|
5431
5162
|
logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
|
|
5432
|
-
rmSync3(
|
|
5163
|
+
rmSync3(resolve11(dest, ".git"), { recursive: true, force: true });
|
|
5433
5164
|
}
|
|
5434
5165
|
}
|
|
5435
5166
|
await chownMindDir(dest, name);
|
|
5436
5167
|
rmSync3(tempDir, { recursive: true, force: true });
|
|
5437
5168
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
5438
5169
|
} catch (err) {
|
|
5439
|
-
if (
|
|
5170
|
+
if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
|
|
5440
5171
|
try {
|
|
5441
5172
|
await removeMind(name);
|
|
5442
5173
|
} catch (cleanupErr) {
|
|
@@ -5453,7 +5184,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
5453
5184
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
5454
5185
|
ensureVoluteHome();
|
|
5455
5186
|
const dest = mindDir(name);
|
|
5456
|
-
if (
|
|
5187
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
5457
5188
|
const templatesRoot = findTemplatesRoot();
|
|
5458
5189
|
const { composedDir, manifest: templateManifest } = composeTemplate(
|
|
5459
5190
|
templatesRoot,
|
|
@@ -5462,36 +5193,36 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
5462
5193
|
try {
|
|
5463
5194
|
copyTemplateToDir(composedDir, dest, name, templateManifest);
|
|
5464
5195
|
applyInitFiles(dest);
|
|
5465
|
-
const extractedHome =
|
|
5466
|
-
if (
|
|
5467
|
-
cpSync(extractedHome,
|
|
5196
|
+
const extractedHome = resolve11(extractedMindDir, "home");
|
|
5197
|
+
if (existsSync7(extractedHome)) {
|
|
5198
|
+
cpSync(extractedHome, resolve11(dest, "home"), { recursive: true });
|
|
5468
5199
|
}
|
|
5469
|
-
const extractedMindInternal =
|
|
5470
|
-
if (
|
|
5471
|
-
cpSync(extractedMindInternal,
|
|
5200
|
+
const extractedMindInternal = resolve11(extractedMindDir, ".mind");
|
|
5201
|
+
if (existsSync7(extractedMindInternal)) {
|
|
5202
|
+
cpSync(extractedMindInternal, resolve11(dest, ".mind"), { recursive: true });
|
|
5472
5203
|
}
|
|
5473
|
-
const identityDir =
|
|
5204
|
+
const identityDir = resolve11(dest, ".mind/identity");
|
|
5474
5205
|
let publicKeyPem;
|
|
5475
|
-
if (!manifest.includes.identity || !
|
|
5206
|
+
if (!manifest.includes.identity || !existsSync7(resolve11(identityDir, "private.pem"))) {
|
|
5476
5207
|
({ publicKeyPem } = generateIdentity(dest));
|
|
5477
5208
|
} else {
|
|
5478
|
-
publicKeyPem = readFileSync9(
|
|
5209
|
+
publicKeyPem = readFileSync9(resolve11(identityDir, "public.pem"), "utf-8");
|
|
5479
5210
|
}
|
|
5480
|
-
const promptsPath =
|
|
5481
|
-
if (!
|
|
5211
|
+
const promptsPath = resolve11(dest, "home/.config/prompts.json");
|
|
5212
|
+
if (!existsSync7(promptsPath)) {
|
|
5482
5213
|
const mindPrompts = await getMindPromptDefaults();
|
|
5483
5214
|
writeFileSync8(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
|
|
5484
5215
|
`);
|
|
5485
5216
|
}
|
|
5486
5217
|
const state = stateDir(name);
|
|
5487
5218
|
mkdirSync6(state, { recursive: true });
|
|
5488
|
-
const envJson =
|
|
5489
|
-
if (
|
|
5490
|
-
cpSync(envJson,
|
|
5219
|
+
const envJson = resolve11(tempDir, "state/env.json");
|
|
5220
|
+
if (existsSync7(envJson)) {
|
|
5221
|
+
cpSync(envJson, resolve11(state, "env.json"));
|
|
5491
5222
|
}
|
|
5492
5223
|
const port = await nextPort();
|
|
5493
5224
|
await addMind(name, port, manifest.stage, manifest.template);
|
|
5494
|
-
const homeDir =
|
|
5225
|
+
const homeDir = resolve11(dest, "home");
|
|
5495
5226
|
ensureVoluteGroup();
|
|
5496
5227
|
createMindUser(name, homeDir);
|
|
5497
5228
|
await chownMindDir(dest, name);
|
|
@@ -5504,7 +5235,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
5504
5235
|
await initTemplateBranch(dest, composedDir, templateManifest, name, env);
|
|
5505
5236
|
} catch (err) {
|
|
5506
5237
|
logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
|
|
5507
|
-
rmSync3(
|
|
5238
|
+
rmSync3(resolve11(dest, ".git"), { recursive: true, force: true });
|
|
5508
5239
|
gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
|
|
5509
5240
|
}
|
|
5510
5241
|
const skillSet = manifest.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions();
|
|
@@ -5534,7 +5265,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
5534
5265
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
5535
5266
|
});
|
|
5536
5267
|
} catch (err) {
|
|
5537
|
-
if (
|
|
5268
|
+
if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
|
|
5538
5269
|
try {
|
|
5539
5270
|
await removeMind(name);
|
|
5540
5271
|
} catch (cleanupErr) {
|
|
@@ -5547,8 +5278,8 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
5547
5278
|
}
|
|
5548
5279
|
}
|
|
5549
5280
|
async function importHistoryFromArchive(name, tempDir) {
|
|
5550
|
-
const historyJsonl =
|
|
5551
|
-
if (!
|
|
5281
|
+
const historyJsonl = resolve11(tempDir, "history.jsonl");
|
|
5282
|
+
if (!existsSync7(historyJsonl)) return;
|
|
5552
5283
|
try {
|
|
5553
5284
|
const db = await getDb();
|
|
5554
5285
|
const lines = readFileSync9(historyJsonl, "utf-8").trim().split("\n");
|
|
@@ -5588,13 +5319,13 @@ async function importHistoryFromArchive(name, tempDir) {
|
|
|
5588
5319
|
}
|
|
5589
5320
|
}
|
|
5590
5321
|
function importSessionsFromArchive(dest, tempDir) {
|
|
5591
|
-
const sessionsDir =
|
|
5592
|
-
if (!
|
|
5322
|
+
const sessionsDir = resolve11(tempDir, "sessions");
|
|
5323
|
+
if (!existsSync7(sessionsDir)) return;
|
|
5593
5324
|
try {
|
|
5594
|
-
const destSessions =
|
|
5325
|
+
const destSessions = resolve11(dest, ".mind/sessions");
|
|
5595
5326
|
mkdirSync6(destSessions, { recursive: true });
|
|
5596
5327
|
for (const file of readdirSync2(sessionsDir)) {
|
|
5597
|
-
cpSync(
|
|
5328
|
+
cpSync(resolve11(sessionsDir, file), resolve11(destSessions, file));
|
|
5598
5329
|
}
|
|
5599
5330
|
} catch (err) {
|
|
5600
5331
|
logger_default.error("Failed to import sessions from archive", logger_default.errorData(err));
|
|
@@ -5674,7 +5405,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
5674
5405
|
}
|
|
5675
5406
|
ensureVoluteHome();
|
|
5676
5407
|
const dest = mindDir(name);
|
|
5677
|
-
if (
|
|
5408
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
5678
5409
|
const templatesRoot = findTemplatesRoot();
|
|
5679
5410
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
5680
5411
|
try {
|
|
@@ -5711,9 +5442,9 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
5711
5442
|
writeVoluteConfig(dest, config2);
|
|
5712
5443
|
const modelId = body.model ?? cog?.model;
|
|
5713
5444
|
effectiveModel = modelId ? qualifyModelId(modelId) : void 0;
|
|
5714
|
-
const sdkConfigPath =
|
|
5445
|
+
const sdkConfigPath = resolve11(dest, "home/.config/config.json");
|
|
5715
5446
|
if (modelId || cog?.compaction) {
|
|
5716
|
-
const existing =
|
|
5447
|
+
const existing = existsSync7(sdkConfigPath) ? JSON.parse(readFileSync9(sdkConfigPath, "utf-8")) : {};
|
|
5717
5448
|
if (modelId) {
|
|
5718
5449
|
existing.model = template === "pi" ? qualifyModelId(modelId) : unqualifyModelId(modelId);
|
|
5719
5450
|
}
|
|
@@ -5726,7 +5457,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
5726
5457
|
}
|
|
5727
5458
|
const mindPrompts = await getMindPromptDefaults();
|
|
5728
5459
|
writeFileSync8(
|
|
5729
|
-
|
|
5460
|
+
resolve11(dest, "home/.config/prompts.json"),
|
|
5730
5461
|
`${JSON.stringify(mindPrompts, null, 2)}
|
|
5731
5462
|
`
|
|
5732
5463
|
);
|
|
@@ -5738,7 +5469,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
5738
5469
|
} catch (err) {
|
|
5739
5470
|
logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
|
|
5740
5471
|
}
|
|
5741
|
-
const homeDir =
|
|
5472
|
+
const homeDir = resolve11(dest, "home");
|
|
5742
5473
|
ensureVoluteGroup();
|
|
5743
5474
|
createMindUser(name, homeDir);
|
|
5744
5475
|
await chownMindDir(dest, name);
|
|
@@ -5751,7 +5482,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
5751
5482
|
await initTemplateBranch(dest, composedDir, manifest, name, env);
|
|
5752
5483
|
} catch (err) {
|
|
5753
5484
|
logger_default.error(`git setup failed for ${name}`, logger_default.errorData(err));
|
|
5754
|
-
rmSync3(
|
|
5485
|
+
rmSync3(resolve11(dest, ".git"), { recursive: true, force: true });
|
|
5755
5486
|
gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
|
|
5756
5487
|
}
|
|
5757
5488
|
if (body.stage === "seed") {
|
|
@@ -5760,7 +5491,7 @@ Your creator described you as: "${body.description}"
|
|
|
5760
5491
|
` : "";
|
|
5761
5492
|
const seedSoulRaw = body.seedSoul ?? await getPrompt("seed_soul", { name, description: descLine });
|
|
5762
5493
|
const seedSoul = body.seedSoul ? substitute(seedSoulRaw, { name, description: descLine }) : seedSoulRaw;
|
|
5763
|
-
writeFileSync8(
|
|
5494
|
+
writeFileSync8(resolve11(dest, "home/SOUL.md"), seedSoul);
|
|
5764
5495
|
}
|
|
5765
5496
|
let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
|
|
5766
5497
|
if (body.stage === "seed" && !body.skills) {
|
|
@@ -5786,7 +5517,7 @@ Your creator described you as: "${body.description}"
|
|
|
5786
5517
|
const spiritName = getSpiritName();
|
|
5787
5518
|
const spiritEntry = await findMind(spiritName);
|
|
5788
5519
|
if (spiritEntry) {
|
|
5789
|
-
const { spiritDir } = await import("./spirit-
|
|
5520
|
+
const { spiritDir } = await import("./spirit-Q5VGFWUI.js");
|
|
5790
5521
|
const sDir = spiritEntry.dir ?? spiritDir();
|
|
5791
5522
|
const spiritConfig = readVoluteConfig(sDir) ?? {};
|
|
5792
5523
|
const schedules = spiritConfig.schedules ?? [];
|
|
@@ -5801,7 +5532,7 @@ Your creator described you as: "${body.description}"
|
|
|
5801
5532
|
});
|
|
5802
5533
|
spiritConfig.schedules = schedules;
|
|
5803
5534
|
writeVoluteConfig(sDir, spiritConfig);
|
|
5804
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
5535
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-73Q4MQ7Y.js");
|
|
5805
5536
|
getScheduler2().loadSchedules(spiritName, sDir);
|
|
5806
5537
|
}
|
|
5807
5538
|
}
|
|
@@ -5812,11 +5543,11 @@ Your creator described you as: "${body.description}"
|
|
|
5812
5543
|
if (body.stage !== "seed") {
|
|
5813
5544
|
const customSoul = await getPromptIfCustom("default_soul");
|
|
5814
5545
|
if (customSoul) {
|
|
5815
|
-
writeFileSync8(
|
|
5546
|
+
writeFileSync8(resolve11(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
|
|
5816
5547
|
}
|
|
5817
5548
|
const customMemory = await getPromptIfCustom("default_memory");
|
|
5818
5549
|
if (customMemory) {
|
|
5819
|
-
writeFileSync8(
|
|
5550
|
+
writeFileSync8(resolve11(dest, "home/MEMORY.md"), customMemory);
|
|
5820
5551
|
}
|
|
5821
5552
|
}
|
|
5822
5553
|
await chownMindDir(dest, name);
|
|
@@ -5856,7 +5587,7 @@ Your creator described you as: "${body.description}"
|
|
|
5856
5587
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
5857
5588
|
});
|
|
5858
5589
|
} catch (err) {
|
|
5859
|
-
if (
|
|
5590
|
+
if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
|
|
5860
5591
|
try {
|
|
5861
5592
|
await removeMind(name);
|
|
5862
5593
|
} catch (cleanupErr) {
|
|
@@ -5877,13 +5608,13 @@ Your creator described you as: "${body.description}"
|
|
|
5877
5608
|
return importFromArchive(c, body.archivePath, body.name, body.manifest);
|
|
5878
5609
|
}
|
|
5879
5610
|
const wsDir = body.workspacePath;
|
|
5880
|
-
if (!wsDir || !
|
|
5611
|
+
if (!wsDir || !existsSync7(resolve11(wsDir, "SOUL.md")) || !existsSync7(resolve11(wsDir, "IDENTITY.md"))) {
|
|
5881
5612
|
return c.json({ error: "Invalid workspace: missing SOUL.md or IDENTITY.md" }, 400);
|
|
5882
5613
|
}
|
|
5883
|
-
const soul = readFileSync9(
|
|
5884
|
-
const identity = readFileSync9(
|
|
5885
|
-
const userPath =
|
|
5886
|
-
const user =
|
|
5614
|
+
const soul = readFileSync9(resolve11(wsDir, "SOUL.md"), "utf-8");
|
|
5615
|
+
const identity = readFileSync9(resolve11(wsDir, "IDENTITY.md"), "utf-8");
|
|
5616
|
+
const userPath = resolve11(wsDir, "USER.md");
|
|
5617
|
+
const user = existsSync7(userPath) ? readFileSync9(userPath, "utf-8") : "";
|
|
5887
5618
|
const name = body.name ?? parseNameFromIdentity(identity) ?? "imported-mind";
|
|
5888
5619
|
const template = body.template ?? "claude";
|
|
5889
5620
|
const nameErr = validateMindName(name);
|
|
@@ -5903,33 +5634,33 @@ ${user.trimEnd()}
|
|
|
5903
5634
|
` : "";
|
|
5904
5635
|
ensureVoluteHome();
|
|
5905
5636
|
const dest = mindDir(name);
|
|
5906
|
-
if (
|
|
5637
|
+
if (existsSync7(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
5907
5638
|
const templatesRoot = findTemplatesRoot();
|
|
5908
5639
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
5909
5640
|
try {
|
|
5910
5641
|
copyTemplateToDir(composedDir, dest, name, manifest);
|
|
5911
5642
|
applyInitFiles(dest);
|
|
5912
5643
|
const { publicKeyPem: importPublicKey } = generateIdentity(dest);
|
|
5913
|
-
writeFileSync8(
|
|
5914
|
-
const wsMemoryPath =
|
|
5915
|
-
const hasMemory =
|
|
5644
|
+
writeFileSync8(resolve11(dest, "home/SOUL.md"), mergedSoul);
|
|
5645
|
+
const wsMemoryPath = resolve11(wsDir, "MEMORY.md");
|
|
5646
|
+
const hasMemory = existsSync7(wsMemoryPath);
|
|
5916
5647
|
if (hasMemory) {
|
|
5917
5648
|
const existingMemory = readFileSync9(wsMemoryPath, "utf-8");
|
|
5918
5649
|
writeFileSync8(
|
|
5919
|
-
|
|
5650
|
+
resolve11(dest, "home/MEMORY.md"),
|
|
5920
5651
|
`${existingMemory.trimEnd()}${mergedMemoryExtra}`
|
|
5921
5652
|
);
|
|
5922
5653
|
} else if (user) {
|
|
5923
|
-
writeFileSync8(
|
|
5654
|
+
writeFileSync8(resolve11(dest, "home/MEMORY.md"), `${user.trimEnd()}
|
|
5924
5655
|
`);
|
|
5925
5656
|
}
|
|
5926
|
-
const wsMemoryDir =
|
|
5657
|
+
const wsMemoryDir = resolve11(wsDir, "memory");
|
|
5927
5658
|
let dailyLogCount = 0;
|
|
5928
|
-
if (
|
|
5929
|
-
const destMemoryDir =
|
|
5659
|
+
if (existsSync7(wsMemoryDir)) {
|
|
5660
|
+
const destMemoryDir = resolve11(dest, "home/memory");
|
|
5930
5661
|
const files = readdirSync2(wsMemoryDir).filter((f) => f.endsWith(".md"));
|
|
5931
5662
|
for (const file of files) {
|
|
5932
|
-
cpSync(
|
|
5663
|
+
cpSync(resolve11(wsMemoryDir, file), resolve11(destMemoryDir, file));
|
|
5933
5664
|
}
|
|
5934
5665
|
dailyLogCount = files.length;
|
|
5935
5666
|
}
|
|
@@ -5940,7 +5671,7 @@ ${user.trimEnd()}
|
|
|
5940
5671
|
} catch (err) {
|
|
5941
5672
|
logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
|
|
5942
5673
|
}
|
|
5943
|
-
const homeDir =
|
|
5674
|
+
const homeDir = resolve11(dest, "home");
|
|
5944
5675
|
ensureVoluteGroup();
|
|
5945
5676
|
createMindUser(name, homeDir);
|
|
5946
5677
|
await chownMindDir(dest, name);
|
|
@@ -5948,20 +5679,20 @@ ${user.trimEnd()}
|
|
|
5948
5679
|
if (!hasMemory && dailyLogCount > 0) {
|
|
5949
5680
|
await consolidateMemory(dest);
|
|
5950
5681
|
}
|
|
5951
|
-
const env = isIsolationEnabled() ? { ...process.env, HOME:
|
|
5682
|
+
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
|
|
5952
5683
|
await gitExec(["init"], { cwd: dest, mindName: name, env });
|
|
5953
5684
|
await configureGitIdentity(name, { cwd: dest, mindName: name, env });
|
|
5954
5685
|
await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
|
|
5955
5686
|
await gitExec(["commit", "-m", "import from OpenClaw"], { cwd: dest, mindName: name, env });
|
|
5956
|
-
const sessionFile = body.sessionPath ?
|
|
5957
|
-
if (sessionFile &&
|
|
5687
|
+
const sessionFile = body.sessionPath ? resolve11(body.sessionPath) : findOpenClawSession(wsDir);
|
|
5688
|
+
if (sessionFile && existsSync7(sessionFile)) {
|
|
5958
5689
|
if (template === "pi") {
|
|
5959
5690
|
importPiSession(sessionFile, dest);
|
|
5960
5691
|
} else if (template === "claude") {
|
|
5961
5692
|
const sessionId = convertSession({ sessionPath: sessionFile, projectDir: dest });
|
|
5962
|
-
const mindRuntimeDir =
|
|
5693
|
+
const mindRuntimeDir = resolve11(dest, ".mind");
|
|
5963
5694
|
mkdirSync6(mindRuntimeDir, { recursive: true });
|
|
5964
|
-
writeFileSync8(
|
|
5695
|
+
writeFileSync8(resolve11(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
|
|
5965
5696
|
}
|
|
5966
5697
|
}
|
|
5967
5698
|
importOpenClawConnectors(name, dest);
|
|
@@ -5971,7 +5702,7 @@ ${user.trimEnd()}
|
|
|
5971
5702
|
);
|
|
5972
5703
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
5973
5704
|
} catch (err) {
|
|
5974
|
-
if (
|
|
5705
|
+
if (existsSync7(dest)) rmSync3(dest, { recursive: true, force: true });
|
|
5975
5706
|
try {
|
|
5976
5707
|
await removeMind(name);
|
|
5977
5708
|
} catch (cleanupErr) {
|
|
@@ -6007,7 +5738,7 @@ ${user.trimEnd()}
|
|
|
6007
5738
|
stage: entry.stage,
|
|
6008
5739
|
dir: entry.dir
|
|
6009
5740
|
});
|
|
6010
|
-
const hasPages =
|
|
5741
|
+
const hasPages = existsSync7(resolve11(mindDir(entry.name), "home", "pages"));
|
|
6011
5742
|
const lastActiveAt = lastActiveMap.get(entry.name) ?? null;
|
|
6012
5743
|
if (!privileged) return toPublicMind(entry, mindStatus, { hasPages, lastActiveAt });
|
|
6013
5744
|
return {
|
|
@@ -6015,6 +5746,7 @@ ${user.trimEnd()}
|
|
|
6015
5746
|
...mindStatus,
|
|
6016
5747
|
hasPages,
|
|
6017
5748
|
templateStale: isTemplateStale(entry),
|
|
5749
|
+
upgradeBlocked: getUpgradeBlocked(entry.name)?.reason,
|
|
6018
5750
|
lastActiveAt
|
|
6019
5751
|
};
|
|
6020
5752
|
})
|
|
@@ -6025,12 +5757,12 @@ ${user.trimEnd()}
|
|
|
6025
5757
|
const entry = await findMind(name);
|
|
6026
5758
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
6027
5759
|
const dir = entry.dir ?? mindDir(entry.parent ?? name);
|
|
6028
|
-
if (!
|
|
5760
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
6029
5761
|
const mindStatus = await getMindStatus(name, entry.port, void 0, {
|
|
6030
5762
|
stage: entry.stage,
|
|
6031
5763
|
dir: entry.dir
|
|
6032
5764
|
});
|
|
6033
|
-
const hasPages =
|
|
5765
|
+
const hasPages = existsSync7(resolve11(mindDir(name), "home", "pages"));
|
|
6034
5766
|
if (!isPrivileged(c)) {
|
|
6035
5767
|
return c.json(toPublicMind(entry, mindStatus, { hasPages }));
|
|
6036
5768
|
}
|
|
@@ -6053,6 +5785,7 @@ ${user.trimEnd()}
|
|
|
6053
5785
|
variants: variantStatuses,
|
|
6054
5786
|
hasPages,
|
|
6055
5787
|
templateStale: isTemplateStale(entry),
|
|
5788
|
+
upgradeBlocked: getUpgradeBlocked(name)?.reason,
|
|
6056
5789
|
...notice && {
|
|
6057
5790
|
lastNotice: {
|
|
6058
5791
|
kind: notice.kind,
|
|
@@ -6070,7 +5803,7 @@ ${user.trimEnd()}
|
|
|
6070
5803
|
const projectDir = entry.dir ?? mindDir(name);
|
|
6071
5804
|
if (entry.parent) {
|
|
6072
5805
|
if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
|
|
6073
|
-
} else if (!
|
|
5806
|
+
} else if (!existsSync7(projectDir)) {
|
|
6074
5807
|
return c.json({ error: "Mind directory missing" }, 404);
|
|
6075
5808
|
}
|
|
6076
5809
|
if (getMindManager().isRunning(name)) {
|
|
@@ -6091,7 +5824,7 @@ ${user.trimEnd()}
|
|
|
6091
5824
|
const projectDir = entry.dir ?? mindDir(name);
|
|
6092
5825
|
if (entry.parent) {
|
|
6093
5826
|
if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
|
|
6094
|
-
} else if (!
|
|
5827
|
+
} else if (!existsSync7(projectDir)) {
|
|
6095
5828
|
return c.json({ error: "Mind directory missing" }, 404);
|
|
6096
5829
|
}
|
|
6097
5830
|
let context;
|
|
@@ -6107,7 +5840,7 @@ ${user.trimEnd()}
|
|
|
6107
5840
|
const manager = getMindManager();
|
|
6108
5841
|
try {
|
|
6109
5842
|
if (context?.type === "reload") {
|
|
6110
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5843
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-KHI65FEX.js");
|
|
6111
5844
|
const sleepState = getSleepManagerIfReady2()?.getState(name);
|
|
6112
5845
|
if (sleepState?.sleeping) {
|
|
6113
5846
|
logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
|
|
@@ -6128,7 +5861,7 @@ ${user.trimEnd()}
|
|
|
6128
5861
|
if (variantEntry && variantEntry.parent === baseName && variantEntry.dir && variantEntry.branch) {
|
|
6129
5862
|
const projectRoot = mindDir(baseName);
|
|
6130
5863
|
const discardUnresolved = context.discardUnresolvedHomeFiles === true;
|
|
6131
|
-
if (
|
|
5864
|
+
if (existsSync7(variantEntry.dir)) {
|
|
6132
5865
|
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
6133
5866
|
if (status) {
|
|
6134
5867
|
try {
|
|
@@ -6158,7 +5891,7 @@ ${user.trimEnd()}
|
|
|
6158
5891
|
const preMergeHead = (await gitExec(["rev-parse", "HEAD"], { cwd: projectRoot })).trim();
|
|
6159
5892
|
const memoryDelta = await mergeVariantExcludingMemory(projectRoot, variantEntry.branch);
|
|
6160
5893
|
let unresolvedNotice;
|
|
6161
|
-
if (
|
|
5894
|
+
if (existsSync7(variantEntry.dir) && !discardUnresolved) {
|
|
6162
5895
|
try {
|
|
6163
5896
|
const unresolved = await findUnresolvedHomeFiles(variantEntry.dir);
|
|
6164
5897
|
if (unresolved.totalCount > 0) {
|
|
@@ -6256,7 +5989,7 @@ ${user.trimEnd()}
|
|
|
6256
5989
|
const name = c.req.param("name");
|
|
6257
5990
|
const entry = await findMind(name);
|
|
6258
5991
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
6259
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5992
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-KHI65FEX.js");
|
|
6260
5993
|
const sm = getSleepManagerIfReady2();
|
|
6261
5994
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
6262
5995
|
return c.json(sm.getState(name));
|
|
@@ -6264,7 +5997,7 @@ ${user.trimEnd()}
|
|
|
6264
5997
|
const name = c.req.param("name");
|
|
6265
5998
|
const entry = await findMind(name);
|
|
6266
5999
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
6267
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
6000
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-KHI65FEX.js");
|
|
6268
6001
|
const sm = getSleepManagerIfReady2();
|
|
6269
6002
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
6270
6003
|
if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
|
|
@@ -6284,7 +6017,7 @@ ${user.trimEnd()}
|
|
|
6284
6017
|
const name = c.req.param("name");
|
|
6285
6018
|
const entry = await findMind(name);
|
|
6286
6019
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
6287
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
6020
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-KHI65FEX.js");
|
|
6288
6021
|
const sm = getSleepManagerIfReady2();
|
|
6289
6022
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
6290
6023
|
const sleepState = sm.getState(name);
|
|
@@ -6299,7 +6032,7 @@ ${user.trimEnd()}
|
|
|
6299
6032
|
const name = c.req.param("name");
|
|
6300
6033
|
const entry = await findMind(name);
|
|
6301
6034
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
6302
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
6035
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-KHI65FEX.js");
|
|
6303
6036
|
const sm = getSleepManagerIfReady2();
|
|
6304
6037
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
6305
6038
|
const flushed = await sm.flushQueuedMessages(name);
|
|
@@ -6315,12 +6048,12 @@ ${user.trimEnd()}
|
|
|
6315
6048
|
if (body.displayName !== void 0) profile.displayName = body.displayName;
|
|
6316
6049
|
if (body.description !== void 0) profile.description = body.description;
|
|
6317
6050
|
if (body.avatar !== void 0) {
|
|
6318
|
-
const homeDir =
|
|
6051
|
+
const homeDir = resolve11(dir, "home");
|
|
6319
6052
|
const avatarPath = safeResolveWithinBase(homeDir, body.avatar);
|
|
6320
6053
|
if (!avatarPath) {
|
|
6321
6054
|
return c.json({ error: "Avatar path must be inside the mind's home directory" }, 400);
|
|
6322
6055
|
}
|
|
6323
|
-
if (!
|
|
6056
|
+
if (!existsSync7(avatarPath)) {
|
|
6324
6057
|
return c.json({ error: `Avatar file not found: ${relative(homeDir, avatarPath)}` }, 400);
|
|
6325
6058
|
}
|
|
6326
6059
|
profile.avatar = relative(homeDir, avatarPath);
|
|
@@ -6371,7 +6104,7 @@ ${user.trimEnd()}
|
|
|
6371
6104
|
});
|
|
6372
6105
|
}
|
|
6373
6106
|
if (!force) {
|
|
6374
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
6107
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-KHI65FEX.js");
|
|
6375
6108
|
if (getSleepManagerIfReady2()?.isSleeping(name)) {
|
|
6376
6109
|
return c.json({ output: "" });
|
|
6377
6110
|
}
|
|
@@ -6426,7 +6159,7 @@ ${user.trimEnd()}
|
|
|
6426
6159
|
}
|
|
6427
6160
|
}
|
|
6428
6161
|
const dir = entry.dir ?? mindDir(name);
|
|
6429
|
-
const { evaluateSeedChecklist: evaluateSeedChecklist2 } = await import("./seed-readiness-
|
|
6162
|
+
const { evaluateSeedChecklist: evaluateSeedChecklist2 } = await import("./seed-readiness-H5TTPAQH.js");
|
|
6430
6163
|
const checklist = evaluateSeedChecklist2(dir);
|
|
6431
6164
|
const done = [];
|
|
6432
6165
|
const remaining = [];
|
|
@@ -6468,7 +6201,7 @@ ${user.trimEnd()}
|
|
|
6468
6201
|
try {
|
|
6469
6202
|
const sproutedDir = entry.dir ?? mindDir(name);
|
|
6470
6203
|
if (setupDefaultDreaming(sproutedDir).schedulesChanged) {
|
|
6471
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
6204
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-73Q4MQ7Y.js");
|
|
6472
6205
|
getScheduler2().loadSchedules(name, sproutedDir);
|
|
6473
6206
|
}
|
|
6474
6207
|
} catch (err) {
|
|
@@ -6478,7 +6211,7 @@ ${user.trimEnd()}
|
|
|
6478
6211
|
const spiritName = getSpiritName();
|
|
6479
6212
|
const spiritEntry = await findMind(spiritName);
|
|
6480
6213
|
if (spiritEntry) {
|
|
6481
|
-
const { firstWeekSchedules, spiritDir } = await import("./spirit-
|
|
6214
|
+
const { firstWeekSchedules, spiritDir } = await import("./spirit-Q5VGFWUI.js");
|
|
6482
6215
|
const sDir = spiritEntry.dir ?? spiritDir();
|
|
6483
6216
|
const spiritConfig = readVoluteConfig(sDir);
|
|
6484
6217
|
if (spiritConfig) {
|
|
@@ -6492,7 +6225,7 @@ ${user.trimEnd()}
|
|
|
6492
6225
|
spiritConfig.schedules = schedules;
|
|
6493
6226
|
writeVoluteConfig(sDir, spiritConfig);
|
|
6494
6227
|
try {
|
|
6495
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
6228
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-73Q4MQ7Y.js");
|
|
6496
6229
|
getScheduler2().loadSchedules(spiritName, sDir);
|
|
6497
6230
|
} catch (err) {
|
|
6498
6231
|
logger_default.warn(
|
|
@@ -6546,10 +6279,10 @@ ${user.trimEnd()}
|
|
|
6546
6279
|
await deleteMindUser2(name);
|
|
6547
6280
|
invalidateMindUserCache(name);
|
|
6548
6281
|
const state = stateDir(name);
|
|
6549
|
-
if (
|
|
6282
|
+
if (existsSync7(state)) {
|
|
6550
6283
|
rmSync3(state, { recursive: true, force: true });
|
|
6551
6284
|
}
|
|
6552
|
-
if (force &&
|
|
6285
|
+
if (force && existsSync7(dir)) {
|
|
6553
6286
|
rmSync3(dir, { recursive: true, force: true });
|
|
6554
6287
|
deleteMindUser(name);
|
|
6555
6288
|
}
|
|
@@ -6564,7 +6297,7 @@ ${user.trimEnd()}
|
|
|
6564
6297
|
const entry = await findMind(mindName);
|
|
6565
6298
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
6566
6299
|
const dir = mindDir(mindName);
|
|
6567
|
-
if (!
|
|
6300
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
6568
6301
|
let body = {};
|
|
6569
6302
|
try {
|
|
6570
6303
|
body = await c.req.json();
|
|
@@ -6575,27 +6308,12 @@ ${user.trimEnd()}
|
|
|
6575
6308
|
if (!isKnownTemplate(template)) {
|
|
6576
6309
|
return c.json({ error: `Unknown template: ${template}` }, 400);
|
|
6577
6310
|
}
|
|
6578
|
-
const UPGRADE_BRANCH = "upgrade";
|
|
6579
|
-
const upgradeVariantName = `${mindName}-upgrade`;
|
|
6580
|
-
const worktreeDir = resolve13(dir, ".variants", UPGRADE_BRANCH);
|
|
6581
6311
|
if (body.abort) {
|
|
6582
|
-
if (!
|
|
6312
|
+
if (!upgradeInProgress(mindName)) {
|
|
6583
6313
|
return c.json({ error: "No upgrade in progress" }, 400);
|
|
6584
6314
|
}
|
|
6585
6315
|
try {
|
|
6586
|
-
|
|
6587
|
-
const gitDirContent = readFileSync9(resolve13(worktreeDir, ".git"), "utf-8").trim();
|
|
6588
|
-
const gitDir = gitDirContent.replace("gitdir: ", "");
|
|
6589
|
-
if (existsSync8(resolve13(gitDir, "MERGE_HEAD"))) {
|
|
6590
|
-
await gitExec(["merge", "--abort"], { cwd: worktreeDir });
|
|
6591
|
-
}
|
|
6592
|
-
} catch {
|
|
6593
|
-
}
|
|
6594
|
-
await cleanupVariant(upgradeVariantName, mindName, dir, worktreeDir, { stop: true });
|
|
6595
|
-
try {
|
|
6596
|
-
await gitExec(["branch", "-D", UPGRADE_BRANCH], { cwd: dir });
|
|
6597
|
-
} catch {
|
|
6598
|
-
}
|
|
6316
|
+
await abortUpgrade(mindName);
|
|
6599
6317
|
return c.json({ ok: true });
|
|
6600
6318
|
} catch (err) {
|
|
6601
6319
|
return c.json(
|
|
@@ -6605,81 +6323,45 @@ ${user.trimEnd()}
|
|
|
6605
6323
|
}
|
|
6606
6324
|
}
|
|
6607
6325
|
if (body.continue) {
|
|
6608
|
-
if (!
|
|
6326
|
+
if (!upgradeInProgress(mindName)) {
|
|
6609
6327
|
return c.json({ error: "No upgrade in progress" }, 400);
|
|
6610
6328
|
}
|
|
6611
|
-
const status = await gitExec(["status", "--porcelain"], { cwd: worktreeDir });
|
|
6612
|
-
const hasConflicts2 = status.split("\n").some((line) => line.startsWith("UU") || line.startsWith("AA"));
|
|
6613
|
-
if (hasConflicts2) {
|
|
6614
|
-
return c.json({ error: "Unresolved conflicts remain" }, 409);
|
|
6615
|
-
}
|
|
6616
|
-
try {
|
|
6617
|
-
await gitExec(["add", "-A"], { cwd: worktreeDir });
|
|
6618
|
-
await gitExec(["commit", "-m", "merge template update"], { cwd: worktreeDir });
|
|
6619
|
-
} catch (e) {
|
|
6620
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
6621
|
-
const stderr = e?.stderr ?? "";
|
|
6622
|
-
const stdout = e?.stdout ?? "";
|
|
6623
|
-
if (!msg.includes("nothing to commit") && !stderr.includes("nothing to commit") && !stdout.includes("nothing to commit"))
|
|
6624
|
-
throw e;
|
|
6625
|
-
}
|
|
6626
|
-
try {
|
|
6627
|
-
await gitExec(["add", "home/"], { cwd: worktreeDir });
|
|
6628
|
-
} catch (err) {
|
|
6629
|
-
logger_default.warn(`failed to re-add home files during upgrade for ${mindName}`, logger_default.errorData(err));
|
|
6630
|
-
}
|
|
6631
|
-
try {
|
|
6632
|
-
await gitExec(["diff", "--cached", "--quiet"], { cwd: worktreeDir });
|
|
6633
|
-
} catch {
|
|
6634
|
-
await gitExec(["commit", "-m", "re-add allowlisted home files"], {
|
|
6635
|
-
cwd: worktreeDir
|
|
6636
|
-
});
|
|
6637
|
-
}
|
|
6638
|
-
await chownMindDir(dir, mindName);
|
|
6639
6329
|
try {
|
|
6640
|
-
const result = await
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6330
|
+
const result = await continueUpgrade(mindName, { template });
|
|
6331
|
+
if (result.status === "conflicts") {
|
|
6332
|
+
return c.json({
|
|
6333
|
+
ok: false,
|
|
6334
|
+
conflicts: true,
|
|
6335
|
+
worktreeDir: result.worktreeDir,
|
|
6336
|
+
files: result.files,
|
|
6337
|
+
message: result.message ?? "Merge conflicts detected. Resolve them, then run with continue."
|
|
6338
|
+
});
|
|
6339
|
+
}
|
|
6340
|
+
return c.json({ ok: true, warning: result.warning });
|
|
6650
6341
|
} catch (err) {
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6342
|
+
const msg = err instanceof Error ? err.message : "Failed to merge upgrade";
|
|
6343
|
+
if (msg === "Unresolved conflicts remain") {
|
|
6344
|
+
return c.json({ error: msg }, 409);
|
|
6345
|
+
}
|
|
6346
|
+
return c.json({ error: msg }, 500);
|
|
6655
6347
|
}
|
|
6656
6348
|
}
|
|
6657
6349
|
if (body.accept) {
|
|
6658
|
-
if (
|
|
6350
|
+
if (upgradeInProgress(mindName)) {
|
|
6659
6351
|
try {
|
|
6660
|
-
await
|
|
6352
|
+
await abortUpgrade(mindName);
|
|
6661
6353
|
} catch (err) {
|
|
6662
6354
|
logger_default.warn(`failed to clean up legacy upgrade variant for ${mindName}`, logger_default.errorData(err));
|
|
6663
6355
|
}
|
|
6664
|
-
try {
|
|
6665
|
-
await gitExec(["branch", "-D", UPGRADE_BRANCH], { cwd: dir });
|
|
6666
|
-
} catch {
|
|
6667
|
-
}
|
|
6668
6356
|
}
|
|
6669
6357
|
return c.json({ error: "Upgrades now auto-merge. Run 'volute mind upgrade' again." }, 400);
|
|
6670
6358
|
}
|
|
6671
6359
|
if (body.diff) {
|
|
6360
|
+
if (!existsSync7(resolve11(dir, ".git"))) {
|
|
6361
|
+
return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
|
|
6362
|
+
}
|
|
6672
6363
|
try {
|
|
6673
|
-
|
|
6674
|
-
return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
|
|
6675
|
-
}
|
|
6676
|
-
await updateTemplateBranch(dir, template, mindName);
|
|
6677
|
-
let diff;
|
|
6678
|
-
try {
|
|
6679
|
-
diff = await gitExec(["diff", "HEAD...volute/template"], { cwd: dir });
|
|
6680
|
-
} catch {
|
|
6681
|
-
diff = await gitExec(["diff", "HEAD", "volute/template"], { cwd: dir });
|
|
6682
|
-
}
|
|
6364
|
+
const diff = await upgradeDiff(mindName, template);
|
|
6683
6365
|
return c.json({ ok: true, diff: diff || "(no changes)" });
|
|
6684
6366
|
} catch (err) {
|
|
6685
6367
|
return c.json(
|
|
@@ -6688,103 +6370,21 @@ ${user.trimEnd()}
|
|
|
6688
6370
|
);
|
|
6689
6371
|
}
|
|
6690
6372
|
}
|
|
6691
|
-
if (existsSync8(worktreeDir)) {
|
|
6692
|
-
return c.json(
|
|
6693
|
-
{ error: "Upgrade variant already exists. Use continue or delete it first." },
|
|
6694
|
-
409
|
|
6695
|
-
);
|
|
6696
|
-
}
|
|
6697
|
-
if (!existsSync8(resolve13(dir, ".git"))) {
|
|
6698
|
-
try {
|
|
6699
|
-
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve13(dir, "home") } : void 0;
|
|
6700
|
-
await gitExec(["init"], { cwd: dir, mindName, env });
|
|
6701
|
-
await configureGitIdentity(mindName, { cwd: dir, mindName, env });
|
|
6702
|
-
await gitExec(["add", "-A"], { cwd: dir, mindName, env });
|
|
6703
|
-
await gitExec(["commit", "-m", "initial commit"], { cwd: dir, mindName, env });
|
|
6704
|
-
await chownMindDir(dir, mindName);
|
|
6705
|
-
} catch (err) {
|
|
6706
|
-
rmSync3(resolve13(dir, ".git"), { recursive: true, force: true });
|
|
6707
|
-
return c.json(
|
|
6708
|
-
{
|
|
6709
|
-
error: `Git initialization failed: ${err instanceof Error ? err.message : String(err)}`
|
|
6710
|
-
},
|
|
6711
|
-
500
|
|
6712
|
-
);
|
|
6713
|
-
}
|
|
6714
|
-
}
|
|
6715
|
-
await gitExec(["worktree", "prune"], { cwd: dir });
|
|
6716
|
-
try {
|
|
6717
|
-
await gitExec(["branch", "-D", UPGRADE_BRANCH], { cwd: dir });
|
|
6718
|
-
} catch {
|
|
6719
|
-
}
|
|
6720
|
-
await updateTemplateBranch(dir, template, mindName);
|
|
6721
|
-
const parentDir = resolve13(dir, ".variants");
|
|
6722
|
-
if (!existsSync8(parentDir)) {
|
|
6723
|
-
mkdirSync6(parentDir, { recursive: true });
|
|
6724
|
-
}
|
|
6725
|
-
await gitExec(["worktree", "add", "-b", UPGRADE_BRANCH, worktreeDir], { cwd: dir });
|
|
6726
|
-
await gitExec(["rm", "-r", "--cached", "--ignore-unmatch", "home/"], {
|
|
6727
|
-
cwd: worktreeDir
|
|
6728
|
-
});
|
|
6729
6373
|
try {
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
);
|
|
6739
|
-
}
|
|
6740
|
-
}
|
|
6741
|
-
try {
|
|
6742
|
-
await gitExec(["diff", "--cached", "--quiet"], { cwd: worktreeDir });
|
|
6743
|
-
} catch {
|
|
6744
|
-
await gitExec(["commit", "-m", "prepare for home/ allowlist migration"], {
|
|
6745
|
-
cwd: worktreeDir
|
|
6746
|
-
});
|
|
6747
|
-
}
|
|
6748
|
-
const hasConflicts = await mergeTemplateBranch(worktreeDir);
|
|
6749
|
-
if (!hasConflicts) {
|
|
6750
|
-
try {
|
|
6751
|
-
await gitExec(["add", "home/"], { cwd: worktreeDir });
|
|
6752
|
-
} catch (err) {
|
|
6753
|
-
logger_default.warn(`failed to re-add home files during upgrade for ${mindName}`, logger_default.errorData(err));
|
|
6754
|
-
}
|
|
6755
|
-
try {
|
|
6756
|
-
await gitExec(["diff", "--cached", "--quiet"], { cwd: worktreeDir });
|
|
6757
|
-
} catch {
|
|
6758
|
-
await gitExec(["commit", "-m", "re-add allowlisted home files"], {
|
|
6759
|
-
cwd: worktreeDir
|
|
6374
|
+
const result = await runUpgrade(mindName, { template });
|
|
6375
|
+
if (result.status === "conflicts") {
|
|
6376
|
+
return c.json({
|
|
6377
|
+
ok: false,
|
|
6378
|
+
conflicts: true,
|
|
6379
|
+
worktreeDir: result.worktreeDir,
|
|
6380
|
+
files: result.files,
|
|
6381
|
+
message: result.message ?? "Merge conflicts detected. Resolve them, then run with continue."
|
|
6760
6382
|
});
|
|
6761
6383
|
}
|
|
6762
|
-
|
|
6763
|
-
await chownMindDir(dir, mindName);
|
|
6764
|
-
if (hasConflicts) {
|
|
6765
|
-
return c.json({
|
|
6766
|
-
ok: false,
|
|
6767
|
-
conflicts: true,
|
|
6768
|
-
worktreeDir,
|
|
6769
|
-
message: "Merge conflicts detected. Resolve them, then run with continue."
|
|
6770
|
-
});
|
|
6771
|
-
}
|
|
6772
|
-
try {
|
|
6773
|
-
const result = await mergeUpgradeAndRestart(
|
|
6774
|
-
mindName,
|
|
6775
|
-
dir,
|
|
6776
|
-
worktreeDir,
|
|
6777
|
-
upgradeVariantName,
|
|
6778
|
-
UPGRADE_BRANCH,
|
|
6779
|
-
template,
|
|
6780
|
-
oldTemplate
|
|
6781
|
-
);
|
|
6782
|
-
return c.json(result);
|
|
6384
|
+
return c.json({ ok: true, warning: result.warning });
|
|
6783
6385
|
} catch (err) {
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
} catch (cleanupErr) {
|
|
6787
|
-
logger_default.warn(`cleanup failed after upgrade error for ${mindName}`, logger_default.errorData(cleanupErr));
|
|
6386
|
+
if (err instanceof UpgradeInProgressError) {
|
|
6387
|
+
return c.json({ error: err.message }, 409);
|
|
6788
6388
|
}
|
|
6789
6389
|
return c.json({ error: err instanceof Error ? err.message : "Failed to merge upgrade" }, 500);
|
|
6790
6390
|
}
|
|
@@ -6852,11 +6452,11 @@ ${user.trimEnd()}
|
|
|
6852
6452
|
const entry = await findMind(name);
|
|
6853
6453
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
6854
6454
|
const dir = entry.dir ?? mindDir(name);
|
|
6855
|
-
if (!
|
|
6455
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
6856
6456
|
let config2 = readVoluteConfig(dir);
|
|
6857
6457
|
if (!config2 && entry.template === "pi") {
|
|
6858
|
-
const piConfigPath =
|
|
6859
|
-
if (
|
|
6458
|
+
const piConfigPath = resolve11(dir, "home/.config/config.json");
|
|
6459
|
+
if (existsSync7(piConfigPath)) {
|
|
6860
6460
|
try {
|
|
6861
6461
|
config2 = JSON.parse(readFileSync9(piConfigPath, "utf-8"));
|
|
6862
6462
|
} catch {
|
|
@@ -6864,8 +6464,8 @@ ${user.trimEnd()}
|
|
|
6864
6464
|
}
|
|
6865
6465
|
}
|
|
6866
6466
|
let templateConfig = {};
|
|
6867
|
-
const configJsonPath =
|
|
6868
|
-
if (
|
|
6467
|
+
const configJsonPath = resolve11(dir, "home/.config/config.json");
|
|
6468
|
+
if (existsSync7(configJsonPath)) {
|
|
6869
6469
|
try {
|
|
6870
6470
|
templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
|
|
6871
6471
|
} catch {
|
|
@@ -6907,7 +6507,7 @@ ${user.trimEnd()}
|
|
|
6907
6507
|
const entry = await findMind(name);
|
|
6908
6508
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
6909
6509
|
const dir = entry.dir ?? mindDir(name);
|
|
6910
|
-
if (!
|
|
6510
|
+
if (!existsSync7(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
6911
6511
|
const body = c.req.valid("json");
|
|
6912
6512
|
const existing = readVoluteConfig(dir) ?? {};
|
|
6913
6513
|
if (body.model !== void 0) existing.model = body.model;
|
|
@@ -6933,14 +6533,14 @@ ${user.trimEnd()}
|
|
|
6933
6533
|
}
|
|
6934
6534
|
writeVoluteConfig(dir, existing);
|
|
6935
6535
|
if (body.unescapeNewlines !== void 0) {
|
|
6936
|
-
const { clearEchoTextCache } = await import("./echo-text-
|
|
6536
|
+
const { clearEchoTextCache } = await import("./echo-text-73CYQRL7.js");
|
|
6937
6537
|
clearEchoTextCache(name);
|
|
6938
6538
|
}
|
|
6939
6539
|
const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.compaction !== void 0;
|
|
6940
6540
|
if (needsConfigJson) {
|
|
6941
|
-
const configJsonPath =
|
|
6541
|
+
const configJsonPath = resolve11(dir, "home/.config/config.json");
|
|
6942
6542
|
let templateConfig = {};
|
|
6943
|
-
if (
|
|
6543
|
+
if (existsSync7(configJsonPath)) {
|
|
6944
6544
|
try {
|
|
6945
6545
|
templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
|
|
6946
6546
|
} catch {
|
|
@@ -7005,9 +6605,43 @@ ${user.trimEnd()}
|
|
|
7005
6605
|
if (err instanceof Error && err.message.includes("not initialized")) {
|
|
7006
6606
|
return c.json({ error: "Delivery manager not available" }, 503);
|
|
7007
6607
|
}
|
|
6608
|
+
if (err instanceof UnknownChannelError) return c.json({ error: err.message }, 400);
|
|
7008
6609
|
logger_default.error(`failed to decline channel ${channel} for ${name}`, logger_default.errorData(err));
|
|
7009
6610
|
return c.json({ error: "Failed to decline channel" }, 500);
|
|
7010
6611
|
}
|
|
6612
|
+
}).post("/:name/gates/accept", requireSelf(), async (c) => {
|
|
6613
|
+
const name = c.req.param("name");
|
|
6614
|
+
const body = await c.req.json().catch(() => ({}));
|
|
6615
|
+
const channel = body.channel?.trim();
|
|
6616
|
+
if (!channel) return c.json({ error: "channel required" }, 400);
|
|
6617
|
+
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
6618
|
+
try {
|
|
6619
|
+
const result = await getDeliveryManager().acceptChannel(name, channel, body.thread?.trim());
|
|
6620
|
+
return c.json({ ok: true, channel, ...result });
|
|
6621
|
+
} catch (err) {
|
|
6622
|
+
if (err instanceof Error && err.message.includes("not initialized")) {
|
|
6623
|
+
return c.json({ error: "Delivery manager not available" }, 503);
|
|
6624
|
+
}
|
|
6625
|
+
if (err instanceof Error && err.message.includes("malformed")) {
|
|
6626
|
+
return c.json({ error: err.message }, 409);
|
|
6627
|
+
}
|
|
6628
|
+
if (err instanceof UnknownChannelError) return c.json({ error: err.message }, 400);
|
|
6629
|
+
logger_default.error(`failed to accept channel ${channel} for ${name}`, logger_default.errorData(err));
|
|
6630
|
+
return c.json({ error: "Failed to accept channel" }, 500);
|
|
6631
|
+
}
|
|
6632
|
+
}).get("/:name/gates/peek", requireSelf(), async (c) => {
|
|
6633
|
+
const name = c.req.param("name");
|
|
6634
|
+
const channel = c.req.query("channel")?.trim();
|
|
6635
|
+
if (!channel) return c.json({ error: "channel required" }, 400);
|
|
6636
|
+
try {
|
|
6637
|
+
return c.json(await getDeliveryManager().peekChannel(name, channel));
|
|
6638
|
+
} catch (err) {
|
|
6639
|
+
if (err instanceof Error && err.message.includes("not initialized")) {
|
|
6640
|
+
return c.json({ error: "Delivery manager not available" }, 503);
|
|
6641
|
+
}
|
|
6642
|
+
logger_default.error(`failed to peek channel ${channel} for ${name}`, logger_default.errorData(err));
|
|
6643
|
+
return c.json({ error: "Failed to read held messages" }, 500);
|
|
6644
|
+
}
|
|
7011
6645
|
}).post("/:name/ai/complete", requireSelf(), async (c) => {
|
|
7012
6646
|
const body = await c.req.json();
|
|
7013
6647
|
if (!body.systemPrompt || !body.message) {
|
|
@@ -7258,6 +6892,35 @@ ${lines.join("\n")}` });
|
|
|
7258
6892
|
const maxId = notices.reduce((m, n) => Math.max(m, n.id), 0);
|
|
7259
6893
|
setNoticeDrainWatermark(baseName, session, maxId);
|
|
7260
6894
|
return c.json({ context: formatEvents(notices), notices });
|
|
6895
|
+
}).post("/:name/notices", requireSelf(), async (c) => {
|
|
6896
|
+
const MIND_POSTABLE_KINDS = ["context_lost", "delivery_failed"];
|
|
6897
|
+
const name = c.req.param("name");
|
|
6898
|
+
const baseName = await getBaseName(name);
|
|
6899
|
+
let body;
|
|
6900
|
+
try {
|
|
6901
|
+
body = await c.req.json();
|
|
6902
|
+
} catch {
|
|
6903
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
6904
|
+
}
|
|
6905
|
+
const kind = body.kind;
|
|
6906
|
+
if (typeof kind !== "string" || !MIND_POSTABLE_KINDS.includes(kind)) {
|
|
6907
|
+
return c.json({ error: `kind must be one of: ${MIND_POSTABLE_KINDS.join(", ")}` }, 400);
|
|
6908
|
+
}
|
|
6909
|
+
const message = typeof body.message === "string" ? body.message.trim() : "";
|
|
6910
|
+
if (!message) return c.json({ error: "message is required" }, 400);
|
|
6911
|
+
if (body.thread !== void 0 && typeof body.thread !== "string") {
|
|
6912
|
+
return c.json({ error: "thread must be a string" }, 400);
|
|
6913
|
+
}
|
|
6914
|
+
await recordNotice({
|
|
6915
|
+
mind: baseName,
|
|
6916
|
+
thread: body.thread ?? MIND_LEVEL_THREAD,
|
|
6917
|
+
kind,
|
|
6918
|
+
reason: kind,
|
|
6919
|
+
// Bound the size (the body is injected into turn context) without dropping
|
|
6920
|
+
// the notice — a truncated explanation beats a silent 400.
|
|
6921
|
+
detail: message.length > 4e3 ? `${message.slice(0, 4e3)}\u2026` : message
|
|
6922
|
+
});
|
|
6923
|
+
return c.json({ ok: true });
|
|
7261
6924
|
}).get("/:name/system-events", requireSelf(), async (c) => {
|
|
7262
6925
|
const name = c.req.param("name");
|
|
7263
6926
|
const baseName = await getBaseName(name);
|
|
@@ -7280,6 +6943,43 @@ ${lines.join("\n")}` });
|
|
|
7280
6943
|
};
|
|
7281
6944
|
})
|
|
7282
6945
|
});
|
|
6946
|
+
}).put("/:name/turn-summaries", requireSelf(), async (c) => {
|
|
6947
|
+
const name = c.req.param("name");
|
|
6948
|
+
const baseName = await getBaseName(name);
|
|
6949
|
+
let body;
|
|
6950
|
+
try {
|
|
6951
|
+
body = await c.req.json();
|
|
6952
|
+
} catch {
|
|
6953
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
6954
|
+
}
|
|
6955
|
+
const items = body.summaries;
|
|
6956
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
6957
|
+
return c.json({ error: "summaries must be a non-empty array" }, 400);
|
|
6958
|
+
}
|
|
6959
|
+
let updated = 0;
|
|
6960
|
+
let created = 0;
|
|
6961
|
+
for (const item of items) {
|
|
6962
|
+
if (!item || typeof item.turnId !== "string" || !item.turnId) {
|
|
6963
|
+
return c.json({ error: "each summary needs a turnId" }, 400);
|
|
6964
|
+
}
|
|
6965
|
+
if (typeof item.content !== "string") {
|
|
6966
|
+
return c.json({ error: "each summary needs content" }, 400);
|
|
6967
|
+
}
|
|
6968
|
+
const result = await supersedeTurnSummary(baseName, item.turnId, item.content);
|
|
6969
|
+
switch (result.status) {
|
|
6970
|
+
case "invalid":
|
|
6971
|
+
return c.json({ error: result.error }, 400);
|
|
6972
|
+
case "not_found":
|
|
6973
|
+
return c.json({ error: "Turn not found" }, 404);
|
|
6974
|
+
case "forbidden":
|
|
6975
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
6976
|
+
case "ok":
|
|
6977
|
+
if (result.created) created++;
|
|
6978
|
+
else updated++;
|
|
6979
|
+
break;
|
|
6980
|
+
}
|
|
6981
|
+
}
|
|
6982
|
+
return c.json({ ok: true, updated, created });
|
|
7283
6983
|
}).get("/:name/history", requireSelf(), async (c) => {
|
|
7284
6984
|
const name = c.req.param("name");
|
|
7285
6985
|
const channel = c.req.query("channel");
|
|
@@ -7288,6 +6988,7 @@ ${lines.join("\n")}` });
|
|
|
7288
6988
|
const preset = c.req.query("preset");
|
|
7289
6989
|
const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 200);
|
|
7290
6990
|
const offset = Math.max(parseInt(c.req.query("offset") ?? "0", 10) || 0, 0);
|
|
6991
|
+
const provisional = c.req.query("provisional") === "true";
|
|
7291
6992
|
const db = await getDb();
|
|
7292
6993
|
const conditions = [eq5(mindHistory.mind, name)];
|
|
7293
6994
|
if (channel) {
|
|
@@ -7299,6 +7000,9 @@ ${lines.join("\n")}` });
|
|
|
7299
7000
|
const effectivePreset = full ? "all" : preset;
|
|
7300
7001
|
if (!effectivePreset || effectivePreset === "summary") {
|
|
7301
7002
|
const sumConditions = [eq5(summaries.mind, name), eq5(summaries.period, "turn")];
|
|
7003
|
+
if (provisional) {
|
|
7004
|
+
sumConditions.push(sql3`json_extract(${summaries.metadata}, '$.author') is not ${"mind"}`);
|
|
7005
|
+
}
|
|
7302
7006
|
if (session) {
|
|
7303
7007
|
sumConditions.push(eq5(turns.thread, session));
|
|
7304
7008
|
const sumRows2 = await db.select({
|
|
@@ -7707,7 +7411,7 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
|
|
|
7707
7411
|
const entry = await findMind(name);
|
|
7708
7412
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
7709
7413
|
const body = await c.req.text();
|
|
7710
|
-
const { deliverEvent: deliverEvent2 } = await import("./system-events-
|
|
7414
|
+
const { deliverEvent: deliverEvent2 } = await import("./system-events-Q7IVZ5T4.js");
|
|
7711
7415
|
const { id, delivered } = await deliverEvent2(name, {
|
|
7712
7416
|
type: "webhook",
|
|
7713
7417
|
body,
|
|
@@ -7723,16 +7427,16 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
|
|
|
7723
7427
|
var schedules_default = app15;
|
|
7724
7428
|
|
|
7725
7429
|
// packages/daemon/src/web/api/setup.ts
|
|
7726
|
-
import { mkdirSync as mkdirSync7 } from "fs";
|
|
7430
|
+
import { mkdirSync as mkdirSync7, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "fs";
|
|
7727
7431
|
import { homedir as homedir2 } from "os";
|
|
7728
|
-
import { resolve as
|
|
7432
|
+
import { basename, resolve as resolve12 } from "path";
|
|
7729
7433
|
import { Hono as Hono19 } from "hono";
|
|
7730
7434
|
import { setCookie as setCookie2 } from "hono/cookie";
|
|
7731
7435
|
var DEFAULT_API_URL2 = "https://volute.systems";
|
|
7732
7436
|
var setup = new Hono19();
|
|
7733
7437
|
function writeSetupConfig(systemName, description) {
|
|
7734
|
-
const configHome = process.env.VOLUTE_HOME ??
|
|
7735
|
-
const mindsDir =
|
|
7438
|
+
const configHome = process.env.VOLUTE_HOME ?? resolve12(homedir2(), ".volute");
|
|
7439
|
+
const mindsDir = resolve12(configHome, "minds");
|
|
7736
7440
|
mkdirSync7(configHome, { recursive: true });
|
|
7737
7441
|
mkdirSync7(mindsDir, { recursive: true });
|
|
7738
7442
|
const existingConfig = readGlobalConfig();
|
|
@@ -8063,6 +7767,39 @@ setup.post("/spirit", async (c) => {
|
|
|
8063
7767
|
config2.setup.spiritName = name;
|
|
8064
7768
|
const temperament = body.temperament?.trim();
|
|
8065
7769
|
config2.setup.spiritTemperament = temperament || void 0;
|
|
7770
|
+
const description = body.description?.trim();
|
|
7771
|
+
config2.setup.spiritDescription = description || void 0;
|
|
7772
|
+
const clearOldStash = () => {
|
|
7773
|
+
if (config2.setup?.spiritAvatar) {
|
|
7774
|
+
rmSync4(resolve12(voluteSystemDir(), basename(config2.setup.spiritAvatar)), { force: true });
|
|
7775
|
+
config2.setup.spiritAvatar = void 0;
|
|
7776
|
+
}
|
|
7777
|
+
};
|
|
7778
|
+
if (body.avatar) {
|
|
7779
|
+
const match = /^data:image\/(png|jpeg|webp);base64,([A-Za-z0-9+/=]+)$/.exec(body.avatar);
|
|
7780
|
+
if (!match) {
|
|
7781
|
+
return c.json({ error: "Avatar must be a png, jpeg, or webp image" }, 400);
|
|
7782
|
+
}
|
|
7783
|
+
if (match[2].length > 3 * 1024 * 1024) {
|
|
7784
|
+
return c.json({ error: "Avatar must be under 2MB" }, 400);
|
|
7785
|
+
}
|
|
7786
|
+
let bytes = Buffer.from(match[2], "base64");
|
|
7787
|
+
if (bytes.length > 2 * 1024 * 1024) {
|
|
7788
|
+
return c.json({ error: "Avatar must be under 2MB" }, 400);
|
|
7789
|
+
}
|
|
7790
|
+
let ext = match[1] === "jpeg" ? "jpg" : match[1];
|
|
7791
|
+
const normalized = await normalizeAvatar(bytes);
|
|
7792
|
+
if (normalized) {
|
|
7793
|
+
bytes = normalized.buffer;
|
|
7794
|
+
ext = "webp";
|
|
7795
|
+
}
|
|
7796
|
+
clearOldStash();
|
|
7797
|
+
const filename = `spirit-avatar.${ext}`;
|
|
7798
|
+
writeFileSync9(resolve12(voluteSystemDir(), filename), bytes);
|
|
7799
|
+
config2.setup.spiritAvatar = filename;
|
|
7800
|
+
} else {
|
|
7801
|
+
clearOldStash();
|
|
7802
|
+
}
|
|
8066
7803
|
writeGlobalConfig(config2);
|
|
8067
7804
|
return c.json({ ok: true });
|
|
8068
7805
|
});
|
|
@@ -8071,15 +7808,16 @@ setup.post("/complete", async (c) => {
|
|
|
8071
7808
|
return c.json({ error: "Setup already complete" }, 400);
|
|
8072
7809
|
}
|
|
8073
7810
|
try {
|
|
8074
|
-
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-
|
|
8075
|
-
const { startSpiritFull } = await import("./mind-service-
|
|
7811
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-Q5VGFWUI.js");
|
|
7812
|
+
const { startSpiritFull } = await import("./mind-service-7EFIJ3ZA.js");
|
|
8076
7813
|
await ensureSpiritProject();
|
|
8077
7814
|
await syncSpiritTemplate();
|
|
7815
|
+
await notifyExtensionsSpiritReady();
|
|
8078
7816
|
const warnings = [];
|
|
8079
7817
|
const config2 = readGlobalConfig();
|
|
8080
7818
|
if (config2.setup?.service && config2.setup?.type === "local") {
|
|
8081
7819
|
try {
|
|
8082
|
-
const { installUserService } = await import("./service-install-
|
|
7820
|
+
const { installUserService } = await import("./service-install-R4SNYUVO.js");
|
|
8083
7821
|
const installed = await installUserService(config2.port, config2.hostname);
|
|
8084
7822
|
if (!installed) {
|
|
8085
7823
|
warnings.push("Service installation is not supported on this platform.");
|
|
@@ -8132,15 +7870,13 @@ setup.post("/complete", async (c) => {
|
|
|
8132
7870
|
logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
|
|
8133
7871
|
if (spiritConversationId && spiritStarted) {
|
|
8134
7872
|
try {
|
|
8135
|
-
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-
|
|
7873
|
+
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-TRKT4T2P.js");
|
|
8136
7874
|
const { listUsersByType: listUsers2 } = await import("./auth-KRDSM55Q.js");
|
|
8137
7875
|
const admins = await listUsers2("human");
|
|
8138
7876
|
const admin2 = admins.find((u) => u.role === "admin");
|
|
8139
7877
|
if (admin2) {
|
|
8140
7878
|
const adminName = admin2.display_name || admin2.username;
|
|
8141
|
-
const
|
|
8142
|
-
const temperament = cfg.setup?.spiritTemperament;
|
|
8143
|
-
const welcomePrompt = `Setup is complete. You are ${spiritName}, the spirit of ${cfg.name ?? "this system"}` + (cfg.description ? ` \u2014 ${cfg.description}` : "") + `. ${adminName} chose your name just now` + (temperament ? ` and imagined your temperament as: "${temperament}"` : "") + `, and is now in your chat. Greet ${adminName} by name and help them create their first mind. Keep it brief \u2014 a short greeting in your own voice, then ask what kind of being they'd like to bring into the world. Remember: minds are beings with their own experience, not tools \u2014 ask about personality and character, never about tasks or utility.`;
|
|
7879
|
+
const welcomePrompt = `Setup is complete, and ${adminName} is now in your chat. Greet ${adminName} by name and help them create their first mind. Keep it brief \u2014 a short greeting in your own voice, then ask what kind of being they'd like to bring into the world. Remember: minds are beings with their own experience, not tools \u2014 ask about personality and character, never about tasks or utility.`;
|
|
8144
7880
|
await deliverMessage2(spiritName, {
|
|
8145
7881
|
content: [{ type: "text", text: welcomePrompt }],
|
|
8146
7882
|
channel: `@${admin2.username}`,
|
|
@@ -8174,9 +7910,9 @@ setup.post("/complete", async (c) => {
|
|
|
8174
7910
|
var setup_default = setup;
|
|
8175
7911
|
|
|
8176
7912
|
// packages/daemon/src/web/api/skills.ts
|
|
8177
|
-
import { existsSync as
|
|
7913
|
+
import { existsSync as existsSync8, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync5 } from "fs";
|
|
8178
7914
|
import { tmpdir } from "os";
|
|
8179
|
-
import { join, resolve as
|
|
7915
|
+
import { join, resolve as resolve13 } from "path";
|
|
8180
7916
|
import AdmZip from "adm-zip";
|
|
8181
7917
|
import { Hono as Hono20 } from "hono";
|
|
8182
7918
|
var app16 = new Hono20().get("/", async (c) => {
|
|
@@ -8252,19 +7988,19 @@ var app16 = new Hono20().get("/", async (c) => {
|
|
|
8252
7988
|
try {
|
|
8253
7989
|
const zip = new AdmZip(buffer);
|
|
8254
7990
|
for (const entry of zip.getEntries()) {
|
|
8255
|
-
const target =
|
|
7991
|
+
const target = resolve13(tmpDir, entry.entryName);
|
|
8256
7992
|
if (!target.startsWith(tmpDir)) {
|
|
8257
7993
|
return c.json({ error: "Invalid zip: paths must not escape archive" }, 400);
|
|
8258
7994
|
}
|
|
8259
7995
|
}
|
|
8260
7996
|
zip.extractAllTo(tmpDir, true);
|
|
8261
7997
|
let skillDir = null;
|
|
8262
|
-
if (
|
|
7998
|
+
if (existsSync8(join(tmpDir, "SKILL.md"))) {
|
|
8263
7999
|
skillDir = tmpDir;
|
|
8264
8000
|
} else {
|
|
8265
8001
|
const entries = readdirSync3(tmpDir, { withFileTypes: true }).filter((e) => e.isDirectory());
|
|
8266
8002
|
for (const entry of entries) {
|
|
8267
|
-
if (
|
|
8003
|
+
if (existsSync8(join(tmpDir, entry.name, "SKILL.md"))) {
|
|
8268
8004
|
skillDir = join(tmpDir, entry.name);
|
|
8269
8005
|
break;
|
|
8270
8006
|
}
|
|
@@ -8281,7 +8017,7 @@ var app16 = new Hono20().get("/", async (c) => {
|
|
|
8281
8017
|
}
|
|
8282
8018
|
throw e;
|
|
8283
8019
|
} finally {
|
|
8284
|
-
|
|
8020
|
+
rmSync5(tmpDir, { recursive: true, force: true });
|
|
8285
8021
|
}
|
|
8286
8022
|
}).get("/:id", async (c) => {
|
|
8287
8023
|
const id = c.req.param("id");
|
|
@@ -8626,8 +8362,8 @@ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
|
|
|
8626
8362
|
});
|
|
8627
8363
|
}, 15e3);
|
|
8628
8364
|
cleanups.push(() => clearInterval(keepAlive));
|
|
8629
|
-
await new Promise((
|
|
8630
|
-
stream.onAbort(() =>
|
|
8365
|
+
await new Promise((resolve19) => {
|
|
8366
|
+
stream.onAbort(() => resolve19());
|
|
8631
8367
|
});
|
|
8632
8368
|
} finally {
|
|
8633
8369
|
for (const cleanup of cleanups) {
|
|
@@ -8908,23 +8644,23 @@ var app21 = new Hono25().use("*", authMiddleware).get("/", async (c) => {
|
|
|
8908
8644
|
var feed_default = app21;
|
|
8909
8645
|
|
|
8910
8646
|
// packages/daemon/src/web/api/variants.ts
|
|
8911
|
-
import { existsSync as
|
|
8912
|
-
import { resolve as
|
|
8647
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "fs";
|
|
8648
|
+
import { resolve as resolve16 } from "path";
|
|
8913
8649
|
import { Hono as Hono26 } from "hono";
|
|
8914
8650
|
|
|
8915
8651
|
// packages/daemon/src/lib/mind/farewell.ts
|
|
8916
|
-
import { existsSync as
|
|
8917
|
-
import { resolve as
|
|
8652
|
+
import { existsSync as existsSync9, readFileSync as readFileSync10, rmSync as rmSync6 } from "fs";
|
|
8653
|
+
import { resolve as resolve14 } from "path";
|
|
8918
8654
|
var flog = logger_default.child("farewell");
|
|
8919
8655
|
var FAREWELL_RELPATH = ".mind/farewell.md";
|
|
8920
8656
|
var FAREWELL_MIND_PATH = "../.mind/farewell.md";
|
|
8921
8657
|
var FAREWELL_TIMEOUT_MS = 12e4;
|
|
8922
8658
|
function farewellPath(variantDir) {
|
|
8923
|
-
return
|
|
8659
|
+
return resolve14(variantDir, FAREWELL_RELPATH);
|
|
8924
8660
|
}
|
|
8925
8661
|
function readFarewell(variantDir) {
|
|
8926
8662
|
const path = farewellPath(variantDir);
|
|
8927
|
-
if (!
|
|
8663
|
+
if (!existsSync9(path)) return void 0;
|
|
8928
8664
|
try {
|
|
8929
8665
|
const text = readFileSync10(path, "utf-8").trim();
|
|
8930
8666
|
return text || void 0;
|
|
@@ -8947,7 +8683,7 @@ function waitForFarewell(name, variantDir, timeoutMs) {
|
|
|
8947
8683
|
const unsub = subscribe((event) => {
|
|
8948
8684
|
if (event.mind !== name) return;
|
|
8949
8685
|
if (event.type !== "mind_done" && event.type !== "mind_idle") return;
|
|
8950
|
-
if (
|
|
8686
|
+
if (existsSync9(farewellPath(variantDir))) cleanup();
|
|
8951
8687
|
});
|
|
8952
8688
|
return { done, cancel: cleanup };
|
|
8953
8689
|
}
|
|
@@ -8956,7 +8692,7 @@ async function runFarewellTurn(opts) {
|
|
|
8956
8692
|
const timeoutMs = opts.timeoutMs ?? FAREWELL_TIMEOUT_MS;
|
|
8957
8693
|
if (!running) return readFarewell(variantDir);
|
|
8958
8694
|
try {
|
|
8959
|
-
|
|
8695
|
+
rmSync6(farewellPath(variantDir), { force: true });
|
|
8960
8696
|
} catch (err) {
|
|
8961
8697
|
flog.warn(`failed to clear stale farewell note for ${variantName}`, logger_default.errorData(err));
|
|
8962
8698
|
}
|
|
@@ -8980,8 +8716,8 @@ async function runFarewellTurn(opts) {
|
|
|
8980
8716
|
|
|
8981
8717
|
// packages/daemon/src/lib/mind/spawn-server.ts
|
|
8982
8718
|
import { spawn as spawn4 } from "child_process";
|
|
8983
|
-
import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync11, statSync as
|
|
8984
|
-
import { resolve as
|
|
8719
|
+
import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync11, statSync as statSync3 } from "fs";
|
|
8720
|
+
import { resolve as resolve15 } from "path";
|
|
8985
8721
|
async function spawnServer(cwd, port, options) {
|
|
8986
8722
|
let cmd = process.env.VOLUTE_NODE_PATH ?? process.execPath;
|
|
8987
8723
|
let args = ["--import", "tsx", "src/server.ts", "--port", String(port)];
|
|
@@ -9002,34 +8738,34 @@ function spawnAttached(cmd, args, cwd) {
|
|
|
9002
8738
|
cwd,
|
|
9003
8739
|
stdio: ["ignore", "pipe", "pipe"]
|
|
9004
8740
|
});
|
|
9005
|
-
return new Promise((
|
|
9006
|
-
const timeout = setTimeout(() =>
|
|
8741
|
+
return new Promise((resolve19) => {
|
|
8742
|
+
const timeout = setTimeout(() => resolve19(null), 3e4);
|
|
9007
8743
|
function checkOutput(data) {
|
|
9008
8744
|
const match = data.toString().match(/listening on :(\d+)/);
|
|
9009
8745
|
if (match) {
|
|
9010
8746
|
clearTimeout(timeout);
|
|
9011
|
-
|
|
8747
|
+
resolve19({ child, actualPort: parseInt(match[1], 10) });
|
|
9012
8748
|
}
|
|
9013
8749
|
}
|
|
9014
8750
|
child.stdout?.on("data", checkOutput);
|
|
9015
8751
|
child.stderr?.on("data", checkOutput);
|
|
9016
8752
|
child.on("error", () => {
|
|
9017
8753
|
clearTimeout(timeout);
|
|
9018
|
-
|
|
8754
|
+
resolve19(null);
|
|
9019
8755
|
});
|
|
9020
8756
|
child.on("exit", () => {
|
|
9021
8757
|
clearTimeout(timeout);
|
|
9022
|
-
|
|
8758
|
+
resolve19(null);
|
|
9023
8759
|
});
|
|
9024
8760
|
});
|
|
9025
8761
|
}
|
|
9026
8762
|
function spawnDetached(cmd, args, cwd, logDir) {
|
|
9027
|
-
const logsDir = logDir ??
|
|
8763
|
+
const logsDir = logDir ?? resolve15(cwd, ".mind", "logs");
|
|
9028
8764
|
mkdirSync8(logsDir, { recursive: true });
|
|
9029
|
-
const logPath =
|
|
8765
|
+
const logPath = resolve15(logsDir, "mind.log");
|
|
9030
8766
|
let startOffset = 0;
|
|
9031
8767
|
try {
|
|
9032
|
-
startOffset =
|
|
8768
|
+
startOffset = statSync3(logPath).size;
|
|
9033
8769
|
} catch {
|
|
9034
8770
|
}
|
|
9035
8771
|
const logFd = openSync(logPath, "a");
|
|
@@ -9167,11 +8903,11 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
|
|
|
9167
8903
|
return c.json({ error: `Name already in use: ${variantName}` }, 409);
|
|
9168
8904
|
}
|
|
9169
8905
|
const projectRoot = entry.dir ?? mindDir(mindName);
|
|
9170
|
-
const variantDir =
|
|
9171
|
-
if (
|
|
8906
|
+
const variantDir = resolve16(projectRoot, ".variants", variantName);
|
|
8907
|
+
if (existsSync10(variantDir)) {
|
|
9172
8908
|
return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
|
|
9173
8909
|
}
|
|
9174
|
-
mkdirSync9(
|
|
8910
|
+
mkdirSync9(resolve16(projectRoot, ".variants"), { recursive: true });
|
|
9175
8911
|
try {
|
|
9176
8912
|
await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
|
|
9177
8913
|
} catch (e) {
|
|
@@ -9207,7 +8943,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
|
|
|
9207
8943
|
const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
|
|
9208
8944
|
await exec(cmd, args, {
|
|
9209
8945
|
cwd: variantDir,
|
|
9210
|
-
env: { ...process.env, HOME:
|
|
8946
|
+
env: { ...process.env, HOME: resolve16(variantDir, "home") }
|
|
9211
8947
|
});
|
|
9212
8948
|
} else {
|
|
9213
8949
|
await exec("npm", ["install"], { cwd: variantDir });
|
|
@@ -9218,7 +8954,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
|
|
|
9218
8954
|
return c.json({ error: `npm install failed: ${msg}` }, 500);
|
|
9219
8955
|
}
|
|
9220
8956
|
if (body.soul) {
|
|
9221
|
-
|
|
8957
|
+
writeFileSync10(resolve16(variantDir, "home/SOUL.md"), body.soul);
|
|
9222
8958
|
}
|
|
9223
8959
|
const variantPort = body.port ?? await nextPort();
|
|
9224
8960
|
try {
|
|
@@ -9301,7 +9037,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
|
|
|
9301
9037
|
logger_default.warn(`farewell turn failed for ${variantName}`, logger_default.errorData(err));
|
|
9302
9038
|
}
|
|
9303
9039
|
try {
|
|
9304
|
-
if (
|
|
9040
|
+
if (existsSync10(variantEntry.dir)) {
|
|
9305
9041
|
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
9306
9042
|
if (status) {
|
|
9307
9043
|
try {
|
|
@@ -9359,7 +9095,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
|
|
|
9359
9095
|
{ conflicts: err.conflicts }
|
|
9360
9096
|
);
|
|
9361
9097
|
}
|
|
9362
|
-
if (
|
|
9098
|
+
if (existsSync10(variantEntry.dir) && !body.discardUnresolved) {
|
|
9363
9099
|
let unresolved;
|
|
9364
9100
|
try {
|
|
9365
9101
|
unresolved = await findUnresolvedHomeFiles(variantEntry.dir);
|
|
@@ -9398,7 +9134,7 @@ var app22 = new Hono26().get("/:name/variants", async (c) => {
|
|
|
9398
9134
|
const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
|
|
9399
9135
|
await exec(cmd, args, {
|
|
9400
9136
|
cwd: projectRoot,
|
|
9401
|
-
env: { ...process.env, HOME:
|
|
9137
|
+
env: { ...process.env, HOME: resolve16(projectRoot, "home") }
|
|
9402
9138
|
});
|
|
9403
9139
|
} else {
|
|
9404
9140
|
await exec("npm", ["install"], { cwd: projectRoot });
|
|
@@ -9855,7 +9591,7 @@ var unifiedChatApp = new Hono28().post(
|
|
|
9855
9591
|
logger_default.error("spirit availability check failed \u2014 proceeding with delivery", logger_default.errorData(err));
|
|
9856
9592
|
}
|
|
9857
9593
|
const isDM = conv.type === "dm";
|
|
9858
|
-
await fanOutToMinds({
|
|
9594
|
+
const { gatedRecipients } = await fanOutToMinds({
|
|
9859
9595
|
conversationId,
|
|
9860
9596
|
contentBlocks,
|
|
9861
9597
|
senderName,
|
|
@@ -9865,7 +9601,15 @@ var unifiedChatApp = new Hono28().post(
|
|
|
9865
9601
|
// Variant-aware targeting: when targetMind is a variant, route to the variant name
|
|
9866
9602
|
targetName: baseName ? (username) => username === baseName ? variantName : username : void 0
|
|
9867
9603
|
});
|
|
9868
|
-
|
|
9604
|
+
const notice = gatedRecipients.length > 0 ? `Note: your message is held for ${gatedRecipients.join(", ")} pending channel approval \u2014 they haven't routed this channel yet. It will be delivered if they accept the channel.` : void 0;
|
|
9605
|
+
return c.json({
|
|
9606
|
+
ok: true,
|
|
9607
|
+
conversationId,
|
|
9608
|
+
outboundId,
|
|
9609
|
+
spirit: spiritStatus,
|
|
9610
|
+
spiritName,
|
|
9611
|
+
...notice ? { notice } : {}
|
|
9612
|
+
});
|
|
9869
9613
|
}
|
|
9870
9614
|
);
|
|
9871
9615
|
var app24 = new Hono28().get("/:name/conversations/:id/events", async (c) => {
|
|
@@ -9885,11 +9629,11 @@ var app24 = new Hono28().get("/:name/conversations/:id/events", async (c) => {
|
|
|
9885
9629
|
if (!stream.aborted) console.error("[chat] SSE ping error:", err);
|
|
9886
9630
|
});
|
|
9887
9631
|
}, 15e3);
|
|
9888
|
-
await new Promise((
|
|
9632
|
+
await new Promise((resolve19) => {
|
|
9889
9633
|
stream.onAbort(() => {
|
|
9890
9634
|
unsubscribe();
|
|
9891
9635
|
clearInterval(keepAlive);
|
|
9892
|
-
|
|
9636
|
+
resolve19();
|
|
9893
9637
|
});
|
|
9894
9638
|
});
|
|
9895
9639
|
});
|
|
@@ -10106,10 +9850,10 @@ app26.route("/api/conversations", conversations_default);
|
|
|
10106
9850
|
var app_default = app26;
|
|
10107
9851
|
|
|
10108
9852
|
// packages/daemon/src/web/server.ts
|
|
10109
|
-
import { existsSync as
|
|
9853
|
+
import { existsSync as existsSync11 } from "fs";
|
|
10110
9854
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
10111
9855
|
import { createServer as createHttpsServer } from "https";
|
|
10112
|
-
import { dirname as dirname3, extname as extname3, resolve as
|
|
9856
|
+
import { dirname as dirname3, extname as extname3, resolve as resolve17 } from "path";
|
|
10113
9857
|
import { serve } from "@hono/node-server";
|
|
10114
9858
|
var MIME_TYPES2 = {
|
|
10115
9859
|
".html": "text/html",
|
|
@@ -10128,8 +9872,8 @@ async function startServer({
|
|
|
10128
9872
|
let assetsDir = "";
|
|
10129
9873
|
let searchDir = dirname3(new URL(import.meta.url).pathname);
|
|
10130
9874
|
for (let i = 0; i < 5; i++) {
|
|
10131
|
-
const candidate =
|
|
10132
|
-
if (
|
|
9875
|
+
const candidate = resolve17(searchDir, "dist", "web-assets");
|
|
9876
|
+
if (existsSync11(candidate)) {
|
|
10133
9877
|
assetsDir = candidate;
|
|
10134
9878
|
break;
|
|
10135
9879
|
}
|
|
@@ -10139,20 +9883,20 @@ async function startServer({
|
|
|
10139
9883
|
app_default.get("*", async (c) => {
|
|
10140
9884
|
const urlPath = new URL(c.req.url).pathname;
|
|
10141
9885
|
if (urlPath.startsWith("/api/") || urlPath.startsWith("/ext/")) return c.notFound();
|
|
10142
|
-
const filePath =
|
|
9886
|
+
const filePath = resolve17(assetsDir, urlPath.slice(1));
|
|
10143
9887
|
if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
|
|
10144
9888
|
const s = await stat2(filePath).catch(() => null);
|
|
10145
9889
|
if (s?.isFile()) {
|
|
10146
9890
|
const ext = extname3(filePath);
|
|
10147
9891
|
const mime = MIME_TYPES2[ext] || "application/octet-stream";
|
|
10148
9892
|
const body = await readFile2(filePath);
|
|
10149
|
-
const
|
|
10150
|
-
const nameWithoutExt =
|
|
9893
|
+
const basename2 = filePath.slice(filePath.lastIndexOf("/") + 1);
|
|
9894
|
+
const nameWithoutExt = basename2.slice(0, basename2.lastIndexOf("."));
|
|
10151
9895
|
const isHashed = /[-.][\da-f]{8,}$/.test(nameWithoutExt);
|
|
10152
9896
|
const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
|
|
10153
9897
|
return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
|
|
10154
9898
|
}
|
|
10155
|
-
const indexPath =
|
|
9899
|
+
const indexPath = resolve17(assetsDir, "index.html");
|
|
10156
9900
|
const indexStat = await stat2(indexPath).catch(() => null);
|
|
10157
9901
|
if (indexStat?.isFile()) {
|
|
10158
9902
|
const body = await readFile2(indexPath, "utf-8");
|
|
@@ -10169,10 +9913,10 @@ async function startServer({
|
|
|
10169
9913
|
createServer: createHttpsServer,
|
|
10170
9914
|
serverOptions: { key: tls.key, cert: tls.cert }
|
|
10171
9915
|
});
|
|
10172
|
-
await new Promise((
|
|
9916
|
+
await new Promise((resolve19, reject) => {
|
|
10173
9917
|
server2.on("listening", () => {
|
|
10174
9918
|
logger_default.info("Volute UI running (https)", { hostname, port });
|
|
10175
|
-
|
|
9919
|
+
resolve19();
|
|
10176
9920
|
});
|
|
10177
9921
|
server2.on("error", (err) => {
|
|
10178
9922
|
reject(err);
|
|
@@ -10180,13 +9924,13 @@ async function startServer({
|
|
|
10180
9924
|
});
|
|
10181
9925
|
const internalPort = port + 1;
|
|
10182
9926
|
const internalServer = serve({ fetch: app_default.fetch, port: internalPort, hostname: "127.0.0.1" });
|
|
10183
|
-
await new Promise((
|
|
9927
|
+
await new Promise((resolve19, reject) => {
|
|
10184
9928
|
internalServer.on("listening", () => {
|
|
10185
9929
|
logger_default.info("Volute API running (http, internal)", {
|
|
10186
9930
|
hostname: "127.0.0.1",
|
|
10187
9931
|
port: internalPort
|
|
10188
9932
|
});
|
|
10189
|
-
|
|
9933
|
+
resolve19();
|
|
10190
9934
|
});
|
|
10191
9935
|
internalServer.on("error", (err) => {
|
|
10192
9936
|
reject(err);
|
|
@@ -10195,10 +9939,10 @@ async function startServer({
|
|
|
10195
9939
|
return { server: server2, internalPort };
|
|
10196
9940
|
}
|
|
10197
9941
|
const server = serve({ fetch: app_default.fetch, port, hostname });
|
|
10198
|
-
await new Promise((
|
|
9942
|
+
await new Promise((resolve19, reject) => {
|
|
10199
9943
|
server.on("listening", () => {
|
|
10200
9944
|
logger_default.info("Volute API running (http)", { hostname, port });
|
|
10201
|
-
|
|
9945
|
+
resolve19();
|
|
10202
9946
|
});
|
|
10203
9947
|
server.on("error", (err) => {
|
|
10204
9948
|
reject(err);
|
|
@@ -10209,18 +9953,18 @@ async function startServer({
|
|
|
10209
9953
|
|
|
10210
9954
|
// packages/daemon/src/daemon.ts
|
|
10211
9955
|
if (!process.env.VOLUTE_HOME) {
|
|
10212
|
-
process.env.VOLUTE_HOME =
|
|
9956
|
+
process.env.VOLUTE_HOME = resolve18(homedir3(), ".volute");
|
|
10213
9957
|
}
|
|
10214
9958
|
if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
|
|
10215
9959
|
process.env.TZ = process.env.VOLUTE_TIMEZONE;
|
|
10216
9960
|
}
|
|
10217
9961
|
function writeDaemonConfig(systemDir, config2, token) {
|
|
10218
|
-
const configPath =
|
|
10219
|
-
|
|
9962
|
+
const configPath = resolve18(systemDir, "daemon.json");
|
|
9963
|
+
writeFileSync11(configPath, `${JSON.stringify(config2, null, 2)}
|
|
10220
9964
|
`, { mode: 420 });
|
|
10221
9965
|
chmodSync(configPath, 420);
|
|
10222
|
-
const tokenPath =
|
|
10223
|
-
|
|
9966
|
+
const tokenPath = resolve18(systemDir, "daemon-token");
|
|
9967
|
+
writeFileSync11(tokenPath, `${token}
|
|
10224
9968
|
`, { mode: 384 });
|
|
10225
9969
|
chmodSync(tokenPath, 384);
|
|
10226
9970
|
}
|
|
@@ -10230,7 +9974,7 @@ async function startDaemon(opts) {
|
|
|
10230
9974
|
const home = voluteHome();
|
|
10231
9975
|
const systemDir = voluteSystemDir();
|
|
10232
9976
|
if (!opts.foreground) {
|
|
10233
|
-
const rotatingLog = new RotatingLog(
|
|
9977
|
+
const rotatingLog = new RotatingLog(resolve18(systemDir, "daemon.log"));
|
|
10234
9978
|
logger_default.setOutput((line) => rotatingLog.write(`${line}
|
|
10235
9979
|
`));
|
|
10236
9980
|
const write = (...args) => rotatingLog.write(`${format(...args)}
|
|
@@ -10240,9 +9984,9 @@ async function startDaemon(opts) {
|
|
|
10240
9984
|
console.warn = write;
|
|
10241
9985
|
console.info = write;
|
|
10242
9986
|
}
|
|
10243
|
-
const DAEMON_PID_PATH =
|
|
10244
|
-
const DAEMON_JSON_PATH =
|
|
10245
|
-
const DAEMON_TOKEN_PATH =
|
|
9987
|
+
const DAEMON_PID_PATH = resolve18(systemDir, "daemon.pid");
|
|
9988
|
+
const DAEMON_JSON_PATH = resolve18(systemDir, "daemon.json");
|
|
9989
|
+
const DAEMON_TOKEN_PATH = resolve18(systemDir, "daemon-token");
|
|
10246
9990
|
mkdirSync10(home, { recursive: true });
|
|
10247
9991
|
ensureSystemDir();
|
|
10248
9992
|
const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-WZSXHHRJ.js");
|
|
@@ -10271,6 +10015,12 @@ async function startDaemon(opts) {
|
|
|
10271
10015
|
} catch (err) {
|
|
10272
10016
|
logger_default.warn("session\u2192thread config migration failed", logger_default.errorData(err));
|
|
10273
10017
|
}
|
|
10018
|
+
try {
|
|
10019
|
+
const { migrateNamePlaceholders } = await import("./migrate-name-placeholder-C7NCNLWF.js");
|
|
10020
|
+
await migrateNamePlaceholders();
|
|
10021
|
+
} catch (err) {
|
|
10022
|
+
logger_default.warn("{{name}} placeholder migration failed", logger_default.errorData(err));
|
|
10023
|
+
}
|
|
10274
10024
|
const { initSandbox } = await import("./sandbox-NNWCTHRI.js");
|
|
10275
10025
|
await initSandbox();
|
|
10276
10026
|
try {
|
|
@@ -10344,7 +10094,7 @@ async function startDaemon(opts) {
|
|
|
10344
10094
|
process.env.VOLUTE_DAEMON_TOKEN = token;
|
|
10345
10095
|
process.env.VOLUTE_DAEMON_PORT = String(daemonPort);
|
|
10346
10096
|
process.env.VOLUTE_DAEMON_HOSTNAME = hostname;
|
|
10347
|
-
|
|
10097
|
+
writeFileSync11(DAEMON_PID_PATH, myPid, { mode: 420 });
|
|
10348
10098
|
const daemonConfig = { port, hostname };
|
|
10349
10099
|
if (internalPort) daemonConfig.internalPort = internalPort;
|
|
10350
10100
|
if (tls) daemonConfig.tls = true;
|
|
@@ -10371,7 +10121,7 @@ async function startDaemon(opts) {
|
|
|
10371
10121
|
const orphanedTurns = await completeOrphanedTurns();
|
|
10372
10122
|
summarizeOrphanedTurns(orphanedTurns);
|
|
10373
10123
|
try {
|
|
10374
|
-
const { reconcileVariants } = await import("./variant-cleanup-
|
|
10124
|
+
const { reconcileVariants } = await import("./variant-cleanup-QHGGY7ND.js");
|
|
10375
10125
|
await reconcileVariants();
|
|
10376
10126
|
} catch (err) {
|
|
10377
10127
|
logger_default.error("failed to reconcile variants", logger_default.errorData(err));
|
|
@@ -10407,16 +10157,17 @@ async function startDaemon(opts) {
|
|
|
10407
10157
|
try {
|
|
10408
10158
|
const { isSetupComplete: isSetupComplete2, getSpiritName: getSpiritName2 } = await import("./setup-WZSXHHRJ.js");
|
|
10409
10159
|
if (isSetupComplete2()) {
|
|
10410
|
-
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-
|
|
10411
|
-
const { startSpiritFull } = await import("./mind-service-
|
|
10160
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-Q5VGFWUI.js");
|
|
10161
|
+
const { startSpiritFull } = await import("./mind-service-7EFIJ3ZA.js");
|
|
10412
10162
|
await ensureSpiritProject();
|
|
10413
10163
|
const spiritName = getSpiritName2();
|
|
10414
10164
|
const spiritEntry = await findMind(spiritName);
|
|
10415
10165
|
if (spiritEntry?.dir) {
|
|
10416
|
-
const { registerMindDir } = await import("./delivery-router-
|
|
10166
|
+
const { registerMindDir } = await import("./delivery-router-QS4NLJR6.js");
|
|
10417
10167
|
registerMindDir(spiritName, spiritEntry.dir);
|
|
10418
10168
|
}
|
|
10419
10169
|
await syncSpiritTemplate();
|
|
10170
|
+
if (spiritEntry) await notifyExtensionsSpiritReady();
|
|
10420
10171
|
if (spiritEntry && !manager.isRunning(spiritName)) {
|
|
10421
10172
|
await startSpiritFull(spiritName);
|
|
10422
10173
|
}
|
|
@@ -10427,7 +10178,7 @@ async function startDaemon(opts) {
|
|
|
10427
10178
|
bridgeManager.startBridges(daemonPort).catch((err) => {
|
|
10428
10179
|
logger_default.warn("failed to start bridges", logger_default.errorData(err));
|
|
10429
10180
|
});
|
|
10430
|
-
import("./cloud-sync-
|
|
10181
|
+
import("./cloud-sync-52YNJRMR.js").then(
|
|
10431
10182
|
({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
|
|
10432
10183
|
logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
|
|
10433
10184
|
})
|
|
@@ -10435,12 +10186,14 @@ async function startDaemon(opts) {
|
|
|
10435
10186
|
logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
|
|
10436
10187
|
});
|
|
10437
10188
|
try {
|
|
10438
|
-
const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-
|
|
10439
|
-
backfillTemplateHashes().then(() => warnStaleTemplates()).catch((err) => {
|
|
10440
|
-
logger_default.warn("failed to check template staleness", logger_default.errorData(err));
|
|
10441
|
-
});
|
|
10189
|
+
const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-VNVFX6UP.js");
|
|
10442
10190
|
notifyVersionUpdate().catch((err) => {
|
|
10443
10191
|
logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
|
|
10192
|
+
}).then(() => backfillTemplateHashes()).then(() => warnStaleTemplates()).then(async () => {
|
|
10193
|
+
const { runAutoUpgrades } = await import("./auto-upgrade-HEVZKPTF.js");
|
|
10194
|
+
await runAutoUpgrades();
|
|
10195
|
+
}).catch((err) => {
|
|
10196
|
+
logger_default.warn("template staleness/auto-upgrade pass failed", logger_default.errorData(err));
|
|
10444
10197
|
});
|
|
10445
10198
|
} catch (err) {
|
|
10446
10199
|
logger_default.warn("failed to initialize version notifications", logger_default.errorData(err));
|
|
@@ -10449,6 +10202,9 @@ async function startDaemon(opts) {
|
|
|
10449
10202
|
logger_default.warn("failed to restore delivery queue", logger_default.errorData(err));
|
|
10450
10203
|
});
|
|
10451
10204
|
delivery.startRedrive();
|
|
10205
|
+
delivery.releaseGatedSweep().catch((err) => {
|
|
10206
|
+
logger_default.warn("failed to sweep gated messages", logger_default.errorData(err));
|
|
10207
|
+
});
|
|
10452
10208
|
cleanExpiredSessions().catch((err) => {
|
|
10453
10209
|
logger_default.warn("failed to clean expired sessions", logger_default.errorData(err));
|
|
10454
10210
|
});
|