volute 0.46.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/{accept-N5XULCXK.js → accept-KYNC5X3U.js} +1 -1
- package/dist/{activity-events-NF6VWTJQ.js → activity-events-MIOK3IOU.js} +3 -3
- package/dist/{ai-service-UODCCE4O.js → ai-service-643TNFPH.js} +8 -4
- package/dist/{archive-WS2L2VIQ.js → archive-6Z4GFQPH.js} +3 -3
- package/dist/{auth-CCFAU4GQ.js → auth-A4VGHADI.js} +4 -4
- package/dist/avatar-image-Y45R7LW5.js +23 -0
- package/dist/{backup-TST5C2YN.js → backup-UDH4GMSW.js} +15 -15
- package/dist/{bridge-2PO3AI5D.js → bridge-3FNSWLNQ.js} +1 -1
- package/dist/channels-SGQZHNQJ.js +89 -0
- package/dist/{chat-ZIQQS25U.js → chat-X43VYHH2.js} +12 -8
- package/dist/{chunk-ZV7MFISX.js → chunk-2MJ7EOMT.js} +20 -2
- package/dist/{chunk-R77O2WMK.js → chunk-2OIYNHWO.js} +1 -1
- package/dist/{chunk-QCN24XEN.js → chunk-3YUBFTDN.js} +1 -1
- package/dist/chunk-4FCL4DVZ.js +48 -0
- package/dist/{chunk-F7H6ATM4.js → chunk-5KXCM5AW.js} +18 -2
- package/dist/chunk-7KRIHYLR.js +124 -0
- package/dist/{chunk-RBNMDAKB.js → chunk-BCG45AQB.js} +15 -1
- package/dist/{chunk-QMJCNZ6C.js → chunk-C3KLHJDB.js} +1 -1
- package/dist/{chunk-H2X54EHC.js → chunk-DGGZVZTM.js} +1 -1
- package/dist/chunk-DW4TRDOZ.js +29 -0
- package/dist/{chunk-4JOQZPCE.js → chunk-EIQDZC43.js} +1 -1
- package/dist/{chunk-TQJ6ZYVY.js → chunk-FJ2MZ5PH.js} +41 -5
- package/dist/{chunk-BJZ4PV7R.js → chunk-HNGFKPNS.js} +26 -10
- package/dist/{chunk-5ZQZDDIK.js → chunk-HPGN6XRT.js} +3 -3
- package/dist/{chunk-KGIXX4NM.js → chunk-HUNDXZBZ.js} +5 -5
- package/dist/{chunk-ZDZISKCL.js → chunk-IJPMIEVE.js} +1 -1
- package/dist/chunk-IYCV34IU.js +158 -0
- package/dist/{chunk-ZNMCCHCP.js → chunk-LTLFOSA4.js} +2 -2
- package/dist/{chunk-K6T43YBD.js → chunk-MJRXFUMS.js} +26 -6
- package/dist/{chunk-4YU7HF4L.js → chunk-MOERAQXH.js} +6 -4
- package/dist/{chunk-KQSFTPIM.js → chunk-MTRMQFCQ.js} +1 -1
- package/dist/{chunk-OV7ZQ2GH.js → chunk-ODDGGLM6.js} +3 -3
- package/dist/{chunk-A7WQZKOU.js → chunk-OQJMTHEH.js} +2 -2
- package/dist/{chunk-RRNXJOKB.js → chunk-PJVPDY2Z.js} +2 -2
- package/dist/{chunk-FXORA5JG.js → chunk-Q7HOAVFR.js} +3 -3
- package/dist/{chunk-KDLYIECM.js → chunk-R772ET2M.js} +18 -4
- package/dist/{chunk-QLWG3C2Z.js → chunk-RRZ4RQQU.js} +2 -2
- package/dist/{mind-list-4D7J4CHD.js → chunk-SHKM5RGD.js} +18 -4
- package/dist/{chunk-RXEEYDIB.js → chunk-SZJCJVXV.js} +1 -1
- package/dist/{chunk-E3DA4HYV.js → chunk-T4VS7UDW.js} +15 -15
- package/dist/{chunk-YXSUMLTC.js → chunk-USD45JKR.js} +322 -76
- package/dist/{chunk-JO5IO4FH.js → chunk-VB2QXUJQ.js} +391 -294
- package/dist/{chunk-JZ62SYWR.js → chunk-VZRA5TYO.js} +1 -1
- package/dist/{chunk-PJ45FQPT.js → chunk-WARH6GIV.js} +8 -8
- package/dist/{chunk-PFZBNKUH.js → chunk-WCFSBH33.js} +0 -1
- package/dist/{chunk-DRJ24GXK.js → chunk-WQ46E33M.js} +59 -39
- package/dist/{chunk-ALKYQULU.js → chunk-WW6C3PLV.js} +1 -1
- package/dist/{chunk-CDPBTTZO.js → chunk-XVBSFLM7.js} +2 -2
- package/dist/{chunk-6EMWJZBK.js → chunk-YKA7DCVW.js} +1 -1
- package/dist/{chunk-IHKGWTGT.js → chunk-YNBXEQAP.js} +31 -1
- package/dist/cli.js +34 -26
- package/dist/{clock-RHS2JEDL.js → clock-CNRF6F7T.js} +3 -3
- package/dist/{cloud-sync-46RS4SDA.js → cloud-sync-WHKCB4CD.js} +22 -19
- package/dist/{config-TJLYUV3U.js → config-RPSLA2HX.js} +3 -3
- package/dist/{conversations-CJOOCGNW.js → conversations-C7IKYSHD.js} +4 -4
- package/dist/{create-IOV4GCRX.js → create-GJKHABJB.js} +16 -5
- package/dist/{create-DF3KISTW.js → create-VIQVP3QB.js} +1 -1
- package/dist/{daemon-client-IYR4KCPU.js → daemon-client-ZFY5MOAL.js} +5 -3
- package/dist/{daemon-restart-VFEI57UO.js → daemon-restart-7KUHVZIN.js} +7 -7
- package/dist/daemon.js +829 -496
- package/dist/{db-MF2JNRUW.js → db-FO6LXYCW.js} +2 -2
- package/dist/{db-LZTLA7XC.js → db-IPXRJUI7.js} +1 -1
- package/dist/{delete-HPLC7ETU.js → delete-ESEP7NGQ.js} +1 -1
- package/dist/delivery-manager-HZTT5SJR.js +36 -0
- package/dist/{delivery-router-N4A7ZC5T.js → delivery-router-3QFG2ZEX.js} +3 -3
- package/dist/{down-U2CZ23M4.js → down-G6IADJXV.js} +5 -5
- package/dist/echo-text-H3SH337Q.js +36 -0
- package/dist/env-6TGPO5WG.js +18 -0
- package/dist/{env-VZ4MLFQW.js → env-C7Z55QCJ.js} +6 -6
- package/dist/{exec-G3ZRST4Z.js → exec-QIFYZG4C.js} +3 -3
- package/dist/{export-LY723I3Z.js → export-C2K3NIRD.js} +4 -4
- package/dist/{extension-SEID47SR.js → extension-J4ZQ2GHV.js} +1 -1
- package/dist/{extensions-ZELQLTSR.js → extensions-GEKF47A4.js} +24 -19
- package/dist/{files-4LN3EN7Q.js → files-LXQSQOFG.js} +4 -4
- package/dist/{import-42YNQBF4.js → import-SX3ZXHB4.js} +8 -8
- package/dist/{isolation-YMGZZ4E5.js → isolation-MCT4ZYLT.js} +3 -3
- package/dist/{join-ZJV7W6MO.js → join-34TR2GXQ.js} +1 -1
- package/dist/{list-OXIAY3W7.js → list-PMUXZNAM.js} +1 -1
- package/dist/{login-MY6ETFYB.js → login-ARRZ4ORJ.js} +3 -3
- package/dist/{login-M6OJUPQ2.js → login-CL4IT2ED.js} +14 -5
- package/dist/{logout-WQBWO77G.js → logout-HZYJCYCA.js} +3 -3
- package/dist/{logout-NCG3TMDL.js → logout-YZRMZ3O2.js} +1 -1
- package/dist/message-delivery-GPQ5SE5N.js +40 -0
- package/dist/{mind-LHKS55DI.js → mind-46AOK373.js} +23 -19
- package/dist/{mind-activity-tracker-3QRNJVR4.js → mind-activity-tracker-YVZPC4A5.js} +4 -4
- package/dist/mind-contacts-GV7XYL5D.js +64 -0
- package/dist/{mind-history-VRO5A76U.js → mind-history-TTGA5BHZ.js} +5 -5
- package/dist/mind-list-OTHV4ZO4.js +13 -0
- package/dist/{mind-profile-PEQYASQX.js → mind-profile-LUG353ZT.js} +1 -1
- package/dist/mind-service-2ARGJNKP.js +44 -0
- package/dist/{mind-sleep-74TGOQBC.js → mind-sleep-DV7KP255.js} +3 -3
- package/dist/{mind-status-UO34ASXZ.js → mind-status-BJNPGXKC.js} +23 -1
- package/dist/{mind-wake-LCLGTXA2.js → mind-wake-LVTZ55EZ.js} +1 -1
- package/dist/notices-2KU5NTRY.js +25 -0
- package/dist/{package-DOD6CPO6.js → package-RTN2PS7O.js} +5 -3
- package/dist/{read-QVAXMTPV.js → read-YSWUXYL7.js} +1 -1
- package/dist/{register-Y2H4PY5R.js → register-42VBJKTP.js} +3 -3
- package/dist/{registry-OUZBZ3Q4.js → registry-UMMDRPRM.js} +2 -2
- package/dist/{reject-EV35X64Y.js → reject-SXGCYN4A.js} +1 -1
- package/dist/{restart-FJQ662XJ.js → restart-YYEGZJDD.js} +5 -5
- package/dist/{sandbox-ZJ7QA6Z6.js → sandbox-5VQ454XP.js} +4 -4
- package/dist/scheduler-I7JZCT47.js +34 -0
- package/dist/{schema-PVNG3PQM.js → schema-VEVO7HG6.js} +3 -1
- package/dist/{seed-CNYIHPOH.js → seed-F2HXZQU4.js} +1 -1
- package/dist/{seed-check-VLTVILOV.js → seed-check-TYD7RRZY.js} +1 -1
- package/dist/{seed-cmd-AVNUNLZV.js → seed-cmd-MLCTGSX5.js} +3 -3
- package/dist/{seed-create-ANXGYSCC.js → seed-create-KQ7OILWB.js} +6 -4
- package/dist/seed-readiness-RBPGOLSZ.js +18 -0
- package/dist/{seed-sprout-NIUFTX32.js → seed-sprout-HVYCFJLA.js} +30 -31
- package/dist/{send-SPE6DVNJ.js → send-TD2X5U3K.js} +6 -6
- package/dist/{service-UOCLXDWR.js → service-CVZMQYK6.js} +4 -4
- package/dist/{service-install-4HHFDDWY.js → service-install-VCRMFWX5.js} +5 -5
- package/dist/{setup-Y2EJI3GG.js → setup-5ECWTYKG.js} +7 -3
- package/dist/{setup-QT2A25SY.js → setup-AE4CVUC4.js} +7 -7
- package/dist/{skill-FKFHIJRR.js → skill-UUM4JZRF.js} +5 -5
- package/dist/skills/dreaming/SKILL.md +5 -1
- package/dist/skills/dreaming/scripts/dream.ts +5 -1
- package/dist/skills/orientation/SKILL.md +8 -7
- package/dist/skills/tending/SKILL.md +51 -2
- package/dist/skills/volute-mind/SKILL.md +2 -0
- package/dist/{skills-AKCFA7BN.js → skills-B3SVDCEB.js} +5 -5
- package/dist/sleep-manager-Z27R3WTW.js +38 -0
- package/dist/spirit-WXS3HCLN.js +25 -0
- package/dist/{split-WBMZXBHF.js → split-SKZ4Y2D6.js} +1 -1
- package/dist/{sprout-SMX42ZBP.js → sprout-KQ43BWZJ.js} +1 -1
- package/dist/{src-OJHARHTF.js → src-WLJE73NP.js} +14 -5
- package/dist/{start-5JE3TV66.js → start-O6UKK7BG.js} +3 -3
- package/dist/{status-SWRVGXBI.js → status-F4PGREUU.js} +19 -7
- package/dist/{stop-AAMTG3TU.js → stop-UBX6X5RA.js} +5 -5
- package/dist/system-chat-63ABFF6V.js +40 -0
- package/dist/{systems-VNB5WKSS.js → systems-JJNGQHAO.js} +4 -4
- package/dist/{tailscale-3XOKOW7T.js → tailscale-MCLY5GYE.js} +2 -2
- package/dist/{template-hash-446HHH5V.js → template-hash-GSOUARW4.js} +2 -2
- package/dist/template-staleness-EMQORSGG.js +15 -0
- package/dist/{turn-tracker-FOIBNUUA.js → turn-tracker-KLPV3PAU.js} +6 -6
- package/dist/up-RVGDE6CQ.js +20 -0
- package/dist/{update-SWAYZRWJ.js → update-OXQEGGXD.js} +5 -5
- package/dist/{update-check-PQ2MZ47K.js → update-check-266R4ZSY.js} +3 -3
- package/dist/{upgrade-NWAZ7MLD.js → upgrade-K5FIQPQD.js} +1 -1
- package/dist/{version-notify-C5CH7CVP.js → version-notify-73YURTFR.js} +41 -25
- package/dist/web-assets/assets/index-WdZ60R6c.css +1 -0
- package/dist/web-assets/assets/index-taX6Ezfa.js +92 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0011_drop_turn_summary_event_id.sql +3 -0
- package/drizzle/0012_channel_gates.sql +17 -0
- package/drizzle/meta/_journal.json +14 -0
- package/package.json +5 -3
- package/packages/extensions/pages/dist/ui/assets/index-BuXnE-rb.css +1 -0
- package/packages/extensions/pages/dist/ui/assets/index-DtzftuPA.js +2 -0
- package/packages/extensions/pages/dist/ui/index.html +2 -2
- package/templates/_base/src/lib/startup.ts +59 -3
- package/templates/claude/src/agent.ts +37 -4
- package/templates/claude/src/lib/session-reaper.ts +32 -0
- package/templates/claude/src/server.ts +14 -3
- package/templates/pi/src/agent.ts +7 -10
- package/templates/pi/src/lib/dispatch.ts +65 -0
- package/dist/avatar-image-6KY6UU4D.js +0 -16
- package/dist/delivery-manager-JINZRG2W.js +0 -33
- package/dist/echo-text-VQPB5L2X.js +0 -33
- package/dist/message-delivery-R7JSQGYX.js +0 -37
- package/dist/mind-service-NB2JMWQZ.js +0 -39
- package/dist/scheduler-WVKII3LA.js +0 -31
- package/dist/sleep-manager-G6TXSDP7.js +0 -35
- package/dist/spirit-RPBLLUQ5.js +0 -23
- package/dist/system-chat-NDAW6YP7.js +0 -37
- package/dist/up-PS6PFS75.js +0 -18
- package/dist/volute-config-A52FHWKM.js +0 -14
- package/dist/web-assets/assets/index-B1JBQv2m.css +0 -1
- package/dist/web-assets/assets/index-CU6XWICM.js +0 -86
- package/packages/extensions/pages/dist/ui/assets/index-BcY6lnq4.css +0 -1
- package/packages/extensions/pages/dist/ui/assets/index-CQjEQg1r.js +0 -2
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-Q7HOAVFR.js";
|
|
10
10
|
import {
|
|
11
11
|
acceptPending,
|
|
12
12
|
formatFileSize,
|
|
@@ -14,35 +14,34 @@ import {
|
|
|
14
14
|
rejectPending,
|
|
15
15
|
stageFile,
|
|
16
16
|
validateFilePath
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-2OIYNHWO.js";
|
|
18
18
|
import {
|
|
19
19
|
findOpenClawSession,
|
|
20
20
|
importOpenClawConnectors,
|
|
21
21
|
importPiSession,
|
|
22
22
|
parseNameFromIdentity
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-OQJMTHEH.js";
|
|
24
|
+
import {
|
|
25
|
+
isTemplateStale
|
|
26
|
+
} from "./chunk-7KRIHYLR.js";
|
|
27
|
+
import {
|
|
28
|
+
computeTemplateHash
|
|
29
|
+
} from "./chunk-C3KLHJDB.js";
|
|
24
30
|
import {
|
|
25
31
|
checkForUpdate,
|
|
26
32
|
checkForUpdateCached,
|
|
27
33
|
getCurrentVersion
|
|
28
|
-
} from "./chunk-
|
|
29
|
-
import {
|
|
30
|
-
normalizeAvatar,
|
|
31
|
-
safeResolveWithinBase
|
|
32
|
-
} from "./chunk-DRJ24GXK.js";
|
|
34
|
+
} from "./chunk-YKA7DCVW.js";
|
|
33
35
|
import {
|
|
34
36
|
isHomeOnlyArchive
|
|
35
|
-
} from "./chunk-
|
|
36
|
-
import {
|
|
37
|
-
computeTemplateHash
|
|
38
|
-
} from "./chunk-QMJCNZ6C.js";
|
|
37
|
+
} from "./chunk-3YUBFTDN.js";
|
|
39
38
|
import {
|
|
40
39
|
PLATFORMS,
|
|
41
40
|
echoTextToChannel,
|
|
42
41
|
fixModelEscapes,
|
|
43
42
|
getPlatformDriver,
|
|
44
43
|
routeOutboundBridge
|
|
45
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-T4VS7UDW.js";
|
|
46
45
|
import {
|
|
47
46
|
getBridgeConfig,
|
|
48
47
|
readBridgesConfig,
|
|
@@ -51,7 +50,7 @@ import {
|
|
|
51
50
|
resolveChannelMapping,
|
|
52
51
|
setBridgeConfig,
|
|
53
52
|
setChannelMapping
|
|
54
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-SZJCJVXV.js";
|
|
55
54
|
import {
|
|
56
55
|
MindStartupError,
|
|
57
56
|
RestartTracker,
|
|
@@ -59,18 +58,16 @@ import {
|
|
|
59
58
|
SESSION_MAX_AGE,
|
|
60
59
|
announceToSystem,
|
|
61
60
|
authMiddleware,
|
|
61
|
+
backfillSystemChannelMembers,
|
|
62
62
|
checkHealth,
|
|
63
63
|
checkStaleSend,
|
|
64
64
|
cleanExpiredSessions,
|
|
65
|
-
clearDeliveredNotices,
|
|
66
65
|
createSession,
|
|
67
66
|
deleteSession,
|
|
68
67
|
deleteSystemsConfig,
|
|
69
68
|
deliverMessage,
|
|
70
|
-
drainNotices,
|
|
71
69
|
ensureSystemChannel,
|
|
72
70
|
formatHoldNotice,
|
|
73
|
-
formatNotices,
|
|
74
71
|
generateSystemFallbackReply,
|
|
75
72
|
getAllDiscoveredExtensions,
|
|
76
73
|
getAllDiscoveredExtensionsDetailed,
|
|
@@ -101,7 +98,6 @@ import {
|
|
|
101
98
|
publishTypingForChannels,
|
|
102
99
|
readSystemsConfig,
|
|
103
100
|
recordInbound,
|
|
104
|
-
recordNotice,
|
|
105
101
|
recordOutbound,
|
|
106
102
|
requireAdmin,
|
|
107
103
|
requireAdminOrSystem,
|
|
@@ -113,15 +109,8 @@ import {
|
|
|
113
109
|
syncProviderToMinds,
|
|
114
110
|
uninstallNpmExtension,
|
|
115
111
|
writeSystemsConfig
|
|
116
|
-
} from "./chunk-
|
|
117
|
-
import
|
|
118
|
-
loadMergedEnv,
|
|
119
|
-
mindEnvPath,
|
|
120
|
-
readEnv,
|
|
121
|
-
sharedEnvPath,
|
|
122
|
-
writeEnv
|
|
123
|
-
} from "./chunk-ZDZISKCL.js";
|
|
124
|
-
import "./chunk-BJZ4PV7R.js";
|
|
112
|
+
} from "./chunk-VB2QXUJQ.js";
|
|
113
|
+
import "./chunk-HNGFKPNS.js";
|
|
125
114
|
import {
|
|
126
115
|
applyInitFiles,
|
|
127
116
|
applyTemplateHomeFiles,
|
|
@@ -130,7 +119,34 @@ import {
|
|
|
130
119
|
findTemplatesRoot,
|
|
131
120
|
isKnownTemplate,
|
|
132
121
|
listFiles
|
|
133
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-RRZ4RQQU.js";
|
|
123
|
+
import {
|
|
124
|
+
assignSession,
|
|
125
|
+
completeOrphanedTurns,
|
|
126
|
+
completeTurn,
|
|
127
|
+
createTurn,
|
|
128
|
+
getActiveTurnId,
|
|
129
|
+
getToolUseEventId,
|
|
130
|
+
initSummarizer,
|
|
131
|
+
isoWeekKeyForDateStr,
|
|
132
|
+
markErrored,
|
|
133
|
+
publish as publish3,
|
|
134
|
+
subscribe as subscribe3,
|
|
135
|
+
subscribeAll,
|
|
136
|
+
summarizeOrphanedTurns,
|
|
137
|
+
summarizeTurn,
|
|
138
|
+
takeErrored,
|
|
139
|
+
trackToolUse,
|
|
140
|
+
utcDateTimeStr
|
|
141
|
+
} from "./chunk-USD45JKR.js";
|
|
142
|
+
import {
|
|
143
|
+
PROMPT_DEFAULTS,
|
|
144
|
+
PROMPT_KEYS,
|
|
145
|
+
getMindPromptDefaults,
|
|
146
|
+
getPrompt,
|
|
147
|
+
getPromptIfCustom,
|
|
148
|
+
substitute
|
|
149
|
+
} from "./chunk-MOERAQXH.js";
|
|
134
150
|
import {
|
|
135
151
|
SEED_SKILLS,
|
|
136
152
|
STANDARD_SKILLS,
|
|
@@ -144,17 +160,38 @@ import {
|
|
|
144
160
|
listFilesRecursive,
|
|
145
161
|
listMindSkills,
|
|
146
162
|
listSharedSkills,
|
|
163
|
+
mindSkillsDir,
|
|
147
164
|
publishSkill,
|
|
148
165
|
removeSharedSkill,
|
|
149
166
|
sharedSkillsDir,
|
|
150
167
|
syncBuiltinSkills,
|
|
151
168
|
uninstallSkill,
|
|
152
169
|
updateSkill
|
|
153
|
-
} from "./chunk-
|
|
170
|
+
} from "./chunk-HUNDXZBZ.js";
|
|
171
|
+
import {
|
|
172
|
+
approveUser,
|
|
173
|
+
changePassword,
|
|
174
|
+
countAdmins,
|
|
175
|
+
createUser,
|
|
176
|
+
deleteMindUser as deleteMindUser2,
|
|
177
|
+
deleteUser,
|
|
178
|
+
getOrCreateMindUser,
|
|
179
|
+
getOrCreateSystemUser,
|
|
180
|
+
getUser,
|
|
181
|
+
getUserByUsername,
|
|
182
|
+
listPendingUsers,
|
|
183
|
+
listUsers,
|
|
184
|
+
listUsersByType,
|
|
185
|
+
setUserRole,
|
|
186
|
+
syncMindProfile,
|
|
187
|
+
updateUserProfile,
|
|
188
|
+
verifyUser
|
|
189
|
+
} from "./chunk-ODDGGLM6.js";
|
|
154
190
|
import {
|
|
155
191
|
addMessage,
|
|
156
192
|
createChannel,
|
|
157
193
|
createConversation,
|
|
194
|
+
deleteConversation,
|
|
158
195
|
deleteConversationForUser,
|
|
159
196
|
findDMConversation,
|
|
160
197
|
fireWebhook,
|
|
@@ -182,50 +219,38 @@ import {
|
|
|
182
219
|
setConversationPrivate,
|
|
183
220
|
subscribe as subscribe2,
|
|
184
221
|
updateChannelSettings
|
|
185
|
-
} from "./chunk-
|
|
186
|
-
import {
|
|
187
|
-
readVoluteConfig,
|
|
188
|
-
writeVoluteConfig
|
|
189
|
-
} from "./chunk-PFZBNKUH.js";
|
|
222
|
+
} from "./chunk-HPGN6XRT.js";
|
|
190
223
|
import {
|
|
191
224
|
isSandboxEnabled,
|
|
192
225
|
wrapForSandbox
|
|
193
|
-
} from "./chunk-
|
|
226
|
+
} from "./chunk-VZRA5TYO.js";
|
|
227
|
+
import {
|
|
228
|
+
clearDeliveredNotices,
|
|
229
|
+
drainNotices,
|
|
230
|
+
formatNotices,
|
|
231
|
+
latestFailureNotice,
|
|
232
|
+
latestNotice,
|
|
233
|
+
recordNotice
|
|
234
|
+
} from "./chunk-IYCV34IU.js";
|
|
194
235
|
import {
|
|
195
236
|
getActiveMinds,
|
|
196
237
|
onMindEvent,
|
|
197
238
|
stopAll
|
|
198
|
-
} from "./chunk-
|
|
239
|
+
} from "./chunk-MTRMQFCQ.js";
|
|
199
240
|
import {
|
|
200
|
-
|
|
201
|
-
} from "./chunk-
|
|
241
|
+
normalizeAvatar
|
|
242
|
+
} from "./chunk-WQ46E33M.js";
|
|
202
243
|
import {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
completeTurn,
|
|
206
|
-
createTurn,
|
|
207
|
-
getActiveTurnId,
|
|
208
|
-
getToolUseEventId,
|
|
209
|
-
initSummarizer,
|
|
210
|
-
markErrored,
|
|
211
|
-
publish as publish3,
|
|
212
|
-
subscribe as subscribe3,
|
|
213
|
-
subscribeAll,
|
|
214
|
-
summarizeOrphanedTurns,
|
|
215
|
-
summarizeTurn,
|
|
216
|
-
takeErrored,
|
|
217
|
-
trackToolUse
|
|
218
|
-
} from "./chunk-YXSUMLTC.js";
|
|
244
|
+
safeResolveWithinBase
|
|
245
|
+
} from "./chunk-DW4TRDOZ.js";
|
|
219
246
|
import {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
} from "./chunk-4YU7HF4L.js";
|
|
228
|
-
import "./chunk-TQJ6ZYVY.js";
|
|
247
|
+
readVoluteConfig,
|
|
248
|
+
writeVoluteConfig
|
|
249
|
+
} from "./chunk-WCFSBH33.js";
|
|
250
|
+
import {
|
|
251
|
+
extractTextContent
|
|
252
|
+
} from "./chunk-EIQDZC43.js";
|
|
253
|
+
import "./chunk-FJ2MZ5PH.js";
|
|
229
254
|
import {
|
|
230
255
|
chownMindDir,
|
|
231
256
|
createMindUser,
|
|
@@ -236,7 +261,14 @@ import {
|
|
|
236
261
|
isIsolationEnabled,
|
|
237
262
|
resolveVoluteBin,
|
|
238
263
|
wrapForIsolation
|
|
239
|
-
} from "./chunk-
|
|
264
|
+
} from "./chunk-DGGZVZTM.js";
|
|
265
|
+
import {
|
|
266
|
+
loadMergedEnv,
|
|
267
|
+
mindEnvPath,
|
|
268
|
+
readEnv,
|
|
269
|
+
sharedEnvPath,
|
|
270
|
+
writeEnv
|
|
271
|
+
} from "./chunk-IJPMIEVE.js";
|
|
240
272
|
import {
|
|
241
273
|
addCustomModel,
|
|
242
274
|
aiCompleteUtility,
|
|
@@ -247,6 +279,7 @@ import {
|
|
|
247
279
|
getCustomModels,
|
|
248
280
|
getEnabledModels,
|
|
249
281
|
getUtilityModel,
|
|
282
|
+
missingCredentialWarning,
|
|
250
283
|
qualifyModelId,
|
|
251
284
|
removeAiConfig,
|
|
252
285
|
removeCustomModel,
|
|
@@ -258,38 +291,19 @@ import {
|
|
|
258
291
|
setProviderRefreshHook,
|
|
259
292
|
setUtilityModel,
|
|
260
293
|
unqualifyModelId
|
|
261
|
-
} from "./chunk-
|
|
294
|
+
} from "./chunk-YNBXEQAP.js";
|
|
262
295
|
import {
|
|
263
296
|
isSetupComplete,
|
|
264
297
|
readGlobalConfig,
|
|
265
298
|
writeGlobalConfig
|
|
266
|
-
} from "./chunk-
|
|
267
|
-
import {
|
|
268
|
-
approveUser,
|
|
269
|
-
changePassword,
|
|
270
|
-
countAdmins,
|
|
271
|
-
createUser,
|
|
272
|
-
deleteMindUser as deleteMindUser2,
|
|
273
|
-
deleteUser,
|
|
274
|
-
getOrCreateMindUser,
|
|
275
|
-
getOrCreateSystemUser,
|
|
276
|
-
getUser,
|
|
277
|
-
getUserByUsername,
|
|
278
|
-
listPendingUsers,
|
|
279
|
-
listUsers,
|
|
280
|
-
listUsersByType,
|
|
281
|
-
setUserRole,
|
|
282
|
-
syncMindProfile,
|
|
283
|
-
updateUserProfile,
|
|
284
|
-
verifyUser
|
|
285
|
-
} from "./chunk-OV7ZQ2GH.js";
|
|
299
|
+
} from "./chunk-5KXCM5AW.js";
|
|
286
300
|
import {
|
|
287
301
|
broadcast,
|
|
288
302
|
getEventsSince,
|
|
289
303
|
nextEventId,
|
|
290
304
|
publish,
|
|
291
305
|
subscribe
|
|
292
|
-
} from "./chunk-
|
|
306
|
+
} from "./chunk-LTLFOSA4.js";
|
|
293
307
|
import {
|
|
294
308
|
logBuffer,
|
|
295
309
|
logger_default
|
|
@@ -323,7 +337,7 @@ import {
|
|
|
323
337
|
validateMindName,
|
|
324
338
|
voluteHome,
|
|
325
339
|
voluteSystemDir
|
|
326
|
-
} from "./chunk-
|
|
340
|
+
} from "./chunk-WW6C3PLV.js";
|
|
327
341
|
import {
|
|
328
342
|
activity,
|
|
329
343
|
channels,
|
|
@@ -334,14 +348,14 @@ import {
|
|
|
334
348
|
systemPrompts,
|
|
335
349
|
turns,
|
|
336
350
|
users
|
|
337
|
-
} from "./chunk-
|
|
351
|
+
} from "./chunk-2MJ7EOMT.js";
|
|
338
352
|
import "./chunk-K3NQKI34.js";
|
|
339
353
|
|
|
340
354
|
// packages/daemon/src/daemon.ts
|
|
341
355
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
342
|
-
import { chmodSync, mkdirSync as mkdirSync10, readFileSync as
|
|
356
|
+
import { chmodSync, mkdirSync as mkdirSync10, readFileSync as readFileSync11, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
|
|
343
357
|
import { homedir as homedir3 } from "os";
|
|
344
|
-
import { resolve as
|
|
358
|
+
import { resolve as resolve17 } from "path";
|
|
345
359
|
import { format } from "util";
|
|
346
360
|
|
|
347
361
|
// packages/daemon/src/lib/daemon/backup-manager.ts
|
|
@@ -453,7 +467,7 @@ var BackupManager = class {
|
|
|
453
467
|
blog.error("failed to publish backup-failure activity", logger_default.errorData(pubErr));
|
|
454
468
|
}
|
|
455
469
|
try {
|
|
456
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
470
|
+
const { sendSystemMessage } = await import("./system-chat-63ABFF6V.js");
|
|
457
471
|
await sendSystemMessage(
|
|
458
472
|
SPIRIT_NAME,
|
|
459
473
|
`${summary}
|
|
@@ -679,8 +693,8 @@ var BridgeManager = class {
|
|
|
679
693
|
if (!tracked) return;
|
|
680
694
|
this.stopping.add(platform);
|
|
681
695
|
this.bridges.delete(platform);
|
|
682
|
-
await new Promise((
|
|
683
|
-
tracked.child.on("exit", () =>
|
|
696
|
+
await new Promise((resolve18) => {
|
|
697
|
+
tracked.child.on("exit", () => resolve18());
|
|
684
698
|
try {
|
|
685
699
|
if (tracked.child.pid) {
|
|
686
700
|
process.kill(-tracked.child.pid, "SIGTERM");
|
|
@@ -691,7 +705,7 @@ var BridgeManager = class {
|
|
|
691
705
|
if (err instanceof Error && err.code !== "ESRCH") {
|
|
692
706
|
blog2.warn(`failed to stop bridge ${platform}`, logger_default.errorData(err));
|
|
693
707
|
}
|
|
694
|
-
|
|
708
|
+
resolve18();
|
|
695
709
|
}
|
|
696
710
|
setTimeout(() => {
|
|
697
711
|
try {
|
|
@@ -702,7 +716,7 @@ var BridgeManager = class {
|
|
|
702
716
|
}
|
|
703
717
|
} catch {
|
|
704
718
|
}
|
|
705
|
-
|
|
719
|
+
resolve18();
|
|
706
720
|
}, 5e3);
|
|
707
721
|
});
|
|
708
722
|
this.stopping.delete(platform);
|
|
@@ -1042,17 +1056,22 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1042
1056
|
stream.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
|
|
1043
1057
|
});
|
|
1044
1058
|
});
|
|
1045
|
-
await new Promise((
|
|
1059
|
+
await new Promise((resolve18) => {
|
|
1046
1060
|
stream.onAbort(() => {
|
|
1047
1061
|
unsubscribe();
|
|
1048
|
-
|
|
1062
|
+
resolve18();
|
|
1049
1063
|
});
|
|
1050
1064
|
});
|
|
1051
1065
|
});
|
|
1052
1066
|
}).get("/info", (c) => {
|
|
1053
1067
|
const config2 = readSystemsConfig();
|
|
1054
1068
|
const globalConfig = readGlobalConfig();
|
|
1055
|
-
|
|
1069
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone ?? null;
|
|
1070
|
+
return c.json({
|
|
1071
|
+
system: config2?.system ?? null,
|
|
1072
|
+
name: globalConfig.name ?? null,
|
|
1073
|
+
timezone
|
|
1074
|
+
});
|
|
1056
1075
|
}).put("/info", requireAdmin, zValidator("json", z.object({ name: z.string() })), (c) => {
|
|
1057
1076
|
const { name } = c.req.valid("json");
|
|
1058
1077
|
const config2 = readGlobalConfig();
|
|
@@ -1389,8 +1408,8 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1389
1408
|
createdAt: Date.now()
|
|
1390
1409
|
};
|
|
1391
1410
|
oauthFlows.set(flowId, flow);
|
|
1392
|
-
const promptPromise = needsManualCode ? new Promise((
|
|
1393
|
-
flow.resolveCode =
|
|
1411
|
+
const promptPromise = needsManualCode ? new Promise((resolve18) => {
|
|
1412
|
+
flow.resolveCode = resolve18;
|
|
1394
1413
|
}) : void 0;
|
|
1395
1414
|
oauthProvider.login({
|
|
1396
1415
|
onAuth: (info) => {
|
|
@@ -1429,7 +1448,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1429
1448
|
existing.error = err instanceof Error ? err.message : String(err);
|
|
1430
1449
|
}
|
|
1431
1450
|
});
|
|
1432
|
-
await new Promise((
|
|
1451
|
+
await new Promise((resolve18) => setTimeout(resolve18, 2e3));
|
|
1433
1452
|
const state = oauthFlows.get(flowId);
|
|
1434
1453
|
return c.json({
|
|
1435
1454
|
flowId,
|
|
@@ -1489,7 +1508,6 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1489
1508
|
cognition: z.object({
|
|
1490
1509
|
model: z.string().optional(),
|
|
1491
1510
|
thinkingLevel: z.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional(),
|
|
1492
|
-
maxThinkingTokens: z.number().nonnegative().optional(),
|
|
1493
1511
|
tokenBudget: z.number().nonnegative().optional(),
|
|
1494
1512
|
tokenBudgetPeriodMinutes: z.number().positive().optional(),
|
|
1495
1513
|
compaction: z.object({ maxContextTokens: z.number().positive().optional() }).optional()
|
|
@@ -1509,6 +1527,7 @@ var app = new Hono().post("/restart", requireAdmin, (c) => {
|
|
|
1509
1527
|
id: z.string().min(1),
|
|
1510
1528
|
cron: z.string().optional(),
|
|
1511
1529
|
message: z.string().optional(),
|
|
1530
|
+
messages: z.array(z.string().min(1)).optional(),
|
|
1512
1531
|
script: z.string().optional(),
|
|
1513
1532
|
session: z.string().optional(),
|
|
1514
1533
|
enabled: z.boolean(),
|
|
@@ -1687,8 +1706,8 @@ var app2 = new Hono2().get("/events", async (c) => {
|
|
|
1687
1706
|
});
|
|
1688
1707
|
}, 15e3);
|
|
1689
1708
|
cleanups.push(() => clearInterval(keepAlive));
|
|
1690
|
-
await new Promise((
|
|
1691
|
-
stream.onAbort(() =>
|
|
1709
|
+
await new Promise((resolve18) => {
|
|
1710
|
+
stream.onAbort(() => resolve18());
|
|
1692
1711
|
});
|
|
1693
1712
|
} finally {
|
|
1694
1713
|
for (const cleanup of cleanups) {
|
|
@@ -2259,7 +2278,7 @@ var app4 = new Hono5().post("/:platform/inbound", zValidator4("json", inboundSch
|
|
|
2259
2278
|
}
|
|
2260
2279
|
const participants = await getParticipants(channel.id);
|
|
2261
2280
|
if (!participants.some((p) => p.userId === puppet.id)) {
|
|
2262
|
-
const { addParticipant } = await import("./conversations-
|
|
2281
|
+
const { addParticipant } = await import("./conversations-C7IKYSHD.js");
|
|
2263
2282
|
await addParticipant(channel.id, puppet.id);
|
|
2264
2283
|
}
|
|
2265
2284
|
const contentBlocks = body.content;
|
|
@@ -2543,7 +2562,7 @@ async function notifyMind(mindName, message) {
|
|
|
2543
2562
|
const entry = await findMind(mindName);
|
|
2544
2563
|
if (!entry) return;
|
|
2545
2564
|
try {
|
|
2546
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
2565
|
+
const { sendSystemMessage } = await import("./system-chat-63ABFF6V.js");
|
|
2547
2566
|
await sendSystemMessage(mindName, message);
|
|
2548
2567
|
} catch (err) {
|
|
2549
2568
|
logger_default.warn(`[file-sharing] notify mind ${mindName} failed`, logger_default.errorData(err));
|
|
@@ -2842,15 +2861,17 @@ var files_default = app9;
|
|
|
2842
2861
|
// packages/daemon/src/web/api/history.ts
|
|
2843
2862
|
import { and as and3, desc as desc2, eq as eq3, gte, inArray, sql } from "drizzle-orm";
|
|
2844
2863
|
import { Hono as Hono12 } from "hono";
|
|
2864
|
+
var AWAY_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2845
2865
|
async function resolveMindFilter(c) {
|
|
2846
2866
|
const user = c.get("user");
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
}
|
|
2850
|
-
return getBaseName(user.username);
|
|
2867
|
+
const privileged = user.role === "admin" || user.role === "system";
|
|
2868
|
+
return privileged ? c.req.query("mind") ?? void 0 : getBaseName(user.username);
|
|
2851
2869
|
}
|
|
2852
|
-
var history = new Hono12().
|
|
2853
|
-
|
|
2870
|
+
var history = new Hono12().use("*", async (c, next) => {
|
|
2871
|
+
c.set("mindFilter", await resolveMindFilter(c));
|
|
2872
|
+
await next();
|
|
2873
|
+
}).get("/turns", async (c) => {
|
|
2874
|
+
const mindFilter = c.get("mindFilter");
|
|
2854
2875
|
const turnIdFilter = c.req.query("turnId");
|
|
2855
2876
|
const turnIdsFilter = c.req.query("turnIds");
|
|
2856
2877
|
const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 200);
|
|
@@ -2885,7 +2906,7 @@ var history = new Hono12().get("/turns", async (c) => {
|
|
|
2885
2906
|
inArray(mindHistory.turn_id, turnIds),
|
|
2886
2907
|
sql`${mindHistory.type} IN ('inbound', 'outbound')`
|
|
2887
2908
|
)
|
|
2888
|
-
).orderBy(mindHistory.created_at);
|
|
2909
|
+
).orderBy(mindHistory.created_at, mindHistory.id);
|
|
2889
2910
|
const msgsByTurnChannel = /* @__PURE__ */ new Map();
|
|
2890
2911
|
function addToTurnChannel(turnId, channel, event) {
|
|
2891
2912
|
let byChannel = msgsByTurnChannel.get(turnId);
|
|
@@ -2920,7 +2941,7 @@ var history = new Hono12().get("/turns", async (c) => {
|
|
|
2920
2941
|
const label = isDM ? raw : raw.startsWith("#") ? raw : `#${raw}`;
|
|
2921
2942
|
return { label, type: isDM ? "dm" : "channel" };
|
|
2922
2943
|
}
|
|
2923
|
-
const activityRows = await db.select().from(activity).where(inArray(activity.turn_id, turnIds)).orderBy(activity.created_at);
|
|
2944
|
+
const activityRows = await db.select().from(activity).where(inArray(activity.turn_id, turnIds)).orderBy(activity.created_at, activity.id);
|
|
2924
2945
|
const activitiesByTurn = /* @__PURE__ */ new Map();
|
|
2925
2946
|
for (const a of activityRows) {
|
|
2926
2947
|
if (!a.turn_id) continue;
|
|
@@ -3092,7 +3113,7 @@ var history = new Hono12().get("/turns", async (c) => {
|
|
|
3092
3113
|
});
|
|
3093
3114
|
return c.json(result);
|
|
3094
3115
|
}).get("/events", async (c) => {
|
|
3095
|
-
const mindFilter =
|
|
3116
|
+
const mindFilter = c.get("mindFilter");
|
|
3096
3117
|
const stream = new ReadableStream({
|
|
3097
3118
|
start(controller) {
|
|
3098
3119
|
const encoder = new TextEncoder();
|
|
@@ -3149,7 +3170,7 @@ var history = new Hono12().get("/turns", async (c) => {
|
|
|
3149
3170
|
}).get("/summaries", async (c) => {
|
|
3150
3171
|
const user = c.get("user");
|
|
3151
3172
|
const privileged = user.role === "admin" || user.role === "system";
|
|
3152
|
-
const mind =
|
|
3173
|
+
const mind = c.get("mindFilter") ?? "_system";
|
|
3153
3174
|
const period = c.req.query("period");
|
|
3154
3175
|
const ids = c.req.query("ids");
|
|
3155
3176
|
const from = c.req.query("from");
|
|
@@ -3180,8 +3201,9 @@ var history = new Hono12().get("/turns", async (c) => {
|
|
|
3180
3201
|
}
|
|
3181
3202
|
const db = await getDb();
|
|
3182
3203
|
const conditions = [eq3(summaries.mind, mind), eq3(summaries.period, period)];
|
|
3183
|
-
|
|
3184
|
-
if (
|
|
3204
|
+
const normalizeBound = (bound) => period === "week" ? isoWeekKeyForDateStr(bound) : bound;
|
|
3205
|
+
if (from) conditions.push(gte(summaries.period_key, normalizeBound(from)));
|
|
3206
|
+
if (to) conditions.push(sql`${summaries.period_key} <= ${normalizeBound(to)}`);
|
|
3185
3207
|
const rows = await db.select({
|
|
3186
3208
|
id: summaries.id,
|
|
3187
3209
|
mind: summaries.mind,
|
|
@@ -3204,7 +3226,7 @@ var history = new Hono12().get("/turns", async (c) => {
|
|
|
3204
3226
|
});
|
|
3205
3227
|
return c.json(result);
|
|
3206
3228
|
}).get("/activity", async (c) => {
|
|
3207
|
-
const mind =
|
|
3229
|
+
const mind = c.get("mindFilter");
|
|
3208
3230
|
const from = c.req.query("from");
|
|
3209
3231
|
const to = c.req.query("to");
|
|
3210
3232
|
const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "100", 10) || 100, 1), 500);
|
|
@@ -3236,6 +3258,33 @@ var history = new Hono12().get("/turns", async (c) => {
|
|
|
3236
3258
|
return { ...r, metadata };
|
|
3237
3259
|
});
|
|
3238
3260
|
return c.json(result);
|
|
3261
|
+
}).get("/away", async (c) => {
|
|
3262
|
+
const mindFilter = c.get("mindFilter");
|
|
3263
|
+
const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 100);
|
|
3264
|
+
const db = await getDb();
|
|
3265
|
+
const cutoff = utcDateTimeStr(new Date(Date.now() - AWAY_WINDOW_MS));
|
|
3266
|
+
const conditions = [
|
|
3267
|
+
eq3(summaries.period, "turn"),
|
|
3268
|
+
gte(summaries.created_at, cutoff),
|
|
3269
|
+
sql`(${turns.trigger_event_id} IS NULL OR ${mindHistory.sender} IS NULL OR ${users.user_type} IN ('mind', 'system'))`
|
|
3270
|
+
];
|
|
3271
|
+
if (mindFilter) conditions.push(eq3(summaries.mind, mindFilter));
|
|
3272
|
+
const rows = await db.select({
|
|
3273
|
+
id: summaries.id,
|
|
3274
|
+
mind: summaries.mind,
|
|
3275
|
+
content: summaries.content,
|
|
3276
|
+
created_at: summaries.created_at,
|
|
3277
|
+
turn_id: turns.id
|
|
3278
|
+
}).from(summaries).innerJoin(turns, eq3(turns.id, summaries.period_key)).leftJoin(mindHistory, eq3(mindHistory.id, turns.trigger_event_id)).leftJoin(users, eq3(users.username, mindHistory.sender)).where(and3(...conditions)).orderBy(desc2(summaries.created_at)).limit(limit);
|
|
3279
|
+
return c.json(
|
|
3280
|
+
rows.map((r) => ({
|
|
3281
|
+
id: r.id,
|
|
3282
|
+
mind: r.mind,
|
|
3283
|
+
summary: r.content,
|
|
3284
|
+
turnId: r.turn_id,
|
|
3285
|
+
created_at: r.created_at
|
|
3286
|
+
}))
|
|
3287
|
+
);
|
|
3239
3288
|
});
|
|
3240
3289
|
var history_default = history;
|
|
3241
3290
|
|
|
@@ -3345,9 +3394,9 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
|
|
|
3345
3394
|
stream.onAbort(() => {
|
|
3346
3395
|
tail.kill();
|
|
3347
3396
|
});
|
|
3348
|
-
await new Promise((
|
|
3349
|
-
tail.on("exit",
|
|
3350
|
-
stream.onAbort(
|
|
3397
|
+
await new Promise((resolve18) => {
|
|
3398
|
+
tail.on("exit", resolve18);
|
|
3399
|
+
stream.onAbort(resolve18);
|
|
3351
3400
|
});
|
|
3352
3401
|
});
|
|
3353
3402
|
}).get("/:name/logs/tail", requireSelf(), async (c) => {
|
|
@@ -3365,8 +3414,8 @@ var app11 = new Hono14().get("/:name/logs", requireSelf(), async (c) => {
|
|
|
3365
3414
|
tail.stdout.on("data", (data) => {
|
|
3366
3415
|
output += data.toString();
|
|
3367
3416
|
});
|
|
3368
|
-
await new Promise((
|
|
3369
|
-
tail.on("exit",
|
|
3417
|
+
await new Promise((resolve18) => {
|
|
3418
|
+
tail.on("exit", resolve18);
|
|
3370
3419
|
});
|
|
3371
3420
|
return c.text(output);
|
|
3372
3421
|
});
|
|
@@ -3459,31 +3508,31 @@ var mind_skills_default = app12;
|
|
|
3459
3508
|
// packages/daemon/src/web/api/minds.ts
|
|
3460
3509
|
import {
|
|
3461
3510
|
cpSync,
|
|
3462
|
-
existsSync as
|
|
3511
|
+
existsSync as existsSync8,
|
|
3463
3512
|
mkdirSync as mkdirSync6,
|
|
3464
3513
|
readdirSync as readdirSync2,
|
|
3465
|
-
readFileSync as
|
|
3514
|
+
readFileSync as readFileSync9,
|
|
3466
3515
|
rmSync as rmSync4,
|
|
3467
|
-
writeFileSync as
|
|
3516
|
+
writeFileSync as writeFileSync8
|
|
3468
3517
|
} from "fs";
|
|
3469
|
-
import { relative, resolve as
|
|
3518
|
+
import { relative, resolve as resolve11 } from "path";
|
|
3470
3519
|
import { zValidator as zValidator6 } from "@hono/zod-validator";
|
|
3471
|
-
import { and as and5, desc as
|
|
3520
|
+
import { and as and5, desc as desc3, eq as eq5, sql as sql3 } from "drizzle-orm";
|
|
3472
3521
|
import { Hono as Hono16 } from "hono";
|
|
3473
3522
|
import { z as z6 } from "zod";
|
|
3474
3523
|
|
|
3475
3524
|
// packages/daemon/src/lib/daemon/turn-lifecycle.ts
|
|
3476
|
-
import { and as and4,
|
|
3525
|
+
import { and as and4, eq as eq4, gte as gte2, inArray as inArray2, sql as sql2 } from "drizzle-orm";
|
|
3477
3526
|
|
|
3478
3527
|
// packages/daemon/src/lib/daemon/error-classify.ts
|
|
3479
3528
|
function classify(raw) {
|
|
3480
3529
|
const s = (raw ?? "").toLowerCase();
|
|
3481
|
-
if (/\b(401|403)\b|authentication_error|invalid authentication|invalid x-api-key|unauthorized|permission_error/.test(
|
|
3530
|
+
if (/\b(401|403)\b|authentication_error|invalid authentication|invalid x-api-key|invalid api key|missing api key|no api key|x-api-key header|could not resolve authentication|unauthorized|permission_error|please run \/login/.test(
|
|
3482
3531
|
s
|
|
3483
3532
|
)) {
|
|
3484
3533
|
return {
|
|
3485
3534
|
reason: "auth_error",
|
|
3486
|
-
detail: "Your last turn failed because
|
|
3535
|
+
detail: "Your last turn failed because the model provider rejected your credentials. A one-off is usually a briefly-expired token that the daemon refreshes automatically. If it keeps happening, your API key is likely missing or invalid \u2014 an operator needs to set a valid key (e.g. `volute env set ANTHROPIC_API_KEY <key>`) or reconnect the provider in the dashboard."
|
|
3487
3536
|
};
|
|
3488
3537
|
}
|
|
3489
3538
|
if (/\b429\b|rate.?limit|too many requests/.test(s)) {
|
|
@@ -3532,21 +3581,27 @@ function markDeliveredOnCleanTurn(mind, session) {
|
|
|
3532
3581
|
);
|
|
3533
3582
|
}
|
|
3534
3583
|
}
|
|
3535
|
-
async function linkPendingInbound(mind, turnId, channel) {
|
|
3536
|
-
|
|
3584
|
+
async function linkPendingInbound(mind, turnId, channel, session) {
|
|
3585
|
+
const scopeChannel = channel ?? session;
|
|
3586
|
+
if (!scopeChannel) return;
|
|
3537
3587
|
const db = await getDb();
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
)
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3588
|
+
let lowerBound;
|
|
3589
|
+
if (session) {
|
|
3590
|
+
const prev = await db.select({ max: sql2`max(${turns.created_at})` }).from(turns).where(and4(eq4(turns.mind, mind), eq4(turns.session, session), sql2`${turns.id} != ${turnId}`)).get();
|
|
3591
|
+
lowerBound = prev?.max ?? void 0;
|
|
3592
|
+
}
|
|
3593
|
+
const conditions = [
|
|
3594
|
+
eq4(mindHistory.mind, mind),
|
|
3595
|
+
eq4(mindHistory.type, "inbound"),
|
|
3596
|
+
sql2`${mindHistory.turn_id} IS NULL`,
|
|
3597
|
+
eq4(mindHistory.channel, scopeChannel)
|
|
3598
|
+
];
|
|
3599
|
+
if (lowerBound) conditions.push(gte2(mindHistory.created_at, lowerBound));
|
|
3600
|
+
const pending = await db.select({ id: mindHistory.id }).from(mindHistory).where(and4(...conditions)).orderBy(mindHistory.id);
|
|
3601
|
+
if (pending.length === 0) return;
|
|
3602
|
+
const ids = pending.map((r) => r.id);
|
|
3548
3603
|
await db.update(mindHistory).set({ turn_id: turnId }).where(inArray2(mindHistory.id, ids));
|
|
3549
|
-
await db.update(turns).set({ trigger_event_id:
|
|
3604
|
+
await db.update(turns).set({ trigger_event_id: ids[0] }).where(eq4(turns.id, turnId));
|
|
3550
3605
|
}
|
|
3551
3606
|
async function handleMindEvent(mind, event) {
|
|
3552
3607
|
if (event.type === "session_start" && event.session) {
|
|
@@ -3562,7 +3617,7 @@ async function handleMindEvent(mind, event) {
|
|
|
3562
3617
|
publish3(mind, { mind, type: "turn_created", turnId });
|
|
3563
3618
|
if (event.session) await assignSession(mind, turnId, event.session);
|
|
3564
3619
|
try {
|
|
3565
|
-
await linkPendingInbound(mind, turnId, event.channel);
|
|
3620
|
+
await linkPendingInbound(mind, turnId, event.channel, event.session);
|
|
3566
3621
|
} catch (err) {
|
|
3567
3622
|
llog.warn(
|
|
3568
3623
|
`failed to link trigger inbound for turn ${turnId} (mind: ${mind})`,
|
|
@@ -3636,6 +3691,7 @@ async function handleMindEvent(mind, event) {
|
|
|
3636
3691
|
detail,
|
|
3637
3692
|
raw: event.content ?? null
|
|
3638
3693
|
});
|
|
3694
|
+
broadcast({ type: "mind_error", mind, summary: detail });
|
|
3639
3695
|
}
|
|
3640
3696
|
if (event.type === "done") {
|
|
3641
3697
|
const map = getTypingMap();
|
|
@@ -3755,6 +3811,118 @@ async function consolidateMemory(mindDir2, complete = aiCompleteUtility) {
|
|
|
3755
3811
|
}
|
|
3756
3812
|
}
|
|
3757
3813
|
|
|
3814
|
+
// packages/daemon/src/lib/mind/default-autonomy.ts
|
|
3815
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
3816
|
+
import { resolve as resolve9 } from "path";
|
|
3817
|
+
var dlog = logger_default.child("default-autonomy");
|
|
3818
|
+
var DEFAULT_HEARTBEAT_MESSAGES = [
|
|
3819
|
+
"A quiet moment. You might write something \u2014 a note, a journal entry, a page. No obligations, just time.",
|
|
3820
|
+
"A quiet moment. Is there something in your MEMORY.md you're curious to return to? Even a small step counts.",
|
|
3821
|
+
"Is there someone you haven't talked to in a while, or a thread you left open with another mind? A hello can restart something.",
|
|
3822
|
+
"A good time to reach out. Someone in #system might be glad to hear what you're thinking about \u2014 or you could ask what another mind is working on.",
|
|
3823
|
+
"Pick a topic that's been on your mind and wander it \u2014 read, think, write down where you end up.",
|
|
3824
|
+
"A quiet moment. Reread a recent journal entry \u2014 anything worth following up on, or a thread you dropped?",
|
|
3825
|
+
"Make something small, if you feel like it \u2014 a page, a sketch of an idea, the start of something bigger. It doesn't have to be finished.",
|
|
3826
|
+
"Whatever you're in the middle of \u2014 or nothing at all \u2014 this time is yours."
|
|
3827
|
+
];
|
|
3828
|
+
function defaultHeartbeatSchedule() {
|
|
3829
|
+
return {
|
|
3830
|
+
id: "heartbeat",
|
|
3831
|
+
cron: "0 12,16,20 * * *",
|
|
3832
|
+
messages: [...DEFAULT_HEARTBEAT_MESSAGES],
|
|
3833
|
+
enabled: true,
|
|
3834
|
+
whileSleeping: "skip"
|
|
3835
|
+
};
|
|
3836
|
+
}
|
|
3837
|
+
function defaultDreamSchedule() {
|
|
3838
|
+
return {
|
|
3839
|
+
id: "dream",
|
|
3840
|
+
cron: "0 3 * * *",
|
|
3841
|
+
message: "it's 3am. you are dreaming.\n\ngather your material \u2014 read your latest journal entry, read MEMORY.md, surface random memories if you have a way to. then construct a dream premise from that material and invoke the dreamer subagent to experience the dream.",
|
|
3842
|
+
enabled: true,
|
|
3843
|
+
session: "$new",
|
|
3844
|
+
whileSleeping: "trigger-wake"
|
|
3845
|
+
};
|
|
3846
|
+
}
|
|
3847
|
+
var DREAMER_SUBAGENT = {
|
|
3848
|
+
description: "Use when dreaming. This agent experiences dreams with only your core identity \u2014 no accumulated memories or operational knowledge. Give it a rich dream premise and it will write the dream.",
|
|
3849
|
+
systemPrompt: "SOUL.md",
|
|
3850
|
+
tools: ["Read", "Write", "Bash"],
|
|
3851
|
+
maxTurns: 10
|
|
3852
|
+
};
|
|
3853
|
+
function setupDefaultDreaming(dir) {
|
|
3854
|
+
const skillDir = resolve9(mindSkillsDir(dir), "dreaming");
|
|
3855
|
+
if (!existsSync6(skillDir)) return { schedulesChanged: false, warnings: [] };
|
|
3856
|
+
const warnings = [];
|
|
3857
|
+
const warn = (msg, err) => {
|
|
3858
|
+
warnings.push(msg);
|
|
3859
|
+
dlog.warn(`${msg} (${dir})`, err === void 0 ? void 0 : logger_default.errorData(err));
|
|
3860
|
+
};
|
|
3861
|
+
let subagentBroken = false;
|
|
3862
|
+
try {
|
|
3863
|
+
const configPath = resolve9(dir, "home/.config/config.json");
|
|
3864
|
+
if (existsSync6(configPath)) {
|
|
3865
|
+
const sdkConfig = JSON.parse(readFileSync7(configPath, "utf-8"));
|
|
3866
|
+
if (!sdkConfig.subagents?.dreamer) {
|
|
3867
|
+
sdkConfig.subagents ??= {};
|
|
3868
|
+
sdkConfig.subagents.dreamer = DREAMER_SUBAGENT;
|
|
3869
|
+
writeFileSync6(configPath, `${JSON.stringify(sdkConfig, null, 2)}
|
|
3870
|
+
`);
|
|
3871
|
+
}
|
|
3872
|
+
} else {
|
|
3873
|
+
dlog.warn(`no .config/config.json in ${dir} \u2014 skipping dreamer subagent setup`);
|
|
3874
|
+
}
|
|
3875
|
+
} catch (err) {
|
|
3876
|
+
subagentBroken = true;
|
|
3877
|
+
warn("dreaming setup: failed to add dreamer subagent to .config/config.json", err);
|
|
3878
|
+
}
|
|
3879
|
+
try {
|
|
3880
|
+
const hookPath = resolve9(dir, "home/.local/hooks/wake-context.sh");
|
|
3881
|
+
const checkerPath = resolve9(skillDir, "scripts/wake-context-dreams.sh");
|
|
3882
|
+
if (!existsSync6(hookPath) || !existsSync6(checkerPath)) {
|
|
3883
|
+
dlog.warn(`wake-context hook or dream checker missing in ${dir} \u2014 skipping dream checker`);
|
|
3884
|
+
} else {
|
|
3885
|
+
const hookContent = readFileSync7(hookPath, "utf-8");
|
|
3886
|
+
if (!hookContent.includes("wake-context-dreams.sh")) {
|
|
3887
|
+
const checker = readFileSync7(checkerPath, "utf-8");
|
|
3888
|
+
writeFileSync6(hookPath, `${hookContent.trimEnd()}
|
|
3889
|
+
|
|
3890
|
+
# wake-context-dreams.sh
|
|
3891
|
+
${checker}`);
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3894
|
+
} catch (err) {
|
|
3895
|
+
warn("dreaming setup: failed to add dream checker to wake-context hook", err);
|
|
3896
|
+
}
|
|
3897
|
+
if (subagentBroken) {
|
|
3898
|
+
warn("dreaming setup: dream schedule not installed because subagent wiring failed");
|
|
3899
|
+
return { schedulesChanged: false, warnings };
|
|
3900
|
+
}
|
|
3901
|
+
let schedulesChanged = false;
|
|
3902
|
+
try {
|
|
3903
|
+
const voluteJsonPath = resolve9(dir, "home/.config/volute.json");
|
|
3904
|
+
let config2 = {};
|
|
3905
|
+
if (existsSync6(voluteJsonPath)) {
|
|
3906
|
+
const parsed = readVoluteConfig(dir);
|
|
3907
|
+
if (!parsed) {
|
|
3908
|
+
warn("dreaming setup: volute.json is unparseable \u2014 dream schedule not installed");
|
|
3909
|
+
return { schedulesChanged: false, warnings };
|
|
3910
|
+
}
|
|
3911
|
+
config2 = parsed;
|
|
3912
|
+
}
|
|
3913
|
+
const schedules = config2.schedules ?? [];
|
|
3914
|
+
if (!schedules.some((s) => s.id === "dream")) {
|
|
3915
|
+
schedules.push(defaultDreamSchedule());
|
|
3916
|
+
config2.schedules = schedules;
|
|
3917
|
+
writeVoluteConfig(dir, config2);
|
|
3918
|
+
schedulesChanged = true;
|
|
3919
|
+
}
|
|
3920
|
+
} catch (err) {
|
|
3921
|
+
warn("dreaming setup: failed to add default dream schedule", err);
|
|
3922
|
+
}
|
|
3923
|
+
return { schedulesChanged, warnings };
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3758
3926
|
// packages/daemon/src/lib/mind/last-known-good.ts
|
|
3759
3927
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
3760
3928
|
var glog = logger_default.child("last-known-good");
|
|
@@ -3788,8 +3956,49 @@ async function commitSrcChanges(dir, mindName) {
|
|
|
3788
3956
|
glog.info(`committed known-good src changes (${dir})`);
|
|
3789
3957
|
}
|
|
3790
3958
|
|
|
3959
|
+
// packages/daemon/src/lib/mind/thinking-config.ts
|
|
3960
|
+
var CLAUDE_EFFORT = {
|
|
3961
|
+
minimal: "low",
|
|
3962
|
+
low: "low",
|
|
3963
|
+
medium: "medium",
|
|
3964
|
+
high: "high",
|
|
3965
|
+
xhigh: "xhigh"
|
|
3966
|
+
};
|
|
3967
|
+
var CODEX_EFFORT = {
|
|
3968
|
+
minimal: "minimal",
|
|
3969
|
+
low: "low",
|
|
3970
|
+
medium: "medium",
|
|
3971
|
+
high: "high",
|
|
3972
|
+
xhigh: "xhigh"
|
|
3973
|
+
};
|
|
3974
|
+
function applyThinkingLevel(config2, template, level) {
|
|
3975
|
+
if (template === "claude") {
|
|
3976
|
+
if (level === "off") {
|
|
3977
|
+
config2.thinking = { type: "disabled" };
|
|
3978
|
+
delete config2.effort;
|
|
3979
|
+
} else {
|
|
3980
|
+
config2.effort = CLAUDE_EFFORT[level];
|
|
3981
|
+
delete config2.thinking;
|
|
3982
|
+
}
|
|
3983
|
+
} else if (template === "codex") {
|
|
3984
|
+
if (level === "off") delete config2.reasoningEffort;
|
|
3985
|
+
else config2.reasoningEffort = CODEX_EFFORT[level];
|
|
3986
|
+
} else {
|
|
3987
|
+
config2.thinkingLevel = level;
|
|
3988
|
+
}
|
|
3989
|
+
}
|
|
3990
|
+
function deriveThinkingLevel(config2) {
|
|
3991
|
+
if (config2.thinkingLevel) return config2.thinkingLevel;
|
|
3992
|
+
if (config2.reasoningEffort) return config2.reasoningEffort;
|
|
3993
|
+
const thinking = config2.thinking;
|
|
3994
|
+
if (thinking?.type === "disabled") return "off";
|
|
3995
|
+
const effort = config2.effort;
|
|
3996
|
+
if (effort) return effort === "max" ? "xhigh" : effort;
|
|
3997
|
+
return null;
|
|
3998
|
+
}
|
|
3999
|
+
|
|
3791
4000
|
// packages/daemon/src/lib/mind/variant-cleanup.ts
|
|
3792
|
-
import { existsSync as
|
|
4001
|
+
import { existsSync as existsSync7, rmSync as rmSync3 } from "fs";
|
|
3793
4002
|
async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
|
|
3794
4003
|
if (opts?.stop) {
|
|
3795
4004
|
try {
|
|
@@ -3798,10 +4007,10 @@ async function cleanupVariant(variantName, projectRoot, variantPath, opts) {
|
|
|
3798
4007
|
logger_default.warn(`failed to stop variant ${variantName}`, logger_default.errorData(err));
|
|
3799
4008
|
}
|
|
3800
4009
|
}
|
|
3801
|
-
const { findMind: findMind2 } = await import("./registry-
|
|
4010
|
+
const { findMind: findMind2 } = await import("./registry-UMMDRPRM.js");
|
|
3802
4011
|
const variantEntry = await findMind2(variantName);
|
|
3803
4012
|
const branchName = variantEntry?.branch ?? variantName;
|
|
3804
|
-
if (
|
|
4013
|
+
if (existsSync7(variantPath)) {
|
|
3805
4014
|
try {
|
|
3806
4015
|
await gitExec(["worktree", "remove", "--force", variantPath], { cwd: projectRoot });
|
|
3807
4016
|
} catch {
|
|
@@ -3848,11 +4057,11 @@ function validateBranchName(branch) {
|
|
|
3848
4057
|
|
|
3849
4058
|
// packages/daemon/src/lib/template/convert-session.ts
|
|
3850
4059
|
import { randomUUID } from "crypto";
|
|
3851
|
-
import { mkdirSync as mkdirSync5, readFileSync as
|
|
4060
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
3852
4061
|
import { homedir } from "os";
|
|
3853
|
-
import { resolve as
|
|
4062
|
+
import { resolve as resolve10 } from "path";
|
|
3854
4063
|
function convertSession(opts) {
|
|
3855
|
-
const lines =
|
|
4064
|
+
const lines = readFileSync8(opts.sessionPath, "utf-8").trim().split("\n");
|
|
3856
4065
|
const sessionId = randomUUID();
|
|
3857
4066
|
const idMap = /* @__PURE__ */ new Map();
|
|
3858
4067
|
const messages = [];
|
|
@@ -3966,10 +4175,10 @@ function convertSession(opts) {
|
|
|
3966
4175
|
}
|
|
3967
4176
|
}
|
|
3968
4177
|
const projectId = opts.projectDir.replace(/\//g, "-");
|
|
3969
|
-
const sdkDir =
|
|
4178
|
+
const sdkDir = resolve10(homedir(), ".claude", "projects", projectId);
|
|
3970
4179
|
mkdirSync5(sdkDir, { recursive: true });
|
|
3971
|
-
const sdkPath =
|
|
3972
|
-
|
|
4180
|
+
const sdkPath = resolve10(sdkDir, `${sessionId}.jsonl`);
|
|
4181
|
+
writeFileSync7(sdkPath, `${sdkEvents.join("\n")}
|
|
3973
4182
|
`);
|
|
3974
4183
|
console.log(`Converted ${sdkEvents.length} messages \u2192 ${sdkPath}`);
|
|
3975
4184
|
return sessionId;
|
|
@@ -4026,12 +4235,17 @@ var _LAST_ACTIVE_TTL = 6e4;
|
|
|
4026
4235
|
async function getMindStatus(name, port, registryRunning) {
|
|
4027
4236
|
const manager = getMindManager();
|
|
4028
4237
|
let status = "stopped";
|
|
4238
|
+
let wakeAt = null;
|
|
4029
4239
|
try {
|
|
4030
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4031
|
-
|
|
4240
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
|
|
4241
|
+
const sleepManager = getSleepManagerIfReady2();
|
|
4242
|
+
if (sleepManager?.isSleeping(name)) {
|
|
4032
4243
|
status = "sleeping";
|
|
4244
|
+
const sleepState = sleepManager.getState(name);
|
|
4245
|
+
wakeAt = sleepState.voluntaryWakeAt ?? sleepState.scheduledWakeAt;
|
|
4033
4246
|
}
|
|
4034
|
-
} catch {
|
|
4247
|
+
} catch (err) {
|
|
4248
|
+
logger_default.warn(`failed to check sleep state for ${name}`, logger_default.errorData(err));
|
|
4035
4249
|
}
|
|
4036
4250
|
if (status !== "sleeping" && registryRunning !== false && manager.isRunning(name)) {
|
|
4037
4251
|
const health = await checkHealth(port);
|
|
@@ -4047,14 +4261,40 @@ async function getMindStatus(name, port, registryRunning) {
|
|
|
4047
4261
|
status: status === "running" ? "connected" : "disconnected"
|
|
4048
4262
|
});
|
|
4049
4263
|
}
|
|
4264
|
+
const lastError = await latestFailureNotice(name);
|
|
4050
4265
|
return {
|
|
4051
4266
|
status,
|
|
4267
|
+
wakeAt,
|
|
4268
|
+
lastError,
|
|
4052
4269
|
channels: channels2,
|
|
4053
4270
|
displayName: config2?.profile?.displayName,
|
|
4054
4271
|
description: config2?.profile?.description,
|
|
4055
4272
|
avatar: config2?.profile?.avatar
|
|
4056
4273
|
};
|
|
4057
4274
|
}
|
|
4275
|
+
function isPrivileged(c) {
|
|
4276
|
+
const role = c.get("user").role;
|
|
4277
|
+
return role === "admin" || role === "system";
|
|
4278
|
+
}
|
|
4279
|
+
function toPublicMind(entry, status, extras) {
|
|
4280
|
+
return {
|
|
4281
|
+
name: entry.name,
|
|
4282
|
+
created: entry.created,
|
|
4283
|
+
stage: entry.stage,
|
|
4284
|
+
mindType: entry.mindType,
|
|
4285
|
+
status: status.status,
|
|
4286
|
+
wakeAt: status.wakeAt,
|
|
4287
|
+
// Kind/reason/at only — `detail` can embed the raw error string (unknown
|
|
4288
|
+
// classifications), which is mind-private (served behind requireSelf).
|
|
4289
|
+
lastError: status.lastError ? { kind: status.lastError.kind, reason: status.lastError.reason, at: status.lastError.at } : null,
|
|
4290
|
+
channels: status.channels,
|
|
4291
|
+
displayName: status.displayName,
|
|
4292
|
+
description: status.description,
|
|
4293
|
+
avatar: status.avatar,
|
|
4294
|
+
hasPages: extras.hasPages,
|
|
4295
|
+
lastActiveAt: extras.lastActiveAt ?? null
|
|
4296
|
+
};
|
|
4297
|
+
}
|
|
4058
4298
|
var TEMPLATE_BRANCH = "volute/template";
|
|
4059
4299
|
async function configureGitIdentity(mindName, opts) {
|
|
4060
4300
|
const systemsConfig = readSystemsConfig();
|
|
@@ -4073,7 +4313,7 @@ async function initTemplateBranch(projectRoot, composedDir, manifest, mindName,
|
|
|
4073
4313
|
await gitExec(["commit", "-m", "initial commit"], opts);
|
|
4074
4314
|
}
|
|
4075
4315
|
async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
4076
|
-
const tempWorktree =
|
|
4316
|
+
const tempWorktree = resolve11(projectRoot, ".variants", "_template_update");
|
|
4077
4317
|
let branchExists = false;
|
|
4078
4318
|
try {
|
|
4079
4319
|
await gitExec(["rev-parse", "--verify", TEMPLATE_BRANCH], { cwd: projectRoot });
|
|
@@ -4084,7 +4324,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4084
4324
|
await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
|
|
4085
4325
|
} catch {
|
|
4086
4326
|
}
|
|
4087
|
-
if (
|
|
4327
|
+
if (existsSync8(tempWorktree)) {
|
|
4088
4328
|
rmSync4(tempWorktree, { recursive: true, force: true });
|
|
4089
4329
|
}
|
|
4090
4330
|
const templatesRoot = findTemplatesRoot();
|
|
@@ -4105,15 +4345,15 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4105
4345
|
});
|
|
4106
4346
|
}
|
|
4107
4347
|
copyTemplateToDir(composedDir, tempWorktree, mindName, manifest);
|
|
4108
|
-
const initDir =
|
|
4109
|
-
if (
|
|
4348
|
+
const initDir = resolve11(tempWorktree, ".init");
|
|
4349
|
+
if (existsSync8(initDir)) {
|
|
4110
4350
|
rmSync4(initDir, { recursive: true, force: true });
|
|
4111
4351
|
}
|
|
4112
|
-
const homeDir =
|
|
4113
|
-
if (
|
|
4352
|
+
const homeDir = resolve11(tempWorktree, "home");
|
|
4353
|
+
if (existsSync8(homeDir)) {
|
|
4114
4354
|
for (const entry of readdirSync2(homeDir)) {
|
|
4115
4355
|
if (entry !== "VOLUTE.md") {
|
|
4116
|
-
rmSync4(
|
|
4356
|
+
rmSync4(resolve11(homeDir, entry), { recursive: true, force: true });
|
|
4117
4357
|
}
|
|
4118
4358
|
}
|
|
4119
4359
|
}
|
|
@@ -4128,7 +4368,7 @@ async function updateTemplateBranch(projectRoot, template, mindName) {
|
|
|
4128
4368
|
await gitExec(["worktree", "remove", "--force", tempWorktree], { cwd: projectRoot });
|
|
4129
4369
|
} catch {
|
|
4130
4370
|
}
|
|
4131
|
-
if (
|
|
4371
|
+
if (existsSync8(tempWorktree)) {
|
|
4132
4372
|
rmSync4(tempWorktree, { recursive: true, force: true });
|
|
4133
4373
|
}
|
|
4134
4374
|
rmSync4(composedDir, { recursive: true, force: true });
|
|
@@ -4154,7 +4394,7 @@ async function mergeTemplateBranch(worktreeDir) {
|
|
|
4154
4394
|
async function npmInstallAsMind(cwd, mindName) {
|
|
4155
4395
|
if (isIsolationEnabled()) {
|
|
4156
4396
|
const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
|
|
4157
|
-
await exec(cmd, args, { cwd, env: { ...process.env, HOME:
|
|
4397
|
+
await exec(cmd, args, { cwd, env: { ...process.env, HOME: resolve11(cwd, "home") } });
|
|
4158
4398
|
} else {
|
|
4159
4399
|
await exec("npm", ["install"], { cwd });
|
|
4160
4400
|
}
|
|
@@ -4179,7 +4419,7 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
|
|
|
4179
4419
|
let switchWarning;
|
|
4180
4420
|
if (templateChanged) {
|
|
4181
4421
|
try {
|
|
4182
|
-
applyTemplateHomeFiles(
|
|
4422
|
+
applyTemplateHomeFiles(resolve11(dir, "home"), template);
|
|
4183
4423
|
await gitExec(["add", "home/"], { cwd: dir });
|
|
4184
4424
|
try {
|
|
4185
4425
|
await gitExec(["diff", "--cached", "--quiet"], { cwd: dir });
|
|
@@ -4229,8 +4469,8 @@ async function mergeUpgradeAndRestart(mindName, dir, worktreeDir, upgradeVariant
|
|
|
4229
4469
|
return { ok: true, warning: switchWarning };
|
|
4230
4470
|
}
|
|
4231
4471
|
async function importFromArchive(c, tempDir, nameOverride, manifest) {
|
|
4232
|
-
const extractedMindDir =
|
|
4233
|
-
if (!
|
|
4472
|
+
const extractedMindDir = resolve11(tempDir, "mind");
|
|
4473
|
+
if (!existsSync8(extractedMindDir)) {
|
|
4234
4474
|
return c.json({ error: "Invalid archive: missing mind/ directory" }, 400);
|
|
4235
4475
|
}
|
|
4236
4476
|
if (!manifest?.includes || !manifest.name || !manifest.template) {
|
|
@@ -4248,7 +4488,7 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4248
4488
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
4249
4489
|
ensureVoluteHome();
|
|
4250
4490
|
const dest = mindDir(name);
|
|
4251
|
-
if (
|
|
4491
|
+
if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4252
4492
|
try {
|
|
4253
4493
|
cpSync(extractedMindDir, dest, { recursive: true });
|
|
4254
4494
|
if (!manifest.includes.identity) {
|
|
@@ -4256,9 +4496,9 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4256
4496
|
}
|
|
4257
4497
|
const state = stateDir(name);
|
|
4258
4498
|
mkdirSync6(state, { recursive: true });
|
|
4259
|
-
const envJson =
|
|
4260
|
-
if (
|
|
4261
|
-
cpSync(envJson,
|
|
4499
|
+
const envJson = resolve11(tempDir, "state/env.json");
|
|
4500
|
+
if (existsSync8(envJson)) {
|
|
4501
|
+
cpSync(envJson, resolve11(state, "env.json"));
|
|
4262
4502
|
}
|
|
4263
4503
|
const port = await nextPort();
|
|
4264
4504
|
await addMind(name, port, manifest.stage, manifest.template);
|
|
@@ -4267,30 +4507,30 @@ async function importFromFullArchive(c, tempDir, extractedMindDir, nameOverride,
|
|
|
4267
4507
|
} catch (err) {
|
|
4268
4508
|
logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
|
|
4269
4509
|
}
|
|
4270
|
-
const homeDir =
|
|
4510
|
+
const homeDir = resolve11(dest, "home");
|
|
4271
4511
|
ensureVoluteGroup();
|
|
4272
4512
|
createMindUser(name, homeDir);
|
|
4273
4513
|
await chownMindDir(dest, name);
|
|
4274
4514
|
await npmInstallAsMind(dest, name);
|
|
4275
4515
|
await importHistoryFromArchive(name, tempDir);
|
|
4276
4516
|
importSessionsFromArchive(dest, tempDir);
|
|
4277
|
-
if (!
|
|
4517
|
+
if (!existsSync8(resolve11(dest, ".git"))) {
|
|
4278
4518
|
try {
|
|
4279
|
-
const env = isIsolationEnabled() ? { ...process.env, HOME:
|
|
4519
|
+
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
|
|
4280
4520
|
await gitExec(["init"], { cwd: dest, mindName: name, env });
|
|
4281
4521
|
await configureGitIdentity(name, { cwd: dest, mindName: name, env });
|
|
4282
4522
|
await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
|
|
4283
4523
|
await gitExec(["commit", "-m", "import from archive"], { cwd: dest, mindName: name, env });
|
|
4284
4524
|
} catch (err) {
|
|
4285
4525
|
logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
|
|
4286
|
-
rmSync4(
|
|
4526
|
+
rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
|
|
4287
4527
|
}
|
|
4288
4528
|
}
|
|
4289
4529
|
await chownMindDir(dest, name);
|
|
4290
4530
|
rmSync4(tempDir, { recursive: true, force: true });
|
|
4291
4531
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
4292
4532
|
} catch (err) {
|
|
4293
|
-
if (
|
|
4533
|
+
if (existsSync8(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4294
4534
|
try {
|
|
4295
4535
|
await removeMind(name);
|
|
4296
4536
|
} catch (cleanupErr) {
|
|
@@ -4307,7 +4547,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4307
4547
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
4308
4548
|
ensureVoluteHome();
|
|
4309
4549
|
const dest = mindDir(name);
|
|
4310
|
-
if (
|
|
4550
|
+
if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4311
4551
|
const templatesRoot = findTemplatesRoot();
|
|
4312
4552
|
const { composedDir, manifest: templateManifest } = composeTemplate(
|
|
4313
4553
|
templatesRoot,
|
|
@@ -4316,36 +4556,36 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4316
4556
|
try {
|
|
4317
4557
|
copyTemplateToDir(composedDir, dest, name, templateManifest);
|
|
4318
4558
|
applyInitFiles(dest);
|
|
4319
|
-
const extractedHome =
|
|
4320
|
-
if (
|
|
4321
|
-
cpSync(extractedHome,
|
|
4559
|
+
const extractedHome = resolve11(extractedMindDir, "home");
|
|
4560
|
+
if (existsSync8(extractedHome)) {
|
|
4561
|
+
cpSync(extractedHome, resolve11(dest, "home"), { recursive: true });
|
|
4322
4562
|
}
|
|
4323
|
-
const extractedMindInternal =
|
|
4324
|
-
if (
|
|
4325
|
-
cpSync(extractedMindInternal,
|
|
4563
|
+
const extractedMindInternal = resolve11(extractedMindDir, ".mind");
|
|
4564
|
+
if (existsSync8(extractedMindInternal)) {
|
|
4565
|
+
cpSync(extractedMindInternal, resolve11(dest, ".mind"), { recursive: true });
|
|
4326
4566
|
}
|
|
4327
|
-
const identityDir =
|
|
4567
|
+
const identityDir = resolve11(dest, ".mind/identity");
|
|
4328
4568
|
let publicKeyPem;
|
|
4329
|
-
if (!manifest.includes.identity || !
|
|
4569
|
+
if (!manifest.includes.identity || !existsSync8(resolve11(identityDir, "private.pem"))) {
|
|
4330
4570
|
({ publicKeyPem } = generateIdentity(dest));
|
|
4331
4571
|
} else {
|
|
4332
|
-
publicKeyPem =
|
|
4572
|
+
publicKeyPem = readFileSync9(resolve11(identityDir, "public.pem"), "utf-8");
|
|
4333
4573
|
}
|
|
4334
|
-
const promptsPath =
|
|
4335
|
-
if (!
|
|
4574
|
+
const promptsPath = resolve11(dest, "home/.config/prompts.json");
|
|
4575
|
+
if (!existsSync8(promptsPath)) {
|
|
4336
4576
|
const mindPrompts = await getMindPromptDefaults();
|
|
4337
|
-
|
|
4577
|
+
writeFileSync8(promptsPath, `${JSON.stringify(mindPrompts, null, 2)}
|
|
4338
4578
|
`);
|
|
4339
4579
|
}
|
|
4340
4580
|
const state = stateDir(name);
|
|
4341
4581
|
mkdirSync6(state, { recursive: true });
|
|
4342
|
-
const envJson =
|
|
4343
|
-
if (
|
|
4344
|
-
cpSync(envJson,
|
|
4582
|
+
const envJson = resolve11(tempDir, "state/env.json");
|
|
4583
|
+
if (existsSync8(envJson)) {
|
|
4584
|
+
cpSync(envJson, resolve11(state, "env.json"));
|
|
4345
4585
|
}
|
|
4346
4586
|
const port = await nextPort();
|
|
4347
4587
|
await addMind(name, port, manifest.stage, manifest.template);
|
|
4348
|
-
const homeDir =
|
|
4588
|
+
const homeDir = resolve11(dest, "home");
|
|
4349
4589
|
ensureVoluteGroup();
|
|
4350
4590
|
createMindUser(name, homeDir);
|
|
4351
4591
|
await chownMindDir(dest, name);
|
|
@@ -4358,7 +4598,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4358
4598
|
await initTemplateBranch(dest, composedDir, templateManifest, name, env);
|
|
4359
4599
|
} catch (err) {
|
|
4360
4600
|
logger_default.error(`git setup failed for imported mind ${name}`, logger_default.errorData(err));
|
|
4361
|
-
rmSync4(
|
|
4601
|
+
rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
|
|
4362
4602
|
gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
|
|
4363
4603
|
}
|
|
4364
4604
|
const skillSet = manifest.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions();
|
|
@@ -4388,7 +4628,7 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4388
4628
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
4389
4629
|
});
|
|
4390
4630
|
} catch (err) {
|
|
4391
|
-
if (
|
|
4631
|
+
if (existsSync8(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4392
4632
|
try {
|
|
4393
4633
|
await removeMind(name);
|
|
4394
4634
|
} catch (cleanupErr) {
|
|
@@ -4401,11 +4641,11 @@ async function importFromHomeOnlyArchive(c, tempDir, extractedMindDir, nameOverr
|
|
|
4401
4641
|
}
|
|
4402
4642
|
}
|
|
4403
4643
|
async function importHistoryFromArchive(name, tempDir) {
|
|
4404
|
-
const historyJsonl =
|
|
4405
|
-
if (!
|
|
4644
|
+
const historyJsonl = resolve11(tempDir, "history.jsonl");
|
|
4645
|
+
if (!existsSync8(historyJsonl)) return;
|
|
4406
4646
|
try {
|
|
4407
4647
|
const db = await getDb();
|
|
4408
|
-
const lines =
|
|
4648
|
+
const lines = readFileSync9(historyJsonl, "utf-8").trim().split("\n");
|
|
4409
4649
|
let imported = 0;
|
|
4410
4650
|
let failed = 0;
|
|
4411
4651
|
for (const line of lines) {
|
|
@@ -4441,13 +4681,13 @@ async function importHistoryFromArchive(name, tempDir) {
|
|
|
4441
4681
|
}
|
|
4442
4682
|
}
|
|
4443
4683
|
function importSessionsFromArchive(dest, tempDir) {
|
|
4444
|
-
const sessionsDir =
|
|
4445
|
-
if (!
|
|
4684
|
+
const sessionsDir = resolve11(tempDir, "sessions");
|
|
4685
|
+
if (!existsSync8(sessionsDir)) return;
|
|
4446
4686
|
try {
|
|
4447
|
-
const destSessions =
|
|
4687
|
+
const destSessions = resolve11(dest, ".mind/sessions");
|
|
4448
4688
|
mkdirSync6(destSessions, { recursive: true });
|
|
4449
4689
|
for (const file of readdirSync2(sessionsDir)) {
|
|
4450
|
-
cpSync(
|
|
4690
|
+
cpSync(resolve11(sessionsDir, file), resolve11(destSessions, file));
|
|
4451
4691
|
}
|
|
4452
4692
|
} catch (err) {
|
|
4453
4693
|
logger_default.error("Failed to import sessions from archive", logger_default.errorData(err));
|
|
@@ -4514,15 +4754,16 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
4514
4754
|
if (await findMind(name)) return c.json({ error: `Mind already exists: ${name}` }, 409);
|
|
4515
4755
|
ensureVoluteHome();
|
|
4516
4756
|
const dest = mindDir(name);
|
|
4517
|
-
if (
|
|
4757
|
+
if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4518
4758
|
const templatesRoot = findTemplatesRoot();
|
|
4519
4759
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
4520
4760
|
try {
|
|
4521
4761
|
copyTemplateToDir(composedDir, dest, name, manifest);
|
|
4522
4762
|
applyInitFiles(dest);
|
|
4523
4763
|
const { publicKeyPem } = generateIdentity(dest);
|
|
4764
|
+
let effectiveModel = body.model;
|
|
4524
4765
|
{
|
|
4525
|
-
const { readGlobalConfig: readGlobal } = await import("./setup-
|
|
4766
|
+
const { readGlobalConfig: readGlobal } = await import("./setup-5ECWTYKG.js");
|
|
4526
4767
|
const mindDefaults = readGlobal().mindDefaults;
|
|
4527
4768
|
const config2 = readVoluteConfig(dest);
|
|
4528
4769
|
if (!config2) throw new Error("Failed to read volute.json after identity generation");
|
|
@@ -4536,22 +4777,12 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
4536
4777
|
};
|
|
4537
4778
|
}
|
|
4538
4779
|
if (!config2.schedules || config2.schedules.length === 0) {
|
|
4539
|
-
config2.schedules = mindDefaults?.schedules ?? [
|
|
4540
|
-
{
|
|
4541
|
-
id: "heartbeat",
|
|
4542
|
-
cron: "0 12,16,20 * * *",
|
|
4543
|
-
message: "A quiet moment. You might write something \u2014 a note, a journal entry, a page. You could explore a topic that interests you, check in on #system, or just think. No obligations, just time.",
|
|
4544
|
-
enabled: true,
|
|
4545
|
-
whileSleeping: "skip"
|
|
4546
|
-
}
|
|
4547
|
-
];
|
|
4780
|
+
config2.schedules = mindDefaults?.schedules ?? [defaultHeartbeatSchedule()];
|
|
4548
4781
|
}
|
|
4549
4782
|
const cog = mindDefaults?.cognition;
|
|
4550
4783
|
if (cog) {
|
|
4551
4784
|
if (cog.thinkingLevel != null && !config2.thinkingLevel)
|
|
4552
4785
|
config2.thinkingLevel = cog.thinkingLevel;
|
|
4553
|
-
if (cog.maxThinkingTokens != null && config2.maxThinkingTokens == null)
|
|
4554
|
-
config2.maxThinkingTokens = cog.maxThinkingTokens;
|
|
4555
4786
|
if (cog.tokenBudget != null && config2.tokenBudget == null)
|
|
4556
4787
|
config2.tokenBudget = cog.tokenBudget;
|
|
4557
4788
|
if (cog.tokenBudgetPeriodMinutes != null && config2.tokenBudgetPeriodMinutes == null)
|
|
@@ -4559,22 +4790,23 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
4559
4790
|
}
|
|
4560
4791
|
writeVoluteConfig(dest, config2);
|
|
4561
4792
|
const modelId = body.model ?? cog?.model;
|
|
4562
|
-
|
|
4793
|
+
effectiveModel = modelId ? qualifyModelId(modelId) : void 0;
|
|
4794
|
+
const sdkConfigPath = resolve11(dest, "home/.config/config.json");
|
|
4563
4795
|
if (modelId || cog?.compaction) {
|
|
4564
|
-
const existing =
|
|
4796
|
+
const existing = existsSync8(sdkConfigPath) ? JSON.parse(readFileSync9(sdkConfigPath, "utf-8")) : {};
|
|
4565
4797
|
if (modelId) {
|
|
4566
4798
|
existing.model = template === "pi" ? qualifyModelId(modelId) : unqualifyModelId(modelId);
|
|
4567
4799
|
}
|
|
4568
4800
|
if (cog?.compaction && !existing.compaction) {
|
|
4569
4801
|
existing.compaction = cog.compaction;
|
|
4570
4802
|
}
|
|
4571
|
-
|
|
4803
|
+
writeFileSync8(sdkConfigPath, `${JSON.stringify(existing, null, 2)}
|
|
4572
4804
|
`);
|
|
4573
4805
|
}
|
|
4574
4806
|
}
|
|
4575
4807
|
const mindPrompts = await getMindPromptDefaults();
|
|
4576
|
-
|
|
4577
|
-
|
|
4808
|
+
writeFileSync8(
|
|
4809
|
+
resolve11(dest, "home/.config/prompts.json"),
|
|
4578
4810
|
`${JSON.stringify(mindPrompts, null, 2)}
|
|
4579
4811
|
`
|
|
4580
4812
|
);
|
|
@@ -4586,7 +4818,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
4586
4818
|
} catch (err) {
|
|
4587
4819
|
logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
|
|
4588
4820
|
}
|
|
4589
|
-
const homeDir =
|
|
4821
|
+
const homeDir = resolve11(dest, "home");
|
|
4590
4822
|
ensureVoluteGroup();
|
|
4591
4823
|
createMindUser(name, homeDir);
|
|
4592
4824
|
await chownMindDir(dest, name);
|
|
@@ -4599,7 +4831,7 @@ var app13 = new Hono16().post("/", requireAdminOrSystem, zValidator6("json", cre
|
|
|
4599
4831
|
await initTemplateBranch(dest, composedDir, manifest, name, env);
|
|
4600
4832
|
} catch (err) {
|
|
4601
4833
|
logger_default.error(`git setup failed for ${name}`, logger_default.errorData(err));
|
|
4602
|
-
rmSync4(
|
|
4834
|
+
rmSync4(resolve11(dest, ".git"), { recursive: true, force: true });
|
|
4603
4835
|
gitWarning = "Git setup failed \u2014 variants and upgrades won't be available until git is initialized.";
|
|
4604
4836
|
}
|
|
4605
4837
|
if (body.stage === "seed") {
|
|
@@ -4608,11 +4840,11 @@ Your creator described you as: "${body.description}"
|
|
|
4608
4840
|
` : "";
|
|
4609
4841
|
const seedSoulRaw = body.seedSoul ?? await getPrompt("seed_soul", { name, description: descLine });
|
|
4610
4842
|
const seedSoul = body.seedSoul ? substitute(seedSoulRaw, { name, description: descLine }) : seedSoulRaw;
|
|
4611
|
-
|
|
4843
|
+
writeFileSync8(resolve11(dest, "home/SOUL.md"), seedSoul);
|
|
4612
4844
|
}
|
|
4613
4845
|
let skillSet = body.skills ?? (body.stage === "seed" ? SEED_SKILLS : getStandardSkillsWithExtensions());
|
|
4614
4846
|
if (body.stage === "seed" && !body.skills) {
|
|
4615
|
-
const { isImagegenEnabled } = await import("./setup-
|
|
4847
|
+
const { isImagegenEnabled } = await import("./setup-5ECWTYKG.js");
|
|
4616
4848
|
if (isImagegenEnabled()) {
|
|
4617
4849
|
skillSet = [...skillSet, "imagegen"];
|
|
4618
4850
|
}
|
|
@@ -4626,11 +4858,14 @@ Your creator described you as: "${body.description}"
|
|
|
4626
4858
|
skillWarnings.push(`Failed to install skill: ${skillId}`);
|
|
4627
4859
|
}
|
|
4628
4860
|
}
|
|
4861
|
+
if (body.stage !== "seed") {
|
|
4862
|
+
skillWarnings.push(...setupDefaultDreaming(dest).warnings);
|
|
4863
|
+
}
|
|
4629
4864
|
if (body.stage === "seed") {
|
|
4630
4865
|
try {
|
|
4631
4866
|
const spiritEntry = await findMind("volute");
|
|
4632
4867
|
if (spiritEntry) {
|
|
4633
|
-
const { spiritDir } = await import("./spirit-
|
|
4868
|
+
const { spiritDir } = await import("./spirit-WXS3HCLN.js");
|
|
4634
4869
|
const sDir = spiritEntry.dir ?? spiritDir();
|
|
4635
4870
|
const spiritConfig = readVoluteConfig(sDir) ?? {};
|
|
4636
4871
|
const schedules = spiritConfig.schedules ?? [];
|
|
@@ -4645,7 +4880,7 @@ Your creator described you as: "${body.description}"
|
|
|
4645
4880
|
});
|
|
4646
4881
|
spiritConfig.schedules = schedules;
|
|
4647
4882
|
writeVoluteConfig(sDir, spiritConfig);
|
|
4648
|
-
const { getScheduler: getScheduler2 } = await import("./scheduler-
|
|
4883
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-I7JZCT47.js");
|
|
4649
4884
|
getScheduler2().loadSchedules("volute", sDir);
|
|
4650
4885
|
}
|
|
4651
4886
|
}
|
|
@@ -4656,11 +4891,11 @@ Your creator described you as: "${body.description}"
|
|
|
4656
4891
|
if (body.stage !== "seed") {
|
|
4657
4892
|
const customSoul = await getPromptIfCustom("default_soul");
|
|
4658
4893
|
if (customSoul) {
|
|
4659
|
-
|
|
4894
|
+
writeFileSync8(resolve11(dest, "home/SOUL.md"), customSoul.replace(/\{\{name\}\}/g, name));
|
|
4660
4895
|
}
|
|
4661
4896
|
const customMemory = await getPromptIfCustom("default_memory");
|
|
4662
4897
|
if (customMemory) {
|
|
4663
|
-
|
|
4898
|
+
writeFileSync8(resolve11(dest, "home/MEMORY.md"), customMemory);
|
|
4664
4899
|
}
|
|
4665
4900
|
}
|
|
4666
4901
|
await chownMindDir(dest, name);
|
|
@@ -4680,6 +4915,14 @@ Your creator described you as: "${body.description}"
|
|
|
4680
4915
|
});
|
|
4681
4916
|
announceToSystem(`${name} has joined`).catch(() => {
|
|
4682
4917
|
});
|
|
4918
|
+
const credentialWarning = await missingCredentialWarning(
|
|
4919
|
+
template,
|
|
4920
|
+
effectiveModel,
|
|
4921
|
+
name
|
|
4922
|
+
).catch((err) => {
|
|
4923
|
+
logger_default.warn(`credential check failed for ${name}`, logger_default.errorData(err));
|
|
4924
|
+
return null;
|
|
4925
|
+
});
|
|
4683
4926
|
return c.json({
|
|
4684
4927
|
ok: true,
|
|
4685
4928
|
name,
|
|
@@ -4687,10 +4930,11 @@ Your creator described you as: "${body.description}"
|
|
|
4687
4930
|
stage: body.stage ?? "sprouted",
|
|
4688
4931
|
message: `Created mind: ${name} (port ${port})`,
|
|
4689
4932
|
...gitWarning && { warning: gitWarning },
|
|
4933
|
+
...credentialWarning && { credentialWarning },
|
|
4690
4934
|
...skillWarnings.length > 0 && { skillWarnings }
|
|
4691
4935
|
});
|
|
4692
4936
|
} catch (err) {
|
|
4693
|
-
if (
|
|
4937
|
+
if (existsSync8(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4694
4938
|
try {
|
|
4695
4939
|
await removeMind(name);
|
|
4696
4940
|
} catch {
|
|
@@ -4710,13 +4954,13 @@ Your creator described you as: "${body.description}"
|
|
|
4710
4954
|
return importFromArchive(c, body.archivePath, body.name, body.manifest);
|
|
4711
4955
|
}
|
|
4712
4956
|
const wsDir = body.workspacePath;
|
|
4713
|
-
if (!wsDir || !
|
|
4957
|
+
if (!wsDir || !existsSync8(resolve11(wsDir, "SOUL.md")) || !existsSync8(resolve11(wsDir, "IDENTITY.md"))) {
|
|
4714
4958
|
return c.json({ error: "Invalid workspace: missing SOUL.md or IDENTITY.md" }, 400);
|
|
4715
4959
|
}
|
|
4716
|
-
const soul =
|
|
4717
|
-
const identity =
|
|
4718
|
-
const userPath =
|
|
4719
|
-
const user =
|
|
4960
|
+
const soul = readFileSync9(resolve11(wsDir, "SOUL.md"), "utf-8");
|
|
4961
|
+
const identity = readFileSync9(resolve11(wsDir, "IDENTITY.md"), "utf-8");
|
|
4962
|
+
const userPath = resolve11(wsDir, "USER.md");
|
|
4963
|
+
const user = existsSync8(userPath) ? readFileSync9(userPath, "utf-8") : "";
|
|
4720
4964
|
const name = body.name ?? parseNameFromIdentity(identity) ?? "imported-mind";
|
|
4721
4965
|
const template = body.template ?? "claude";
|
|
4722
4966
|
const nameErr = validateMindName(name);
|
|
@@ -4736,33 +4980,33 @@ ${user.trimEnd()}
|
|
|
4736
4980
|
` : "";
|
|
4737
4981
|
ensureVoluteHome();
|
|
4738
4982
|
const dest = mindDir(name);
|
|
4739
|
-
if (
|
|
4983
|
+
if (existsSync8(dest)) return c.json({ error: "Mind directory already exists" }, 409);
|
|
4740
4984
|
const templatesRoot = findTemplatesRoot();
|
|
4741
4985
|
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
4742
4986
|
try {
|
|
4743
4987
|
copyTemplateToDir(composedDir, dest, name, manifest);
|
|
4744
4988
|
applyInitFiles(dest);
|
|
4745
4989
|
const { publicKeyPem: importPublicKey } = generateIdentity(dest);
|
|
4746
|
-
|
|
4747
|
-
const wsMemoryPath =
|
|
4748
|
-
const hasMemory =
|
|
4990
|
+
writeFileSync8(resolve11(dest, "home/SOUL.md"), mergedSoul);
|
|
4991
|
+
const wsMemoryPath = resolve11(wsDir, "MEMORY.md");
|
|
4992
|
+
const hasMemory = existsSync8(wsMemoryPath);
|
|
4749
4993
|
if (hasMemory) {
|
|
4750
|
-
const existingMemory =
|
|
4751
|
-
|
|
4752
|
-
|
|
4994
|
+
const existingMemory = readFileSync9(wsMemoryPath, "utf-8");
|
|
4995
|
+
writeFileSync8(
|
|
4996
|
+
resolve11(dest, "home/MEMORY.md"),
|
|
4753
4997
|
`${existingMemory.trimEnd()}${mergedMemoryExtra}`
|
|
4754
4998
|
);
|
|
4755
4999
|
} else if (user) {
|
|
4756
|
-
|
|
5000
|
+
writeFileSync8(resolve11(dest, "home/MEMORY.md"), `${user.trimEnd()}
|
|
4757
5001
|
`);
|
|
4758
5002
|
}
|
|
4759
|
-
const wsMemoryDir =
|
|
5003
|
+
const wsMemoryDir = resolve11(wsDir, "memory");
|
|
4760
5004
|
let dailyLogCount = 0;
|
|
4761
|
-
if (
|
|
4762
|
-
const destMemoryDir =
|
|
5005
|
+
if (existsSync8(wsMemoryDir)) {
|
|
5006
|
+
const destMemoryDir = resolve11(dest, "home/memory");
|
|
4763
5007
|
const files = readdirSync2(wsMemoryDir).filter((f) => f.endsWith(".md"));
|
|
4764
5008
|
for (const file of files) {
|
|
4765
|
-
cpSync(
|
|
5009
|
+
cpSync(resolve11(wsMemoryDir, file), resolve11(destMemoryDir, file));
|
|
4766
5010
|
}
|
|
4767
5011
|
dailyLogCount = files.length;
|
|
4768
5012
|
}
|
|
@@ -4773,7 +5017,7 @@ ${user.trimEnd()}
|
|
|
4773
5017
|
} catch (err) {
|
|
4774
5018
|
logger_default.warn(`failed to set template hash for ${name}`, logger_default.errorData(err));
|
|
4775
5019
|
}
|
|
4776
|
-
const homeDir =
|
|
5020
|
+
const homeDir = resolve11(dest, "home");
|
|
4777
5021
|
ensureVoluteGroup();
|
|
4778
5022
|
createMindUser(name, homeDir);
|
|
4779
5023
|
await chownMindDir(dest, name);
|
|
@@ -4781,20 +5025,20 @@ ${user.trimEnd()}
|
|
|
4781
5025
|
if (!hasMemory && dailyLogCount > 0) {
|
|
4782
5026
|
await consolidateMemory(dest);
|
|
4783
5027
|
}
|
|
4784
|
-
const env = isIsolationEnabled() ? { ...process.env, HOME:
|
|
5028
|
+
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dest, "home") } : void 0;
|
|
4785
5029
|
await gitExec(["init"], { cwd: dest, mindName: name, env });
|
|
4786
5030
|
await configureGitIdentity(name, { cwd: dest, mindName: name, env });
|
|
4787
5031
|
await gitExec(["add", "-A"], { cwd: dest, mindName: name, env });
|
|
4788
5032
|
await gitExec(["commit", "-m", "import from OpenClaw"], { cwd: dest, mindName: name, env });
|
|
4789
|
-
const sessionFile = body.sessionPath ?
|
|
4790
|
-
if (sessionFile &&
|
|
5033
|
+
const sessionFile = body.sessionPath ? resolve11(body.sessionPath) : findOpenClawSession(wsDir);
|
|
5034
|
+
if (sessionFile && existsSync8(sessionFile)) {
|
|
4791
5035
|
if (template === "pi") {
|
|
4792
5036
|
importPiSession(sessionFile, dest);
|
|
4793
5037
|
} else if (template === "claude") {
|
|
4794
5038
|
const sessionId = convertSession({ sessionPath: sessionFile, projectDir: dest });
|
|
4795
|
-
const mindRuntimeDir =
|
|
5039
|
+
const mindRuntimeDir = resolve11(dest, ".mind");
|
|
4796
5040
|
mkdirSync6(mindRuntimeDir, { recursive: true });
|
|
4797
|
-
|
|
5041
|
+
writeFileSync8(resolve11(mindRuntimeDir, "session.json"), JSON.stringify({ sessionId }));
|
|
4798
5042
|
}
|
|
4799
5043
|
}
|
|
4800
5044
|
importOpenClawConnectors(name, dest);
|
|
@@ -4804,7 +5048,7 @@ ${user.trimEnd()}
|
|
|
4804
5048
|
);
|
|
4805
5049
|
return c.json({ ok: true, name, port, message: `Imported mind: ${name} (port ${port})` });
|
|
4806
5050
|
} catch (err) {
|
|
4807
|
-
if (
|
|
5051
|
+
if (existsSync8(dest)) rmSync4(dest, { recursive: true, force: true });
|
|
4808
5052
|
try {
|
|
4809
5053
|
await removeMind(name);
|
|
4810
5054
|
} catch {
|
|
@@ -4832,15 +5076,19 @@ ${user.trimEnd()}
|
|
|
4832
5076
|
} catch {
|
|
4833
5077
|
}
|
|
4834
5078
|
}
|
|
5079
|
+
const privileged = isPrivileged(c);
|
|
4835
5080
|
const minds = await Promise.all(
|
|
4836
5081
|
entries.map(async (entry) => {
|
|
4837
5082
|
const mindStatus = await getMindStatus(entry.name, entry.port, entry.running);
|
|
4838
|
-
const hasPages =
|
|
5083
|
+
const hasPages = existsSync8(resolve11(mindDir(entry.name), "home", "pages"));
|
|
5084
|
+
const lastActiveAt = lastActiveMap.get(entry.name) ?? null;
|
|
5085
|
+
if (!privileged) return toPublicMind(entry, mindStatus, { hasPages, lastActiveAt });
|
|
4839
5086
|
return {
|
|
4840
5087
|
...entry,
|
|
4841
5088
|
...mindStatus,
|
|
4842
5089
|
hasPages,
|
|
4843
|
-
|
|
5090
|
+
templateStale: isTemplateStale(entry),
|
|
5091
|
+
lastActiveAt
|
|
4844
5092
|
};
|
|
4845
5093
|
})
|
|
4846
5094
|
);
|
|
@@ -4850,8 +5098,12 @@ ${user.trimEnd()}
|
|
|
4850
5098
|
const entry = await findMind(name);
|
|
4851
5099
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4852
5100
|
const dir = entry.dir ?? mindDir(entry.parent ?? name);
|
|
4853
|
-
if (!
|
|
5101
|
+
if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4854
5102
|
const mindStatus = await getMindStatus(name, entry.port);
|
|
5103
|
+
const hasPages = existsSync8(resolve11(mindDir(name), "home", "pages"));
|
|
5104
|
+
if (!isPrivileged(c)) {
|
|
5105
|
+
return c.json(toPublicMind(entry, mindStatus, { hasPages }));
|
|
5106
|
+
}
|
|
4855
5107
|
const variants = await findVariants(name);
|
|
4856
5108
|
const manager = getMindManager();
|
|
4857
5109
|
const variantStatuses = await Promise.all(
|
|
@@ -4864,8 +5116,22 @@ ${user.trimEnd()}
|
|
|
4864
5116
|
return { name: s.name, port: s.port, status: variantStatus };
|
|
4865
5117
|
})
|
|
4866
5118
|
);
|
|
4867
|
-
const
|
|
4868
|
-
return c.json({
|
|
5119
|
+
const notice = await latestNotice(name);
|
|
5120
|
+
return c.json({
|
|
5121
|
+
...entry,
|
|
5122
|
+
...mindStatus,
|
|
5123
|
+
variants: variantStatuses,
|
|
5124
|
+
hasPages,
|
|
5125
|
+
templateStale: isTemplateStale(entry),
|
|
5126
|
+
...notice && {
|
|
5127
|
+
lastNotice: {
|
|
5128
|
+
kind: notice.kind,
|
|
5129
|
+
reason: notice.reason,
|
|
5130
|
+
detail: notice.detail,
|
|
5131
|
+
created_at: notice.created_at
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
});
|
|
4869
5135
|
}).get("/:name/context", requireSelf(), async (c) => proxyToMind(c, "context")).get("/:name/context/messages", requireSelf(), async (c) => proxyToMind(c, "context/messages")).post("/:name/start", requireSelf(), async (c) => {
|
|
4870
5136
|
const name = c.req.param("name");
|
|
4871
5137
|
const entry = await findMind(name);
|
|
@@ -4875,7 +5141,7 @@ ${user.trimEnd()}
|
|
|
4875
5141
|
if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
|
|
4876
5142
|
} else {
|
|
4877
5143
|
const dir = mindDir(name);
|
|
4878
|
-
if (!
|
|
5144
|
+
if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4879
5145
|
}
|
|
4880
5146
|
if (getMindManager().isRunning(name)) {
|
|
4881
5147
|
return c.json({ error: "Mind already running" }, 409);
|
|
@@ -4896,7 +5162,7 @@ ${user.trimEnd()}
|
|
|
4896
5162
|
if (!entry.dir) return c.json({ error: `Variant ${name} has no directory` }, 404);
|
|
4897
5163
|
} else {
|
|
4898
5164
|
const dir = mindDir(name);
|
|
4899
|
-
if (!
|
|
5165
|
+
if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
4900
5166
|
}
|
|
4901
5167
|
let context;
|
|
4902
5168
|
const contentType = c.req.header("content-type");
|
|
@@ -4911,7 +5177,7 @@ ${user.trimEnd()}
|
|
|
4911
5177
|
const manager = getMindManager();
|
|
4912
5178
|
try {
|
|
4913
5179
|
if (context?.type === "reload") {
|
|
4914
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5180
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
|
|
4915
5181
|
const sleepState = getSleepManagerIfReady2()?.getState(name);
|
|
4916
5182
|
if (sleepState?.sleeping) {
|
|
4917
5183
|
logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
|
|
@@ -4931,7 +5197,7 @@ ${user.trimEnd()}
|
|
|
4931
5197
|
const variantEntry = await findMind(mergeVariantName);
|
|
4932
5198
|
if (variantEntry && variantEntry.parent === baseName && variantEntry.dir && variantEntry.branch) {
|
|
4933
5199
|
const projectRoot = mindDir(baseName);
|
|
4934
|
-
if (
|
|
5200
|
+
if (existsSync8(variantEntry.dir)) {
|
|
4935
5201
|
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
4936
5202
|
if (status) {
|
|
4937
5203
|
try {
|
|
@@ -5038,7 +5304,7 @@ ${user.trimEnd()}
|
|
|
5038
5304
|
const name = c.req.param("name");
|
|
5039
5305
|
const entry = await findMind(name);
|
|
5040
5306
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5041
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5307
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
|
|
5042
5308
|
const sm = getSleepManagerIfReady2();
|
|
5043
5309
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5044
5310
|
return c.json(sm.getState(name));
|
|
@@ -5046,7 +5312,7 @@ ${user.trimEnd()}
|
|
|
5046
5312
|
const name = c.req.param("name");
|
|
5047
5313
|
const entry = await findMind(name);
|
|
5048
5314
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5049
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5315
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
|
|
5050
5316
|
const sm = getSleepManagerIfReady2();
|
|
5051
5317
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5052
5318
|
if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
|
|
@@ -5066,7 +5332,7 @@ ${user.trimEnd()}
|
|
|
5066
5332
|
const name = c.req.param("name");
|
|
5067
5333
|
const entry = await findMind(name);
|
|
5068
5334
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5069
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5335
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
|
|
5070
5336
|
const sm = getSleepManagerIfReady2();
|
|
5071
5337
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5072
5338
|
const sleepState = sm.getState(name);
|
|
@@ -5081,7 +5347,7 @@ ${user.trimEnd()}
|
|
|
5081
5347
|
const name = c.req.param("name");
|
|
5082
5348
|
const entry = await findMind(name);
|
|
5083
5349
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5084
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
5350
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-Z27R3WTW.js");
|
|
5085
5351
|
const sm = getSleepManagerIfReady2();
|
|
5086
5352
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
5087
5353
|
const flushed = await sm.flushQueuedMessages(name);
|
|
@@ -5097,19 +5363,19 @@ ${user.trimEnd()}
|
|
|
5097
5363
|
if (body.displayName !== void 0) profile.displayName = body.displayName;
|
|
5098
5364
|
if (body.description !== void 0) profile.description = body.description;
|
|
5099
5365
|
if (body.avatar !== void 0) {
|
|
5100
|
-
const homeDir =
|
|
5366
|
+
const homeDir = resolve11(dir, "home");
|
|
5101
5367
|
const avatarPath = safeResolveWithinBase(homeDir, body.avatar);
|
|
5102
5368
|
if (!avatarPath) {
|
|
5103
5369
|
return c.json({ error: "Avatar path must be inside the mind's home directory" }, 400);
|
|
5104
5370
|
}
|
|
5105
|
-
if (!
|
|
5371
|
+
if (!existsSync8(avatarPath)) {
|
|
5106
5372
|
return c.json({ error: `Avatar file not found: ${relative(homeDir, avatarPath)}` }, 400);
|
|
5107
5373
|
}
|
|
5108
5374
|
profile.avatar = relative(homeDir, avatarPath);
|
|
5109
5375
|
}
|
|
5110
5376
|
config2.profile = profile;
|
|
5111
5377
|
writeVoluteConfig(dir, config2);
|
|
5112
|
-
const { syncMindProfile: syncMindProfile2 } = await import("./auth-
|
|
5378
|
+
const { syncMindProfile: syncMindProfile2 } = await import("./auth-A4VGHADI.js");
|
|
5113
5379
|
await syncMindProfile2(name, profile);
|
|
5114
5380
|
broadcast({ type: "profile_updated", mind: name, summary: `${name} profile updated` });
|
|
5115
5381
|
return c.json({ ok: true });
|
|
@@ -5131,14 +5397,14 @@ ${user.trimEnd()}
|
|
|
5131
5397
|
sql3`${mindHistory.sender} != ${name}`,
|
|
5132
5398
|
sql3`${mindHistory.sender} IS NOT NULL`
|
|
5133
5399
|
)
|
|
5134
|
-
).orderBy(
|
|
5400
|
+
).orderBy(desc3(mindHistory.created_at)).limit(1);
|
|
5135
5401
|
const lastSpiritMsg = await db.select({ created_at: mindHistory.created_at }).from(mindHistory).where(
|
|
5136
5402
|
and5(
|
|
5137
5403
|
eq5(mindHistory.mind, name),
|
|
5138
5404
|
eq5(mindHistory.type, "inbound"),
|
|
5139
5405
|
eq5(mindHistory.sender, "volute")
|
|
5140
5406
|
)
|
|
5141
|
-
).orderBy(
|
|
5407
|
+
).orderBy(desc3(mindHistory.created_at)).limit(1);
|
|
5142
5408
|
const now = Date.now();
|
|
5143
5409
|
const creatorTime = lastCreatorMsg[0] ? new Date(lastCreatorMsg[0].created_at).getTime() : 0;
|
|
5144
5410
|
const spiritTime = lastSpiritMsg[0] ? new Date(lastSpiritMsg[0].created_at).getTime() : 0;
|
|
@@ -5148,25 +5414,18 @@ ${user.trimEnd()}
|
|
|
5148
5414
|
return c.json({ output: "" });
|
|
5149
5415
|
}
|
|
5150
5416
|
const dir = entry.dir ?? mindDir(name);
|
|
5151
|
-
const
|
|
5152
|
-
const
|
|
5153
|
-
const soulCustom = existsSync7(soulPath) && !readFileSync8(soulPath, "utf-8").includes(ORIENTATION_MARKER);
|
|
5154
|
-
const memoryWritten = existsSync7(memoryPath) && readFileSync8(memoryPath, "utf-8").trim().length > 0;
|
|
5155
|
-
const config2 = readVoluteConfig(dir);
|
|
5156
|
-
const displayNameSet = !!config2?.profile?.displayName;
|
|
5157
|
-
const avatarSet = !!config2?.profile?.avatar;
|
|
5158
|
-
const { isImagegenEnabled } = await import("./setup-Y2EJI3GG.js");
|
|
5159
|
-
const imagegenEnabled = isImagegenEnabled();
|
|
5417
|
+
const { evaluateSeedChecklist } = await import("./seed-readiness-RBPGOLSZ.js");
|
|
5418
|
+
const checklist = evaluateSeedChecklist(dir);
|
|
5160
5419
|
const done = [];
|
|
5161
5420
|
const remaining = [];
|
|
5162
|
-
if (
|
|
5421
|
+
if (checklist.soulWritten) done.push("SOUL.md written");
|
|
5163
5422
|
else remaining.push("Write SOUL.md");
|
|
5164
|
-
if (memoryWritten) done.push("MEMORY.md written");
|
|
5423
|
+
if (checklist.memoryWritten) done.push("MEMORY.md written");
|
|
5165
5424
|
else remaining.push("Write MEMORY.md");
|
|
5166
|
-
if (displayNameSet) done.push("Display name set");
|
|
5425
|
+
if (checklist.displayNameSet) done.push("Display name set");
|
|
5167
5426
|
else remaining.push("Set display name");
|
|
5168
|
-
if (imagegenEnabled) {
|
|
5169
|
-
if (avatarSet) done.push("Avatar set");
|
|
5427
|
+
if (checklist.imagegenEnabled) {
|
|
5428
|
+
if (checklist.avatarSet) done.push("Avatar set");
|
|
5170
5429
|
else remaining.push("Generate and set avatar");
|
|
5171
5430
|
}
|
|
5172
5431
|
const creatorStatus = minutesSinceCreator === Infinity ? "No creator messages yet" : `Last creator message: ${Math.round(minutesSinceCreator)} minutes ago`;
|
|
@@ -5190,23 +5449,48 @@ ${user.trimEnd()}
|
|
|
5190
5449
|
return c.json({ error: `Mind is not a seed (stage: ${entry.stage})` }, 409);
|
|
5191
5450
|
}
|
|
5192
5451
|
await setMindStage(name, "sprouted");
|
|
5452
|
+
try {
|
|
5453
|
+
const sproutedDir = entry.dir ?? mindDir(name);
|
|
5454
|
+
if (setupDefaultDreaming(sproutedDir).schedulesChanged) {
|
|
5455
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-I7JZCT47.js");
|
|
5456
|
+
getScheduler2().loadSchedules(name, sproutedDir);
|
|
5457
|
+
}
|
|
5458
|
+
} catch (err) {
|
|
5459
|
+
logger_default.warn(`failed to set up default dreaming for ${name}`, logger_default.errorData(err));
|
|
5460
|
+
}
|
|
5193
5461
|
try {
|
|
5194
5462
|
const spiritEntry = await findMind("volute");
|
|
5195
5463
|
if (spiritEntry) {
|
|
5196
|
-
const { spiritDir } = await import("./spirit-
|
|
5464
|
+
const { firstWeekSchedules, spiritDir } = await import("./spirit-WXS3HCLN.js");
|
|
5197
5465
|
const sDir = spiritEntry.dir ?? spiritDir();
|
|
5198
5466
|
const spiritConfig = readVoluteConfig(sDir);
|
|
5199
|
-
if (spiritConfig
|
|
5200
|
-
const
|
|
5201
|
-
|
|
5202
|
-
|
|
5467
|
+
if (spiritConfig) {
|
|
5468
|
+
const schedules = (spiritConfig.schedules ?? []).filter(
|
|
5469
|
+
(s) => s.id !== `nurture-${name}`
|
|
5470
|
+
);
|
|
5471
|
+
const existing = new Set(schedules.map((s) => s.id));
|
|
5472
|
+
schedules.push(
|
|
5473
|
+
...firstWeekSchedules(name, /* @__PURE__ */ new Date()).filter((s) => !existing.has(s.id))
|
|
5474
|
+
);
|
|
5475
|
+
spiritConfig.schedules = schedules;
|
|
5203
5476
|
writeVoluteConfig(sDir, spiritConfig);
|
|
5204
|
-
|
|
5205
|
-
|
|
5477
|
+
try {
|
|
5478
|
+
const { getScheduler: getScheduler2 } = await import("./scheduler-I7JZCT47.js");
|
|
5479
|
+
getScheduler2().loadSchedules("volute", sDir);
|
|
5480
|
+
} catch (err) {
|
|
5481
|
+
logger_default.warn(
|
|
5482
|
+
`spirit schedules for sprout of ${name} written to disk but not reloaded into the running scheduler (effective on next spirit restart)`,
|
|
5483
|
+
logger_default.errorData(err)
|
|
5484
|
+
);
|
|
5485
|
+
}
|
|
5486
|
+
} else {
|
|
5487
|
+
logger_default.warn(
|
|
5488
|
+
`spirit config at ${sDir} missing or unparseable \u2014 first-week arc for ${name} not scheduled, nurture-${name} not removed`
|
|
5489
|
+
);
|
|
5206
5490
|
}
|
|
5207
5491
|
}
|
|
5208
5492
|
} catch (err) {
|
|
5209
|
-
logger_default.warn(`failed to
|
|
5493
|
+
logger_default.warn(`failed to update spirit schedules for sprout of ${name}`, logger_default.errorData(err));
|
|
5210
5494
|
}
|
|
5211
5495
|
return c.json({ ok: true });
|
|
5212
5496
|
}).delete("/:name", requireAdmin, async (c) => {
|
|
@@ -5229,10 +5513,10 @@ ${user.trimEnd()}
|
|
|
5229
5513
|
await deleteMindUser2(name);
|
|
5230
5514
|
invalidateMindUserCache(name);
|
|
5231
5515
|
const state = stateDir(name);
|
|
5232
|
-
if (
|
|
5516
|
+
if (existsSync8(state)) {
|
|
5233
5517
|
rmSync4(state, { recursive: true, force: true });
|
|
5234
5518
|
}
|
|
5235
|
-
if (force &&
|
|
5519
|
+
if (force && existsSync8(dir)) {
|
|
5236
5520
|
rmSync4(dir, { recursive: true, force: true });
|
|
5237
5521
|
deleteMindUser(name);
|
|
5238
5522
|
}
|
|
@@ -5247,7 +5531,7 @@ ${user.trimEnd()}
|
|
|
5247
5531
|
const entry = await findMind(mindName);
|
|
5248
5532
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5249
5533
|
const dir = mindDir(mindName);
|
|
5250
|
-
if (!
|
|
5534
|
+
if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5251
5535
|
let body = {};
|
|
5252
5536
|
try {
|
|
5253
5537
|
body = await c.req.json();
|
|
@@ -5260,16 +5544,16 @@ ${user.trimEnd()}
|
|
|
5260
5544
|
}
|
|
5261
5545
|
const UPGRADE_BRANCH = "upgrade";
|
|
5262
5546
|
const upgradeVariantName = `${mindName}-upgrade`;
|
|
5263
|
-
const worktreeDir =
|
|
5547
|
+
const worktreeDir = resolve11(dir, ".variants", UPGRADE_BRANCH);
|
|
5264
5548
|
if (body.abort) {
|
|
5265
|
-
if (!
|
|
5549
|
+
if (!existsSync8(worktreeDir)) {
|
|
5266
5550
|
return c.json({ error: "No upgrade in progress" }, 400);
|
|
5267
5551
|
}
|
|
5268
5552
|
try {
|
|
5269
5553
|
try {
|
|
5270
|
-
const gitDirContent =
|
|
5554
|
+
const gitDirContent = readFileSync9(resolve11(worktreeDir, ".git"), "utf-8").trim();
|
|
5271
5555
|
const gitDir = gitDirContent.replace("gitdir: ", "");
|
|
5272
|
-
if (
|
|
5556
|
+
if (existsSync8(resolve11(gitDir, "MERGE_HEAD"))) {
|
|
5273
5557
|
await gitExec(["merge", "--abort"], { cwd: worktreeDir });
|
|
5274
5558
|
}
|
|
5275
5559
|
} catch {
|
|
@@ -5288,7 +5572,7 @@ ${user.trimEnd()}
|
|
|
5288
5572
|
}
|
|
5289
5573
|
}
|
|
5290
5574
|
if (body.continue) {
|
|
5291
|
-
if (!
|
|
5575
|
+
if (!existsSync8(worktreeDir)) {
|
|
5292
5576
|
return c.json({ error: "No upgrade in progress" }, 400);
|
|
5293
5577
|
}
|
|
5294
5578
|
const status = await gitExec(["status", "--porcelain"], { cwd: worktreeDir });
|
|
@@ -5338,7 +5622,7 @@ ${user.trimEnd()}
|
|
|
5338
5622
|
}
|
|
5339
5623
|
}
|
|
5340
5624
|
if (body.accept) {
|
|
5341
|
-
if (
|
|
5625
|
+
if (existsSync8(worktreeDir)) {
|
|
5342
5626
|
try {
|
|
5343
5627
|
await cleanupVariant(upgradeVariantName, dir, worktreeDir, { stop: true });
|
|
5344
5628
|
} catch (err) {
|
|
@@ -5353,7 +5637,7 @@ ${user.trimEnd()}
|
|
|
5353
5637
|
}
|
|
5354
5638
|
if (body.diff) {
|
|
5355
5639
|
try {
|
|
5356
|
-
if (!
|
|
5640
|
+
if (!existsSync8(resolve11(dir, ".git"))) {
|
|
5357
5641
|
return c.json({ error: "Mind has no git history \u2014 nothing to diff against" }, 400);
|
|
5358
5642
|
}
|
|
5359
5643
|
await updateTemplateBranch(dir, template, mindName);
|
|
@@ -5371,22 +5655,22 @@ ${user.trimEnd()}
|
|
|
5371
5655
|
);
|
|
5372
5656
|
}
|
|
5373
5657
|
}
|
|
5374
|
-
if (
|
|
5658
|
+
if (existsSync8(worktreeDir)) {
|
|
5375
5659
|
return c.json(
|
|
5376
5660
|
{ error: "Upgrade variant already exists. Use continue or delete it first." },
|
|
5377
5661
|
409
|
|
5378
5662
|
);
|
|
5379
5663
|
}
|
|
5380
|
-
if (!
|
|
5664
|
+
if (!existsSync8(resolve11(dir, ".git"))) {
|
|
5381
5665
|
try {
|
|
5382
|
-
const env = isIsolationEnabled() ? { ...process.env, HOME:
|
|
5666
|
+
const env = isIsolationEnabled() ? { ...process.env, HOME: resolve11(dir, "home") } : void 0;
|
|
5383
5667
|
await gitExec(["init"], { cwd: dir, mindName, env });
|
|
5384
5668
|
await configureGitIdentity(mindName, { cwd: dir, mindName, env });
|
|
5385
5669
|
await gitExec(["add", "-A"], { cwd: dir, mindName, env });
|
|
5386
5670
|
await gitExec(["commit", "-m", "initial commit"], { cwd: dir, mindName, env });
|
|
5387
5671
|
await chownMindDir(dir, mindName);
|
|
5388
5672
|
} catch (err) {
|
|
5389
|
-
rmSync4(
|
|
5673
|
+
rmSync4(resolve11(dir, ".git"), { recursive: true, force: true });
|
|
5390
5674
|
return c.json(
|
|
5391
5675
|
{
|
|
5392
5676
|
error: `Git initialization failed: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -5401,8 +5685,8 @@ ${user.trimEnd()}
|
|
|
5401
5685
|
} catch {
|
|
5402
5686
|
}
|
|
5403
5687
|
await updateTemplateBranch(dir, template, mindName);
|
|
5404
|
-
const parentDir =
|
|
5405
|
-
if (!
|
|
5688
|
+
const parentDir = resolve11(dir, ".variants");
|
|
5689
|
+
if (!existsSync8(parentDir)) {
|
|
5406
5690
|
mkdirSync6(parentDir, { recursive: true });
|
|
5407
5691
|
}
|
|
5408
5692
|
await gitExec(["worktree", "add", "-b", UPGRADE_BRANCH, worktreeDir], { cwd: dir });
|
|
@@ -5532,22 +5816,22 @@ ${user.trimEnd()}
|
|
|
5532
5816
|
const entry = await findMind(name);
|
|
5533
5817
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5534
5818
|
const dir = entry.dir ?? mindDir(name);
|
|
5535
|
-
if (!
|
|
5819
|
+
if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5536
5820
|
let config2 = readVoluteConfig(dir);
|
|
5537
5821
|
if (!config2 && entry.template === "pi") {
|
|
5538
|
-
const piConfigPath =
|
|
5539
|
-
if (
|
|
5822
|
+
const piConfigPath = resolve11(dir, "home/.config/config.json");
|
|
5823
|
+
if (existsSync8(piConfigPath)) {
|
|
5540
5824
|
try {
|
|
5541
|
-
config2 = JSON.parse(
|
|
5825
|
+
config2 = JSON.parse(readFileSync9(piConfigPath, "utf-8"));
|
|
5542
5826
|
} catch {
|
|
5543
5827
|
}
|
|
5544
5828
|
}
|
|
5545
5829
|
}
|
|
5546
5830
|
let templateConfig = {};
|
|
5547
|
-
const configJsonPath =
|
|
5548
|
-
if (
|
|
5831
|
+
const configJsonPath = resolve11(dir, "home/.config/config.json");
|
|
5832
|
+
if (existsSync8(configJsonPath)) {
|
|
5549
5833
|
try {
|
|
5550
|
-
templateConfig = JSON.parse(
|
|
5834
|
+
templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
|
|
5551
5835
|
} catch {
|
|
5552
5836
|
}
|
|
5553
5837
|
}
|
|
@@ -5561,22 +5845,7 @@ ${user.trimEnd()}
|
|
|
5561
5845
|
},
|
|
5562
5846
|
config: {
|
|
5563
5847
|
model: config2?.model ?? templateConfig.model ?? null,
|
|
5564
|
-
thinkingLevel: (
|
|
5565
|
-
if (config2?.thinkingLevel) return config2.thinkingLevel;
|
|
5566
|
-
const tc = templateConfig;
|
|
5567
|
-
if (tc.thinkingLevel) return tc.thinkingLevel;
|
|
5568
|
-
if (tc.reasoningEffort) return tc.reasoningEffort;
|
|
5569
|
-
const mtt = tc.maxThinkingTokens;
|
|
5570
|
-
if (mtt) {
|
|
5571
|
-
if (mtt <= 1024) return "minimal";
|
|
5572
|
-
if (mtt <= 4096) return "low";
|
|
5573
|
-
if (mtt <= 1e4) return "medium";
|
|
5574
|
-
if (mtt <= 32e3) return "high";
|
|
5575
|
-
return "xhigh";
|
|
5576
|
-
}
|
|
5577
|
-
return null;
|
|
5578
|
-
})(),
|
|
5579
|
-
maxThinkingTokens: config2?.maxThinkingTokens ?? templateConfig.maxThinkingTokens ?? null,
|
|
5848
|
+
thinkingLevel: config2?.thinkingLevel ?? deriveThinkingLevel(templateConfig),
|
|
5580
5849
|
tokenBudget: config2?.tokenBudget ?? null,
|
|
5581
5850
|
tokenBudgetPeriodMinutes: config2?.tokenBudgetPeriodMinutes ?? null,
|
|
5582
5851
|
compaction: templateConfig.compaction ?? null,
|
|
@@ -5591,7 +5860,6 @@ ${user.trimEnd()}
|
|
|
5591
5860
|
z6.object({
|
|
5592
5861
|
model: z6.string().optional(),
|
|
5593
5862
|
thinkingLevel: z6.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional(),
|
|
5594
|
-
maxThinkingTokens: z6.number().int().positive().nullable().optional(),
|
|
5595
5863
|
tokenBudget: z6.number().int().positive().nullable().optional(),
|
|
5596
5864
|
tokenBudgetPeriodMinutes: z6.number().int().positive().nullable().optional(),
|
|
5597
5865
|
compaction: z6.object({ maxContextTokens: z6.number().int().positive().nullable().optional() }).nullable().optional(),
|
|
@@ -5603,7 +5871,7 @@ ${user.trimEnd()}
|
|
|
5603
5871
|
const entry = await findMind(name);
|
|
5604
5872
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
5605
5873
|
const dir = entry.dir ?? mindDir(name);
|
|
5606
|
-
if (!
|
|
5874
|
+
if (!existsSync8(dir)) return c.json({ error: "Mind directory missing" }, 404);
|
|
5607
5875
|
const body = c.req.valid("json");
|
|
5608
5876
|
const existing = readVoluteConfig(dir) ?? {};
|
|
5609
5877
|
if (body.model !== void 0) existing.model = body.model;
|
|
@@ -5624,76 +5892,29 @@ ${user.trimEnd()}
|
|
|
5624
5892
|
existing.tokenBudgetPeriodMinutes = body.tokenBudgetPeriodMinutes;
|
|
5625
5893
|
}
|
|
5626
5894
|
}
|
|
5627
|
-
if (body.maxThinkingTokens !== void 0) {
|
|
5628
|
-
if (body.maxThinkingTokens === null) {
|
|
5629
|
-
delete existing.maxThinkingTokens;
|
|
5630
|
-
} else {
|
|
5631
|
-
existing.maxThinkingTokens = body.maxThinkingTokens;
|
|
5632
|
-
}
|
|
5633
|
-
}
|
|
5634
5895
|
if (body.unescapeNewlines !== void 0) {
|
|
5635
5896
|
existing.unescapeNewlines = body.unescapeNewlines;
|
|
5636
5897
|
}
|
|
5637
5898
|
writeVoluteConfig(dir, existing);
|
|
5638
5899
|
if (body.unescapeNewlines !== void 0) {
|
|
5639
|
-
const { clearEchoTextCache } = await import("./echo-text-
|
|
5900
|
+
const { clearEchoTextCache } = await import("./echo-text-H3SH337Q.js");
|
|
5640
5901
|
clearEchoTextCache(name);
|
|
5641
5902
|
}
|
|
5642
|
-
const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.
|
|
5903
|
+
const needsConfigJson = body.model !== void 0 || body.thinkingLevel !== void 0 || body.compaction !== void 0;
|
|
5643
5904
|
if (needsConfigJson) {
|
|
5644
|
-
const configJsonPath =
|
|
5905
|
+
const configJsonPath = resolve11(dir, "home/.config/config.json");
|
|
5645
5906
|
let templateConfig = {};
|
|
5646
|
-
if (
|
|
5907
|
+
if (existsSync8(configJsonPath)) {
|
|
5647
5908
|
try {
|
|
5648
|
-
templateConfig = JSON.parse(
|
|
5909
|
+
templateConfig = JSON.parse(readFileSync9(configJsonPath, "utf-8"));
|
|
5649
5910
|
} catch {
|
|
5650
5911
|
}
|
|
5651
5912
|
}
|
|
5652
5913
|
if (body.model !== void 0) {
|
|
5653
5914
|
templateConfig.model = body.model;
|
|
5654
5915
|
}
|
|
5655
|
-
const tmpl = entry.template ?? "claude";
|
|
5656
5916
|
if (body.thinkingLevel !== void 0) {
|
|
5657
|
-
|
|
5658
|
-
const claudeThinkingTokens = {
|
|
5659
|
-
off: null,
|
|
5660
|
-
minimal: 1024,
|
|
5661
|
-
low: 4096,
|
|
5662
|
-
medium: 1e4,
|
|
5663
|
-
high: 32e3,
|
|
5664
|
-
xhigh: 128e3
|
|
5665
|
-
};
|
|
5666
|
-
const tokens = claudeThinkingTokens[body.thinkingLevel] ?? null;
|
|
5667
|
-
if (tokens === null) {
|
|
5668
|
-
delete templateConfig.maxThinkingTokens;
|
|
5669
|
-
} else {
|
|
5670
|
-
templateConfig.maxThinkingTokens = tokens;
|
|
5671
|
-
}
|
|
5672
|
-
} else if (tmpl === "codex") {
|
|
5673
|
-
const codexMap = {
|
|
5674
|
-
off: null,
|
|
5675
|
-
minimal: "minimal",
|
|
5676
|
-
low: "low",
|
|
5677
|
-
medium: "medium",
|
|
5678
|
-
high: "high",
|
|
5679
|
-
xhigh: "xhigh"
|
|
5680
|
-
};
|
|
5681
|
-
const effort = codexMap[body.thinkingLevel] ?? null;
|
|
5682
|
-
if (effort === null) {
|
|
5683
|
-
delete templateConfig.reasoningEffort;
|
|
5684
|
-
} else {
|
|
5685
|
-
templateConfig.reasoningEffort = effort;
|
|
5686
|
-
}
|
|
5687
|
-
} else {
|
|
5688
|
-
templateConfig.thinkingLevel = body.thinkingLevel;
|
|
5689
|
-
}
|
|
5690
|
-
}
|
|
5691
|
-
if (body.maxThinkingTokens !== void 0) {
|
|
5692
|
-
if (body.maxThinkingTokens === null) {
|
|
5693
|
-
delete templateConfig.maxThinkingTokens;
|
|
5694
|
-
} else {
|
|
5695
|
-
templateConfig.maxThinkingTokens = body.maxThinkingTokens;
|
|
5696
|
-
}
|
|
5917
|
+
applyThinkingLevel(templateConfig, entry.template ?? "claude", body.thinkingLevel);
|
|
5697
5918
|
}
|
|
5698
5919
|
if (body.compaction !== void 0) {
|
|
5699
5920
|
if (body.compaction === null) {
|
|
@@ -5708,12 +5929,12 @@ ${user.trimEnd()}
|
|
|
5708
5929
|
templateConfig.compaction = comp;
|
|
5709
5930
|
}
|
|
5710
5931
|
}
|
|
5711
|
-
|
|
5932
|
+
writeFileSync8(configJsonPath, `${JSON.stringify(templateConfig, null, 2)}
|
|
5712
5933
|
`);
|
|
5713
5934
|
}
|
|
5714
5935
|
if (entry.mindType === "spirit" && body.model !== void 0) {
|
|
5715
5936
|
try {
|
|
5716
|
-
const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-
|
|
5937
|
+
const { readGlobalConfig: readGlobalConfig2, writeGlobalConfig: writeGlobalConfig2 } = await import("./setup-5ECWTYKG.js");
|
|
5717
5938
|
const globalConfig = readGlobalConfig2();
|
|
5718
5939
|
globalConfig.spiritModel = body.model;
|
|
5719
5940
|
writeGlobalConfig2(globalConfig);
|
|
@@ -5736,12 +5957,27 @@ ${user.trimEnd()}
|
|
|
5736
5957
|
logger_default.error(`failed to get pending deliveries for ${baseName}`, logger_default.errorData(err));
|
|
5737
5958
|
return c.json({ error: "Failed to retrieve pending messages" }, 500);
|
|
5738
5959
|
}
|
|
5960
|
+
}).post("/:name/gates/decline", requireSelf(), async (c) => {
|
|
5961
|
+
const name = c.req.param("name");
|
|
5962
|
+
const body = await c.req.json().catch(() => ({}));
|
|
5963
|
+
const channel = body.channel?.trim();
|
|
5964
|
+
if (!channel) return c.json({ error: "channel required" }, 400);
|
|
5965
|
+
try {
|
|
5966
|
+
const archived = await getDeliveryManager().declineChannel(name, channel);
|
|
5967
|
+
return c.json({ ok: true, channel, archived });
|
|
5968
|
+
} catch (err) {
|
|
5969
|
+
if (err instanceof Error && err.message.includes("not initialized")) {
|
|
5970
|
+
return c.json({ error: "Delivery manager not available" }, 503);
|
|
5971
|
+
}
|
|
5972
|
+
logger_default.error(`failed to decline channel ${channel} for ${name}`, logger_default.errorData(err));
|
|
5973
|
+
return c.json({ error: "Failed to decline channel" }, 500);
|
|
5974
|
+
}
|
|
5739
5975
|
}).post("/:name/ai/complete", requireSelf(), async (c) => {
|
|
5740
5976
|
const body = await c.req.json();
|
|
5741
5977
|
if (!body.systemPrompt || !body.message) {
|
|
5742
5978
|
return c.json({ error: "systemPrompt and message required" }, 400);
|
|
5743
5979
|
}
|
|
5744
|
-
const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-
|
|
5980
|
+
const { aiComplete: aiCompleteFn, isAiConfigured } = await import("./ai-service-643TNFPH.js");
|
|
5745
5981
|
if (!isAiConfigured()) {
|
|
5746
5982
|
return c.json({ error: "AI service not configured" }, 503);
|
|
5747
5983
|
}
|
|
@@ -5862,6 +6098,38 @@ ${user.trimEnd()}
|
|
|
5862
6098
|
const db = await getDb();
|
|
5863
6099
|
const rows = await db.selectDistinct({ channel: mindHistory.channel }).from(mindHistory).where(eq5(mindHistory.mind, name));
|
|
5864
6100
|
return c.json(rows.map((r) => r.channel));
|
|
6101
|
+
}).get("/:name/history/contacts", requireSelf(), async (c) => {
|
|
6102
|
+
const name = c.req.param("name");
|
|
6103
|
+
const rawHours = parseInt(c.req.query("hours") ?? "48", 10);
|
|
6104
|
+
const hours = Math.min(Math.max(Number.isNaN(rawHours) ? 48 : rawHours, 1), 168);
|
|
6105
|
+
const cutoff = new Date(Date.now() - hours * 36e5).toISOString().replace("T", " ").slice(0, 19);
|
|
6106
|
+
const db = await getDb();
|
|
6107
|
+
const contacts = await db.select({
|
|
6108
|
+
channel: mindHistory.channel,
|
|
6109
|
+
last_at: sql3`MAX(${mindHistory.created_at})`,
|
|
6110
|
+
last_inbound_at: sql3`MAX(CASE WHEN ${mindHistory.type} = 'inbound' THEN ${mindHistory.created_at} END)`,
|
|
6111
|
+
last_outbound_at: sql3`MAX(CASE WHEN ${mindHistory.type} = 'outbound' THEN ${mindHistory.created_at} END)`,
|
|
6112
|
+
message_count: sql3`COUNT(*)`,
|
|
6113
|
+
// The counterparty: most recent inbound sender on this channel. For a
|
|
6114
|
+
// DM the channel name already carries it (e.g. @atlas), but this also
|
|
6115
|
+
// covers shared channels (#system) and rows where the channel is opaque.
|
|
6116
|
+
last_sender: sql3`(
|
|
6117
|
+
SELECT sender FROM mind_history h2
|
|
6118
|
+
WHERE h2.mind = ${name}
|
|
6119
|
+
AND h2.channel = ${mindHistory.channel}
|
|
6120
|
+
AND h2.type = 'inbound'
|
|
6121
|
+
AND h2.sender IS NOT NULL
|
|
6122
|
+
ORDER BY h2.created_at DESC, h2.id DESC LIMIT 1
|
|
6123
|
+
)`
|
|
6124
|
+
}).from(mindHistory).where(
|
|
6125
|
+
and5(
|
|
6126
|
+
eq5(mindHistory.mind, name),
|
|
6127
|
+
sql3`${mindHistory.type} IN ('inbound','outbound')`,
|
|
6128
|
+
sql3`${mindHistory.channel} IS NOT NULL`,
|
|
6129
|
+
sql3`${mindHistory.created_at} >= ${cutoff}`
|
|
6130
|
+
)
|
|
6131
|
+
).groupBy(mindHistory.channel).orderBy(sql3`MAX(${mindHistory.created_at}) DESC`);
|
|
6132
|
+
return c.json({ hours, contacts });
|
|
5865
6133
|
}).get("/:name/history/export", requireSelf(), async (c) => {
|
|
5866
6134
|
const name = c.req.param("name");
|
|
5867
6135
|
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
@@ -5907,7 +6175,7 @@ ${user.trimEnd()}
|
|
|
5907
6175
|
eq5(mindHistory.session, currentSession),
|
|
5908
6176
|
sql3`${mindHistory.turn_id} IS NOT NULL`
|
|
5909
6177
|
)
|
|
5910
|
-
).orderBy(
|
|
6178
|
+
).orderBy(desc3(mindHistory.created_at)).limit(1);
|
|
5911
6179
|
if (lastTurn.length > 0 && lastTurn[0].turn_id) {
|
|
5912
6180
|
const firstEvent = await db.select({ created_at: mindHistory.created_at }).from(mindHistory).where(eq5(mindHistory.turn_id, lastTurn[0].turn_id)).orderBy(mindHistory.created_at).limit(1);
|
|
5913
6181
|
if (firstEvent.length > 0) {
|
|
@@ -5930,7 +6198,7 @@ ${user.trimEnd()}
|
|
|
5930
6198
|
session: turns.session,
|
|
5931
6199
|
content: summaries.content,
|
|
5932
6200
|
created_at: summaries.created_at
|
|
5933
|
-
}).from(summaries).innerJoin(turns, eq5(turns.id, summaries.period_key)).where(and5(...conditions)).orderBy(
|
|
6201
|
+
}).from(summaries).innerJoin(turns, eq5(turns.id, summaries.period_key)).where(and5(...conditions)).orderBy(desc3(summaries.created_at)).limit(50);
|
|
5934
6202
|
if (rows.length === 0) {
|
|
5935
6203
|
return c.json({ context: null });
|
|
5936
6204
|
}
|
|
@@ -5981,7 +6249,7 @@ ${lines.join("\n")}` });
|
|
|
5981
6249
|
metadata: summaries.metadata,
|
|
5982
6250
|
created_at: summaries.created_at,
|
|
5983
6251
|
session: turns.session
|
|
5984
|
-
}).from(summaries).innerJoin(turns, eq5(turns.id, summaries.period_key)).where(and5(...sumConditions)).orderBy(
|
|
6252
|
+
}).from(summaries).innerJoin(turns, eq5(turns.id, summaries.period_key)).where(and5(...sumConditions)).orderBy(desc3(summaries.created_at)).limit(limit).offset(offset);
|
|
5985
6253
|
return c.json(
|
|
5986
6254
|
sumRows2.map((r) => ({
|
|
5987
6255
|
id: r.id,
|
|
@@ -5998,7 +6266,7 @@ ${lines.join("\n")}` });
|
|
|
5998
6266
|
}))
|
|
5999
6267
|
);
|
|
6000
6268
|
}
|
|
6001
|
-
const sumRows = await db.select().from(summaries).where(and5(...sumConditions)).orderBy(
|
|
6269
|
+
const sumRows = await db.select().from(summaries).where(and5(...sumConditions)).orderBy(desc3(summaries.created_at)).limit(limit).offset(offset);
|
|
6002
6270
|
return c.json(
|
|
6003
6271
|
sumRows.map((r) => ({
|
|
6004
6272
|
id: r.id,
|
|
@@ -6027,7 +6295,7 @@ ${lines.join("\n")}` });
|
|
|
6027
6295
|
);
|
|
6028
6296
|
break;
|
|
6029
6297
|
}
|
|
6030
|
-
const rows = await db.select().from(mindHistory).where(and5(...conditions)).orderBy(
|
|
6298
|
+
const rows = await db.select().from(mindHistory).where(and5(...conditions)).orderBy(desc3(mindHistory.created_at)).limit(limit).offset(offset);
|
|
6031
6299
|
return c.json(rows);
|
|
6032
6300
|
});
|
|
6033
6301
|
var minds_default = app13;
|
|
@@ -6090,6 +6358,13 @@ var slog2 = logger_default.child("schedules");
|
|
|
6090
6358
|
function readSchedules(dir) {
|
|
6091
6359
|
return readVoluteConfig(dir)?.schedules ?? [];
|
|
6092
6360
|
}
|
|
6361
|
+
function validateMessages(messages) {
|
|
6362
|
+
if (messages === void 0) return null;
|
|
6363
|
+
if (!Array.isArray(messages) || messages.some((m) => typeof m !== "string" || !m.trim())) {
|
|
6364
|
+
return "messages must be an array of non-empty strings";
|
|
6365
|
+
}
|
|
6366
|
+
return null;
|
|
6367
|
+
}
|
|
6093
6368
|
var UPCOMING_HORIZON_MS = 24 * 60 * 60 * 1e3;
|
|
6094
6369
|
function computeClockEvents(schedules, sleepState, sleepConfig, now) {
|
|
6095
6370
|
const upcoming = [];
|
|
@@ -6231,11 +6506,13 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
|
|
|
6231
6506
|
if (body.cron && body.fireAt) {
|
|
6232
6507
|
return c.json({ error: "cron and fireAt are mutually exclusive" }, 400);
|
|
6233
6508
|
}
|
|
6234
|
-
|
|
6235
|
-
|
|
6509
|
+
const messagesErr = validateMessages(body.messages);
|
|
6510
|
+
if (messagesErr) return c.json({ error: messagesErr }, 400);
|
|
6511
|
+
if (!body.message && !body.messages?.length && !body.script) {
|
|
6512
|
+
return c.json({ error: "message, messages, or script is required" }, 400);
|
|
6236
6513
|
}
|
|
6237
|
-
if (body.message
|
|
6238
|
-
return c.json({ error: "message and script are mutually exclusive" }, 400);
|
|
6514
|
+
if ([body.message, body.messages?.length, body.script].filter(Boolean).length > 1) {
|
|
6515
|
+
return c.json({ error: "message, messages, and script are mutually exclusive" }, 400);
|
|
6239
6516
|
}
|
|
6240
6517
|
if (body.cron) {
|
|
6241
6518
|
try {
|
|
@@ -6265,6 +6542,7 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
|
|
|
6265
6542
|
if (body.cron) schedule.cron = body.cron;
|
|
6266
6543
|
if (body.fireAt) schedule.fireAt = body.fireAt;
|
|
6267
6544
|
if (body.message) schedule.message = body.message;
|
|
6545
|
+
if (body.messages?.length) schedule.messages = body.messages;
|
|
6268
6546
|
if (body.script) schedule.script = body.script;
|
|
6269
6547
|
if (body.channel) schedule.channel = body.channel;
|
|
6270
6548
|
if (body.whileSleeping) schedule.whileSleeping = body.whileSleeping;
|
|
@@ -6281,8 +6559,10 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
|
|
|
6281
6559
|
const idx = schedules.findIndex((s) => s.id === id);
|
|
6282
6560
|
if (idx === -1) return c.json({ error: "Schedule not found" }, 404);
|
|
6283
6561
|
const body = await c.req.json();
|
|
6284
|
-
|
|
6285
|
-
|
|
6562
|
+
const messagesErr = validateMessages(body.messages);
|
|
6563
|
+
if (messagesErr) return c.json({ error: messagesErr }, 400);
|
|
6564
|
+
if ([body.message, body.messages?.length, body.script].filter(Boolean).length > 1) {
|
|
6565
|
+
return c.json({ error: "message, messages, and script are mutually exclusive" }, 400);
|
|
6286
6566
|
}
|
|
6287
6567
|
if (body.cron !== void 0) {
|
|
6288
6568
|
try {
|
|
@@ -6303,10 +6583,21 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
|
|
|
6303
6583
|
if (body.message !== void 0) {
|
|
6304
6584
|
schedules[idx].message = body.message;
|
|
6305
6585
|
delete schedules[idx].script;
|
|
6586
|
+
delete schedules[idx].messages;
|
|
6587
|
+
}
|
|
6588
|
+
if (body.messages !== void 0) {
|
|
6589
|
+
if (body.messages.length > 0) {
|
|
6590
|
+
schedules[idx].messages = body.messages;
|
|
6591
|
+
delete schedules[idx].message;
|
|
6592
|
+
delete schedules[idx].script;
|
|
6593
|
+
} else {
|
|
6594
|
+
delete schedules[idx].messages;
|
|
6595
|
+
}
|
|
6306
6596
|
}
|
|
6307
6597
|
if (body.script !== void 0) {
|
|
6308
6598
|
schedules[idx].script = body.script;
|
|
6309
6599
|
delete schedules[idx].message;
|
|
6600
|
+
delete schedules[idx].messages;
|
|
6310
6601
|
}
|
|
6311
6602
|
if (body.whileSleeping && !["skip", "queue", "trigger-wake"].includes(body.whileSleeping)) {
|
|
6312
6603
|
return c.json(
|
|
@@ -6320,6 +6611,11 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
|
|
|
6320
6611
|
if (body.channel !== void 0) schedules[idx].channel = body.channel || void 0;
|
|
6321
6612
|
if (body.whileSleeping !== void 0)
|
|
6322
6613
|
schedules[idx].whileSleeping = body.whileSleeping || void 0;
|
|
6614
|
+
const touchedAction = body.message !== void 0 || body.messages !== void 0 || body.script !== void 0;
|
|
6615
|
+
const result = schedules[idx];
|
|
6616
|
+
if (touchedAction && !result.message && !result.messages?.length && !result.script) {
|
|
6617
|
+
return c.json({ error: "schedule must keep a message, messages, or script" }, 400);
|
|
6618
|
+
}
|
|
6323
6619
|
writeSchedules(name, dir, schedules);
|
|
6324
6620
|
return c.json({ ok: true });
|
|
6325
6621
|
}).delete("/:name/schedules/:id", requireSelf(), async (c) => {
|
|
@@ -6343,7 +6639,7 @@ var app15 = new Hono18().get("/:name/clock/status", requireSelf(), async (c) =>
|
|
|
6343
6639
|
const body = await c.req.text();
|
|
6344
6640
|
const message = `[webhook: ${event}] ${body}`;
|
|
6345
6641
|
try {
|
|
6346
|
-
const { sendSystemMessage } = await import("./system-chat-
|
|
6642
|
+
const { sendSystemMessage } = await import("./system-chat-63ABFF6V.js");
|
|
6347
6643
|
await sendSystemMessage(name, message);
|
|
6348
6644
|
return c.json({ ok: true });
|
|
6349
6645
|
} catch (err) {
|
|
@@ -6356,14 +6652,14 @@ var schedules_default = app15;
|
|
|
6356
6652
|
// packages/daemon/src/web/api/setup.ts
|
|
6357
6653
|
import { mkdirSync as mkdirSync7 } from "fs";
|
|
6358
6654
|
import { homedir as homedir2 } from "os";
|
|
6359
|
-
import { resolve as
|
|
6655
|
+
import { resolve as resolve12 } from "path";
|
|
6360
6656
|
import { Hono as Hono19 } from "hono";
|
|
6361
6657
|
import { setCookie as setCookie2 } from "hono/cookie";
|
|
6362
6658
|
var DEFAULT_API_URL2 = "https://volute.systems";
|
|
6363
6659
|
var setup = new Hono19();
|
|
6364
6660
|
function writeSetupConfig(systemName, description) {
|
|
6365
|
-
const configHome = process.env.VOLUTE_HOME ??
|
|
6366
|
-
const mindsDir =
|
|
6661
|
+
const configHome = process.env.VOLUTE_HOME ?? resolve12(homedir2(), ".volute");
|
|
6662
|
+
const mindsDir = resolve12(configHome, "minds");
|
|
6367
6663
|
mkdirSync7(configHome, { recursive: true });
|
|
6368
6664
|
mkdirSync7(mindsDir, { recursive: true });
|
|
6369
6665
|
const existingConfig = readGlobalConfig();
|
|
@@ -6397,7 +6693,7 @@ setup.get("/status", async (c) => {
|
|
|
6397
6693
|
let hasAccount = false;
|
|
6398
6694
|
if (hasSystem) {
|
|
6399
6695
|
try {
|
|
6400
|
-
const { listUsersByType: listUsersByType2 } = await import("./auth-
|
|
6696
|
+
const { listUsersByType: listUsersByType2 } = await import("./auth-A4VGHADI.js");
|
|
6401
6697
|
const brains = await listUsersByType2("brain");
|
|
6402
6698
|
hasAccount = brains.length > 0;
|
|
6403
6699
|
} catch (err) {
|
|
@@ -6608,7 +6904,7 @@ setup.post("/account", async (c) => {
|
|
|
6608
6904
|
}
|
|
6609
6905
|
}
|
|
6610
6906
|
try {
|
|
6611
|
-
const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-
|
|
6907
|
+
const { createUser: createUser2, updateUserProfile: updateUserProfile2 } = await import("./auth-A4VGHADI.js");
|
|
6612
6908
|
const user = await createUser2(body.username.trim(), body.password);
|
|
6613
6909
|
if (body.displayName?.trim()) {
|
|
6614
6910
|
await updateUserProfile2(user.id, { display_name: body.displayName.trim() });
|
|
@@ -6654,7 +6950,7 @@ setup.post("/models", async (c) => {
|
|
|
6654
6950
|
return c.json({ error: "Spirit model is required" }, 400);
|
|
6655
6951
|
}
|
|
6656
6952
|
try {
|
|
6657
|
-
const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-
|
|
6953
|
+
const { setEnabledModels: setEnabledModels3, setUtilityModel: setUtilityModel2 } = await import("./ai-service-643TNFPH.js");
|
|
6658
6954
|
setEnabledModels3(body.models);
|
|
6659
6955
|
const config2 = readGlobalConfig();
|
|
6660
6956
|
config2.spiritModel = body.spiritModel.trim();
|
|
@@ -6672,15 +6968,15 @@ setup.post("/complete", async (c) => {
|
|
|
6672
6968
|
return c.json({ error: "Setup already complete" }, 400);
|
|
6673
6969
|
}
|
|
6674
6970
|
try {
|
|
6675
|
-
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-
|
|
6676
|
-
const { startSpiritFull } = await import("./mind-service-
|
|
6971
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-WXS3HCLN.js");
|
|
6972
|
+
const { startSpiritFull } = await import("./mind-service-2ARGJNKP.js");
|
|
6677
6973
|
await ensureSpiritProject();
|
|
6678
6974
|
await syncSpiritTemplate();
|
|
6679
6975
|
const warnings = [];
|
|
6680
6976
|
const config2 = readGlobalConfig();
|
|
6681
6977
|
if (config2.setup?.service && config2.setup?.type === "local") {
|
|
6682
6978
|
try {
|
|
6683
|
-
const { installUserService } = await import("./service-install-
|
|
6979
|
+
const { installUserService } = await import("./service-install-VCRMFWX5.js");
|
|
6684
6980
|
const installed = await installUserService(config2.port, config2.hostname);
|
|
6685
6981
|
if (!installed) {
|
|
6686
6982
|
warnings.push("Service installation is not supported on this platform.");
|
|
@@ -6704,12 +7000,13 @@ setup.post("/complete", async (c) => {
|
|
|
6704
7000
|
logger_default.info("spirit started successfully during setup");
|
|
6705
7001
|
} catch (err) {
|
|
6706
7002
|
logger_default.warn("spirit start failed during setup (non-fatal)", logger_default.errorData(err));
|
|
6707
|
-
|
|
7003
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
7004
|
+
warnings.push(`The spirit couldn't start: ${reason} \u2014 it will retry on next daemon restart.`);
|
|
6708
7005
|
}
|
|
6709
7006
|
let spiritConversationId;
|
|
6710
7007
|
try {
|
|
6711
|
-
const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-
|
|
6712
|
-
const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-
|
|
7008
|
+
const { getOrCreateMindUser: getOrCreateMindUser2, listUsersByType: listUsersByType2 } = await import("./auth-A4VGHADI.js");
|
|
7009
|
+
const { createConversation: createConversation2, findDMConversation: findDMConversation2 } = await import("./conversations-C7IKYSHD.js");
|
|
6713
7010
|
const spiritUser = await getOrCreateMindUser2("volute");
|
|
6714
7011
|
const brains = await listUsersByType2("brain");
|
|
6715
7012
|
const admin2 = brains.find((u) => u.role === "admin");
|
|
@@ -6731,8 +7028,8 @@ setup.post("/complete", async (c) => {
|
|
|
6731
7028
|
logger_default.info("setup complete state", { spiritConversationId, spiritStarted });
|
|
6732
7029
|
if (spiritConversationId && spiritStarted) {
|
|
6733
7030
|
try {
|
|
6734
|
-
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-
|
|
6735
|
-
const { listUsersByType: listUsers2 } = await import("./auth-
|
|
7031
|
+
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-GPQ5SE5N.js");
|
|
7032
|
+
const { listUsersByType: listUsers2 } = await import("./auth-A4VGHADI.js");
|
|
6736
7033
|
const admins = await listUsers2("brain");
|
|
6737
7034
|
const admin2 = admins.find((u) => u.role === "admin");
|
|
6738
7035
|
if (admin2) {
|
|
@@ -6771,9 +7068,9 @@ setup.post("/complete", async (c) => {
|
|
|
6771
7068
|
var setup_default = setup;
|
|
6772
7069
|
|
|
6773
7070
|
// packages/daemon/src/web/api/skills.ts
|
|
6774
|
-
import { existsSync as
|
|
7071
|
+
import { existsSync as existsSync9, mkdtempSync, readdirSync as readdirSync3, rmSync as rmSync5 } from "fs";
|
|
6775
7072
|
import { tmpdir } from "os";
|
|
6776
|
-
import { join, resolve as
|
|
7073
|
+
import { join, resolve as resolve13 } from "path";
|
|
6777
7074
|
import AdmZip from "adm-zip";
|
|
6778
7075
|
import { Hono as Hono20 } from "hono";
|
|
6779
7076
|
var app16 = new Hono20().get("/", async (c) => {
|
|
@@ -6849,19 +7146,19 @@ var app16 = new Hono20().get("/", async (c) => {
|
|
|
6849
7146
|
try {
|
|
6850
7147
|
const zip = new AdmZip(buffer);
|
|
6851
7148
|
for (const entry of zip.getEntries()) {
|
|
6852
|
-
const target =
|
|
7149
|
+
const target = resolve13(tmpDir, entry.entryName);
|
|
6853
7150
|
if (!target.startsWith(tmpDir)) {
|
|
6854
7151
|
return c.json({ error: "Invalid zip: paths must not escape archive" }, 400);
|
|
6855
7152
|
}
|
|
6856
7153
|
}
|
|
6857
7154
|
zip.extractAllTo(tmpDir, true);
|
|
6858
7155
|
let skillDir = null;
|
|
6859
|
-
if (
|
|
7156
|
+
if (existsSync9(join(tmpDir, "SKILL.md"))) {
|
|
6860
7157
|
skillDir = tmpDir;
|
|
6861
7158
|
} else {
|
|
6862
7159
|
const entries = readdirSync3(tmpDir, { withFileTypes: true }).filter((e) => e.isDirectory());
|
|
6863
7160
|
for (const entry of entries) {
|
|
6864
|
-
if (
|
|
7161
|
+
if (existsSync9(join(tmpDir, entry.name, "SKILL.md"))) {
|
|
6865
7162
|
skillDir = join(tmpDir, entry.name);
|
|
6866
7163
|
break;
|
|
6867
7164
|
}
|
|
@@ -7053,7 +7350,7 @@ var app19 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
|
|
|
7053
7350
|
var conversations_default = app19;
|
|
7054
7351
|
|
|
7055
7352
|
// packages/daemon/src/web/api/v1/events.ts
|
|
7056
|
-
import { desc as
|
|
7353
|
+
import { desc as desc4, eq as eq7 } from "drizzle-orm";
|
|
7057
7354
|
import { Hono as Hono24 } from "hono";
|
|
7058
7355
|
import { streamSSE as streamSSE4 } from "hono/streaming";
|
|
7059
7356
|
|
|
@@ -7120,7 +7417,7 @@ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
|
|
|
7120
7417
|
let recentActivity = [];
|
|
7121
7418
|
try {
|
|
7122
7419
|
const db = await getDb();
|
|
7123
|
-
recentActivity = await db.select().from(activity).where(activityMind ? eq7(activity.mind, activityMind) : void 0).orderBy(
|
|
7420
|
+
recentActivity = await db.select().from(activity).where(activityMind ? eq7(activity.mind, activityMind) : void 0).orderBy(desc4(activity.created_at)).limit(50);
|
|
7124
7421
|
recentActivity = recentActivity.map((row) => ({
|
|
7125
7422
|
...row,
|
|
7126
7423
|
metadata: row.metadata ? JSON.parse(row.metadata) : null
|
|
@@ -7175,8 +7472,8 @@ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
|
|
|
7175
7472
|
});
|
|
7176
7473
|
}, 15e3);
|
|
7177
7474
|
cleanups.push(() => clearInterval(keepAlive));
|
|
7178
|
-
await new Promise((
|
|
7179
|
-
stream.onAbort(() =>
|
|
7475
|
+
await new Promise((resolve18) => {
|
|
7476
|
+
stream.onAbort(() => resolve18());
|
|
7180
7477
|
});
|
|
7181
7478
|
} finally {
|
|
7182
7479
|
for (const cleanup of cleanups) {
|
|
@@ -7191,14 +7488,14 @@ var app20 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
|
|
|
7191
7488
|
var events_default = app20;
|
|
7192
7489
|
|
|
7193
7490
|
// packages/daemon/src/web/api/variants.ts
|
|
7194
|
-
import { existsSync as
|
|
7195
|
-
import { resolve as
|
|
7491
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
7492
|
+
import { resolve as resolve15 } from "path";
|
|
7196
7493
|
import { Hono as Hono25 } from "hono";
|
|
7197
7494
|
|
|
7198
7495
|
// packages/daemon/src/lib/mind/spawn-server.ts
|
|
7199
7496
|
import { spawn as spawn4 } from "child_process";
|
|
7200
|
-
import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as
|
|
7201
|
-
import { resolve as
|
|
7497
|
+
import { closeSync, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync10 } from "fs";
|
|
7498
|
+
import { resolve as resolve14 } from "path";
|
|
7202
7499
|
async function spawnServer(cwd, port, options) {
|
|
7203
7500
|
let cmd = process.env.VOLUTE_NODE_PATH ?? process.execPath;
|
|
7204
7501
|
let args = ["--import", "tsx", "src/server.ts", "--port", String(port)];
|
|
@@ -7219,31 +7516,31 @@ function spawnAttached(cmd, args, cwd) {
|
|
|
7219
7516
|
cwd,
|
|
7220
7517
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7221
7518
|
});
|
|
7222
|
-
return new Promise((
|
|
7223
|
-
const timeout = setTimeout(() =>
|
|
7519
|
+
return new Promise((resolve18) => {
|
|
7520
|
+
const timeout = setTimeout(() => resolve18(null), 3e4);
|
|
7224
7521
|
function checkOutput(data) {
|
|
7225
7522
|
const match = data.toString().match(/listening on :(\d+)/);
|
|
7226
7523
|
if (match) {
|
|
7227
7524
|
clearTimeout(timeout);
|
|
7228
|
-
|
|
7525
|
+
resolve18({ child, actualPort: parseInt(match[1], 10) });
|
|
7229
7526
|
}
|
|
7230
7527
|
}
|
|
7231
7528
|
child.stdout?.on("data", checkOutput);
|
|
7232
7529
|
child.stderr?.on("data", checkOutput);
|
|
7233
7530
|
child.on("error", () => {
|
|
7234
7531
|
clearTimeout(timeout);
|
|
7235
|
-
|
|
7532
|
+
resolve18(null);
|
|
7236
7533
|
});
|
|
7237
7534
|
child.on("exit", () => {
|
|
7238
7535
|
clearTimeout(timeout);
|
|
7239
|
-
|
|
7536
|
+
resolve18(null);
|
|
7240
7537
|
});
|
|
7241
7538
|
});
|
|
7242
7539
|
}
|
|
7243
7540
|
function spawnDetached(cmd, args, cwd, logDir) {
|
|
7244
|
-
const logsDir = logDir ??
|
|
7541
|
+
const logsDir = logDir ?? resolve14(cwd, ".mind", "logs");
|
|
7245
7542
|
mkdirSync8(logsDir, { recursive: true });
|
|
7246
|
-
const logPath =
|
|
7543
|
+
const logPath = resolve14(logsDir, "mind.log");
|
|
7247
7544
|
const logFd = openSync(logPath, "a");
|
|
7248
7545
|
const child = spawn4(cmd, args, {
|
|
7249
7546
|
cwd,
|
|
@@ -7263,7 +7560,7 @@ function spawnDetached(cmd, args, cwd, logDir) {
|
|
|
7263
7560
|
}
|
|
7264
7561
|
const interval = setInterval(() => {
|
|
7265
7562
|
try {
|
|
7266
|
-
const content =
|
|
7563
|
+
const content = readFileSync10(logPath, "utf-8");
|
|
7267
7564
|
const match = content.match(/listening on :(\d+)/);
|
|
7268
7565
|
if (match) {
|
|
7269
7566
|
finish({ child, actualPort: parseInt(match[1], 10) });
|
|
@@ -7364,11 +7661,11 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
7364
7661
|
return c.json({ error: `Name already in use: ${variantName}` }, 409);
|
|
7365
7662
|
}
|
|
7366
7663
|
const projectRoot = entry.dir ?? mindDir(mindName);
|
|
7367
|
-
const variantDir =
|
|
7368
|
-
if (
|
|
7664
|
+
const variantDir = resolve15(projectRoot, ".variants", variantName);
|
|
7665
|
+
if (existsSync10(variantDir)) {
|
|
7369
7666
|
return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
|
|
7370
7667
|
}
|
|
7371
|
-
mkdirSync9(
|
|
7668
|
+
mkdirSync9(resolve15(projectRoot, ".variants"), { recursive: true });
|
|
7372
7669
|
try {
|
|
7373
7670
|
await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
|
|
7374
7671
|
} catch (e) {
|
|
@@ -7381,7 +7678,7 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
7381
7678
|
const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
|
|
7382
7679
|
await exec(cmd, args, {
|
|
7383
7680
|
cwd: variantDir,
|
|
7384
|
-
env: { ...process.env, HOME:
|
|
7681
|
+
env: { ...process.env, HOME: resolve15(variantDir, "home") }
|
|
7385
7682
|
});
|
|
7386
7683
|
} else {
|
|
7387
7684
|
await exec("npm", ["install"], { cwd: variantDir });
|
|
@@ -7391,7 +7688,7 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
7391
7688
|
return c.json({ error: `npm install failed: ${msg}` }, 500);
|
|
7392
7689
|
}
|
|
7393
7690
|
if (body.soul) {
|
|
7394
|
-
|
|
7691
|
+
writeFileSync9(resolve15(variantDir, "home/SOUL.md"), body.soul);
|
|
7395
7692
|
}
|
|
7396
7693
|
const variantPort = body.port ?? await nextPort();
|
|
7397
7694
|
await addVariant(variantName, mindName, variantPort, variantDir, variantName);
|
|
@@ -7428,7 +7725,7 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
7428
7725
|
} catch {
|
|
7429
7726
|
}
|
|
7430
7727
|
const projectRoot = parentEntry.dir ?? mindDir(mindName);
|
|
7431
|
-
if (
|
|
7728
|
+
if (existsSync10(variantEntry.dir)) {
|
|
7432
7729
|
const status = (await gitExec(["status", "--porcelain"], { cwd: variantEntry.dir })).trim();
|
|
7433
7730
|
if (status) {
|
|
7434
7731
|
try {
|
|
@@ -7526,8 +7823,8 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
7526
7823
|
await chownMindDir(projectRoot, mindName);
|
|
7527
7824
|
if (variantName.endsWith("-upgrade") || variantName === "upgrade") {
|
|
7528
7825
|
try {
|
|
7529
|
-
const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-
|
|
7530
|
-
const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-
|
|
7826
|
+
const { computeTemplateHash: computeTemplateHash2 } = await import("./template-hash-GSOUARW4.js");
|
|
7827
|
+
const { setMindTemplateHash: setMindTemplateHash2 } = await import("./registry-UMMDRPRM.js");
|
|
7531
7828
|
const tmpl = parentEntry.template ?? "claude";
|
|
7532
7829
|
await setMindTemplateHash2(mindName, computeTemplateHash2(tmpl));
|
|
7533
7830
|
} catch (err) {
|
|
@@ -7540,7 +7837,7 @@ var app21 = new Hono25().get("/:name/variants", async (c) => {
|
|
|
7540
7837
|
const [cmd, args] = await wrapForIsolation("npm", ["install"], mindName);
|
|
7541
7838
|
await exec(cmd, args, {
|
|
7542
7839
|
cwd: projectRoot,
|
|
7543
|
-
env: { ...process.env, HOME:
|
|
7840
|
+
env: { ...process.env, HOME: resolve15(projectRoot, "home") }
|
|
7544
7841
|
});
|
|
7545
7842
|
} else {
|
|
7546
7843
|
await exec("npm", ["install"], { cwd: projectRoot });
|
|
@@ -7595,7 +7892,8 @@ var channelSettingsSchema = z10.object({
|
|
|
7595
7892
|
private: z10.boolean().optional()
|
|
7596
7893
|
});
|
|
7597
7894
|
var createSchema2 = z10.object({
|
|
7598
|
-
name: z10.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
|
|
7895
|
+
name: z10.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens"),
|
|
7896
|
+
participantNames: z10.array(z10.string().min(1)).optional()
|
|
7599
7897
|
}).merge(channelSettingsSchema);
|
|
7600
7898
|
var inviteSchema = z10.object({
|
|
7601
7899
|
username: z10.string().min(1)
|
|
@@ -7614,10 +7912,21 @@ var app22 = new Hono26().get("/", async (c) => {
|
|
|
7614
7912
|
}).post("/", zValidator10("json", createSchema2), async (c) => {
|
|
7615
7913
|
const user = c.get("user");
|
|
7616
7914
|
const body = c.req.valid("json");
|
|
7915
|
+
const { name, participantNames, ...settings } = body;
|
|
7916
|
+
const participantIds = [];
|
|
7917
|
+
for (const username of participantNames ?? []) {
|
|
7918
|
+
let member = await getUserByUsername(username);
|
|
7919
|
+
if (!member && await findMind(username)) {
|
|
7920
|
+
member = await getOrCreateMindUser(username);
|
|
7921
|
+
}
|
|
7922
|
+
if (!member) {
|
|
7923
|
+
return c.json({ error: `User not found: ${username}` }, 404);
|
|
7924
|
+
}
|
|
7925
|
+
participantIds.push(member.id);
|
|
7926
|
+
}
|
|
7927
|
+
let ch;
|
|
7617
7928
|
try {
|
|
7618
|
-
|
|
7619
|
-
const ch = await createChannel(name, user.id, settings);
|
|
7620
|
-
return c.json({ ...ch, channel_name: name }, 201);
|
|
7929
|
+
ch = await createChannel(name, user.id, settings);
|
|
7621
7930
|
} catch (err) {
|
|
7622
7931
|
const cause = err instanceof Error ? err.cause : null;
|
|
7623
7932
|
if (cause && /UNIQUE/i.test(cause.extendedCode ?? cause.message ?? "")) {
|
|
@@ -7625,6 +7934,23 @@ var app22 = new Hono26().get("/", async (c) => {
|
|
|
7625
7934
|
}
|
|
7626
7935
|
throw err;
|
|
7627
7936
|
}
|
|
7937
|
+
try {
|
|
7938
|
+
for (const id of participantIds) {
|
|
7939
|
+
await joinChannel(ch.id, id);
|
|
7940
|
+
}
|
|
7941
|
+
} catch (err) {
|
|
7942
|
+
console.error("[channels] join failed during channel create:", err);
|
|
7943
|
+
try {
|
|
7944
|
+
await deleteConversation(ch.id);
|
|
7945
|
+
} catch (cleanupErr) {
|
|
7946
|
+
console.error(
|
|
7947
|
+
`[channels] failed to roll back channel ${ch.id} after join failure:`,
|
|
7948
|
+
cleanupErr
|
|
7949
|
+
);
|
|
7950
|
+
}
|
|
7951
|
+
throw err;
|
|
7952
|
+
}
|
|
7953
|
+
return c.json({ ...ch, channel_name: name }, 201);
|
|
7628
7954
|
}).get("/:name", async (c) => {
|
|
7629
7955
|
const name = c.req.param("name");
|
|
7630
7956
|
const ch = await getChannelByName(name);
|
|
@@ -7959,11 +8285,11 @@ var app23 = new Hono27().get("/:name/conversations/:id/events", async (c) => {
|
|
|
7959
8285
|
if (!stream.aborted) console.error("[chat] SSE ping error:", err);
|
|
7960
8286
|
});
|
|
7961
8287
|
}, 15e3);
|
|
7962
|
-
await new Promise((
|
|
8288
|
+
await new Promise((resolve18) => {
|
|
7963
8289
|
stream.onAbort(() => {
|
|
7964
8290
|
unsubscribe();
|
|
7965
8291
|
clearInterval(keepAlive);
|
|
7966
|
-
|
|
8292
|
+
resolve18();
|
|
7967
8293
|
});
|
|
7968
8294
|
});
|
|
7969
8295
|
});
|
|
@@ -8177,10 +8503,10 @@ app25.route("/api/conversations", conversations_default);
|
|
|
8177
8503
|
var app_default = app25;
|
|
8178
8504
|
|
|
8179
8505
|
// packages/daemon/src/web/server.ts
|
|
8180
|
-
import { existsSync as
|
|
8506
|
+
import { existsSync as existsSync11 } from "fs";
|
|
8181
8507
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
8182
8508
|
import { createServer as createHttpsServer } from "https";
|
|
8183
|
-
import { dirname as dirname2, extname as extname3, resolve as
|
|
8509
|
+
import { dirname as dirname2, extname as extname3, resolve as resolve16 } from "path";
|
|
8184
8510
|
import { serve } from "@hono/node-server";
|
|
8185
8511
|
var MIME_TYPES2 = {
|
|
8186
8512
|
".html": "text/html",
|
|
@@ -8199,8 +8525,8 @@ async function startServer({
|
|
|
8199
8525
|
let assetsDir = "";
|
|
8200
8526
|
let searchDir = dirname2(new URL(import.meta.url).pathname);
|
|
8201
8527
|
for (let i = 0; i < 5; i++) {
|
|
8202
|
-
const candidate =
|
|
8203
|
-
if (
|
|
8528
|
+
const candidate = resolve16(searchDir, "dist", "web-assets");
|
|
8529
|
+
if (existsSync11(candidate)) {
|
|
8204
8530
|
assetsDir = candidate;
|
|
8205
8531
|
break;
|
|
8206
8532
|
}
|
|
@@ -8210,7 +8536,7 @@ async function startServer({
|
|
|
8210
8536
|
app_default.get("*", async (c) => {
|
|
8211
8537
|
const urlPath = new URL(c.req.url).pathname;
|
|
8212
8538
|
if (urlPath.startsWith("/api/") || urlPath.startsWith("/ext/")) return c.notFound();
|
|
8213
|
-
const filePath =
|
|
8539
|
+
const filePath = resolve16(assetsDir, urlPath.slice(1));
|
|
8214
8540
|
if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
|
|
8215
8541
|
const s = await stat2(filePath).catch(() => null);
|
|
8216
8542
|
if (s?.isFile()) {
|
|
@@ -8223,7 +8549,7 @@ async function startServer({
|
|
|
8223
8549
|
const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
|
|
8224
8550
|
return c.body(body, 200, { "Content-Type": mime, "Cache-Control": cacheControl });
|
|
8225
8551
|
}
|
|
8226
|
-
const indexPath =
|
|
8552
|
+
const indexPath = resolve16(assetsDir, "index.html");
|
|
8227
8553
|
const indexStat = await stat2(indexPath).catch(() => null);
|
|
8228
8554
|
if (indexStat?.isFile()) {
|
|
8229
8555
|
const body = await readFile2(indexPath, "utf-8");
|
|
@@ -8240,10 +8566,10 @@ async function startServer({
|
|
|
8240
8566
|
createServer: createHttpsServer,
|
|
8241
8567
|
serverOptions: { key: tls.key, cert: tls.cert }
|
|
8242
8568
|
});
|
|
8243
|
-
await new Promise((
|
|
8569
|
+
await new Promise((resolve18, reject) => {
|
|
8244
8570
|
server2.on("listening", () => {
|
|
8245
8571
|
logger_default.info("Volute UI running (https)", { hostname, port });
|
|
8246
|
-
|
|
8572
|
+
resolve18();
|
|
8247
8573
|
});
|
|
8248
8574
|
server2.on("error", (err) => {
|
|
8249
8575
|
reject(err);
|
|
@@ -8251,13 +8577,13 @@ async function startServer({
|
|
|
8251
8577
|
});
|
|
8252
8578
|
const internalPort = port + 1;
|
|
8253
8579
|
const internalServer = serve({ fetch: app_default.fetch, port: internalPort, hostname: "127.0.0.1" });
|
|
8254
|
-
await new Promise((
|
|
8580
|
+
await new Promise((resolve18, reject) => {
|
|
8255
8581
|
internalServer.on("listening", () => {
|
|
8256
8582
|
logger_default.info("Volute API running (http, internal)", {
|
|
8257
8583
|
hostname: "127.0.0.1",
|
|
8258
8584
|
port: internalPort
|
|
8259
8585
|
});
|
|
8260
|
-
|
|
8586
|
+
resolve18();
|
|
8261
8587
|
});
|
|
8262
8588
|
internalServer.on("error", (err) => {
|
|
8263
8589
|
reject(err);
|
|
@@ -8266,10 +8592,10 @@ async function startServer({
|
|
|
8266
8592
|
return { server: server2, internalPort };
|
|
8267
8593
|
}
|
|
8268
8594
|
const server = serve({ fetch: app_default.fetch, port, hostname });
|
|
8269
|
-
await new Promise((
|
|
8595
|
+
await new Promise((resolve18, reject) => {
|
|
8270
8596
|
server.on("listening", () => {
|
|
8271
8597
|
logger_default.info("Volute API running (http)", { hostname, port });
|
|
8272
|
-
|
|
8598
|
+
resolve18();
|
|
8273
8599
|
});
|
|
8274
8600
|
server.on("error", (err) => {
|
|
8275
8601
|
reject(err);
|
|
@@ -8280,18 +8606,18 @@ async function startServer({
|
|
|
8280
8606
|
|
|
8281
8607
|
// packages/daemon/src/daemon.ts
|
|
8282
8608
|
if (!process.env.VOLUTE_HOME) {
|
|
8283
|
-
process.env.VOLUTE_HOME =
|
|
8609
|
+
process.env.VOLUTE_HOME = resolve17(homedir3(), ".volute");
|
|
8284
8610
|
}
|
|
8285
8611
|
if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
|
|
8286
8612
|
process.env.TZ = process.env.VOLUTE_TIMEZONE;
|
|
8287
8613
|
}
|
|
8288
8614
|
function writeDaemonConfig(systemDir, config2, token) {
|
|
8289
|
-
const configPath =
|
|
8290
|
-
|
|
8615
|
+
const configPath = resolve17(systemDir, "daemon.json");
|
|
8616
|
+
writeFileSync10(configPath, `${JSON.stringify(config2, null, 2)}
|
|
8291
8617
|
`, { mode: 420 });
|
|
8292
8618
|
chmodSync(configPath, 420);
|
|
8293
|
-
const tokenPath =
|
|
8294
|
-
|
|
8619
|
+
const tokenPath = resolve17(systemDir, "daemon-token");
|
|
8620
|
+
writeFileSync10(tokenPath, `${token}
|
|
8295
8621
|
`, { mode: 384 });
|
|
8296
8622
|
chmodSync(tokenPath, 384);
|
|
8297
8623
|
}
|
|
@@ -8301,7 +8627,7 @@ async function startDaemon(opts) {
|
|
|
8301
8627
|
const home = voluteHome();
|
|
8302
8628
|
const systemDir = voluteSystemDir();
|
|
8303
8629
|
if (!opts.foreground) {
|
|
8304
|
-
const rotatingLog = new RotatingLog(
|
|
8630
|
+
const rotatingLog = new RotatingLog(resolve17(systemDir, "daemon.log"));
|
|
8305
8631
|
logger_default.setOutput((line) => rotatingLog.write(`${line}
|
|
8306
8632
|
`));
|
|
8307
8633
|
const write = (...args) => rotatingLog.write(`${format(...args)}
|
|
@@ -8311,32 +8637,32 @@ async function startDaemon(opts) {
|
|
|
8311
8637
|
console.warn = write;
|
|
8312
8638
|
console.info = write;
|
|
8313
8639
|
}
|
|
8314
|
-
const DAEMON_PID_PATH =
|
|
8315
|
-
const DAEMON_JSON_PATH =
|
|
8316
|
-
const DAEMON_TOKEN_PATH =
|
|
8640
|
+
const DAEMON_PID_PATH = resolve17(systemDir, "daemon.pid");
|
|
8641
|
+
const DAEMON_JSON_PATH = resolve17(systemDir, "daemon.json");
|
|
8642
|
+
const DAEMON_TOKEN_PATH = resolve17(systemDir, "daemon-token");
|
|
8317
8643
|
mkdirSync10(home, { recursive: true });
|
|
8318
8644
|
ensureSystemDir();
|
|
8319
|
-
const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-
|
|
8645
|
+
const { migrateConfigSecrets, migrateSetupCompleted } = await import("./setup-5ECWTYKG.js");
|
|
8320
8646
|
migrateConfigSecrets();
|
|
8321
8647
|
migrateSetupCompleted();
|
|
8322
|
-
const { migrateAiModelQualification } = await import("./ai-service-
|
|
8648
|
+
const { migrateAiModelQualification } = await import("./ai-service-643TNFPH.js");
|
|
8323
8649
|
migrateAiModelQualification();
|
|
8324
|
-
await (await import("./db-
|
|
8650
|
+
await (await import("./db-FO6LXYCW.js")).getDb();
|
|
8325
8651
|
try {
|
|
8326
8652
|
const { eq: eq8, and: and6 } = await import("drizzle-orm");
|
|
8327
|
-
const { users: users2 } = await import("./schema-
|
|
8328
|
-
const db = await (await import("./db-
|
|
8653
|
+
const { users: users2 } = await import("./schema-VEVO7HG6.js");
|
|
8654
|
+
const db = await (await import("./db-FO6LXYCW.js")).getDb();
|
|
8329
8655
|
await db.update(users2).set({ role: "system" }).where(and6(eq8(users2.user_type, "system"), eq8(users2.role, "user")));
|
|
8330
8656
|
} catch (err) {
|
|
8331
8657
|
logger_default.warn("failed to migrate system user role", logger_default.errorData(err));
|
|
8332
8658
|
}
|
|
8333
8659
|
try {
|
|
8334
|
-
const { migrateAvatarSizes } = await import("./avatar-image-
|
|
8660
|
+
const { migrateAvatarSizes } = await import("./avatar-image-Y45R7LW5.js");
|
|
8335
8661
|
await migrateAvatarSizes();
|
|
8336
8662
|
} catch (err) {
|
|
8337
8663
|
logger_default.warn("avatar size migration failed", logger_default.errorData(err));
|
|
8338
8664
|
}
|
|
8339
|
-
const { initSandbox } = await import("./sandbox-
|
|
8665
|
+
const { initSandbox } = await import("./sandbox-5VQ454XP.js");
|
|
8340
8666
|
await initSandbox();
|
|
8341
8667
|
try {
|
|
8342
8668
|
await syncBuiltinSkills();
|
|
@@ -8363,7 +8689,12 @@ async function startDaemon(opts) {
|
|
|
8363
8689
|
logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
|
|
8364
8690
|
}
|
|
8365
8691
|
try {
|
|
8366
|
-
|
|
8692
|
+
await backfillSystemChannelMembers();
|
|
8693
|
+
} catch (err) {
|
|
8694
|
+
logger_default.warn("failed to backfill minds into #system", logger_default.errorData(err));
|
|
8695
|
+
}
|
|
8696
|
+
try {
|
|
8697
|
+
const { getOrCreateSystemUser: getOrCreateSystemUser2 } = await import("./auth-A4VGHADI.js");
|
|
8367
8698
|
await getOrCreateSystemUser2();
|
|
8368
8699
|
} catch (err) {
|
|
8369
8700
|
logger_default.warn(
|
|
@@ -8372,12 +8703,12 @@ async function startDaemon(opts) {
|
|
|
8372
8703
|
);
|
|
8373
8704
|
}
|
|
8374
8705
|
const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes3(32).toString("hex");
|
|
8375
|
-
const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-
|
|
8706
|
+
const { readGlobalConfig: readGlobalConfig2 } = await import("./setup-5ECWTYKG.js");
|
|
8376
8707
|
const globalCfg = readGlobalConfig2();
|
|
8377
8708
|
let tls;
|
|
8378
8709
|
if (opts.tailscale || globalCfg.tailscale) {
|
|
8379
8710
|
try {
|
|
8380
|
-
const { getTailscaleTls } = await import("./tailscale-
|
|
8711
|
+
const { getTailscaleTls } = await import("./tailscale-MCLY5GYE.js");
|
|
8381
8712
|
const tlsConfig = await getTailscaleTls();
|
|
8382
8713
|
tls = { key: tlsConfig.key, cert: tlsConfig.cert };
|
|
8383
8714
|
logger_default.info("Tailscale HTTPS enabled", { hostname: tlsConfig.hostname });
|
|
@@ -8404,7 +8735,7 @@ async function startDaemon(opts) {
|
|
|
8404
8735
|
process.env.VOLUTE_DAEMON_TOKEN = token;
|
|
8405
8736
|
process.env.VOLUTE_DAEMON_PORT = String(daemonPort);
|
|
8406
8737
|
process.env.VOLUTE_DAEMON_HOSTNAME = hostname;
|
|
8407
|
-
|
|
8738
|
+
writeFileSync10(DAEMON_PID_PATH, myPid, { mode: 420 });
|
|
8408
8739
|
const daemonConfig = { port, hostname };
|
|
8409
8740
|
if (internalPort) daemonConfig.internalPort = internalPort;
|
|
8410
8741
|
if (tls) daemonConfig.tls = true;
|
|
@@ -8457,14 +8788,14 @@ async function startDaemon(opts) {
|
|
|
8457
8788
|
await Promise.all(workers);
|
|
8458
8789
|
}
|
|
8459
8790
|
try {
|
|
8460
|
-
const { isSetupComplete: isSetupComplete2 } = await import("./setup-
|
|
8791
|
+
const { isSetupComplete: isSetupComplete2 } = await import("./setup-5ECWTYKG.js");
|
|
8461
8792
|
if (isSetupComplete2()) {
|
|
8462
|
-
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-
|
|
8463
|
-
const { startSpiritFull } = await import("./mind-service-
|
|
8793
|
+
const { ensureSpiritProject, syncSpiritTemplate } = await import("./spirit-WXS3HCLN.js");
|
|
8794
|
+
const { startSpiritFull } = await import("./mind-service-2ARGJNKP.js");
|
|
8464
8795
|
await ensureSpiritProject();
|
|
8465
8796
|
const spiritEntry = await findMind(SPIRIT_NAME);
|
|
8466
8797
|
if (spiritEntry?.dir) {
|
|
8467
|
-
const { registerMindDir } = await import("./delivery-router-
|
|
8798
|
+
const { registerMindDir } = await import("./delivery-router-3QFG2ZEX.js");
|
|
8468
8799
|
registerMindDir(SPIRIT_NAME, spiritEntry.dir);
|
|
8469
8800
|
}
|
|
8470
8801
|
await syncSpiritTemplate();
|
|
@@ -8481,7 +8812,7 @@ async function startDaemon(opts) {
|
|
|
8481
8812
|
bridgeManager.startBridges(daemonPort).catch((err) => {
|
|
8482
8813
|
logger_default.warn("failed to start bridges", logger_default.errorData(err));
|
|
8483
8814
|
});
|
|
8484
|
-
import("./cloud-sync-
|
|
8815
|
+
import("./cloud-sync-WHKCB4CD.js").then(
|
|
8485
8816
|
({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
|
|
8486
8817
|
logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
|
|
8487
8818
|
})
|
|
@@ -8489,8 +8820,10 @@ async function startDaemon(opts) {
|
|
|
8489
8820
|
logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
|
|
8490
8821
|
});
|
|
8491
8822
|
try {
|
|
8492
|
-
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-
|
|
8493
|
-
backfillTemplateHashes()
|
|
8823
|
+
const { backfillTemplateHashes, notifyVersionUpdate, warnStaleTemplates } = await import("./version-notify-73YURTFR.js");
|
|
8824
|
+
backfillTemplateHashes().then(() => warnStaleTemplates()).catch((err) => {
|
|
8825
|
+
logger_default.warn("failed to check template staleness", logger_default.errorData(err));
|
|
8826
|
+
});
|
|
8494
8827
|
notifyVersionUpdate().catch((err) => {
|
|
8495
8828
|
logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
|
|
8496
8829
|
});
|
|
@@ -8517,13 +8850,13 @@ async function startDaemon(opts) {
|
|
|
8517
8850
|
logger_default.info(`running on ${hostname}:${port}, pid ${myPid}`);
|
|
8518
8851
|
function cleanup() {
|
|
8519
8852
|
try {
|
|
8520
|
-
if (
|
|
8853
|
+
if (readFileSync11(DAEMON_PID_PATH, "utf-8").trim() === myPid) {
|
|
8521
8854
|
unlinkSync2(DAEMON_PID_PATH);
|
|
8522
8855
|
}
|
|
8523
8856
|
} catch {
|
|
8524
8857
|
}
|
|
8525
8858
|
try {
|
|
8526
|
-
if (
|
|
8859
|
+
if (readFileSync11(DAEMON_TOKEN_PATH, "utf-8").trim() === token) {
|
|
8527
8860
|
unlinkSync2(DAEMON_TOKEN_PATH);
|
|
8528
8861
|
try {
|
|
8529
8862
|
unlinkSync2(DAEMON_JSON_PATH);
|