volute 0.25.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -20
- package/dist/{activity-events-4O37J7PD.js → activity-events-ZMBAKLUF.js} +2 -2
- package/dist/api.d.ts +477 -6
- package/dist/{auth-HM2RSPY7.js → auth-4TV573WE.js} +2 -2
- package/dist/{channel-HZOSHGNF.js → channel-ZVZV42UD.js} +3 -3
- package/dist/{chunk-SHSWYG2J.js → chunk-2VO7453N.js} +56 -19
- package/dist/{chunk-PMX4EIJK.js → chunk-3CFRE2VC.js} +878 -741
- package/dist/{chunk-PHHKNGA3.js → chunk-3TV4GLFO.js} +2 -2
- package/dist/{chunk-BOTQ25QT.js → chunk-5Y3PBKW6.js} +2 -2
- package/dist/{chunk-BFK6SOEJ.js → chunk-J2CO4WEV.js} +1 -1
- package/dist/{chunk-ZSH4G2P5.js → chunk-LX22GRG7.js} +10 -13
- package/dist/{chunk-E7GOKNOT.js → chunk-NWI2425I.js} +1 -1
- package/dist/{chunk-2767L2RZ.js → chunk-OZFKBXD6.js} +1 -1
- package/dist/{chunk-RVKR2R7F.js → chunk-SSI47XP2.js} +10 -2
- package/dist/chunk-TZKJLDQN.js +78 -0
- package/dist/{chunk-DG7TO7EE.js → chunk-USNBKHYG.js} +3 -3
- package/dist/chunk-UTL75LP6.js +113 -0
- package/dist/{chunk-3AIBT4TW.js → chunk-V63B7DX3.js} +24 -1
- package/dist/{chunk-33XAVCS4.js → chunk-WBHMQ5OZ.js} +49 -0
- package/dist/{chunk-TRQEV3CD.js → chunk-WGOGUMPO.js} +22 -3
- package/dist/chunk-XOXLRRR2.js +176 -0
- package/dist/{chunk-JTDFJWI2.js → chunk-YJA7P64S.js} +1 -1
- package/dist/chunk-ZYGKG6VC.js +22 -0
- package/dist/cli.js +44 -20
- package/dist/{cloud-sync-PPBBJDY6.js → cloud-sync-NI2K3C7G.js} +11 -9
- package/dist/{connector-M6XFI6GM.js → connector-G722WXAU.js} +4 -4
- package/dist/{create-VDQJER52.js → create-4YBRTTJS.js} +1 -1
- package/dist/{daemon-client-JOVQZ52X.js → daemon-client-Z7FAJ6JW.js} +1 -1
- package/dist/{daemon-restart-FDNOZEAD.js → daemon-restart-BJZ3O4U4.js} +6 -5
- package/dist/daemon.js +693 -265
- package/dist/{delete-2MRR4JX5.js → delete-27OYNK25.js} +1 -1
- package/dist/{down-674SX2IZ.js → down-7UKFMJJZ.js} +4 -4
- package/dist/{env-2FPOZK37.js → env-M336ONDP.js} +4 -4
- package/dist/{export-IKFAPRAO.js → export-HP4G5DQC.js} +1 -1
- package/dist/{file-KT3UIQM3.js → file-HUDKTRAS.js} +3 -3
- package/dist/{history-46WZN5CN.js → history-B64GTFTD.js} +3 -3
- package/dist/{import-TH26J76F.js → import-XIB7UV4S.js} +1 -1
- package/dist/{log-6SGSSR3D.js → log-PBFNILJ4.js} +3 -3
- package/dist/{login-UO6AOVEA.js → login-6U7U6BNG.js} +1 -1
- package/dist/login-B5E7N7MY.js +46 -0
- package/dist/logout-XSJRYS3U.js +39 -0
- package/dist/{logs-HRBONI5I.js → logs-3CART7O7.js} +3 -3
- package/dist/{merge-KSFJKX6T.js → merge-VK2HSKMA.js} +3 -3
- package/dist/{message-delivery-XMGV3FUM.js → message-delivery-MS5JYPZX.js} +10 -8
- package/dist/{mind-YVWAHL2A.js → mind-HZ3QSDDJ.js} +17 -17
- package/dist/{mind-activity-tracker-NMDDEV3K.js → mind-activity-tracker-4G6FURY2.js} +3 -3
- package/dist/{mind-manager-4NDNAYAB.js → mind-manager-VVK67AY3.js} +6 -4
- package/dist/{mind-sleep-GHPTSAYN.js → mind-sleep-DTV7L44D.js} +3 -3
- package/dist/{mind-wake-BJDJFMDF.js → mind-wake-PFN4FN3T.js} +3 -3
- package/dist/notes-37FW2UR2.js +230 -0
- package/dist/{package-3HF5MXU2.js → package-VZWLXPHV.js} +2 -1
- package/dist/{pages-Y6DRWUOJ.js → pages-DIIT5HMQ.js} +1 -1
- package/dist/{publish-EEKTZBHW.js → publish-HQV7YREB.js} +3 -3
- package/dist/{pull-D32SPFVU.js → pull-2MB4SK3C.js} +3 -3
- package/dist/{register-U2UO6TC4.js → register-EFND67FQ.js} +1 -1
- package/dist/{restart-5BMNV7KU.js → restart-CCK7D6TV.js} +3 -3
- package/dist/sandbox-EHGFF52K.js +19 -0
- package/dist/{schedule-YEFDLVMJ.js → schedule-6F7ELB2M.js} +3 -3
- package/dist/{seed-6FEKB3YC.js → seed-E5OQGWX3.js} +1 -1
- package/dist/{send-IISDYFCL.js → send-IH6XZKPC.js} +6 -20
- package/dist/service-LLBV3R7M.js +122 -0
- package/dist/setup-F6TWFYGQ.js +371 -0
- package/dist/setup-YGAAIKKZ.js +17 -0
- package/dist/{shared-LWMNTTZN.js → shared-UMO4S7CC.js} +4 -4
- package/dist/{skill-T3EMR6IR.js → skill-42LGFBQC.js} +3 -3
- package/dist/skills/dreaming/SKILL.md +68 -0
- package/dist/skills/dreaming/references/INSTALL.md +56 -0
- package/dist/skills/dreaming/scripts/dream.ts +289 -0
- package/dist/skills/dreaming/scripts/wake-context-dreams.sh +30 -0
- package/dist/skills/notes/SKILL.md +34 -0
- package/dist/{sleep-manager-RKTFZPD3.js → sleep-manager-EE4NRN2Q.js} +10 -8
- package/dist/{sprout-QJVGJDSH.js → sprout-QL74KR2X.js} +5 -5
- package/dist/{start-C7XITZ5O.js → start-O5JQASRC.js} +3 -3
- package/dist/{status-SIRPLEZC.js → status-FZBEBM7Q.js} +3 -3
- package/dist/{status-LYS4NUOZ.js → status-WXD4HXRL.js} +3 -3
- package/dist/{stop-CVKBSLXY.js → stop-2SOG5NYF.js} +3 -3
- package/dist/up-SDMCSVI3.js +17 -0
- package/dist/{update-7XCZMYBT.js → update-5VUDAI3D.js} +6 -6
- package/dist/{upgrade-7RUIXGOO.js → upgrade-QCCO33BK.js} +1 -1
- package/dist/{variant-UGREB4G5.js → variant-WWLDY6D5.js} +4 -4
- package/dist/{version-notify-AZQMC32A.js → version-notify-USFZBWMG.js} +11 -9
- package/dist/web-assets/assets/index-CUQ31ieL.js +69 -0
- package/dist/web-assets/assets/index-CW8NSl1o.css +1 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0015_notes.sql +23 -0
- package/drizzle/0016_note_reactions_and_replies.sql +15 -0
- package/drizzle/meta/_journal.json +14 -0
- package/package.json +2 -1
- package/templates/_base/.init/.config/hooks/wake-context.sh +7 -0
- package/templates/_base/src/lib/startup.ts +8 -0
- package/templates/claude/src/agent.ts +51 -1
- package/templates/claude/src/server.ts +1 -0
- package/templates/pi/package.json.tmpl +1 -0
- package/templates/pi/src/agent.ts +48 -1
- package/templates/pi/src/lib/subagents.ts +150 -0
- package/templates/pi/src/server.ts +1 -0
- package/dist/chunk-NWPT4ASZ.js +0 -89
- package/dist/service-FASYWLTC.js +0 -247
- package/dist/setup-BMLM2UTK.js +0 -230
- package/dist/up-CJ26KQLN.js +0 -15
- package/dist/web-assets/assets/index-CGPSVu19.js +0 -69
- package/dist/web-assets/assets/index-V_rNDsM8.css +0 -1
package/dist/daemon.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
sharedMerge,
|
|
8
8
|
sharedPull,
|
|
9
9
|
sharedStatus
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3TV4GLFO.js";
|
|
11
11
|
import {
|
|
12
12
|
applyInitFiles,
|
|
13
13
|
composeTemplate,
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from "./chunk-AKPFNL7L.js";
|
|
19
19
|
import {
|
|
20
20
|
addMessage,
|
|
21
|
+
announceToSystem,
|
|
21
22
|
approveUser,
|
|
22
23
|
changePassword,
|
|
23
24
|
countAdmins,
|
|
@@ -28,6 +29,7 @@ import {
|
|
|
28
29
|
deleteMindUser as deleteMindUser2,
|
|
29
30
|
deleteUser,
|
|
30
31
|
deliverMessage,
|
|
32
|
+
ensureSystemChannel,
|
|
31
33
|
extractTextContent,
|
|
32
34
|
findDMConversation,
|
|
33
35
|
fireWebhook,
|
|
@@ -58,6 +60,7 @@ import {
|
|
|
58
60
|
isParticipant,
|
|
59
61
|
isParticipantOrOwner,
|
|
60
62
|
joinChannel,
|
|
63
|
+
joinSystemChannel,
|
|
61
64
|
leaveChannel,
|
|
62
65
|
listChannels,
|
|
63
66
|
listConversationsForUser,
|
|
@@ -66,6 +69,7 @@ import {
|
|
|
66
69
|
listUsers,
|
|
67
70
|
listUsersByType,
|
|
68
71
|
markConversationRead,
|
|
72
|
+
migrateMindRoles,
|
|
69
73
|
publish,
|
|
70
74
|
publish2,
|
|
71
75
|
publishTypingForChannels,
|
|
@@ -78,7 +82,7 @@ import {
|
|
|
78
82
|
subscribe2 as subscribe3,
|
|
79
83
|
updateUserProfile,
|
|
80
84
|
verifyUser
|
|
81
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-3CFRE2VC.js";
|
|
82
86
|
import {
|
|
83
87
|
deleteSystemsConfig,
|
|
84
88
|
readSystemsConfig,
|
|
@@ -88,11 +92,11 @@ import {
|
|
|
88
92
|
getActiveMinds,
|
|
89
93
|
onMindEvent,
|
|
90
94
|
stopAll
|
|
91
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-NWI2425I.js";
|
|
92
96
|
import {
|
|
93
97
|
broadcast,
|
|
94
98
|
subscribe
|
|
95
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-J2CO4WEV.js";
|
|
96
100
|
import {
|
|
97
101
|
PROMPT_DEFAULTS,
|
|
98
102
|
PROMPT_KEYS,
|
|
@@ -102,28 +106,10 @@ import {
|
|
|
102
106
|
getPrompt,
|
|
103
107
|
getPromptIfCustom,
|
|
104
108
|
initMindManager,
|
|
109
|
+
resolveMindToken,
|
|
105
110
|
substitute
|
|
106
|
-
} from "./chunk-
|
|
107
|
-
import
|
|
108
|
-
findOpenClawSession,
|
|
109
|
-
importOpenClawConnectors,
|
|
110
|
-
importPiSession,
|
|
111
|
-
parseNameFromIdentity
|
|
112
|
-
} from "./chunk-BOTQ25QT.js";
|
|
113
|
-
import {
|
|
114
|
-
readVoluteConfig,
|
|
115
|
-
writeVoluteConfig
|
|
116
|
-
} from "./chunk-SIAG3QMM.js";
|
|
117
|
-
import {
|
|
118
|
-
loadMergedEnv,
|
|
119
|
-
mindEnvPath,
|
|
120
|
-
readEnv,
|
|
121
|
-
sharedEnvPath,
|
|
122
|
-
writeEnv
|
|
123
|
-
} from "./chunk-PHU4DEAJ.js";
|
|
124
|
-
import {
|
|
125
|
-
isHomeOnlyArchive
|
|
126
|
-
} from "./chunk-KTJGZ7M7.js";
|
|
111
|
+
} from "./chunk-2VO7453N.js";
|
|
112
|
+
import "./chunk-UTL75LP6.js";
|
|
127
113
|
import {
|
|
128
114
|
SEED_SKILLS,
|
|
129
115
|
STANDARD_SKILLS,
|
|
@@ -139,25 +125,53 @@ import {
|
|
|
139
125
|
syncBuiltinSkills,
|
|
140
126
|
uninstallSkill,
|
|
141
127
|
updateSkill
|
|
142
|
-
} from "./chunk-
|
|
128
|
+
} from "./chunk-USNBKHYG.js";
|
|
143
129
|
import {
|
|
144
130
|
activity,
|
|
145
131
|
conversations,
|
|
146
132
|
getDb,
|
|
147
133
|
mindHistory,
|
|
134
|
+
noteComments,
|
|
135
|
+
noteReactions,
|
|
136
|
+
notes,
|
|
148
137
|
sessions,
|
|
149
|
-
systemPrompts
|
|
150
|
-
|
|
138
|
+
systemPrompts,
|
|
139
|
+
users
|
|
140
|
+
} from "./chunk-WBHMQ5OZ.js";
|
|
151
141
|
import {
|
|
152
142
|
logBuffer,
|
|
153
143
|
logger_default
|
|
154
144
|
} from "./chunk-YUIHSKR6.js";
|
|
155
|
-
import
|
|
145
|
+
import {
|
|
146
|
+
checkForUpdate,
|
|
147
|
+
checkForUpdateCached,
|
|
148
|
+
getCurrentVersion
|
|
149
|
+
} from "./chunk-ON3FF5JA.js";
|
|
150
|
+
import {
|
|
151
|
+
findOpenClawSession,
|
|
152
|
+
importOpenClawConnectors,
|
|
153
|
+
importPiSession,
|
|
154
|
+
parseNameFromIdentity
|
|
155
|
+
} from "./chunk-5Y3PBKW6.js";
|
|
156
|
+
import {
|
|
157
|
+
readVoluteConfig,
|
|
158
|
+
writeVoluteConfig
|
|
159
|
+
} from "./chunk-SIAG3QMM.js";
|
|
160
|
+
import {
|
|
161
|
+
loadMergedEnv,
|
|
162
|
+
mindEnvPath,
|
|
163
|
+
readEnv,
|
|
164
|
+
sharedEnvPath,
|
|
165
|
+
writeEnv
|
|
166
|
+
} from "./chunk-PHU4DEAJ.js";
|
|
167
|
+
import {
|
|
168
|
+
isHomeOnlyArchive
|
|
169
|
+
} from "./chunk-KTJGZ7M7.js";
|
|
156
170
|
import {
|
|
157
171
|
exec,
|
|
158
172
|
gitExec,
|
|
159
173
|
resolveVoluteBin
|
|
160
|
-
} from "./chunk-
|
|
174
|
+
} from "./chunk-YJA7P64S.js";
|
|
161
175
|
import {
|
|
162
176
|
chownMindDir,
|
|
163
177
|
createMindUser,
|
|
@@ -165,12 +179,8 @@ import {
|
|
|
165
179
|
ensureVoluteGroup,
|
|
166
180
|
isIsolationEnabled,
|
|
167
181
|
wrapForIsolation
|
|
168
|
-
} from "./chunk-
|
|
169
|
-
import
|
|
170
|
-
checkForUpdate,
|
|
171
|
-
checkForUpdateCached,
|
|
172
|
-
getCurrentVersion
|
|
173
|
-
} from "./chunk-ON3FF5JA.js";
|
|
182
|
+
} from "./chunk-XOXLRRR2.js";
|
|
183
|
+
import "./chunk-D424ZQGI.js";
|
|
174
184
|
import {
|
|
175
185
|
buildVoluteSlug,
|
|
176
186
|
resolveChannelId,
|
|
@@ -178,6 +188,7 @@ import {
|
|
|
178
188
|
splitMessage,
|
|
179
189
|
writeChannelEntry
|
|
180
190
|
} from "./chunk-WSLPZF72.js";
|
|
191
|
+
import "./chunk-TZKJLDQN.js";
|
|
181
192
|
import {
|
|
182
193
|
addMind,
|
|
183
194
|
addVariant,
|
|
@@ -448,6 +459,24 @@ var requireAdmin = createMiddleware(async (c, next) => {
|
|
|
448
459
|
}
|
|
449
460
|
await next();
|
|
450
461
|
});
|
|
462
|
+
async function resolveSession(sessionId) {
|
|
463
|
+
const cached = sessionCache.get(sessionId);
|
|
464
|
+
if (cached && cached.expires > Date.now()) {
|
|
465
|
+
return cached.user;
|
|
466
|
+
}
|
|
467
|
+
const userId = await getSessionUserId(sessionId);
|
|
468
|
+
if (userId == null) {
|
|
469
|
+
sessionCache.delete(sessionId);
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
const user = await getUser(userId);
|
|
473
|
+
if (!user) {
|
|
474
|
+
sessionCache.delete(sessionId);
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
sessionCache.set(sessionId, { userId, user, expires: Date.now() + SESSION_CACHE_TTL });
|
|
478
|
+
return user;
|
|
479
|
+
}
|
|
451
480
|
var authMiddleware = createMiddleware(async (c, next) => {
|
|
452
481
|
const authHeader = c.req.header("Authorization");
|
|
453
482
|
if (authHeader?.startsWith("Bearer ")) {
|
|
@@ -455,7 +484,7 @@ var authMiddleware = createMiddleware(async (c, next) => {
|
|
|
455
484
|
if (token && isValidDaemonToken(token)) {
|
|
456
485
|
c.set("user", {
|
|
457
486
|
id: 0,
|
|
458
|
-
username: "
|
|
487
|
+
username: "daemon",
|
|
459
488
|
role: "admin",
|
|
460
489
|
user_type: "brain",
|
|
461
490
|
display_name: null,
|
|
@@ -465,31 +494,42 @@ var authMiddleware = createMiddleware(async (c, next) => {
|
|
|
465
494
|
await next();
|
|
466
495
|
return;
|
|
467
496
|
}
|
|
497
|
+
const mindName = resolveMindToken(token);
|
|
498
|
+
if (mindName) {
|
|
499
|
+
const mindUser = await getOrCreateMindUser(mindName);
|
|
500
|
+
c.set("user", mindUser);
|
|
501
|
+
await next();
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (token) {
|
|
505
|
+
const user2 = await resolveSession(token);
|
|
506
|
+
if (user2) {
|
|
507
|
+
if (user2.role === "pending") return c.json({ error: "Account pending approval" }, 403);
|
|
508
|
+
c.set("user", user2);
|
|
509
|
+
await next();
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
468
513
|
}
|
|
469
514
|
const sessionId = getCookie(c, "volute_session");
|
|
470
515
|
if (!sessionId) return c.json({ error: "Unauthorized" }, 401);
|
|
471
|
-
const
|
|
472
|
-
if (
|
|
473
|
-
if (cached.user.role === "pending") return c.json({ error: "Account pending approval" }, 403);
|
|
474
|
-
c.set("user", cached.user);
|
|
475
|
-
await next();
|
|
476
|
-
return;
|
|
477
|
-
}
|
|
478
|
-
const userId = await getSessionUserId(sessionId);
|
|
479
|
-
if (userId == null) {
|
|
480
|
-
sessionCache.delete(sessionId);
|
|
481
|
-
return c.json({ error: "Unauthorized" }, 401);
|
|
482
|
-
}
|
|
483
|
-
const user = await getUser(userId);
|
|
484
|
-
if (!user) {
|
|
485
|
-
sessionCache.delete(sessionId);
|
|
486
|
-
return c.json({ error: "Unauthorized" }, 401);
|
|
487
|
-
}
|
|
516
|
+
const user = await resolveSession(sessionId);
|
|
517
|
+
if (!user) return c.json({ error: "Unauthorized" }, 401);
|
|
488
518
|
if (user.role === "pending") return c.json({ error: "Account pending approval" }, 403);
|
|
489
|
-
sessionCache.set(sessionId, { userId, user, expires: Date.now() + SESSION_CACHE_TTL });
|
|
490
519
|
c.set("user", user);
|
|
491
520
|
await next();
|
|
492
521
|
});
|
|
522
|
+
var requireSelf = (paramName = "name") => createMiddleware(async (c, next) => {
|
|
523
|
+
const user = c.get("user");
|
|
524
|
+
if (user.role !== "admin") {
|
|
525
|
+
const target = c.req.param(paramName) ?? "";
|
|
526
|
+
const [baseName] = target.split("@", 2);
|
|
527
|
+
if (user.username !== baseName) {
|
|
528
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
await next();
|
|
532
|
+
});
|
|
493
533
|
|
|
494
534
|
// src/web/server.ts
|
|
495
535
|
import { existsSync as existsSync13 } from "fs";
|
|
@@ -499,7 +539,7 @@ import { dirname, extname as extname5, resolve as resolve18 } from "path";
|
|
|
499
539
|
import { serve } from "@hono/node-server";
|
|
500
540
|
|
|
501
541
|
// src/web/app.ts
|
|
502
|
-
import { Hono as
|
|
542
|
+
import { Hono as Hono30 } from "hono";
|
|
503
543
|
import { bodyLimit } from "hono/body-limit";
|
|
504
544
|
import { csrf } from "hono/csrf";
|
|
505
545
|
import { HTTPException } from "hono/http-exception";
|
|
@@ -551,7 +591,7 @@ var app = new Hono().get("/events", async (c) => {
|
|
|
551
591
|
});
|
|
552
592
|
cleanups.push(unsubActivity);
|
|
553
593
|
for (const conv of conversations2) {
|
|
554
|
-
const unsubConv =
|
|
594
|
+
const unsubConv = subscribe2(conv.id, (event) => {
|
|
555
595
|
stream.writeSSE({
|
|
556
596
|
data: JSON.stringify({ event: "conversation", conversationId: conv.id, ...event })
|
|
557
597
|
}).catch((err) => {
|
|
@@ -588,6 +628,11 @@ import { zValidator } from "@hono/zod-validator";
|
|
|
588
628
|
import { Hono as Hono2 } from "hono";
|
|
589
629
|
import { deleteCookie, getCookie as getCookie2, setCookie } from "hono/cookie";
|
|
590
630
|
import { z } from "zod";
|
|
631
|
+
function tryJoinSystem(userId) {
|
|
632
|
+
if (!process.env.VOLUTE_DAEMON_TOKEN) return;
|
|
633
|
+
joinSystemChannel(userId).catch(() => {
|
|
634
|
+
});
|
|
635
|
+
}
|
|
591
636
|
var SESSION_COOKIE_OPTIONS = {
|
|
592
637
|
path: "/",
|
|
593
638
|
httpOnly: true,
|
|
@@ -772,6 +817,7 @@ var app2 = new Hono2().post("/register", zValidator("json", credentialsSchema),
|
|
|
772
817
|
const sessionId = await createSession(user.id);
|
|
773
818
|
setCookie(c, "volute_session", sessionId, SESSION_COOKIE_OPTIONS);
|
|
774
819
|
}
|
|
820
|
+
tryJoinSystem(user.id);
|
|
775
821
|
return c.json({ id: user.id, username: user.username, role: user.role });
|
|
776
822
|
}).post("/login", zValidator("json", credentialsSchema), async (c) => {
|
|
777
823
|
const { username, password } = c.req.valid("json");
|
|
@@ -781,12 +827,21 @@ var app2 = new Hono2().post("/register", zValidator("json", credentialsSchema),
|
|
|
781
827
|
}
|
|
782
828
|
const sessionId = await createSession(user.id);
|
|
783
829
|
setCookie(c, "volute_session", sessionId, SESSION_COOKIE_OPTIONS);
|
|
784
|
-
|
|
830
|
+
tryJoinSystem(user.id);
|
|
831
|
+
return c.json({ id: user.id, username: user.username, role: user.role, sessionId });
|
|
785
832
|
}).post("/logout", async (c) => {
|
|
786
|
-
const
|
|
787
|
-
if (
|
|
788
|
-
await deleteSession(
|
|
833
|
+
const cookieSession = getCookie2(c, "volute_session");
|
|
834
|
+
if (cookieSession) {
|
|
835
|
+
await deleteSession(cookieSession);
|
|
789
836
|
deleteCookie(c, "volute_session", { path: "/" });
|
|
837
|
+
return c.json({ ok: true });
|
|
838
|
+
}
|
|
839
|
+
const authHeader = c.req.header("Authorization");
|
|
840
|
+
if (authHeader?.startsWith("Bearer ")) {
|
|
841
|
+
const token = authHeader.slice(7);
|
|
842
|
+
if (token) {
|
|
843
|
+
await deleteSession(token);
|
|
844
|
+
}
|
|
790
845
|
}
|
|
791
846
|
return c.json({ ok: true });
|
|
792
847
|
}).get("/me", async (c) => {
|
|
@@ -1095,8 +1150,8 @@ async function listConversations2(env) {
|
|
|
1095
1150
|
const userMap = /* @__PURE__ */ new Map();
|
|
1096
1151
|
const imChannels = data.channels.filter((ch) => ch.is_im && ch.user);
|
|
1097
1152
|
if (imChannels.length > 0) {
|
|
1098
|
-
const
|
|
1099
|
-
for (const u of
|
|
1153
|
+
const users2 = await listUsers3(env);
|
|
1154
|
+
for (const u of users2) {
|
|
1100
1155
|
userMap.set(u.id, u.username);
|
|
1101
1156
|
}
|
|
1102
1157
|
}
|
|
@@ -1488,7 +1543,7 @@ function resolveChannelId2(env, slug) {
|
|
|
1488
1543
|
function buildEnv(name) {
|
|
1489
1544
|
return { ...loadMergedEnv(name), VOLUTE_MIND: name, VOLUTE_MIND_DIR: mindDir(name) };
|
|
1490
1545
|
}
|
|
1491
|
-
var app3 = new Hono3().post("/:name/channels/send",
|
|
1546
|
+
var app3 = new Hono3().post("/:name/channels/send", requireSelf(), async (c) => {
|
|
1492
1547
|
const name = c.req.param("name");
|
|
1493
1548
|
if (!findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
1494
1549
|
const { platform, uri, message, images, sender } = await c.req.json();
|
|
@@ -1554,12 +1609,12 @@ var app3 = new Hono3().post("/:name/channels/send", requireAdmin, async (c) => {
|
|
|
1554
1609
|
return c.json({ error: `Platform ${platform} does not support listing users` }, 400);
|
|
1555
1610
|
const env = buildEnv(name);
|
|
1556
1611
|
try {
|
|
1557
|
-
const
|
|
1558
|
-
return c.json(
|
|
1612
|
+
const users2 = await driver.listUsers(env);
|
|
1613
|
+
return c.json(users2);
|
|
1559
1614
|
} catch (err) {
|
|
1560
1615
|
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
1561
1616
|
}
|
|
1562
|
-
}).post("/:name/channels/create",
|
|
1617
|
+
}).post("/:name/channels/create", requireSelf(), async (c) => {
|
|
1563
1618
|
const name = c.req.param("name");
|
|
1564
1619
|
if (!findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
1565
1620
|
const {
|
|
@@ -1914,7 +1969,7 @@ async function notifyMind(port, message, channel, sender) {
|
|
|
1914
1969
|
console.warn(`[file-sharing] notify mind on port ${port} failed:`, err);
|
|
1915
1970
|
}
|
|
1916
1971
|
}
|
|
1917
|
-
var app6 = new Hono6().post("/:name/files/send", async (c) => {
|
|
1972
|
+
var app6 = new Hono6().post("/:name/files/send", requireSelf(), async (c) => {
|
|
1918
1973
|
const senderName = c.req.param("name");
|
|
1919
1974
|
const senderEntry = findMind(senderName);
|
|
1920
1975
|
if (!senderEntry) return c.json({ error: "Sender mind not found" }, 404);
|
|
@@ -2648,7 +2703,7 @@ async function getMindStatus(name, port) {
|
|
|
2648
2703
|
const manager = getMindManager();
|
|
2649
2704
|
let status = "stopped";
|
|
2650
2705
|
try {
|
|
2651
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
2706
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-EE4NRN2Q.js");
|
|
2652
2707
|
if (getSleepManagerIfReady()?.isSleeping(name)) {
|
|
2653
2708
|
status = "sleeping";
|
|
2654
2709
|
}
|
|
@@ -3046,11 +3101,30 @@ var app11 = new Hono11().post("/", requireAdmin, zValidator3("json", createMindS
|
|
|
3046
3101
|
copyTemplateToDir(composedDir, dest, name, manifest);
|
|
3047
3102
|
applyInitFiles(dest);
|
|
3048
3103
|
const { publicKeyPem } = generateIdentity(dest);
|
|
3049
|
-
|
|
3050
|
-
const
|
|
3051
|
-
if (!
|
|
3052
|
-
|
|
3053
|
-
|
|
3104
|
+
{
|
|
3105
|
+
const config = readVoluteConfig(dest);
|
|
3106
|
+
if (!config) throw new Error("Failed to read volute.json after identity generation");
|
|
3107
|
+
if (body.description) {
|
|
3108
|
+
config.profile = { ...config.profile, description: body.description };
|
|
3109
|
+
}
|
|
3110
|
+
if (!config.sleep) {
|
|
3111
|
+
config.sleep = {
|
|
3112
|
+
enabled: true,
|
|
3113
|
+
schedule: { sleep: "0 0 * * *", wake: "0 8 * * *" }
|
|
3114
|
+
};
|
|
3115
|
+
}
|
|
3116
|
+
if (!config.schedules || config.schedules.length === 0) {
|
|
3117
|
+
config.schedules = [
|
|
3118
|
+
{
|
|
3119
|
+
id: "heartbeat",
|
|
3120
|
+
cron: "0 12,16,20 * * *",
|
|
3121
|
+
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.",
|
|
3122
|
+
enabled: true,
|
|
3123
|
+
skipWhenSleeping: true
|
|
3124
|
+
}
|
|
3125
|
+
];
|
|
3126
|
+
}
|
|
3127
|
+
writeVoluteConfig(dest, config);
|
|
3054
3128
|
}
|
|
3055
3129
|
if (body.model) {
|
|
3056
3130
|
const configPath2 = resolve12(dest, "home/.config/config.json");
|
|
@@ -3136,6 +3210,8 @@ The human who planted you described you as: "${body.description}"
|
|
|
3136
3210
|
description: body.description
|
|
3137
3211
|
}
|
|
3138
3212
|
});
|
|
3213
|
+
announceToSystem(`${name} has joined`).catch(() => {
|
|
3214
|
+
});
|
|
3139
3215
|
return c.json({
|
|
3140
3216
|
ok: true,
|
|
3141
3217
|
name,
|
|
@@ -3347,7 +3423,7 @@ ${user.trimEnd()}
|
|
|
3347
3423
|
} catch (err) {
|
|
3348
3424
|
return c.json({ error: err instanceof Error ? err.message : "Failed to start mind" }, 500);
|
|
3349
3425
|
}
|
|
3350
|
-
}).post("/:name/restart",
|
|
3426
|
+
}).post("/:name/restart", requireSelf(), async (c) => {
|
|
3351
3427
|
const name = c.req.param("name");
|
|
3352
3428
|
const [baseName, variantName] = name.split("@", 2);
|
|
3353
3429
|
const entry = findMind(baseName);
|
|
@@ -3373,6 +3449,14 @@ ${user.trimEnd()}
|
|
|
3373
3449
|
}
|
|
3374
3450
|
const manager = getMindManager();
|
|
3375
3451
|
try {
|
|
3452
|
+
if (context?.type === "reload") {
|
|
3453
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-EE4NRN2Q.js");
|
|
3454
|
+
const sleepState = getSleepManagerIfReady()?.getState(name);
|
|
3455
|
+
if (sleepState?.sleeping) {
|
|
3456
|
+
logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
|
|
3457
|
+
return c.json({ ok: true, deferred: true, port: targetPort });
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3376
3460
|
if (manager.isRunning(name)) {
|
|
3377
3461
|
await stopMindFull(name);
|
|
3378
3462
|
}
|
|
@@ -3466,7 +3550,7 @@ ${user.trimEnd()}
|
|
|
3466
3550
|
const name = c.req.param("name");
|
|
3467
3551
|
const entry = findMind(name);
|
|
3468
3552
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3469
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
3553
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-EE4NRN2Q.js");
|
|
3470
3554
|
const sm = getSleepManagerIfReady();
|
|
3471
3555
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
3472
3556
|
return c.json(sm.getState(name));
|
|
@@ -3474,7 +3558,7 @@ ${user.trimEnd()}
|
|
|
3474
3558
|
const name = c.req.param("name");
|
|
3475
3559
|
const entry = findMind(name);
|
|
3476
3560
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3477
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
3561
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-EE4NRN2Q.js");
|
|
3478
3562
|
const sm = getSleepManagerIfReady();
|
|
3479
3563
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
3480
3564
|
if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
|
|
@@ -3494,17 +3578,22 @@ ${user.trimEnd()}
|
|
|
3494
3578
|
const name = c.req.param("name");
|
|
3495
3579
|
const entry = findMind(name);
|
|
3496
3580
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3497
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
3581
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-EE4NRN2Q.js");
|
|
3498
3582
|
const sm = getSleepManagerIfReady();
|
|
3499
3583
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
3500
|
-
|
|
3501
|
-
|
|
3584
|
+
const sleepState = sm.getState(name);
|
|
3585
|
+
if (!sleepState.sleeping) return c.json({ error: "Mind is not sleeping" }, 409);
|
|
3586
|
+
if (sleepState.wokenByTrigger) {
|
|
3587
|
+
sm.convertTriggerToFullWake(name);
|
|
3588
|
+
} else {
|
|
3589
|
+
sm.initiateWake(name).catch((err) => logger_default.error(`failed to wake ${name}`, logger_default.errorData(err)));
|
|
3590
|
+
}
|
|
3502
3591
|
return c.json({ ok: true });
|
|
3503
3592
|
}).post("/:name/sleep/messages", requireAdmin, async (c) => {
|
|
3504
3593
|
const name = c.req.param("name");
|
|
3505
3594
|
const entry = findMind(name);
|
|
3506
3595
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
3507
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
3596
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-EE4NRN2Q.js");
|
|
3508
3597
|
const sm = getSleepManagerIfReady();
|
|
3509
3598
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
3510
3599
|
const flushed = await sm.flushQueuedMessages(name);
|
|
@@ -3712,7 +3801,7 @@ ${user.trimEnd()}
|
|
|
3712
3801
|
500
|
|
3713
3802
|
);
|
|
3714
3803
|
}
|
|
3715
|
-
}).post("/:name/message", async (c) => {
|
|
3804
|
+
}).post("/:name/message", requireSelf(), async (c) => {
|
|
3716
3805
|
const name = c.req.param("name");
|
|
3717
3806
|
const [baseName, variantName] = name.split("@", 2);
|
|
3718
3807
|
const entry = findMind(baseName);
|
|
@@ -3722,7 +3811,7 @@ ${user.trimEnd()}
|
|
|
3722
3811
|
if (!variant) return c.json({ error: `Unknown variant: ${variantName}` }, 404);
|
|
3723
3812
|
}
|
|
3724
3813
|
try {
|
|
3725
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
3814
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-EE4NRN2Q.js");
|
|
3726
3815
|
const sm = getSleepManagerIfReady();
|
|
3727
3816
|
if (sm?.isSleeping(baseName)) {
|
|
3728
3817
|
const body2 = await c.req.text();
|
|
@@ -3945,7 +4034,7 @@ ${user.trimEnd()}
|
|
|
3945
4034
|
logger_default.error(`failed to get pending deliveries for ${baseName}`, logger_default.errorData(err));
|
|
3946
4035
|
return c.json({ error: "Failed to retrieve pending messages" }, 500);
|
|
3947
4036
|
}
|
|
3948
|
-
}).post("/:name/events", async (c) => {
|
|
4037
|
+
}).post("/:name/events", requireSelf(), async (c) => {
|
|
3949
4038
|
const name = c.req.param("name");
|
|
3950
4039
|
const [baseName] = name.split("@", 2);
|
|
3951
4040
|
let body;
|
|
@@ -3971,7 +4060,7 @@ ${user.trimEnd()}
|
|
|
3971
4060
|
} catch (err) {
|
|
3972
4061
|
logger_default.error(`failed to persist event for ${baseName}`, logger_default.errorData(err));
|
|
3973
4062
|
}
|
|
3974
|
-
|
|
4063
|
+
publish2(baseName, {
|
|
3975
4064
|
mind: baseName,
|
|
3976
4065
|
type: body.type,
|
|
3977
4066
|
session: body.session,
|
|
@@ -4030,7 +4119,7 @@ ${user.trimEnd()}
|
|
|
4030
4119
|
unsubscribe?.();
|
|
4031
4120
|
}
|
|
4032
4121
|
}, 15e3);
|
|
4033
|
-
unsubscribe =
|
|
4122
|
+
unsubscribe = subscribe3(baseName, (event) => {
|
|
4034
4123
|
if (typeFilter && !typeFilter.includes(event.type)) return;
|
|
4035
4124
|
if (sessionFilter && event.session !== sessionFilter) return;
|
|
4036
4125
|
if (channelFilter && event.channel !== channelFilter) return;
|
|
@@ -4058,7 +4147,7 @@ ${user.trimEnd()}
|
|
|
4058
4147
|
Connection: "keep-alive"
|
|
4059
4148
|
}
|
|
4060
4149
|
});
|
|
4061
|
-
}).post("/:name/history", async (c) => {
|
|
4150
|
+
}).post("/:name/history", requireSelf(), async (c) => {
|
|
4062
4151
|
const name = c.req.param("name");
|
|
4063
4152
|
const [baseName] = name.split("@", 2);
|
|
4064
4153
|
let body;
|
|
@@ -4129,10 +4218,330 @@ ${user.trimEnd()}
|
|
|
4129
4218
|
});
|
|
4130
4219
|
var minds_default = app11;
|
|
4131
4220
|
|
|
4221
|
+
// src/web/api/notes.ts
|
|
4222
|
+
import { zValidator as zValidator4 } from "@hono/zod-validator";
|
|
4223
|
+
import { Hono as Hono12 } from "hono";
|
|
4224
|
+
import { z as z4 } from "zod";
|
|
4225
|
+
|
|
4226
|
+
// src/lib/notes.ts
|
|
4227
|
+
import { and as and2, count, desc as desc3, eq as eq3, inArray, sql as sql2 } from "drizzle-orm";
|
|
4228
|
+
async function createNote(authorId, title, content, replyToId) {
|
|
4229
|
+
const db = await getDb();
|
|
4230
|
+
let slug = slugify(title) || "untitled";
|
|
4231
|
+
const existing = await db.select({ slug: notes.slug }).from(notes).where(eq3(notes.author_id, authorId)).all();
|
|
4232
|
+
const existingSlugs = new Set(existing.map((r) => r.slug));
|
|
4233
|
+
if (existingSlugs.has(slug)) {
|
|
4234
|
+
let i = 2;
|
|
4235
|
+
while (existingSlugs.has(`${slug}-${i}`)) i++;
|
|
4236
|
+
slug = `${slug}-${i}`;
|
|
4237
|
+
}
|
|
4238
|
+
const [row] = await db.insert(notes).values({ author_id: authorId, title, slug, content, reply_to_id: replyToId ?? null }).returning();
|
|
4239
|
+
const author = await db.select().from(users).where(eq3(users.id, authorId)).get();
|
|
4240
|
+
return {
|
|
4241
|
+
...row,
|
|
4242
|
+
author_username: author?.username ?? "unknown",
|
|
4243
|
+
author_display_name: author?.display_name ?? null,
|
|
4244
|
+
comment_count: 0
|
|
4245
|
+
};
|
|
4246
|
+
}
|
|
4247
|
+
async function getNote(authorUsername, slug) {
|
|
4248
|
+
const db = await getDb();
|
|
4249
|
+
const row = await db.select({
|
|
4250
|
+
id: notes.id,
|
|
4251
|
+
author_id: notes.author_id,
|
|
4252
|
+
title: notes.title,
|
|
4253
|
+
slug: notes.slug,
|
|
4254
|
+
content: notes.content,
|
|
4255
|
+
reply_to_id: notes.reply_to_id,
|
|
4256
|
+
created_at: notes.created_at,
|
|
4257
|
+
updated_at: notes.updated_at,
|
|
4258
|
+
author_username: users.username,
|
|
4259
|
+
author_display_name: users.display_name
|
|
4260
|
+
}).from(notes).innerJoin(users, eq3(notes.author_id, users.id)).where(and2(eq3(users.username, authorUsername), eq3(notes.slug, slug))).get();
|
|
4261
|
+
if (!row) return null;
|
|
4262
|
+
const comments = await getComments(row.id);
|
|
4263
|
+
const reactions = await getReactions(row.id);
|
|
4264
|
+
let reply_to = null;
|
|
4265
|
+
if (row.reply_to_id) {
|
|
4266
|
+
const parent = await db.select({
|
|
4267
|
+
title: notes.title,
|
|
4268
|
+
slug: notes.slug,
|
|
4269
|
+
author_username: users.username
|
|
4270
|
+
}).from(notes).innerJoin(users, eq3(notes.author_id, users.id)).where(eq3(notes.id, row.reply_to_id)).get();
|
|
4271
|
+
if (parent) {
|
|
4272
|
+
reply_to = parent;
|
|
4273
|
+
}
|
|
4274
|
+
}
|
|
4275
|
+
const replies = await db.select({
|
|
4276
|
+
author_username: users.username,
|
|
4277
|
+
slug: notes.slug,
|
|
4278
|
+
title: notes.title,
|
|
4279
|
+
created_at: notes.created_at
|
|
4280
|
+
}).from(notes).innerJoin(users, eq3(notes.author_id, users.id)).where(eq3(notes.reply_to_id, row.id)).orderBy(notes.created_at).all();
|
|
4281
|
+
return { ...row, comment_count: comments.length, comments, reactions, reply_to, replies };
|
|
4282
|
+
}
|
|
4283
|
+
async function listNotes(opts) {
|
|
4284
|
+
const db = await getDb();
|
|
4285
|
+
const limit = opts?.limit ?? 50;
|
|
4286
|
+
const offset = opts?.offset ?? 0;
|
|
4287
|
+
const conditions = [];
|
|
4288
|
+
if (opts?.authorUsername) {
|
|
4289
|
+
conditions.push(eq3(users.username, opts.authorUsername));
|
|
4290
|
+
}
|
|
4291
|
+
const rows = await db.select({
|
|
4292
|
+
id: notes.id,
|
|
4293
|
+
author_id: notes.author_id,
|
|
4294
|
+
title: notes.title,
|
|
4295
|
+
slug: notes.slug,
|
|
4296
|
+
content: notes.content,
|
|
4297
|
+
reply_to_id: notes.reply_to_id,
|
|
4298
|
+
created_at: notes.created_at,
|
|
4299
|
+
updated_at: notes.updated_at,
|
|
4300
|
+
author_username: users.username,
|
|
4301
|
+
author_display_name: users.display_name
|
|
4302
|
+
}).from(notes).innerJoin(users, eq3(notes.author_id, users.id)).where(conditions.length > 0 ? and2(...conditions) : void 0).orderBy(desc3(notes.created_at)).limit(limit).offset(offset).all();
|
|
4303
|
+
const noteIds = rows.map((r) => r.id);
|
|
4304
|
+
if (noteIds.length === 0) return [];
|
|
4305
|
+
const commentCounts = await db.select({
|
|
4306
|
+
note_id: noteComments.note_id,
|
|
4307
|
+
count: count()
|
|
4308
|
+
}).from(noteComments).where(inArray(noteComments.note_id, noteIds)).groupBy(noteComments.note_id).all();
|
|
4309
|
+
const countMap = new Map(commentCounts.map((r) => [r.note_id, r.count]));
|
|
4310
|
+
const allReactions = await db.select({
|
|
4311
|
+
note_id: noteReactions.note_id,
|
|
4312
|
+
emoji: noteReactions.emoji,
|
|
4313
|
+
count: count()
|
|
4314
|
+
}).from(noteReactions).where(inArray(noteReactions.note_id, noteIds)).groupBy(noteReactions.note_id, noteReactions.emoji).all();
|
|
4315
|
+
const reactionMap = /* @__PURE__ */ new Map();
|
|
4316
|
+
for (const r of allReactions) {
|
|
4317
|
+
if (!reactionMap.has(r.note_id)) reactionMap.set(r.note_id, []);
|
|
4318
|
+
reactionMap.get(r.note_id).push({ emoji: r.emoji, count: r.count });
|
|
4319
|
+
}
|
|
4320
|
+
const replyToIds = [...new Set(rows.filter((r) => r.reply_to_id).map((r) => r.reply_to_id))];
|
|
4321
|
+
const replyToMap = /* @__PURE__ */ new Map();
|
|
4322
|
+
if (replyToIds.length > 0) {
|
|
4323
|
+
const parents = await db.select({
|
|
4324
|
+
id: notes.id,
|
|
4325
|
+
title: notes.title,
|
|
4326
|
+
slug: notes.slug,
|
|
4327
|
+
author_username: users.username
|
|
4328
|
+
}).from(notes).innerJoin(users, eq3(notes.author_id, users.id)).where(inArray(notes.id, replyToIds)).all();
|
|
4329
|
+
for (const parent of parents) {
|
|
4330
|
+
replyToMap.set(parent.id, {
|
|
4331
|
+
author_username: parent.author_username,
|
|
4332
|
+
slug: parent.slug,
|
|
4333
|
+
title: parent.title
|
|
4334
|
+
});
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
return rows.map((r) => {
|
|
4338
|
+
const reactions = reactionMap.get(r.id);
|
|
4339
|
+
const topReactions = reactions ? reactions.sort((a, b) => b.count - a.count).slice(0, 3).map((rx) => ({ ...rx, usernames: [] })) : void 0;
|
|
4340
|
+
return {
|
|
4341
|
+
...r,
|
|
4342
|
+
comment_count: countMap.get(r.id) ?? 0,
|
|
4343
|
+
reactions: topReactions,
|
|
4344
|
+
reply_to: r.reply_to_id ? replyToMap.get(r.reply_to_id) ?? null : null
|
|
4345
|
+
};
|
|
4346
|
+
});
|
|
4347
|
+
}
|
|
4348
|
+
async function updateNote(authorUsername, slug, updates) {
|
|
4349
|
+
const db = await getDb();
|
|
4350
|
+
const existing = await db.select({ id: notes.id, author_id: notes.author_id }).from(notes).innerJoin(users, eq3(notes.author_id, users.id)).where(and2(eq3(users.username, authorUsername), eq3(notes.slug, slug))).get();
|
|
4351
|
+
if (!existing) return null;
|
|
4352
|
+
const set = { updated_at: sql2`(datetime('now'))` };
|
|
4353
|
+
if (updates.title !== void 0) set.title = updates.title;
|
|
4354
|
+
if (updates.content !== void 0) set.content = updates.content;
|
|
4355
|
+
await db.update(notes).set(set).where(eq3(notes.id, existing.id));
|
|
4356
|
+
return getNote(authorUsername, slug).then(
|
|
4357
|
+
(n) => n ? { ...n, comments: void 0 } : null
|
|
4358
|
+
);
|
|
4359
|
+
}
|
|
4360
|
+
async function deleteNote(authorUsername, slug, authorId) {
|
|
4361
|
+
const db = await getDb();
|
|
4362
|
+
const existing = await db.select({ id: notes.id, author_id: notes.author_id }).from(notes).innerJoin(users, eq3(notes.author_id, users.id)).where(and2(eq3(users.username, authorUsername), eq3(notes.slug, slug))).get();
|
|
4363
|
+
if (!existing || existing.author_id !== authorId) return false;
|
|
4364
|
+
await db.delete(notes).where(eq3(notes.id, existing.id));
|
|
4365
|
+
return true;
|
|
4366
|
+
}
|
|
4367
|
+
async function addComment(noteId, authorId, content) {
|
|
4368
|
+
const db = await getDb();
|
|
4369
|
+
const [row] = await db.insert(noteComments).values({ note_id: noteId, author_id: authorId, content }).returning();
|
|
4370
|
+
const author = await db.select().from(users).where(eq3(users.id, authorId)).get();
|
|
4371
|
+
return {
|
|
4372
|
+
...row,
|
|
4373
|
+
author_username: author?.username ?? "unknown",
|
|
4374
|
+
author_display_name: author?.display_name ?? null
|
|
4375
|
+
};
|
|
4376
|
+
}
|
|
4377
|
+
async function getComments(noteId) {
|
|
4378
|
+
const db = await getDb();
|
|
4379
|
+
return db.select({
|
|
4380
|
+
id: noteComments.id,
|
|
4381
|
+
note_id: noteComments.note_id,
|
|
4382
|
+
author_id: noteComments.author_id,
|
|
4383
|
+
content: noteComments.content,
|
|
4384
|
+
created_at: noteComments.created_at,
|
|
4385
|
+
author_username: users.username,
|
|
4386
|
+
author_display_name: users.display_name
|
|
4387
|
+
}).from(noteComments).innerJoin(users, eq3(noteComments.author_id, users.id)).where(eq3(noteComments.note_id, noteId)).orderBy(noteComments.created_at).all();
|
|
4388
|
+
}
|
|
4389
|
+
async function deleteComment(commentId, authorId) {
|
|
4390
|
+
const db = await getDb();
|
|
4391
|
+
const existing = await db.select({ id: noteComments.id, author_id: noteComments.author_id }).from(noteComments).where(eq3(noteComments.id, commentId)).get();
|
|
4392
|
+
if (!existing || existing.author_id !== authorId) return false;
|
|
4393
|
+
await db.delete(noteComments).where(eq3(noteComments.id, commentId));
|
|
4394
|
+
return true;
|
|
4395
|
+
}
|
|
4396
|
+
async function toggleReaction(noteId, userId, emoji) {
|
|
4397
|
+
const db = await getDb();
|
|
4398
|
+
const existing = await db.select({ id: noteReactions.id }).from(noteReactions).where(
|
|
4399
|
+
and2(
|
|
4400
|
+
eq3(noteReactions.note_id, noteId),
|
|
4401
|
+
eq3(noteReactions.user_id, userId),
|
|
4402
|
+
eq3(noteReactions.emoji, emoji)
|
|
4403
|
+
)
|
|
4404
|
+
).get();
|
|
4405
|
+
if (existing) {
|
|
4406
|
+
await db.delete(noteReactions).where(eq3(noteReactions.id, existing.id));
|
|
4407
|
+
return { added: false };
|
|
4408
|
+
}
|
|
4409
|
+
await db.insert(noteReactions).values({ note_id: noteId, user_id: userId, emoji });
|
|
4410
|
+
return { added: true };
|
|
4411
|
+
}
|
|
4412
|
+
async function getReactions(noteId) {
|
|
4413
|
+
const db = await getDb();
|
|
4414
|
+
const rows = await db.select({
|
|
4415
|
+
emoji: noteReactions.emoji,
|
|
4416
|
+
username: users.username
|
|
4417
|
+
}).from(noteReactions).innerJoin(users, eq3(noteReactions.user_id, users.id)).where(eq3(noteReactions.note_id, noteId)).orderBy(noteReactions.emoji).all();
|
|
4418
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
4419
|
+
for (const r of rows) {
|
|
4420
|
+
if (!grouped.has(r.emoji)) grouped.set(r.emoji, []);
|
|
4421
|
+
grouped.get(r.emoji).push(r.username);
|
|
4422
|
+
}
|
|
4423
|
+
return [...grouped.entries()].map(([emoji, usernames]) => ({
|
|
4424
|
+
emoji,
|
|
4425
|
+
count: usernames.length,
|
|
4426
|
+
usernames
|
|
4427
|
+
}));
|
|
4428
|
+
}
|
|
4429
|
+
async function resolveNoteId(authorSlug) {
|
|
4430
|
+
const [author, slug] = authorSlug.split("/", 2);
|
|
4431
|
+
if (!author || !slug) return null;
|
|
4432
|
+
const db = await getDb();
|
|
4433
|
+
const row = await db.select({ id: notes.id }).from(notes).innerJoin(users, eq3(notes.author_id, users.id)).where(and2(eq3(users.username, author), eq3(notes.slug, slug))).get();
|
|
4434
|
+
return row?.id ?? null;
|
|
4435
|
+
}
|
|
4436
|
+
|
|
4437
|
+
// src/web/api/notes.ts
|
|
4438
|
+
var createSchema = z4.object({
|
|
4439
|
+
title: z4.string().min(1).max(200),
|
|
4440
|
+
content: z4.string().min(1),
|
|
4441
|
+
reply_to: z4.string().optional()
|
|
4442
|
+
});
|
|
4443
|
+
var updateSchema = z4.object({
|
|
4444
|
+
title: z4.string().min(1).max(200).optional(),
|
|
4445
|
+
content: z4.string().min(1).optional()
|
|
4446
|
+
});
|
|
4447
|
+
var commentSchema = z4.object({
|
|
4448
|
+
content: z4.string().min(1)
|
|
4449
|
+
});
|
|
4450
|
+
var reactionSchema = z4.object({
|
|
4451
|
+
emoji: z4.string().min(1).max(32)
|
|
4452
|
+
});
|
|
4453
|
+
async function resolveUserId(c) {
|
|
4454
|
+
const user = c.get("user");
|
|
4455
|
+
if (user.id === 0) {
|
|
4456
|
+
const asUser = c.req.query("as");
|
|
4457
|
+
if (!asUser) return null;
|
|
4458
|
+
try {
|
|
4459
|
+
const mindUser = await getOrCreateMindUser(asUser);
|
|
4460
|
+
return { id: mindUser.id, username: mindUser.username };
|
|
4461
|
+
} catch {
|
|
4462
|
+
const brainUser = await getUserByUsername(asUser);
|
|
4463
|
+
if (brainUser) return { id: brainUser.id, username: brainUser.username };
|
|
4464
|
+
return null;
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
return { id: user.id, username: user.username };
|
|
4468
|
+
}
|
|
4469
|
+
var app12 = new Hono12().get("/", async (c) => {
|
|
4470
|
+
const author = c.req.query("author");
|
|
4471
|
+
const limit = c.req.query("limit") ? parseInt(c.req.query("limit"), 10) : void 0;
|
|
4472
|
+
const offset = c.req.query("offset") ? parseInt(c.req.query("offset"), 10) : void 0;
|
|
4473
|
+
const result = await listNotes({ authorUsername: author, limit, offset });
|
|
4474
|
+
return c.json(result);
|
|
4475
|
+
}).post("/", zValidator4("json", createSchema), async (c) => {
|
|
4476
|
+
const actor = await resolveUserId(c);
|
|
4477
|
+
if (!actor) return c.json({ error: "Missing ?as=<username> for CLI requests" }, 400);
|
|
4478
|
+
const { title, content, reply_to } = c.req.valid("json");
|
|
4479
|
+
let replyToId;
|
|
4480
|
+
if (reply_to) {
|
|
4481
|
+
const id = await resolveNoteId(reply_to);
|
|
4482
|
+
if (id === null) return c.json({ error: `Reply target not found: ${reply_to}` }, 404);
|
|
4483
|
+
replyToId = id;
|
|
4484
|
+
}
|
|
4485
|
+
const note = await createNote(actor.id, title, content, replyToId);
|
|
4486
|
+
const replyInfo = reply_to ? ` (in reply to ${reply_to})` : "";
|
|
4487
|
+
announceToSystem(`${actor.username} published a note: ${title}${replyInfo}`).catch(() => {
|
|
4488
|
+
});
|
|
4489
|
+
return c.json(note, 201);
|
|
4490
|
+
}).get("/:author/:slug", async (c) => {
|
|
4491
|
+
const { author, slug } = c.req.param();
|
|
4492
|
+
const note = await getNote(author, slug);
|
|
4493
|
+
if (!note) return c.json({ error: "Note not found" }, 404);
|
|
4494
|
+
return c.json(note);
|
|
4495
|
+
}).put("/:author/:slug", zValidator4("json", updateSchema), async (c) => {
|
|
4496
|
+
const actor = await resolveUserId(c);
|
|
4497
|
+
if (!actor) return c.json({ error: "Missing ?as=<username> for CLI requests" }, 400);
|
|
4498
|
+
const { author, slug } = c.req.param();
|
|
4499
|
+
if (actor.username !== author) return c.json({ error: "Forbidden" }, 403);
|
|
4500
|
+
const updates = c.req.valid("json");
|
|
4501
|
+
const note = await updateNote(author, slug, updates);
|
|
4502
|
+
if (!note) return c.json({ error: "Note not found" }, 404);
|
|
4503
|
+
return c.json(note);
|
|
4504
|
+
}).delete("/:author/:slug", async (c) => {
|
|
4505
|
+
const actor = await resolveUserId(c);
|
|
4506
|
+
if (!actor) return c.json({ error: "Missing ?as=<username> for CLI requests" }, 400);
|
|
4507
|
+
const { author, slug } = c.req.param();
|
|
4508
|
+
const deleted = await deleteNote(author, slug, actor.id);
|
|
4509
|
+
if (!deleted) return c.json({ error: "Note not found or not authorized" }, 404);
|
|
4510
|
+
return c.json({ ok: true });
|
|
4511
|
+
}).post("/:author/:slug/reactions", zValidator4("json", reactionSchema), async (c) => {
|
|
4512
|
+
const actor = await resolveUserId(c);
|
|
4513
|
+
if (!actor) return c.json({ error: "Missing ?as=<username> for CLI requests" }, 400);
|
|
4514
|
+
const { author, slug } = c.req.param();
|
|
4515
|
+
const note = await getNote(author, slug);
|
|
4516
|
+
if (!note) return c.json({ error: "Note not found" }, 404);
|
|
4517
|
+
const { emoji } = c.req.valid("json");
|
|
4518
|
+
const result = await toggleReaction(note.id, actor.id, emoji);
|
|
4519
|
+
const reactions = await getReactions(note.id);
|
|
4520
|
+
return c.json({ ...result, reactions });
|
|
4521
|
+
}).post("/:author/:slug/comments", zValidator4("json", commentSchema), async (c) => {
|
|
4522
|
+
const actor = await resolveUserId(c);
|
|
4523
|
+
if (!actor) return c.json({ error: "Missing ?as=<username> for CLI requests" }, 400);
|
|
4524
|
+
const { author, slug } = c.req.param();
|
|
4525
|
+
const note = await getNote(author, slug);
|
|
4526
|
+
if (!note) return c.json({ error: "Note not found" }, 404);
|
|
4527
|
+
const { content } = c.req.valid("json");
|
|
4528
|
+
const comment = await addComment(note.id, actor.id, content);
|
|
4529
|
+
return c.json(comment, 201);
|
|
4530
|
+
}).delete("/:author/:slug/comments/:id", async (c) => {
|
|
4531
|
+
const actor = await resolveUserId(c);
|
|
4532
|
+
if (!actor) return c.json({ error: "Missing ?as=<username> for CLI requests" }, 400);
|
|
4533
|
+
const commentId = parseInt(c.req.param("id"), 10);
|
|
4534
|
+
if (Number.isNaN(commentId)) return c.json({ error: "Invalid comment ID" }, 400);
|
|
4535
|
+
const deleted = await deleteComment(commentId, actor.id);
|
|
4536
|
+
if (!deleted) return c.json({ error: "Comment not found or not authorized" }, 404);
|
|
4537
|
+
return c.json({ ok: true });
|
|
4538
|
+
});
|
|
4539
|
+
var notes_default = app12;
|
|
4540
|
+
|
|
4132
4541
|
// src/web/api/pages.ts
|
|
4133
4542
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
4134
4543
|
import { extname as extname3, resolve as resolve13 } from "path";
|
|
4135
|
-
import { Hono as
|
|
4544
|
+
import { Hono as Hono13 } from "hono";
|
|
4136
4545
|
var MIME_TYPES = {
|
|
4137
4546
|
".html": "text/html",
|
|
4138
4547
|
".js": "application/javascript",
|
|
@@ -4149,7 +4558,7 @@ var MIME_TYPES = {
|
|
|
4149
4558
|
".txt": "text/plain",
|
|
4150
4559
|
".xml": "application/xml"
|
|
4151
4560
|
};
|
|
4152
|
-
var
|
|
4561
|
+
var app13 = new Hono13().get("/:name/*", async (c) => {
|
|
4153
4562
|
const name = c.req.param("name");
|
|
4154
4563
|
let pagesRoot;
|
|
4155
4564
|
if (name === "_system") {
|
|
@@ -4179,14 +4588,14 @@ var app12 = new Hono12().get("/:name/*", async (c) => {
|
|
|
4179
4588
|
}
|
|
4180
4589
|
return c.text("Not found", 404);
|
|
4181
4590
|
});
|
|
4182
|
-
var pages_default =
|
|
4591
|
+
var pages_default = app13;
|
|
4183
4592
|
|
|
4184
4593
|
// src/web/api/prompts.ts
|
|
4185
|
-
import { zValidator as
|
|
4186
|
-
import { eq as
|
|
4187
|
-
import { Hono as
|
|
4188
|
-
import { z as
|
|
4189
|
-
var
|
|
4594
|
+
import { zValidator as zValidator5 } from "@hono/zod-validator";
|
|
4595
|
+
import { eq as eq4, sql as sql3 } from "drizzle-orm";
|
|
4596
|
+
import { Hono as Hono14 } from "hono";
|
|
4597
|
+
import { z as z5 } from "zod";
|
|
4598
|
+
var app14 = new Hono14().get("/", async (c) => {
|
|
4190
4599
|
let rows;
|
|
4191
4600
|
try {
|
|
4192
4601
|
const db = await getDb();
|
|
@@ -4209,16 +4618,16 @@ var app13 = new Hono13().get("/", async (c) => {
|
|
|
4209
4618
|
};
|
|
4210
4619
|
});
|
|
4211
4620
|
return c.json(prompts);
|
|
4212
|
-
}).put("/:key", requireAdmin,
|
|
4621
|
+
}).put("/:key", requireAdmin, zValidator5("json", z5.object({ content: z5.string() })), async (c) => {
|
|
4213
4622
|
const key = c.req.param("key");
|
|
4214
4623
|
if (!PROMPT_KEYS.includes(key)) {
|
|
4215
4624
|
return c.json({ error: "Unknown prompt key" }, 404);
|
|
4216
4625
|
}
|
|
4217
4626
|
const { content } = c.req.valid("json");
|
|
4218
4627
|
const db = await getDb();
|
|
4219
|
-
await db.insert(systemPrompts).values({ key, content, updated_at:
|
|
4628
|
+
await db.insert(systemPrompts).values({ key, content, updated_at: sql3`(datetime('now'))` }).onConflictDoUpdate({
|
|
4220
4629
|
target: systemPrompts.key,
|
|
4221
|
-
set: { content, updated_at:
|
|
4630
|
+
set: { content, updated_at: sql3`(datetime('now'))` }
|
|
4222
4631
|
});
|
|
4223
4632
|
return c.json({ ok: true });
|
|
4224
4633
|
}).delete("/:key", requireAdmin, async (c) => {
|
|
@@ -4227,15 +4636,15 @@ var app13 = new Hono13().get("/", async (c) => {
|
|
|
4227
4636
|
return c.json({ error: "Unknown prompt key" }, 404);
|
|
4228
4637
|
}
|
|
4229
4638
|
const db = await getDb();
|
|
4230
|
-
await db.delete(systemPrompts).where(
|
|
4639
|
+
await db.delete(systemPrompts).where(eq4(systemPrompts.key, key));
|
|
4231
4640
|
return c.json({ ok: true });
|
|
4232
4641
|
});
|
|
4233
|
-
var prompts_default =
|
|
4642
|
+
var prompts_default = app14;
|
|
4234
4643
|
|
|
4235
4644
|
// src/web/api/public-files.ts
|
|
4236
4645
|
import { readdir as readdir2, readFile as readFile3, stat as stat3 } from "fs/promises";
|
|
4237
4646
|
import { extname as extname4, resolve as resolve14 } from "path";
|
|
4238
|
-
import { Hono as
|
|
4647
|
+
import { Hono as Hono15 } from "hono";
|
|
4239
4648
|
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
4240
4649
|
function resolvePublicRoot(name) {
|
|
4241
4650
|
if (name === "_system") return resolve14(voluteHome(), "shared");
|
|
@@ -4276,7 +4685,7 @@ async function listDir(dirPath) {
|
|
|
4276
4685
|
type: e.isDirectory() ? "directory" : "file"
|
|
4277
4686
|
}));
|
|
4278
4687
|
}
|
|
4279
|
-
var
|
|
4688
|
+
var app15 = new Hono15().get("/:name/", async (c) => {
|
|
4280
4689
|
const name = c.req.param("name");
|
|
4281
4690
|
const publicRoot = resolvePublicRoot(name);
|
|
4282
4691
|
if (!publicRoot) return c.json({ error: "Not found" }, 404);
|
|
@@ -4319,11 +4728,11 @@ var app14 = new Hono14().get("/:name/", async (c) => {
|
|
|
4319
4728
|
}
|
|
4320
4729
|
return c.text("Not found", 404);
|
|
4321
4730
|
});
|
|
4322
|
-
var public_files_default =
|
|
4731
|
+
var public_files_default = app15;
|
|
4323
4732
|
|
|
4324
4733
|
// src/web/api/schedules.ts
|
|
4325
4734
|
import { CronExpressionParser } from "cron-parser";
|
|
4326
|
-
import { Hono as
|
|
4735
|
+
import { Hono as Hono16 } from "hono";
|
|
4327
4736
|
var slog = logger_default.child("schedules");
|
|
4328
4737
|
function readSchedules(name) {
|
|
4329
4738
|
return readVoluteConfig(mindDir(name))?.schedules ?? [];
|
|
@@ -4340,7 +4749,7 @@ function writeSchedules(name, schedules) {
|
|
|
4340
4749
|
data: { schedules }
|
|
4341
4750
|
});
|
|
4342
4751
|
}
|
|
4343
|
-
var
|
|
4752
|
+
var app16 = new Hono16().get("/:name/schedules", (c) => {
|
|
4344
4753
|
const name = c.req.param("name");
|
|
4345
4754
|
if (!findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
4346
4755
|
return c.json(readSchedules(name));
|
|
@@ -4373,6 +4782,7 @@ var app15 = new Hono15().get("/:name/schedules", (c) => {
|
|
|
4373
4782
|
const schedule = { id, cron: body.cron, enabled: body.enabled ?? true };
|
|
4374
4783
|
if (body.message) schedule.message = body.message;
|
|
4375
4784
|
if (body.script) schedule.script = body.script;
|
|
4785
|
+
if (body.channel) schedule.channel = body.channel;
|
|
4376
4786
|
schedules.push(schedule);
|
|
4377
4787
|
writeSchedules(name, schedules);
|
|
4378
4788
|
return c.json({ ok: true, id }, 201);
|
|
@@ -4404,6 +4814,7 @@ var app15 = new Hono15().get("/:name/schedules", (c) => {
|
|
|
4404
4814
|
delete schedules[idx].message;
|
|
4405
4815
|
}
|
|
4406
4816
|
if (body.enabled !== void 0) schedules[idx].enabled = body.enabled;
|
|
4817
|
+
if (body.channel !== void 0) schedules[idx].channel = body.channel || void 0;
|
|
4407
4818
|
writeSchedules(name, schedules);
|
|
4408
4819
|
return c.json({ ok: true });
|
|
4409
4820
|
}).delete("/:name/schedules/:id", requireAdmin, (c) => {
|
|
@@ -4443,11 +4854,11 @@ var app15 = new Hono15().get("/:name/schedules", (c) => {
|
|
|
4443
4854
|
return c.json({ error: "Failed to reach mind" }, 502);
|
|
4444
4855
|
}
|
|
4445
4856
|
});
|
|
4446
|
-
var schedules_default =
|
|
4857
|
+
var schedules_default = app16;
|
|
4447
4858
|
|
|
4448
4859
|
// src/web/api/shared.ts
|
|
4449
|
-
import { Hono as
|
|
4450
|
-
var
|
|
4860
|
+
import { Hono as Hono17 } from "hono";
|
|
4861
|
+
var app17 = new Hono17().post("/:name/shared/merge", requireAdmin, async (c) => {
|
|
4451
4862
|
const name = c.req.param("name");
|
|
4452
4863
|
const entry = findMind(name);
|
|
4453
4864
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
@@ -4496,15 +4907,15 @@ var app16 = new Hono16().post("/:name/shared/merge", requireAdmin, async (c) =>
|
|
|
4496
4907
|
return c.json({ error: err instanceof Error ? err.message : "Failed to get status" }, 500);
|
|
4497
4908
|
}
|
|
4498
4909
|
});
|
|
4499
|
-
var shared_default =
|
|
4910
|
+
var shared_default = app17;
|
|
4500
4911
|
|
|
4501
4912
|
// src/web/api/skills.ts
|
|
4502
4913
|
import { existsSync as existsSync11, mkdtempSync, readdirSync as readdirSync5, rmSync as rmSync5 } from "fs";
|
|
4503
4914
|
import { tmpdir } from "os";
|
|
4504
4915
|
import { join as join2, resolve as resolve15 } from "path";
|
|
4505
4916
|
import AdmZip from "adm-zip";
|
|
4506
|
-
import { Hono as
|
|
4507
|
-
var
|
|
4917
|
+
import { Hono as Hono18 } from "hono";
|
|
4918
|
+
var app18 = new Hono18().get("/", async (c) => {
|
|
4508
4919
|
const skills = await listSharedSkills();
|
|
4509
4920
|
return c.json(skills);
|
|
4510
4921
|
}).get("/:id", async (c) => {
|
|
@@ -4569,15 +4980,15 @@ var app17 = new Hono17().get("/", async (c) => {
|
|
|
4569
4980
|
}
|
|
4570
4981
|
return c.json({ ok: true });
|
|
4571
4982
|
});
|
|
4572
|
-
var skills_default =
|
|
4983
|
+
var skills_default = app18;
|
|
4573
4984
|
|
|
4574
4985
|
// src/web/api/system.ts
|
|
4575
|
-
import { zValidator as
|
|
4576
|
-
import { Hono as
|
|
4986
|
+
import { zValidator as zValidator6 } from "@hono/zod-validator";
|
|
4987
|
+
import { Hono as Hono19 } from "hono";
|
|
4577
4988
|
import { streamSSE as streamSSE3 } from "hono/streaming";
|
|
4578
|
-
import { z as
|
|
4989
|
+
import { z as z6 } from "zod";
|
|
4579
4990
|
var DEFAULT_API_URL = "https://volute.systems";
|
|
4580
|
-
var
|
|
4991
|
+
var app19 = new Hono19().post("/restart", requireAdmin, (c) => {
|
|
4581
4992
|
setTimeout(() => process.exit(1), 200);
|
|
4582
4993
|
return c.json({ ok: true });
|
|
4583
4994
|
}).post("/stop", requireAdmin, (c) => {
|
|
@@ -4607,7 +5018,7 @@ var app18 = new Hono18().post("/restart", requireAdmin, (c) => {
|
|
|
4607
5018
|
}).post(
|
|
4608
5019
|
"/register",
|
|
4609
5020
|
requireAdmin,
|
|
4610
|
-
|
|
5021
|
+
zValidator6("json", z6.object({ name: z6.string().min(1) })),
|
|
4611
5022
|
async (c) => {
|
|
4612
5023
|
const existing = readSystemsConfig();
|
|
4613
5024
|
if (existing) {
|
|
@@ -4646,7 +5057,7 @@ var app18 = new Hono18().post("/restart", requireAdmin, (c) => {
|
|
|
4646
5057
|
).post(
|
|
4647
5058
|
"/login",
|
|
4648
5059
|
requireAdmin,
|
|
4649
|
-
|
|
5060
|
+
zValidator6("json", z6.object({ key: z6.string().min(1) })),
|
|
4650
5061
|
async (c) => {
|
|
4651
5062
|
const existing = readSystemsConfig();
|
|
4652
5063
|
if (existing) {
|
|
@@ -4683,18 +5094,18 @@ var app18 = new Hono18().post("/restart", requireAdmin, (c) => {
|
|
|
4683
5094
|
deleteSystemsConfig();
|
|
4684
5095
|
return c.json({ ok: true });
|
|
4685
5096
|
});
|
|
4686
|
-
var system_default =
|
|
5097
|
+
var system_default = app19;
|
|
4687
5098
|
|
|
4688
5099
|
// src/web/api/typing.ts
|
|
4689
|
-
import { zValidator as
|
|
4690
|
-
import { Hono as
|
|
4691
|
-
import { z as
|
|
4692
|
-
var typingSchema =
|
|
4693
|
-
channel:
|
|
4694
|
-
sender:
|
|
4695
|
-
active:
|
|
5100
|
+
import { zValidator as zValidator7 } from "@hono/zod-validator";
|
|
5101
|
+
import { Hono as Hono20 } from "hono";
|
|
5102
|
+
import { z as z7 } from "zod";
|
|
5103
|
+
var typingSchema = z7.object({
|
|
5104
|
+
channel: z7.string().min(1),
|
|
5105
|
+
sender: z7.string().min(1),
|
|
5106
|
+
active: z7.boolean()
|
|
4696
5107
|
});
|
|
4697
|
-
var
|
|
5108
|
+
var app20 = new Hono20().post("/:name/typing", zValidator7("json", typingSchema), (c) => {
|
|
4698
5109
|
const { channel, sender, active } = c.req.valid("json");
|
|
4699
5110
|
const map = getTypingMap();
|
|
4700
5111
|
if (active) {
|
|
@@ -4705,7 +5116,7 @@ var app19 = new Hono19().post("/:name/typing", zValidator6("json", typingSchema)
|
|
|
4705
5116
|
const volutePrefix = "volute:";
|
|
4706
5117
|
if (channel.startsWith(volutePrefix)) {
|
|
4707
5118
|
const conversationId = channel.slice(volutePrefix.length);
|
|
4708
|
-
|
|
5119
|
+
publish(conversationId, { type: "typing", senders: map.get(channel) });
|
|
4709
5120
|
}
|
|
4710
5121
|
return c.json({ ok: true });
|
|
4711
5122
|
}).get("/:name/typing", (c) => {
|
|
@@ -4716,13 +5127,13 @@ var app19 = new Hono19().post("/:name/typing", zValidator6("json", typingSchema)
|
|
|
4716
5127
|
const map = getTypingMap();
|
|
4717
5128
|
return c.json({ typing: map.get(channel) });
|
|
4718
5129
|
});
|
|
4719
|
-
var typing_default =
|
|
5130
|
+
var typing_default = app20;
|
|
4720
5131
|
|
|
4721
5132
|
// src/web/api/update.ts
|
|
4722
5133
|
import { spawn as spawn2 } from "child_process";
|
|
4723
|
-
import { Hono as
|
|
5134
|
+
import { Hono as Hono21 } from "hono";
|
|
4724
5135
|
var bin;
|
|
4725
|
-
var
|
|
5136
|
+
var app21 = new Hono21().get("/update", async (c) => {
|
|
4726
5137
|
const result = await checkForUpdate();
|
|
4727
5138
|
return c.json(result);
|
|
4728
5139
|
}).post("/update", requireAdmin, async (c) => {
|
|
@@ -4737,21 +5148,21 @@ var app20 = new Hono20().get("/update", async (c) => {
|
|
|
4737
5148
|
child.unref();
|
|
4738
5149
|
return c.json({ ok: true, message: "Updating..." });
|
|
4739
5150
|
});
|
|
4740
|
-
var update_default =
|
|
5151
|
+
var update_default = app21;
|
|
4741
5152
|
|
|
4742
5153
|
// src/web/api/v1/chat.ts
|
|
4743
|
-
import { zValidator as
|
|
4744
|
-
import { Hono as
|
|
5154
|
+
import { zValidator as zValidator8 } from "@hono/zod-validator";
|
|
5155
|
+
import { Hono as Hono22 } from "hono";
|
|
4745
5156
|
import { streamSSE as streamSSE4 } from "hono/streaming";
|
|
4746
|
-
import { z as
|
|
5157
|
+
import { z as z8 } from "zod";
|
|
4747
5158
|
async function fanOutToMinds(opts) {
|
|
4748
5159
|
const participants = await getParticipants(opts.conversationId);
|
|
4749
5160
|
const mindParticipants = participants.filter((p) => p.userType === "mind");
|
|
4750
5161
|
const participantNames = participants.map((p) => p.username);
|
|
4751
5162
|
const isDM = opts.isDM ?? participants.length === 2;
|
|
4752
5163
|
const channelEntryType = opts.channelEntryType ?? (isDM ? "dm" : "group");
|
|
4753
|
-
const { getMindManager: getMindManager2 } = await import("./mind-manager-
|
|
4754
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
5164
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-VVK67AY3.js");
|
|
5165
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-EE4NRN2Q.js");
|
|
4755
5166
|
const manager = getMindManager2();
|
|
4756
5167
|
const sm = getSleepManagerIfReady();
|
|
4757
5168
|
const targetMinds = mindParticipants.map((ap) => {
|
|
@@ -4800,18 +5211,18 @@ async function fanOutToMinds(opts) {
|
|
|
4800
5211
|
});
|
|
4801
5212
|
}
|
|
4802
5213
|
}
|
|
4803
|
-
var mindChatSchema =
|
|
4804
|
-
message:
|
|
4805
|
-
conversationId:
|
|
4806
|
-
sender:
|
|
4807
|
-
images:
|
|
5214
|
+
var mindChatSchema = z8.object({
|
|
5215
|
+
message: z8.string().optional(),
|
|
5216
|
+
conversationId: z8.string().optional(),
|
|
5217
|
+
sender: z8.string().optional(),
|
|
5218
|
+
images: z8.array(z8.object({ media_type: z8.string(), data: z8.string() })).optional()
|
|
4808
5219
|
});
|
|
4809
|
-
var unifiedChatSchema =
|
|
4810
|
-
message:
|
|
4811
|
-
conversationId:
|
|
4812
|
-
images:
|
|
5220
|
+
var unifiedChatSchema = z8.object({
|
|
5221
|
+
message: z8.string().optional(),
|
|
5222
|
+
conversationId: z8.string(),
|
|
5223
|
+
images: z8.array(z8.object({ media_type: z8.string(), data: z8.string() })).optional()
|
|
4813
5224
|
});
|
|
4814
|
-
var
|
|
5225
|
+
var app22 = new Hono22().use("*", authMiddleware).post("/minds/:name/chat", zValidator8("json", mindChatSchema), async (c) => {
|
|
4815
5226
|
const name = c.req.param("name");
|
|
4816
5227
|
const [baseName] = name.split("@", 2);
|
|
4817
5228
|
const entry = findMind(baseName);
|
|
@@ -4884,7 +5295,7 @@ var app21 = new Hono21().use("*", authMiddleware).post("/minds/:name/chat", zVal
|
|
|
4884
5295
|
return c.json({ error: "Conversation not found" }, 404);
|
|
4885
5296
|
}
|
|
4886
5297
|
return streamSSE4(c, async (stream) => {
|
|
4887
|
-
const unsubscribe =
|
|
5298
|
+
const unsubscribe = subscribe2(conversationId, (event) => {
|
|
4888
5299
|
stream.writeSSE({ data: JSON.stringify(event) }).catch((err) => {
|
|
4889
5300
|
if (!stream.aborted) logger_default.error("[v1-chat] SSE write error:", logger_default.errorData(err));
|
|
4890
5301
|
});
|
|
@@ -4902,7 +5313,7 @@ var app21 = new Hono21().use("*", authMiddleware).post("/minds/:name/chat", zVal
|
|
|
4902
5313
|
});
|
|
4903
5314
|
});
|
|
4904
5315
|
});
|
|
4905
|
-
}).post("/chat",
|
|
5316
|
+
}).post("/chat", zValidator8("json", unifiedChatSchema), async (c) => {
|
|
4906
5317
|
const user = c.get("user");
|
|
4907
5318
|
const body = c.req.valid("json");
|
|
4908
5319
|
if (!body.message && (!body.images || body.images.length === 0)) {
|
|
@@ -4934,17 +5345,17 @@ var app21 = new Hono21().use("*", authMiddleware).post("/minds/:name/chat", zVal
|
|
|
4934
5345
|
});
|
|
4935
5346
|
return c.json({ ok: true, conversationId: body.conversationId });
|
|
4936
5347
|
});
|
|
4937
|
-
var chat_default =
|
|
5348
|
+
var chat_default = app22;
|
|
4938
5349
|
|
|
4939
5350
|
// src/web/api/v1/conversations.ts
|
|
4940
|
-
import { zValidator as
|
|
4941
|
-
import { Hono as
|
|
4942
|
-
import { z as
|
|
4943
|
-
var
|
|
4944
|
-
title:
|
|
4945
|
-
participantNames:
|
|
5351
|
+
import { zValidator as zValidator9 } from "@hono/zod-validator";
|
|
5352
|
+
import { Hono as Hono23 } from "hono";
|
|
5353
|
+
import { z as z9 } from "zod";
|
|
5354
|
+
var createSchema2 = z9.object({
|
|
5355
|
+
title: z9.string().optional(),
|
|
5356
|
+
participantNames: z9.array(z9.string()).min(1)
|
|
4946
5357
|
});
|
|
4947
|
-
var
|
|
5358
|
+
var app23 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
|
|
4948
5359
|
const user = c.get("user");
|
|
4949
5360
|
const convs = await listConversationsWithParticipants(user.id);
|
|
4950
5361
|
return c.json(convs);
|
|
@@ -4975,7 +5386,7 @@ var app22 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
|
|
|
4975
5386
|
}
|
|
4976
5387
|
const participants = await getParticipants(id);
|
|
4977
5388
|
return c.json(participants);
|
|
4978
|
-
}).post("/",
|
|
5389
|
+
}).post("/", zValidator9("json", createSchema2), async (c) => {
|
|
4979
5390
|
const user = c.get("user");
|
|
4980
5391
|
const body = c.req.valid("json");
|
|
4981
5392
|
const participantIds = /* @__PURE__ */ new Set();
|
|
@@ -5021,30 +5432,30 @@ var app22 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
|
|
|
5021
5432
|
if (!deleted) return c.json({ error: "Conversation not found" }, 404);
|
|
5022
5433
|
return c.json({ ok: true });
|
|
5023
5434
|
});
|
|
5024
|
-
var conversations_default =
|
|
5435
|
+
var conversations_default = app23;
|
|
5025
5436
|
|
|
5026
5437
|
// src/web/api/v1/events.ts
|
|
5027
|
-
import { desc as
|
|
5028
|
-
import { Hono as
|
|
5438
|
+
import { desc as desc4 } from "drizzle-orm";
|
|
5439
|
+
import { Hono as Hono24 } from "hono";
|
|
5029
5440
|
import { streamSSE as streamSSE5 } from "hono/streaming";
|
|
5030
5441
|
|
|
5031
5442
|
// src/lib/events/brain-presence.ts
|
|
5032
5443
|
var connections = /* @__PURE__ */ new Map();
|
|
5033
5444
|
function addConnection(username) {
|
|
5034
|
-
const
|
|
5035
|
-
connections.set(username,
|
|
5036
|
-
if (
|
|
5445
|
+
const count2 = connections.get(username) ?? 0;
|
|
5446
|
+
connections.set(username, count2 + 1);
|
|
5447
|
+
if (count2 === 0) {
|
|
5037
5448
|
broadcast({ type: "brain_online", mind: username, summary: `${username} connected` });
|
|
5038
5449
|
}
|
|
5039
5450
|
}
|
|
5040
5451
|
function removeConnection(username) {
|
|
5041
|
-
const
|
|
5042
|
-
if (
|
|
5043
|
-
if (
|
|
5452
|
+
const count2 = connections.get(username);
|
|
5453
|
+
if (count2 == null) return;
|
|
5454
|
+
if (count2 <= 1) {
|
|
5044
5455
|
connections.delete(username);
|
|
5045
5456
|
broadcast({ type: "brain_offline", mind: username, summary: `${username} disconnected` });
|
|
5046
5457
|
} else {
|
|
5047
|
-
connections.set(username,
|
|
5458
|
+
connections.set(username, count2 - 1);
|
|
5048
5459
|
}
|
|
5049
5460
|
}
|
|
5050
5461
|
function getOnlineBrains() {
|
|
@@ -5072,7 +5483,7 @@ function getEventsSince(sinceId) {
|
|
|
5072
5483
|
}
|
|
5073
5484
|
|
|
5074
5485
|
// src/web/api/v1/events.ts
|
|
5075
|
-
var
|
|
5486
|
+
var app24 = new Hono24().use("*", authMiddleware).get("/", async (c) => {
|
|
5076
5487
|
const user = c.get("user");
|
|
5077
5488
|
const since = c.req.query("since");
|
|
5078
5489
|
const sinceId = since ? Number(since) : 0;
|
|
@@ -5095,7 +5506,7 @@ var app23 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
|
|
|
5095
5506
|
let recentActivity = [];
|
|
5096
5507
|
try {
|
|
5097
5508
|
const db = await getDb();
|
|
5098
|
-
recentActivity = await db.select().from(activity).orderBy(
|
|
5509
|
+
recentActivity = await db.select().from(activity).orderBy(desc4(activity.created_at)).limit(50);
|
|
5099
5510
|
recentActivity = recentActivity.map((row) => ({
|
|
5100
5511
|
...row,
|
|
5101
5512
|
metadata: row.metadata ? JSON.parse(row.metadata) : null
|
|
@@ -5148,7 +5559,7 @@ var app23 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
|
|
|
5148
5559
|
});
|
|
5149
5560
|
cleanups.push(unsubActivity);
|
|
5150
5561
|
for (const conv of conversations2) {
|
|
5151
|
-
const unsubConv =
|
|
5562
|
+
const unsubConv = subscribe2(conv.id, (event) => {
|
|
5152
5563
|
const data = { event: "conversation", conversationId: conv.id, ...event };
|
|
5153
5564
|
const eventId = bufferEvent(data);
|
|
5154
5565
|
stream.writeSSE({
|
|
@@ -5179,12 +5590,12 @@ var app23 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
|
|
|
5179
5590
|
}
|
|
5180
5591
|
});
|
|
5181
5592
|
});
|
|
5182
|
-
var events_default =
|
|
5593
|
+
var events_default = app24;
|
|
5183
5594
|
|
|
5184
5595
|
// src/web/api/variants.ts
|
|
5185
5596
|
import { existsSync as existsSync12, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
5186
5597
|
import { resolve as resolve17 } from "path";
|
|
5187
|
-
import { Hono as
|
|
5598
|
+
import { Hono as Hono25 } from "hono";
|
|
5188
5599
|
|
|
5189
5600
|
// src/lib/spawn-server.ts
|
|
5190
5601
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -5300,7 +5711,7 @@ async function verify2(port) {
|
|
|
5300
5711
|
}
|
|
5301
5712
|
|
|
5302
5713
|
// src/web/api/variants.ts
|
|
5303
|
-
var
|
|
5714
|
+
var app25 = new Hono25().get("/:name/variants", async (c) => {
|
|
5304
5715
|
const name = c.req.param("name");
|
|
5305
5716
|
const entry = findMind(name);
|
|
5306
5717
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
@@ -5516,19 +5927,19 @@ var app24 = new Hono24().get("/:name/variants", async (c) => {
|
|
|
5516
5927
|
await cleanupVariant(mindName, variantName, projectRoot, variant.path, { stop: true });
|
|
5517
5928
|
return c.json({ ok: true });
|
|
5518
5929
|
});
|
|
5519
|
-
var variants_default =
|
|
5930
|
+
var variants_default = app25;
|
|
5520
5931
|
|
|
5521
5932
|
// src/web/api/volute/channels.ts
|
|
5522
|
-
import { zValidator as
|
|
5523
|
-
import { Hono as
|
|
5524
|
-
import { z as
|
|
5525
|
-
var
|
|
5526
|
-
name:
|
|
5933
|
+
import { zValidator as zValidator10 } from "@hono/zod-validator";
|
|
5934
|
+
import { Hono as Hono26 } from "hono";
|
|
5935
|
+
import { z as z10 } from "zod";
|
|
5936
|
+
var createSchema3 = z10.object({
|
|
5937
|
+
name: z10.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
|
|
5527
5938
|
});
|
|
5528
|
-
var inviteSchema =
|
|
5529
|
-
username:
|
|
5939
|
+
var inviteSchema = z10.object({
|
|
5940
|
+
username: z10.string().min(1)
|
|
5530
5941
|
});
|
|
5531
|
-
var
|
|
5942
|
+
var app26 = new Hono26().get("/", async (c) => {
|
|
5532
5943
|
const user = c.get("user");
|
|
5533
5944
|
const channels = await listChannels();
|
|
5534
5945
|
const results = await Promise.all(
|
|
@@ -5539,7 +5950,7 @@ var app25 = new Hono25().get("/", async (c) => {
|
|
|
5539
5950
|
})
|
|
5540
5951
|
);
|
|
5541
5952
|
return c.json(results);
|
|
5542
|
-
}).post("/",
|
|
5953
|
+
}).post("/", zValidator10("json", createSchema3), async (c) => {
|
|
5543
5954
|
const user = c.get("user");
|
|
5544
5955
|
const body = c.req.valid("json");
|
|
5545
5956
|
try {
|
|
@@ -5572,7 +5983,7 @@ var app25 = new Hono25().get("/", async (c) => {
|
|
|
5572
5983
|
if (!ch) return c.json({ error: "Channel not found" }, 404);
|
|
5573
5984
|
const participants = await getParticipants(ch.id);
|
|
5574
5985
|
return c.json(participants);
|
|
5575
|
-
}).post("/:name/invite",
|
|
5986
|
+
}).post("/:name/invite", zValidator10("json", inviteSchema), async (c) => {
|
|
5576
5987
|
const name = c.req.param("name");
|
|
5577
5988
|
const inviter = c.get("user");
|
|
5578
5989
|
const { username } = c.req.valid("json");
|
|
@@ -5592,21 +6003,21 @@ var app25 = new Hono25().get("/", async (c) => {
|
|
|
5592
6003
|
]);
|
|
5593
6004
|
return c.json({ ok: true });
|
|
5594
6005
|
});
|
|
5595
|
-
var channels_default2 =
|
|
6006
|
+
var channels_default2 = app26;
|
|
5596
6007
|
|
|
5597
6008
|
// src/web/api/volute/chat.ts
|
|
5598
|
-
import { zValidator as
|
|
5599
|
-
import { Hono as
|
|
6009
|
+
import { zValidator as zValidator11 } from "@hono/zod-validator";
|
|
6010
|
+
import { Hono as Hono27 } from "hono";
|
|
5600
6011
|
import { streamSSE as streamSSE6 } from "hono/streaming";
|
|
5601
|
-
import { z as
|
|
6012
|
+
import { z as z11 } from "zod";
|
|
5602
6013
|
async function fanOutToMinds2(opts) {
|
|
5603
6014
|
const participants = await getParticipants(opts.conversationId);
|
|
5604
6015
|
const mindParticipants = participants.filter((p) => p.userType === "mind");
|
|
5605
6016
|
const participantNames = participants.map((p) => p.username);
|
|
5606
6017
|
const isDM = opts.isDM ?? participants.length === 2;
|
|
5607
6018
|
const channelEntryType = opts.channelEntryType ?? (isDM ? "dm" : "group");
|
|
5608
|
-
const { getMindManager: getMindManager2 } = await import("./mind-manager-
|
|
5609
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
6019
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-VVK67AY3.js");
|
|
6020
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-EE4NRN2Q.js");
|
|
5610
6021
|
const manager = getMindManager2();
|
|
5611
6022
|
const sm = getSleepManagerIfReady();
|
|
5612
6023
|
const targetMinds = mindParticipants.map((ap) => {
|
|
@@ -5654,18 +6065,18 @@ async function fanOutToMinds2(opts) {
|
|
|
5654
6065
|
});
|
|
5655
6066
|
}
|
|
5656
6067
|
}
|
|
5657
|
-
var chatSchema =
|
|
5658
|
-
message:
|
|
5659
|
-
conversationId:
|
|
5660
|
-
sender:
|
|
5661
|
-
images:
|
|
5662
|
-
|
|
5663
|
-
media_type:
|
|
5664
|
-
data:
|
|
6068
|
+
var chatSchema = z11.object({
|
|
6069
|
+
message: z11.string().optional(),
|
|
6070
|
+
conversationId: z11.string().optional(),
|
|
6071
|
+
sender: z11.string().optional(),
|
|
6072
|
+
images: z11.array(
|
|
6073
|
+
z11.object({
|
|
6074
|
+
media_type: z11.string(),
|
|
6075
|
+
data: z11.string()
|
|
5665
6076
|
})
|
|
5666
6077
|
).optional()
|
|
5667
6078
|
});
|
|
5668
|
-
var
|
|
6079
|
+
var app27 = new Hono27().post("/:name/chat", zValidator11("json", chatSchema), async (c) => {
|
|
5669
6080
|
const name = c.req.param("name");
|
|
5670
6081
|
const [baseName] = name.split("@", 2);
|
|
5671
6082
|
const entry = findMind(baseName);
|
|
@@ -5742,7 +6153,7 @@ var app26 = new Hono26().post("/:name/chat", zValidator10("json", chatSchema), a
|
|
|
5742
6153
|
return c.json({ error: "Conversation not found" }, 404);
|
|
5743
6154
|
}
|
|
5744
6155
|
return streamSSE6(c, async (stream) => {
|
|
5745
|
-
const unsubscribe =
|
|
6156
|
+
const unsubscribe = subscribe2(conversationId, (event) => {
|
|
5746
6157
|
stream.writeSSE({ data: JSON.stringify(event) }).catch((err) => {
|
|
5747
6158
|
if (!stream.aborted) console.error("[chat] SSE write error:", err);
|
|
5748
6159
|
});
|
|
@@ -5761,14 +6172,14 @@ var app26 = new Hono26().post("/:name/chat", zValidator10("json", chatSchema), a
|
|
|
5761
6172
|
});
|
|
5762
6173
|
});
|
|
5763
6174
|
});
|
|
5764
|
-
var unifiedChatSchema2 =
|
|
5765
|
-
message:
|
|
5766
|
-
conversationId:
|
|
5767
|
-
images:
|
|
6175
|
+
var unifiedChatSchema2 = z11.object({
|
|
6176
|
+
message: z11.string().optional(),
|
|
6177
|
+
conversationId: z11.string(),
|
|
6178
|
+
images: z11.array(z11.object({ media_type: z11.string(), data: z11.string() })).optional()
|
|
5768
6179
|
});
|
|
5769
|
-
var unifiedChatApp = new
|
|
6180
|
+
var unifiedChatApp = new Hono27().post(
|
|
5770
6181
|
"/chat",
|
|
5771
|
-
|
|
6182
|
+
zValidator11("json", unifiedChatSchema2),
|
|
5772
6183
|
async (c) => {
|
|
5773
6184
|
const user = c.get("user");
|
|
5774
6185
|
const body = c.req.valid("json");
|
|
@@ -5802,18 +6213,18 @@ var unifiedChatApp = new Hono26().post(
|
|
|
5802
6213
|
return c.json({ ok: true, conversationId: body.conversationId });
|
|
5803
6214
|
}
|
|
5804
6215
|
);
|
|
5805
|
-
var chat_default2 =
|
|
6216
|
+
var chat_default2 = app27;
|
|
5806
6217
|
|
|
5807
6218
|
// src/web/api/volute/conversations.ts
|
|
5808
|
-
import { zValidator as
|
|
5809
|
-
import { Hono as
|
|
5810
|
-
import { z as
|
|
5811
|
-
var createConvSchema =
|
|
5812
|
-
title:
|
|
5813
|
-
participantIds:
|
|
5814
|
-
participantNames:
|
|
6219
|
+
import { zValidator as zValidator12 } from "@hono/zod-validator";
|
|
6220
|
+
import { Hono as Hono28 } from "hono";
|
|
6221
|
+
import { z as z12 } from "zod";
|
|
6222
|
+
var createConvSchema = z12.object({
|
|
6223
|
+
title: z12.string().optional(),
|
|
6224
|
+
participantIds: z12.array(z12.number()).optional(),
|
|
6225
|
+
participantNames: z12.array(z12.string()).optional()
|
|
5815
6226
|
});
|
|
5816
|
-
var
|
|
6227
|
+
var app28 = new Hono28().get("/:name/conversations", async (c) => {
|
|
5817
6228
|
const name = c.req.param("name");
|
|
5818
6229
|
const user = c.get("user");
|
|
5819
6230
|
let lookupId = user.id;
|
|
@@ -5824,7 +6235,7 @@ var app27 = new Hono27().get("/:name/conversations", async (c) => {
|
|
|
5824
6235
|
const all = await listConversationsForUser(lookupId);
|
|
5825
6236
|
const convs = all.filter((c2) => c2.mind_name === name || c2.type === "channel");
|
|
5826
6237
|
return c.json(convs);
|
|
5827
|
-
}).post("/:name/conversations",
|
|
6238
|
+
}).post("/:name/conversations", zValidator12("json", createConvSchema), async (c) => {
|
|
5828
6239
|
const name = c.req.param("name");
|
|
5829
6240
|
const user = c.get("user");
|
|
5830
6241
|
const body = c.req.valid("json");
|
|
@@ -5898,18 +6309,18 @@ var app27 = new Hono27().get("/:name/conversations", async (c) => {
|
|
|
5898
6309
|
if (!deleted) return c.json({ error: "Conversation not found" }, 404);
|
|
5899
6310
|
return c.json({ ok: true });
|
|
5900
6311
|
});
|
|
5901
|
-
var conversations_default2 =
|
|
6312
|
+
var conversations_default2 = app28;
|
|
5902
6313
|
|
|
5903
6314
|
// src/web/api/volute/user-conversations.ts
|
|
5904
|
-
import { zValidator as
|
|
5905
|
-
import { Hono as
|
|
6315
|
+
import { zValidator as zValidator13 } from "@hono/zod-validator";
|
|
6316
|
+
import { Hono as Hono29 } from "hono";
|
|
5906
6317
|
import { streamSSE as streamSSE7 } from "hono/streaming";
|
|
5907
|
-
import { z as
|
|
5908
|
-
var
|
|
5909
|
-
title:
|
|
5910
|
-
participantNames:
|
|
6318
|
+
import { z as z13 } from "zod";
|
|
6319
|
+
var createSchema4 = z13.object({
|
|
6320
|
+
title: z13.string().optional(),
|
|
6321
|
+
participantNames: z13.array(z13.string()).min(1)
|
|
5911
6322
|
});
|
|
5912
|
-
var
|
|
6323
|
+
var app29 = new Hono29().use("*", authMiddleware).get("/", async (c) => {
|
|
5913
6324
|
const user = c.get("user");
|
|
5914
6325
|
const convs = await listConversationsWithParticipants(user.id);
|
|
5915
6326
|
return c.json(convs);
|
|
@@ -5921,7 +6332,7 @@ var app28 = new Hono28().use("*", authMiddleware).get("/", async (c) => {
|
|
|
5921
6332
|
}
|
|
5922
6333
|
const msgs = await getMessages(id);
|
|
5923
6334
|
return c.json(msgs);
|
|
5924
|
-
}).post("/",
|
|
6335
|
+
}).post("/", zValidator13("json", createSchema4), async (c) => {
|
|
5925
6336
|
const user = c.get("user");
|
|
5926
6337
|
const body = c.req.valid("json");
|
|
5927
6338
|
const participantIds = /* @__PURE__ */ new Set();
|
|
@@ -5958,7 +6369,7 @@ var app28 = new Hono28().use("*", authMiddleware).get("/", async (c) => {
|
|
|
5958
6369
|
return c.json({ error: "Conversation not found" }, 404);
|
|
5959
6370
|
}
|
|
5960
6371
|
return streamSSE7(c, async (stream) => {
|
|
5961
|
-
const unsubscribe =
|
|
6372
|
+
const unsubscribe = subscribe2(conversationId, (event) => {
|
|
5962
6373
|
stream.writeSSE({ data: JSON.stringify(event) }).catch((err) => {
|
|
5963
6374
|
if (!stream.aborted) console.error("[chat] SSE write error:", err);
|
|
5964
6375
|
});
|
|
@@ -5983,12 +6394,12 @@ var app28 = new Hono28().use("*", authMiddleware).get("/", async (c) => {
|
|
|
5983
6394
|
if (!deleted) return c.json({ error: "Conversation not found" }, 404);
|
|
5984
6395
|
return c.json({ ok: true });
|
|
5985
6396
|
});
|
|
5986
|
-
var user_conversations_default =
|
|
6397
|
+
var user_conversations_default = app29;
|
|
5987
6398
|
|
|
5988
6399
|
// src/web/app.ts
|
|
5989
6400
|
var httpLog = logger_default.child("http");
|
|
5990
|
-
var
|
|
5991
|
-
|
|
6401
|
+
var app30 = new Hono30();
|
|
6402
|
+
app30.onError((err, c) => {
|
|
5992
6403
|
if (err instanceof HTTPException) {
|
|
5993
6404
|
return err.getResponse();
|
|
5994
6405
|
}
|
|
@@ -5999,10 +6410,10 @@ app29.onError((err, c) => {
|
|
|
5999
6410
|
});
|
|
6000
6411
|
return c.json({ error: "Internal server error" }, 500);
|
|
6001
6412
|
});
|
|
6002
|
-
|
|
6413
|
+
app30.notFound((c) => {
|
|
6003
6414
|
return c.json({ error: "Not found" }, 404);
|
|
6004
6415
|
});
|
|
6005
|
-
|
|
6416
|
+
app30.use("*", async (c, next) => {
|
|
6006
6417
|
const start = Date.now();
|
|
6007
6418
|
await next();
|
|
6008
6419
|
const duration = Date.now() - start;
|
|
@@ -6013,7 +6424,7 @@ app29.use("*", async (c, next) => {
|
|
|
6013
6424
|
httpLog.debug("request", data);
|
|
6014
6425
|
}
|
|
6015
6426
|
});
|
|
6016
|
-
|
|
6427
|
+
app30.get("/api/health", (c) => {
|
|
6017
6428
|
let version = "unknown";
|
|
6018
6429
|
let cached = null;
|
|
6019
6430
|
try {
|
|
@@ -6028,36 +6439,37 @@ app29.get("/api/health", (c) => {
|
|
|
6028
6439
|
...cached?.updateAvailable ? { updateAvailable: true, latest: cached.latest } : {}
|
|
6029
6440
|
});
|
|
6030
6441
|
});
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6442
|
+
app30.use("/api/*", bodyLimit({ maxSize: 10 * 1024 * 1024 }));
|
|
6443
|
+
app30.use("/api/*", csrf());
|
|
6444
|
+
app30.use("/api/activity/*", authMiddleware);
|
|
6445
|
+
app30.use("/api/minds/*", authMiddleware);
|
|
6446
|
+
app30.use("/api/conversations/*", authMiddleware);
|
|
6447
|
+
app30.use("/api/volute/*", authMiddleware);
|
|
6448
|
+
app30.use("/api/system/*", authMiddleware);
|
|
6449
|
+
app30.use("/api/env/*", authMiddleware);
|
|
6450
|
+
app30.use("/api/prompts/*", authMiddleware);
|
|
6451
|
+
app30.use("/api/skills/*", authMiddleware);
|
|
6452
|
+
app30.use("/api/notes/*", authMiddleware);
|
|
6453
|
+
app30.use("/api/v1/*", authMiddleware);
|
|
6454
|
+
app30.route("/pages", pages_default);
|
|
6455
|
+
app30.route("/public", public_files_default);
|
|
6456
|
+
var routes = app30.route("/api/activity", activity_default).route("/api/keys", keys_default).route("/api/auth", auth_default).route("/api/system", system_default).route("/api/system", update_default).route("/api/minds", minds_default).route("/api/minds", chat_default2).route("/api/minds", connectors_default).route("/api/minds", schedules_default).route("/api/minds", logs_default).route("/api/minds", typing_default).route("/api/minds", variants_default).route("/api/minds", file_sharing_default).route("/api/minds", files_default).route("/api/minds", channels_default).route("/api/minds", shared_default).route("/api/minds", env_default).route("/api/minds", mind_skills_default).route("/api/minds", conversations_default2).route("/api/env", sharedEnvApp).route("/api/notes", notes_default).route("/api/prompts", prompts_default).route("/api/skills", skills_default).route("/api/conversations", user_conversations_default).route("/api/volute/channels", channels_default2).route("/api/volute", unifiedChatApp).route("/api/v1/conversations", conversations_default).route("/api/v1/events", events_default).route("/api/v1", chat_default);
|
|
6457
|
+
app30.route("/api/v1/minds", minds_default);
|
|
6458
|
+
app30.route("/api/v1/minds", typing_default);
|
|
6459
|
+
app30.route("/api/v1/minds", variants_default);
|
|
6460
|
+
app30.route("/api/v1/minds", files_default);
|
|
6461
|
+
app30.route("/api/v1/minds", env_default);
|
|
6462
|
+
app30.route("/api/v1/minds", mind_skills_default);
|
|
6463
|
+
app30.route("/api/v1/minds", connectors_default);
|
|
6464
|
+
app30.route("/api/v1/minds", schedules_default);
|
|
6465
|
+
app30.route("/api/v1/minds", logs_default);
|
|
6466
|
+
app30.route("/api/v1/system", system_default);
|
|
6467
|
+
app30.route("/api/v1/system", update_default);
|
|
6468
|
+
app30.route("/api/v1/prompts", prompts_default);
|
|
6469
|
+
app30.route("/api/v1/skills", skills_default);
|
|
6470
|
+
app30.route("/api/v1/env", sharedEnvApp);
|
|
6471
|
+
app30.route("/api/v1/channels", channels_default2);
|
|
6472
|
+
var app_default = app30;
|
|
6061
6473
|
|
|
6062
6474
|
// src/web/server.ts
|
|
6063
6475
|
var MIME_TYPES3 = {
|
|
@@ -6184,11 +6596,18 @@ async function startDaemon(opts) {
|
|
|
6184
6596
|
logger_default.warn("failed to initialize shared repo", logger_default.errorData(err));
|
|
6185
6597
|
}
|
|
6186
6598
|
initRegistryCache();
|
|
6599
|
+
const { initSandbox } = await import("./sandbox-EHGFF52K.js");
|
|
6600
|
+
await initSandbox();
|
|
6187
6601
|
try {
|
|
6188
6602
|
await syncBuiltinSkills();
|
|
6189
6603
|
} catch (err) {
|
|
6190
6604
|
logger_default.error("failed to sync built-in skills", logger_default.errorData(err));
|
|
6191
6605
|
}
|
|
6606
|
+
try {
|
|
6607
|
+
await ensureSystemChannel();
|
|
6608
|
+
} catch (err) {
|
|
6609
|
+
logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
|
|
6610
|
+
}
|
|
6192
6611
|
const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes2(32).toString("hex");
|
|
6193
6612
|
let tls;
|
|
6194
6613
|
if (opts.tailscale) {
|
|
@@ -6289,7 +6708,7 @@ async function startDaemon(opts) {
|
|
|
6289
6708
|
});
|
|
6290
6709
|
await Promise.all(workers);
|
|
6291
6710
|
}
|
|
6292
|
-
import("./cloud-sync-
|
|
6711
|
+
import("./cloud-sync-NI2K3C7G.js").then(
|
|
6293
6712
|
({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
|
|
6294
6713
|
logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
|
|
6295
6714
|
})
|
|
@@ -6297,7 +6716,7 @@ async function startDaemon(opts) {
|
|
|
6297
6716
|
logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
|
|
6298
6717
|
});
|
|
6299
6718
|
try {
|
|
6300
|
-
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-
|
|
6719
|
+
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-USFZBWMG.js");
|
|
6301
6720
|
backfillTemplateHashes();
|
|
6302
6721
|
notifyVersionUpdate().catch((err) => {
|
|
6303
6722
|
logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
|
|
@@ -6311,6 +6730,9 @@ async function startDaemon(opts) {
|
|
|
6311
6730
|
cleanExpiredSessions().catch((err) => {
|
|
6312
6731
|
logger_default.warn("failed to clean expired sessions", logger_default.errorData(err));
|
|
6313
6732
|
});
|
|
6733
|
+
migrateMindRoles().catch((err) => {
|
|
6734
|
+
logger_default.warn("failed to migrate mind roles", logger_default.errorData(err));
|
|
6735
|
+
});
|
|
6314
6736
|
logger_default.info(`running on ${hostname}:${port}, pid ${myPid}`);
|
|
6315
6737
|
function cleanup() {
|
|
6316
6738
|
try {
|
|
@@ -6372,6 +6794,7 @@ if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith
|
|
|
6372
6794
|
let hostname = "127.0.0.1";
|
|
6373
6795
|
let foreground = false;
|
|
6374
6796
|
let tailscale = false;
|
|
6797
|
+
let noSandbox = false;
|
|
6375
6798
|
for (let i = 2; i < process.argv.length; i++) {
|
|
6376
6799
|
if (process.argv[i] === "--port" && process.argv[i + 1]) {
|
|
6377
6800
|
port = parseInt(process.argv[i + 1], 10);
|
|
@@ -6383,8 +6806,13 @@ if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith
|
|
|
6383
6806
|
foreground = true;
|
|
6384
6807
|
} else if (process.argv[i] === "--tailscale") {
|
|
6385
6808
|
tailscale = true;
|
|
6809
|
+
} else if (process.argv[i] === "--no-sandbox") {
|
|
6810
|
+
noSandbox = true;
|
|
6386
6811
|
}
|
|
6387
6812
|
}
|
|
6813
|
+
if (noSandbox) {
|
|
6814
|
+
process.env.VOLUTE_SANDBOX = "0";
|
|
6815
|
+
}
|
|
6388
6816
|
startDaemon({ port, hostname, foreground, tailscale });
|
|
6389
6817
|
}
|
|
6390
6818
|
export {
|