volute 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-X7GJLBLW.js → agent-7JF7MT73.js} +1 -1
- package/dist/{agent-manager-JDVXU3ON.js → agent-manager-IMZ7ZMBF.js} +1 -1
- package/dist/{chunk-G6ZNGLUX.js → chunk-62X577Y7.js} +7 -5
- package/dist/chunk-7ACDT3P2.js +265 -0
- package/dist/{up-CSX3ZUIU.js → chunk-EG45HBSJ.js} +1 -1
- package/dist/{down-FXWAN66A.js → chunk-LLJNZPCU.js} +47 -12
- package/dist/{chunk-AOKAQGO4.js → chunk-NKXULRSW.js} +1 -0
- package/dist/cli.js +10 -6
- package/dist/connectors/discord.js +8 -4
- package/dist/daemon-restart-4HVEKYFY.js +23 -0
- package/dist/daemon.js +143 -347
- package/dist/{delete-2PH2CGDY.js → delete-UOU4AFQN.js} +4 -0
- package/dist/down-AZVH5TCD.js +11 -0
- package/dist/{package-4DP4Y4UO.js → package-T2WAVJOU.js} +1 -1
- package/dist/up-RWZF6MLT.js +12 -0
- package/dist/{update-XSIX3GGP.js → update-F7QWV2LB.js} +1 -1
- package/dist/{update-check-5ZADDHCK.js → update-check-B4J6IEQ4.js} +1 -1
- package/dist/web-assets/assets/index-B1CqjUYD.js +308 -0
- package/dist/web-assets/index.html +1 -1
- package/package.json +1 -1
- package/dist/web-assets/assets/index-D5PzIndO.js +0 -308
package/dist/daemon.js
CHANGED
|
@@ -6,18 +6,37 @@ import {
|
|
|
6
6
|
initAgentManager,
|
|
7
7
|
loadJsonMap,
|
|
8
8
|
saveJsonMap
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-62X577Y7.js";
|
|
10
10
|
import {
|
|
11
11
|
checkForUpdate,
|
|
12
12
|
checkForUpdateCached,
|
|
13
13
|
getCurrentVersion
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-NKXULRSW.js";
|
|
15
15
|
import {
|
|
16
16
|
collectPart
|
|
17
17
|
} from "./chunk-B3R6L2GW.js";
|
|
18
18
|
import {
|
|
19
19
|
CHANNELS
|
|
20
20
|
} from "./chunk-ZZOOTYXK.js";
|
|
21
|
+
import {
|
|
22
|
+
agentMessages,
|
|
23
|
+
approveUser,
|
|
24
|
+
conversationParticipants,
|
|
25
|
+
conversations,
|
|
26
|
+
createUser,
|
|
27
|
+
deleteAgentUser,
|
|
28
|
+
getDb,
|
|
29
|
+
getOrCreateAgentUser,
|
|
30
|
+
getUser,
|
|
31
|
+
getUserByUsername,
|
|
32
|
+
listPendingUsers,
|
|
33
|
+
listUsers,
|
|
34
|
+
listUsersByType,
|
|
35
|
+
messages,
|
|
36
|
+
sessions,
|
|
37
|
+
users,
|
|
38
|
+
verifyUser
|
|
39
|
+
} from "./chunk-7ACDT3P2.js";
|
|
21
40
|
import {
|
|
22
41
|
readVoluteConfig,
|
|
23
42
|
writeVoluteConfig
|
|
@@ -25,7 +44,10 @@ import {
|
|
|
25
44
|
import {
|
|
26
45
|
loadMergedEnv
|
|
27
46
|
} from "./chunk-H7AMDUIA.js";
|
|
28
|
-
import
|
|
47
|
+
import {
|
|
48
|
+
slugify,
|
|
49
|
+
writeChannelEntry
|
|
50
|
+
} from "./chunk-BX7KI4S3.js";
|
|
29
51
|
import {
|
|
30
52
|
applyIsolation
|
|
31
53
|
} from "./chunk-W76KWE23.js";
|
|
@@ -47,15 +69,13 @@ import {
|
|
|
47
69
|
setVariantRunning,
|
|
48
70
|
voluteHome
|
|
49
71
|
} from "./chunk-UWHWAPGO.js";
|
|
50
|
-
import
|
|
51
|
-
__export
|
|
52
|
-
} from "./chunk-K3NQKI34.js";
|
|
72
|
+
import "./chunk-K3NQKI34.js";
|
|
53
73
|
|
|
54
74
|
// src/daemon.ts
|
|
55
75
|
import { randomBytes } from "crypto";
|
|
56
76
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
57
77
|
import { homedir } from "os";
|
|
58
|
-
import { resolve as
|
|
78
|
+
import { resolve as resolve9 } from "path";
|
|
59
79
|
import { format } from "util";
|
|
60
80
|
|
|
61
81
|
// src/lib/connector-manager.ts
|
|
@@ -295,19 +315,19 @@ var ConnectorManager = class {
|
|
|
295
315
|
const stopKey = `${agentName}:${type}`;
|
|
296
316
|
this.stopping.add(stopKey);
|
|
297
317
|
agentMap.delete(type);
|
|
298
|
-
await new Promise((
|
|
299
|
-
tracked.child.on("exit", () =>
|
|
318
|
+
await new Promise((resolve10) => {
|
|
319
|
+
tracked.child.on("exit", () => resolve10());
|
|
300
320
|
try {
|
|
301
321
|
tracked.child.kill("SIGTERM");
|
|
302
322
|
} catch {
|
|
303
|
-
|
|
323
|
+
resolve10();
|
|
304
324
|
}
|
|
305
325
|
setTimeout(() => {
|
|
306
326
|
try {
|
|
307
327
|
tracked.child.kill("SIGKILL");
|
|
308
328
|
} catch {
|
|
309
329
|
}
|
|
310
|
-
|
|
330
|
+
resolve10();
|
|
311
331
|
}, 5e3);
|
|
312
332
|
});
|
|
313
333
|
this.stopping.delete(stopKey);
|
|
@@ -705,245 +725,9 @@ function getTokenBudget() {
|
|
|
705
725
|
|
|
706
726
|
// src/web/middleware/auth.ts
|
|
707
727
|
import { timingSafeEqual } from "crypto";
|
|
708
|
-
import { eq
|
|
728
|
+
import { eq, lt } from "drizzle-orm";
|
|
709
729
|
import { getCookie } from "hono/cookie";
|
|
710
730
|
import { createMiddleware } from "hono/factory";
|
|
711
|
-
|
|
712
|
-
// src/lib/auth.ts
|
|
713
|
-
import { compareSync, hashSync } from "bcryptjs";
|
|
714
|
-
import { and, count, eq } from "drizzle-orm";
|
|
715
|
-
|
|
716
|
-
// src/lib/db.ts
|
|
717
|
-
import { chmodSync, existsSync as existsSync3 } from "fs";
|
|
718
|
-
import { dirname as dirname2, resolve as resolve4 } from "path";
|
|
719
|
-
import { fileURLToPath } from "url";
|
|
720
|
-
import { drizzle } from "drizzle-orm/libsql";
|
|
721
|
-
import { migrate } from "drizzle-orm/libsql/migrator";
|
|
722
|
-
|
|
723
|
-
// src/lib/schema.ts
|
|
724
|
-
var schema_exports = {};
|
|
725
|
-
__export(schema_exports, {
|
|
726
|
-
agentMessages: () => agentMessages,
|
|
727
|
-
conversationParticipants: () => conversationParticipants,
|
|
728
|
-
conversations: () => conversations,
|
|
729
|
-
messages: () => messages,
|
|
730
|
-
sessions: () => sessions,
|
|
731
|
-
users: () => users
|
|
732
|
-
});
|
|
733
|
-
import { sql } from "drizzle-orm";
|
|
734
|
-
import { index, integer, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
|
|
735
|
-
var users = sqliteTable("users", {
|
|
736
|
-
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
737
|
-
username: text("username").unique().notNull(),
|
|
738
|
-
password_hash: text("password_hash").notNull(),
|
|
739
|
-
role: text("role").notNull().default("pending"),
|
|
740
|
-
user_type: text("user_type").notNull().default("human"),
|
|
741
|
-
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
742
|
-
});
|
|
743
|
-
var conversations = sqliteTable(
|
|
744
|
-
"conversations",
|
|
745
|
-
{
|
|
746
|
-
id: text("id").primaryKey(),
|
|
747
|
-
agent_name: text("agent_name").notNull(),
|
|
748
|
-
channel: text("channel").notNull(),
|
|
749
|
-
user_id: integer("user_id").references(() => users.id),
|
|
750
|
-
title: text("title"),
|
|
751
|
-
created_at: text("created_at").notNull().default(sql`(datetime('now'))`),
|
|
752
|
-
updated_at: text("updated_at").notNull().default(sql`(datetime('now'))`)
|
|
753
|
-
},
|
|
754
|
-
(table) => [
|
|
755
|
-
index("idx_conversations_agent_name").on(table.agent_name),
|
|
756
|
-
index("idx_conversations_user_id").on(table.user_id),
|
|
757
|
-
index("idx_conversations_updated_at").on(table.updated_at)
|
|
758
|
-
]
|
|
759
|
-
);
|
|
760
|
-
var agentMessages = sqliteTable(
|
|
761
|
-
"agent_messages",
|
|
762
|
-
{
|
|
763
|
-
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
764
|
-
agent: text("agent").notNull(),
|
|
765
|
-
channel: text("channel").notNull(),
|
|
766
|
-
role: text("role").notNull(),
|
|
767
|
-
sender: text("sender"),
|
|
768
|
-
content: text("content").notNull(),
|
|
769
|
-
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
770
|
-
},
|
|
771
|
-
(table) => [
|
|
772
|
-
index("idx_agent_messages_agent").on(table.agent),
|
|
773
|
-
index("idx_agent_messages_channel").on(table.agent, table.channel)
|
|
774
|
-
]
|
|
775
|
-
);
|
|
776
|
-
var conversationParticipants = sqliteTable(
|
|
777
|
-
"conversation_participants",
|
|
778
|
-
{
|
|
779
|
-
conversation_id: text("conversation_id").notNull().references(() => conversations.id, { onDelete: "cascade" }),
|
|
780
|
-
user_id: integer("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
781
|
-
role: text("role").notNull().default("member"),
|
|
782
|
-
joined_at: text("joined_at").notNull().default(sql`(datetime('now'))`)
|
|
783
|
-
},
|
|
784
|
-
(table) => [
|
|
785
|
-
uniqueIndex("idx_cp_unique").on(table.conversation_id, table.user_id),
|
|
786
|
-
index("idx_cp_user_id").on(table.user_id)
|
|
787
|
-
]
|
|
788
|
-
);
|
|
789
|
-
var sessions = sqliteTable("sessions", {
|
|
790
|
-
id: text("id").primaryKey(),
|
|
791
|
-
userId: integer("user_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
|
|
792
|
-
createdAt: integer("created_at").notNull()
|
|
793
|
-
});
|
|
794
|
-
var messages = sqliteTable(
|
|
795
|
-
"messages",
|
|
796
|
-
{
|
|
797
|
-
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
798
|
-
conversation_id: text("conversation_id").notNull().references(() => conversations.id, { onDelete: "cascade" }),
|
|
799
|
-
role: text("role").notNull(),
|
|
800
|
-
sender_name: text("sender_name"),
|
|
801
|
-
content: text("content").notNull(),
|
|
802
|
-
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
803
|
-
},
|
|
804
|
-
(table) => [index("idx_messages_conversation_id").on(table.conversation_id)]
|
|
805
|
-
);
|
|
806
|
-
|
|
807
|
-
// src/lib/db.ts
|
|
808
|
-
var __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
809
|
-
var migrationsFolder = existsSync3(resolve4(__dirname, "../drizzle")) ? resolve4(__dirname, "../drizzle") : resolve4(__dirname, "../../drizzle");
|
|
810
|
-
var db = null;
|
|
811
|
-
async function getDb() {
|
|
812
|
-
if (db) return db;
|
|
813
|
-
const dbPath = process.env.VOLUTE_DB_PATH || resolve4(voluteHome(), "volute.db");
|
|
814
|
-
db = drizzle({ connection: { url: `file:${dbPath}` }, schema: schema_exports });
|
|
815
|
-
await migrate(db, { migrationsFolder });
|
|
816
|
-
try {
|
|
817
|
-
chmodSync(dbPath, 384);
|
|
818
|
-
} catch (err) {
|
|
819
|
-
console.error(
|
|
820
|
-
`[volute] WARNING: Failed to restrict database file permissions on ${dbPath}:`,
|
|
821
|
-
err
|
|
822
|
-
);
|
|
823
|
-
}
|
|
824
|
-
return db;
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
// src/lib/auth.ts
|
|
828
|
-
async function createUser(username, password) {
|
|
829
|
-
const db2 = await getDb();
|
|
830
|
-
const hash = hashSync(password, 10);
|
|
831
|
-
const [{ value }] = await db2.select({ value: count() }).from(users).where(eq(users.user_type, "human"));
|
|
832
|
-
const role = value === 0 ? "admin" : "pending";
|
|
833
|
-
const [result] = await db2.insert(users).values({ username, password_hash: hash, role }).returning({
|
|
834
|
-
id: users.id,
|
|
835
|
-
username: users.username,
|
|
836
|
-
role: users.role,
|
|
837
|
-
user_type: users.user_type,
|
|
838
|
-
created_at: users.created_at
|
|
839
|
-
});
|
|
840
|
-
return result;
|
|
841
|
-
}
|
|
842
|
-
async function verifyUser(username, password) {
|
|
843
|
-
const db2 = await getDb();
|
|
844
|
-
const row = await db2.select().from(users).where(eq(users.username, username)).get();
|
|
845
|
-
if (!row) return null;
|
|
846
|
-
if (row.user_type === "agent") return null;
|
|
847
|
-
if (!compareSync(password, row.password_hash)) return null;
|
|
848
|
-
const { password_hash: _, ...user } = row;
|
|
849
|
-
return user;
|
|
850
|
-
}
|
|
851
|
-
async function getUser(id) {
|
|
852
|
-
const db2 = await getDb();
|
|
853
|
-
const row = await db2.select({
|
|
854
|
-
id: users.id,
|
|
855
|
-
username: users.username,
|
|
856
|
-
role: users.role,
|
|
857
|
-
user_type: users.user_type,
|
|
858
|
-
created_at: users.created_at
|
|
859
|
-
}).from(users).where(eq(users.id, id)).get();
|
|
860
|
-
return row ?? null;
|
|
861
|
-
}
|
|
862
|
-
async function getUserByUsername(username) {
|
|
863
|
-
const db2 = await getDb();
|
|
864
|
-
const row = await db2.select({
|
|
865
|
-
id: users.id,
|
|
866
|
-
username: users.username,
|
|
867
|
-
role: users.role,
|
|
868
|
-
user_type: users.user_type,
|
|
869
|
-
created_at: users.created_at
|
|
870
|
-
}).from(users).where(eq(users.username, username)).get();
|
|
871
|
-
return row ?? null;
|
|
872
|
-
}
|
|
873
|
-
async function listUsers() {
|
|
874
|
-
const db2 = await getDb();
|
|
875
|
-
return db2.select({
|
|
876
|
-
id: users.id,
|
|
877
|
-
username: users.username,
|
|
878
|
-
role: users.role,
|
|
879
|
-
user_type: users.user_type,
|
|
880
|
-
created_at: users.created_at
|
|
881
|
-
}).from(users).orderBy(users.created_at).all();
|
|
882
|
-
}
|
|
883
|
-
async function listPendingUsers() {
|
|
884
|
-
const db2 = await getDb();
|
|
885
|
-
return db2.select({
|
|
886
|
-
id: users.id,
|
|
887
|
-
username: users.username,
|
|
888
|
-
role: users.role,
|
|
889
|
-
user_type: users.user_type,
|
|
890
|
-
created_at: users.created_at
|
|
891
|
-
}).from(users).where(eq(users.role, "pending")).orderBy(users.created_at).all();
|
|
892
|
-
}
|
|
893
|
-
async function listUsersByType(userType) {
|
|
894
|
-
const db2 = await getDb();
|
|
895
|
-
return db2.select({
|
|
896
|
-
id: users.id,
|
|
897
|
-
username: users.username,
|
|
898
|
-
role: users.role,
|
|
899
|
-
user_type: users.user_type,
|
|
900
|
-
created_at: users.created_at
|
|
901
|
-
}).from(users).where(eq(users.user_type, userType)).orderBy(users.created_at).all();
|
|
902
|
-
}
|
|
903
|
-
async function getOrCreateAgentUser(agentName) {
|
|
904
|
-
const db2 = await getDb();
|
|
905
|
-
const existing = await db2.select({
|
|
906
|
-
id: users.id,
|
|
907
|
-
username: users.username,
|
|
908
|
-
role: users.role,
|
|
909
|
-
user_type: users.user_type,
|
|
910
|
-
created_at: users.created_at
|
|
911
|
-
}).from(users).where(and(eq(users.username, agentName), eq(users.user_type, "agent"))).get();
|
|
912
|
-
if (existing) return existing;
|
|
913
|
-
try {
|
|
914
|
-
const [result] = await db2.insert(users).values({
|
|
915
|
-
username: agentName,
|
|
916
|
-
password_hash: "!agent",
|
|
917
|
-
role: "agent",
|
|
918
|
-
user_type: "agent"
|
|
919
|
-
}).returning({
|
|
920
|
-
id: users.id,
|
|
921
|
-
username: users.username,
|
|
922
|
-
role: users.role,
|
|
923
|
-
user_type: users.user_type,
|
|
924
|
-
created_at: users.created_at
|
|
925
|
-
});
|
|
926
|
-
return result;
|
|
927
|
-
} catch (err) {
|
|
928
|
-
if (err instanceof Error && err.message.includes("UNIQUE constraint")) {
|
|
929
|
-
const retried = await db2.select({
|
|
930
|
-
id: users.id,
|
|
931
|
-
username: users.username,
|
|
932
|
-
role: users.role,
|
|
933
|
-
user_type: users.user_type,
|
|
934
|
-
created_at: users.created_at
|
|
935
|
-
}).from(users).where(and(eq(users.username, agentName), eq(users.user_type, "agent"))).get();
|
|
936
|
-
if (retried) return retried;
|
|
937
|
-
}
|
|
938
|
-
throw err;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
async function approveUser(id) {
|
|
942
|
-
const db2 = await getDb();
|
|
943
|
-
await db2.update(users).set({ role: "user" }).where(and(eq(users.id, id), eq(users.role, "pending")));
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
// src/web/middleware/auth.ts
|
|
947
731
|
function isValidDaemonToken(token) {
|
|
948
732
|
const expected = process.env.VOLUTE_DAEMON_TOKEN;
|
|
949
733
|
if (!expected || token.length !== expected.length) return false;
|
|
@@ -951,29 +735,29 @@ function isValidDaemonToken(token) {
|
|
|
951
735
|
}
|
|
952
736
|
var SESSION_MAX_AGE = 864e5;
|
|
953
737
|
async function createSession(userId) {
|
|
954
|
-
const
|
|
738
|
+
const db = await getDb();
|
|
955
739
|
const sessionId = crypto.randomUUID();
|
|
956
|
-
await
|
|
740
|
+
await db.insert(sessions).values({ id: sessionId, userId, createdAt: Date.now() });
|
|
957
741
|
return sessionId;
|
|
958
742
|
}
|
|
959
743
|
async function deleteSession(sessionId) {
|
|
960
|
-
const
|
|
961
|
-
await
|
|
744
|
+
const db = await getDb();
|
|
745
|
+
await db.delete(sessions).where(eq(sessions.id, sessionId));
|
|
962
746
|
}
|
|
963
747
|
async function getSessionUserId(sessionId) {
|
|
964
|
-
const
|
|
965
|
-
const row = await
|
|
748
|
+
const db = await getDb();
|
|
749
|
+
const row = await db.select().from(sessions).where(eq(sessions.id, sessionId)).get();
|
|
966
750
|
if (!row) return void 0;
|
|
967
751
|
if (Date.now() - row.createdAt > SESSION_MAX_AGE) {
|
|
968
|
-
await
|
|
752
|
+
await db.delete(sessions).where(eq(sessions.id, sessionId));
|
|
969
753
|
return void 0;
|
|
970
754
|
}
|
|
971
755
|
return row.userId;
|
|
972
756
|
}
|
|
973
757
|
async function cleanExpiredSessions() {
|
|
974
|
-
const
|
|
758
|
+
const db = await getDb();
|
|
975
759
|
const cutoff = Date.now() - SESSION_MAX_AGE;
|
|
976
|
-
await
|
|
760
|
+
await db.delete(sessions).where(lt(sessions.createdAt, cutoff));
|
|
977
761
|
}
|
|
978
762
|
var requireAdmin = createMiddleware(async (c, next) => {
|
|
979
763
|
const user = c.get("user");
|
|
@@ -1004,9 +788,9 @@ var authMiddleware = createMiddleware(async (c, next) => {
|
|
|
1004
788
|
});
|
|
1005
789
|
|
|
1006
790
|
// src/web/server.ts
|
|
1007
|
-
import { existsSync as
|
|
791
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1008
792
|
import { readFile as readFile2, stat } from "fs/promises";
|
|
1009
|
-
import { dirname as
|
|
793
|
+
import { dirname as dirname2, extname, resolve as resolve8 } from "path";
|
|
1010
794
|
import { serve } from "@hono/node-server";
|
|
1011
795
|
|
|
1012
796
|
// src/lib/log-buffer.ts
|
|
@@ -1060,9 +844,9 @@ import { csrf } from "hono/csrf";
|
|
|
1060
844
|
import { HTTPException } from "hono/http-exception";
|
|
1061
845
|
|
|
1062
846
|
// src/web/routes/agents.ts
|
|
1063
|
-
import { existsSync as
|
|
1064
|
-
import { resolve as
|
|
1065
|
-
import { and
|
|
847
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, rmSync } from "fs";
|
|
848
|
+
import { resolve as resolve4 } from "path";
|
|
849
|
+
import { and, desc, eq as eq2 } from "drizzle-orm";
|
|
1066
850
|
import { Hono } from "hono";
|
|
1067
851
|
import { stream } from "hono/streaming";
|
|
1068
852
|
|
|
@@ -1175,7 +959,7 @@ function getTypingMap() {
|
|
|
1175
959
|
// src/web/routes/agents.ts
|
|
1176
960
|
function getDaemonPort() {
|
|
1177
961
|
try {
|
|
1178
|
-
const data = JSON.parse(readFileSync3(
|
|
962
|
+
const data = JSON.parse(readFileSync3(resolve4(voluteHome(), "daemon.json"), "utf-8"));
|
|
1179
963
|
return data.port;
|
|
1180
964
|
} catch {
|
|
1181
965
|
return void 0;
|
|
@@ -1224,7 +1008,7 @@ var app = new Hono().get("/", async (c) => {
|
|
|
1224
1008
|
const name = c.req.param("name");
|
|
1225
1009
|
const entry = findAgent(name);
|
|
1226
1010
|
if (!entry) return c.json({ error: "Agent not found" }, 404);
|
|
1227
|
-
if (!
|
|
1011
|
+
if (!existsSync3(agentDir(name))) return c.json({ error: "Agent directory missing" }, 404);
|
|
1228
1012
|
const { status, channels } = await getAgentStatus(name, entry.port);
|
|
1229
1013
|
const variants = readVariants(name);
|
|
1230
1014
|
const manager = getAgentManager();
|
|
@@ -1250,7 +1034,7 @@ var app = new Hono().get("/", async (c) => {
|
|
|
1250
1034
|
if (!variant) return c.json({ error: `Unknown variant: ${variantName}` }, 404);
|
|
1251
1035
|
} else {
|
|
1252
1036
|
const dir = agentDir(baseName);
|
|
1253
|
-
if (!
|
|
1037
|
+
if (!existsSync3(dir)) return c.json({ error: "Agent directory missing" }, 404);
|
|
1254
1038
|
}
|
|
1255
1039
|
const manager = getAgentManager();
|
|
1256
1040
|
if (manager.isRunning(name)) {
|
|
@@ -1285,7 +1069,7 @@ var app = new Hono().get("/", async (c) => {
|
|
|
1285
1069
|
if (!variant) return c.json({ error: `Unknown variant: ${variantName}` }, 404);
|
|
1286
1070
|
} else {
|
|
1287
1071
|
const dir = agentDir(baseName);
|
|
1288
|
-
if (!
|
|
1072
|
+
if (!existsSync3(dir)) return c.json({ error: "Agent directory missing" }, 404);
|
|
1289
1073
|
}
|
|
1290
1074
|
const manager = getAgentManager();
|
|
1291
1075
|
const connectorManager = getConnectorManager();
|
|
@@ -1353,7 +1137,8 @@ var app = new Hono().get("/", async (c) => {
|
|
|
1353
1137
|
}
|
|
1354
1138
|
removeAllVariants(name);
|
|
1355
1139
|
removeAgent(name);
|
|
1356
|
-
|
|
1140
|
+
await deleteAgentUser(name);
|
|
1141
|
+
if (force && existsSync3(dir)) {
|
|
1357
1142
|
rmSync(dir, { recursive: true, force: true });
|
|
1358
1143
|
}
|
|
1359
1144
|
return c.json({ ok: true });
|
|
@@ -1379,10 +1164,10 @@ var app = new Hono().get("/", async (c) => {
|
|
|
1379
1164
|
console.error(`[daemon] failed to parse message body for ${baseName}:`, err);
|
|
1380
1165
|
}
|
|
1381
1166
|
const channel = parsed?.channel ?? "unknown";
|
|
1382
|
-
const
|
|
1167
|
+
const db = await getDb();
|
|
1383
1168
|
if (parsed) {
|
|
1384
1169
|
try {
|
|
1385
|
-
const
|
|
1170
|
+
const sender2 = parsed.sender ?? null;
|
|
1386
1171
|
let content;
|
|
1387
1172
|
if (typeof parsed.content === "string") {
|
|
1388
1173
|
content = parsed.content;
|
|
@@ -1391,11 +1176,11 @@ var app = new Hono().get("/", async (c) => {
|
|
|
1391
1176
|
} else {
|
|
1392
1177
|
content = JSON.stringify(parsed.content);
|
|
1393
1178
|
}
|
|
1394
|
-
await
|
|
1179
|
+
await db.insert(agentMessages).values({
|
|
1395
1180
|
agent: baseName,
|
|
1396
1181
|
channel,
|
|
1397
1182
|
role: "user",
|
|
1398
|
-
sender,
|
|
1183
|
+
sender: sender2,
|
|
1399
1184
|
content
|
|
1400
1185
|
});
|
|
1401
1186
|
} catch (err) {
|
|
@@ -1432,6 +1217,8 @@ var app = new Hono().get("/", async (c) => {
|
|
|
1432
1217
|
});
|
|
1433
1218
|
}
|
|
1434
1219
|
const typingMap = getTypingMap();
|
|
1220
|
+
const sender = parsed?.sender ?? "";
|
|
1221
|
+
if (sender) typingMap.delete(channel, sender);
|
|
1435
1222
|
const currentlyTyping = typingMap.get(channel).filter((s) => s !== baseName);
|
|
1436
1223
|
let forwardBody = body;
|
|
1437
1224
|
if (parsed && currentlyTyping.length > 0) {
|
|
@@ -1493,7 +1280,7 @@ var app = new Hono().get("/", async (c) => {
|
|
|
1493
1280
|
const content = [textParts.join(""), ...toolParts].filter(Boolean).join("\n");
|
|
1494
1281
|
if (content) {
|
|
1495
1282
|
try {
|
|
1496
|
-
await
|
|
1283
|
+
await db.insert(agentMessages).values({
|
|
1497
1284
|
agent: baseName,
|
|
1498
1285
|
channel,
|
|
1499
1286
|
role: "assistant",
|
|
@@ -1526,9 +1313,9 @@ var app = new Hono().get("/", async (c) => {
|
|
|
1526
1313
|
if (!body.channel || !body.content) {
|
|
1527
1314
|
return c.json({ error: "channel and content required" }, 400);
|
|
1528
1315
|
}
|
|
1529
|
-
const
|
|
1316
|
+
const db = await getDb();
|
|
1530
1317
|
try {
|
|
1531
|
-
await
|
|
1318
|
+
await db.insert(agentMessages).values({
|
|
1532
1319
|
agent: baseName,
|
|
1533
1320
|
channel: body.channel,
|
|
1534
1321
|
role: "assistant",
|
|
@@ -1542,20 +1329,20 @@ var app = new Hono().get("/", async (c) => {
|
|
|
1542
1329
|
return c.json({ ok: true });
|
|
1543
1330
|
}).get("/:name/history/channels", async (c) => {
|
|
1544
1331
|
const name = c.req.param("name");
|
|
1545
|
-
const
|
|
1546
|
-
const rows = await
|
|
1332
|
+
const db = await getDb();
|
|
1333
|
+
const rows = await db.selectDistinct({ channel: agentMessages.channel }).from(agentMessages).where(eq2(agentMessages.agent, name));
|
|
1547
1334
|
return c.json(rows.map((r) => r.channel));
|
|
1548
1335
|
}).get("/:name/history", async (c) => {
|
|
1549
1336
|
const name = c.req.param("name");
|
|
1550
1337
|
const channel = c.req.query("channel");
|
|
1551
1338
|
const limit = Math.min(Math.max(parseInt(c.req.query("limit") ?? "50", 10) || 50, 1), 200);
|
|
1552
1339
|
const offset = Math.max(parseInt(c.req.query("offset") ?? "0", 10) || 0, 0);
|
|
1553
|
-
const
|
|
1554
|
-
const conditions = [
|
|
1340
|
+
const db = await getDb();
|
|
1341
|
+
const conditions = [eq2(agentMessages.agent, name)];
|
|
1555
1342
|
if (channel) {
|
|
1556
|
-
conditions.push(
|
|
1343
|
+
conditions.push(eq2(agentMessages.channel, channel));
|
|
1557
1344
|
}
|
|
1558
|
-
const rows = await
|
|
1345
|
+
const rows = await db.select().from(agentMessages).where(and(...conditions)).orderBy(desc(agentMessages.created_at)).limit(limit).offset(offset);
|
|
1559
1346
|
return c.json(rows);
|
|
1560
1347
|
});
|
|
1561
1348
|
var agents_default = app;
|
|
@@ -1703,9 +1490,9 @@ var app3 = new Hono3().get("/:name/connectors", (c) => {
|
|
|
1703
1490
|
var connectors_default = app3;
|
|
1704
1491
|
|
|
1705
1492
|
// src/web/routes/files.ts
|
|
1706
|
-
import { existsSync as
|
|
1493
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1707
1494
|
import { readdir, readFile, writeFile } from "fs/promises";
|
|
1708
|
-
import { resolve as
|
|
1495
|
+
import { resolve as resolve5 } from "path";
|
|
1709
1496
|
import { zValidator as zValidator2 } from "@hono/zod-validator";
|
|
1710
1497
|
import { Hono as Hono4 } from "hono";
|
|
1711
1498
|
import { z as z2 } from "zod";
|
|
@@ -1716,8 +1503,8 @@ var app4 = new Hono4().get("/:name/files", async (c) => {
|
|
|
1716
1503
|
const entry = findAgent(name);
|
|
1717
1504
|
if (!entry) return c.json({ error: "Agent not found" }, 404);
|
|
1718
1505
|
const dir = agentDir(name);
|
|
1719
|
-
const homeDir =
|
|
1720
|
-
if (!
|
|
1506
|
+
const homeDir = resolve5(dir, "home");
|
|
1507
|
+
if (!existsSync4(homeDir)) return c.json({ error: "Home directory missing" }, 404);
|
|
1721
1508
|
const allFiles = await readdir(homeDir);
|
|
1722
1509
|
const files = allFiles.filter((f) => f.endsWith(".md") && ALLOWED_FILES.has(f));
|
|
1723
1510
|
return c.json(files);
|
|
@@ -1730,8 +1517,8 @@ var app4 = new Hono4().get("/:name/files", async (c) => {
|
|
|
1730
1517
|
const entry = findAgent(name);
|
|
1731
1518
|
if (!entry) return c.json({ error: "Agent not found" }, 404);
|
|
1732
1519
|
const dir = agentDir(name);
|
|
1733
|
-
const filePath =
|
|
1734
|
-
if (!
|
|
1520
|
+
const filePath = resolve5(dir, "home", filename);
|
|
1521
|
+
if (!existsSync4(filePath)) {
|
|
1735
1522
|
return c.json({ error: "File not found" }, 404);
|
|
1736
1523
|
}
|
|
1737
1524
|
const content = await readFile(filePath, "utf-8");
|
|
@@ -1745,7 +1532,7 @@ var app4 = new Hono4().get("/:name/files", async (c) => {
|
|
|
1745
1532
|
const entry = findAgent(name);
|
|
1746
1533
|
if (!entry) return c.json({ error: "Agent not found" }, 404);
|
|
1747
1534
|
const dir = agentDir(name);
|
|
1748
|
-
const filePath =
|
|
1535
|
+
const filePath = resolve5(dir, "home", filename);
|
|
1749
1536
|
const { content } = c.req.valid("json");
|
|
1750
1537
|
await writeFile(filePath, content);
|
|
1751
1538
|
return c.json({ ok: true });
|
|
@@ -1754,8 +1541,8 @@ var files_default = app4;
|
|
|
1754
1541
|
|
|
1755
1542
|
// src/web/routes/logs.ts
|
|
1756
1543
|
import { spawn as spawn2 } from "child_process";
|
|
1757
|
-
import { existsSync as
|
|
1758
|
-
import { resolve as
|
|
1544
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1545
|
+
import { resolve as resolve6 } from "path";
|
|
1759
1546
|
import { Hono as Hono5 } from "hono";
|
|
1760
1547
|
import { streamSSE } from "hono/streaming";
|
|
1761
1548
|
var app5 = new Hono5().get("/:name/logs", async (c) => {
|
|
@@ -1763,8 +1550,8 @@ var app5 = new Hono5().get("/:name/logs", async (c) => {
|
|
|
1763
1550
|
const entry = findAgent(name);
|
|
1764
1551
|
if (!entry) return c.json({ error: "Agent not found" }, 404);
|
|
1765
1552
|
const dir = agentDir(name);
|
|
1766
|
-
const logFile =
|
|
1767
|
-
if (!
|
|
1553
|
+
const logFile = resolve6(dir, ".volute", "logs", "agent.log");
|
|
1554
|
+
if (!existsSync5(logFile)) {
|
|
1768
1555
|
return c.json({ error: "No log file found" }, 404);
|
|
1769
1556
|
}
|
|
1770
1557
|
return streamSSE(c, async (stream2) => {
|
|
@@ -1782,9 +1569,9 @@ var app5 = new Hono5().get("/:name/logs", async (c) => {
|
|
|
1782
1569
|
stream2.onAbort(() => {
|
|
1783
1570
|
tail.kill();
|
|
1784
1571
|
});
|
|
1785
|
-
await new Promise((
|
|
1786
|
-
tail.on("exit",
|
|
1787
|
-
stream2.onAbort(
|
|
1572
|
+
await new Promise((resolve10) => {
|
|
1573
|
+
tail.on("exit", resolve10);
|
|
1574
|
+
stream2.onAbort(resolve10);
|
|
1788
1575
|
});
|
|
1789
1576
|
});
|
|
1790
1577
|
});
|
|
@@ -1886,10 +1673,10 @@ var app7 = new Hono7().get("/logs", async (c) => {
|
|
|
1886
1673
|
stream2.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
|
|
1887
1674
|
});
|
|
1888
1675
|
});
|
|
1889
|
-
await new Promise((
|
|
1676
|
+
await new Promise((resolve10) => {
|
|
1890
1677
|
stream2.onAbort(() => {
|
|
1891
1678
|
unsubscribe();
|
|
1892
|
-
|
|
1679
|
+
resolve10();
|
|
1893
1680
|
});
|
|
1894
1681
|
});
|
|
1895
1682
|
});
|
|
@@ -1965,7 +1752,7 @@ var variants_default = app10;
|
|
|
1965
1752
|
|
|
1966
1753
|
// src/web/routes/volute/chat.ts
|
|
1967
1754
|
import { readFileSync as readFileSync4 } from "fs";
|
|
1968
|
-
import { resolve as
|
|
1755
|
+
import { resolve as resolve7 } from "path";
|
|
1969
1756
|
import { zValidator as zValidator4 } from "@hono/zod-validator";
|
|
1970
1757
|
import { Hono as Hono11 } from "hono";
|
|
1971
1758
|
import { streamSSE as streamSSE3 } from "hono/streaming";
|
|
@@ -1973,11 +1760,11 @@ import { z as z4 } from "zod";
|
|
|
1973
1760
|
|
|
1974
1761
|
// src/lib/conversations.ts
|
|
1975
1762
|
import { randomUUID } from "crypto";
|
|
1976
|
-
import { and as
|
|
1763
|
+
import { and as and2, desc as desc2, eq as eq3, inArray, isNull, sql } from "drizzle-orm";
|
|
1977
1764
|
async function createConversation(agentName, channel, opts) {
|
|
1978
|
-
const
|
|
1765
|
+
const db = await getDb();
|
|
1979
1766
|
const id = randomUUID();
|
|
1980
|
-
await
|
|
1767
|
+
await db.insert(conversations).values({
|
|
1981
1768
|
id,
|
|
1982
1769
|
agent_name: agentName,
|
|
1983
1770
|
channel,
|
|
@@ -1985,7 +1772,7 @@ async function createConversation(agentName, channel, opts) {
|
|
|
1985
1772
|
title: opts?.title ?? null
|
|
1986
1773
|
});
|
|
1987
1774
|
if (opts?.participantIds && opts.participantIds.length > 0) {
|
|
1988
|
-
await
|
|
1775
|
+
await db.insert(conversationParticipants).values(
|
|
1989
1776
|
opts.participantIds.map((uid, i) => ({
|
|
1990
1777
|
conversation_id: id,
|
|
1991
1778
|
user_id: uid,
|
|
@@ -2004,41 +1791,41 @@ async function createConversation(agentName, channel, opts) {
|
|
|
2004
1791
|
};
|
|
2005
1792
|
}
|
|
2006
1793
|
async function getConversation(id) {
|
|
2007
|
-
const
|
|
2008
|
-
const row = await
|
|
1794
|
+
const db = await getDb();
|
|
1795
|
+
const row = await db.select().from(conversations).where(eq3(conversations.id, id)).get();
|
|
2009
1796
|
return row ?? null;
|
|
2010
1797
|
}
|
|
2011
1798
|
async function getParticipants(conversationId) {
|
|
2012
|
-
const
|
|
2013
|
-
const rows = await
|
|
1799
|
+
const db = await getDb();
|
|
1800
|
+
const rows = await db.select({
|
|
2014
1801
|
userId: conversationParticipants.user_id,
|
|
2015
1802
|
username: users.username,
|
|
2016
1803
|
userType: users.user_type,
|
|
2017
1804
|
role: conversationParticipants.role
|
|
2018
|
-
}).from(conversationParticipants).innerJoin(users,
|
|
1805
|
+
}).from(conversationParticipants).innerJoin(users, eq3(conversationParticipants.user_id, users.id)).where(eq3(conversationParticipants.conversation_id, conversationId)).all();
|
|
2019
1806
|
return rows;
|
|
2020
1807
|
}
|
|
2021
1808
|
async function isParticipant(conversationId, userId) {
|
|
2022
|
-
const
|
|
2023
|
-
const row = await
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
1809
|
+
const db = await getDb();
|
|
1810
|
+
const row = await db.select({ user_id: conversationParticipants.user_id }).from(conversationParticipants).where(
|
|
1811
|
+
and2(
|
|
1812
|
+
eq3(conversationParticipants.conversation_id, conversationId),
|
|
1813
|
+
eq3(conversationParticipants.user_id, userId)
|
|
2027
1814
|
)
|
|
2028
1815
|
).get();
|
|
2029
1816
|
return row != null;
|
|
2030
1817
|
}
|
|
2031
1818
|
async function listConversationsForUser(userId) {
|
|
2032
|
-
const
|
|
2033
|
-
const participantRows = await
|
|
1819
|
+
const db = await getDb();
|
|
1820
|
+
const participantRows = await db.select({ conversation_id: conversationParticipants.conversation_id }).from(conversationParticipants).where(eq3(conversationParticipants.user_id, userId)).all();
|
|
2034
1821
|
if (participantRows.length === 0) return [];
|
|
2035
1822
|
const convIds = participantRows.map((r) => r.conversation_id);
|
|
2036
|
-
return
|
|
1823
|
+
return db.select().from(conversations).where(inArray(conversations.id, convIds)).orderBy(desc2(conversations.updated_at)).all();
|
|
2037
1824
|
}
|
|
2038
1825
|
async function isParticipantOrOwner(conversationId, userId) {
|
|
2039
1826
|
if (await isParticipant(conversationId, userId)) return true;
|
|
2040
|
-
const
|
|
2041
|
-
const row = await
|
|
1827
|
+
const db = await getDb();
|
|
1828
|
+
const row = await db.select().from(conversations).where(and2(eq3(conversations.id, conversationId), eq3(conversations.user_id, userId))).get();
|
|
2042
1829
|
return row != null;
|
|
2043
1830
|
}
|
|
2044
1831
|
async function deleteConversationForUser(id, userId) {
|
|
@@ -2047,15 +1834,15 @@ async function deleteConversationForUser(id, userId) {
|
|
|
2047
1834
|
return true;
|
|
2048
1835
|
}
|
|
2049
1836
|
async function addMessage(conversationId, role, senderName, content) {
|
|
2050
|
-
const
|
|
1837
|
+
const db = await getDb();
|
|
2051
1838
|
const serialized = JSON.stringify(content);
|
|
2052
|
-
const [result] = await
|
|
2053
|
-
await
|
|
1839
|
+
const [result] = await db.insert(messages).values({ conversation_id: conversationId, role, sender_name: senderName, content: serialized }).returning({ id: messages.id, created_at: messages.created_at });
|
|
1840
|
+
await db.update(conversations).set({ updated_at: sql`datetime('now')` }).where(eq3(conversations.id, conversationId));
|
|
2054
1841
|
if (role === "user") {
|
|
2055
1842
|
const firstText = content.find((b) => b.type === "text");
|
|
2056
1843
|
const title = firstText ? firstText.text.slice(0, 80) : "";
|
|
2057
1844
|
if (title) {
|
|
2058
|
-
await
|
|
1845
|
+
await db.update(conversations).set({ title }).where(and2(eq3(conversations.id, conversationId), isNull(conversations.title)));
|
|
2059
1846
|
}
|
|
2060
1847
|
}
|
|
2061
1848
|
return {
|
|
@@ -2068,8 +1855,8 @@ async function addMessage(conversationId, role, senderName, content) {
|
|
|
2068
1855
|
};
|
|
2069
1856
|
}
|
|
2070
1857
|
async function getMessages(conversationId) {
|
|
2071
|
-
const
|
|
2072
|
-
const rows = await
|
|
1858
|
+
const db = await getDb();
|
|
1859
|
+
const rows = await db.select().from(messages).where(eq3(messages.conversation_id, conversationId)).orderBy(messages.created_at).all();
|
|
2073
1860
|
return rows.map((row) => {
|
|
2074
1861
|
let content;
|
|
2075
1862
|
try {
|
|
@@ -2084,15 +1871,15 @@ async function getMessages(conversationId) {
|
|
|
2084
1871
|
async function listConversationsWithParticipants(userId) {
|
|
2085
1872
|
const convs = await listConversationsForUser(userId);
|
|
2086
1873
|
if (convs.length === 0) return [];
|
|
2087
|
-
const
|
|
1874
|
+
const db = await getDb();
|
|
2088
1875
|
const convIds = convs.map((c) => c.id);
|
|
2089
|
-
const rows = await
|
|
1876
|
+
const rows = await db.select({
|
|
2090
1877
|
conversationId: conversationParticipants.conversation_id,
|
|
2091
1878
|
userId: users.id,
|
|
2092
1879
|
username: users.username,
|
|
2093
1880
|
userType: users.user_type,
|
|
2094
1881
|
role: conversationParticipants.role
|
|
2095
|
-
}).from(conversationParticipants).innerJoin(users,
|
|
1882
|
+
}).from(conversationParticipants).innerJoin(users, eq3(conversationParticipants.user_id, users.id)).where(inArray(conversationParticipants.conversation_id, convIds));
|
|
2096
1883
|
const byConv = /* @__PURE__ */ new Map();
|
|
2097
1884
|
for (const r of rows) {
|
|
2098
1885
|
let arr = byConv.get(r.conversationId);
|
|
@@ -2110,10 +1897,10 @@ async function listConversationsWithParticipants(userId) {
|
|
|
2110
1897
|
return convs.map((c) => ({ ...c, participants: byConv.get(c.id) ?? [] }));
|
|
2111
1898
|
}
|
|
2112
1899
|
async function findDMConversation(agentName, participantIds) {
|
|
2113
|
-
const
|
|
2114
|
-
const agentConvs = await
|
|
1900
|
+
const db = await getDb();
|
|
1901
|
+
const agentConvs = await db.select({ id: conversations.id }).from(conversations).where(eq3(conversations.agent_name, agentName)).all();
|
|
2115
1902
|
for (const conv of agentConvs) {
|
|
2116
|
-
const rows = await
|
|
1903
|
+
const rows = await db.select({ user_id: conversationParticipants.user_id }).from(conversationParticipants).where(eq3(conversationParticipants.conversation_id, conv.id)).all();
|
|
2117
1904
|
if (rows.length !== 2) continue;
|
|
2118
1905
|
const ids = new Set(rows.map((r) => r.user_id));
|
|
2119
1906
|
if (ids.has(participantIds[0]) && ids.has(participantIds[1])) {
|
|
@@ -2123,8 +1910,8 @@ async function findDMConversation(agentName, participantIds) {
|
|
|
2123
1910
|
return null;
|
|
2124
1911
|
}
|
|
2125
1912
|
async function deleteConversation(id) {
|
|
2126
|
-
const
|
|
2127
|
-
await
|
|
1913
|
+
const db = await getDb();
|
|
1914
|
+
await db.delete(conversations).where(eq3(conversations.id, id));
|
|
2128
1915
|
}
|
|
2129
1916
|
|
|
2130
1917
|
// src/web/routes/volute/chat.ts
|
|
@@ -2140,7 +1927,7 @@ var chatSchema = z4.object({
|
|
|
2140
1927
|
).optional()
|
|
2141
1928
|
});
|
|
2142
1929
|
function getDaemonUrl() {
|
|
2143
|
-
const data = JSON.parse(readFileSync4(
|
|
1930
|
+
const data = JSON.parse(readFileSync4(resolve7(voluteHome(), "daemon.json"), "utf-8"));
|
|
2144
1931
|
return `http://${daemonLoopback()}:${data.port}`;
|
|
2145
1932
|
}
|
|
2146
1933
|
function daemonFetchInternal(path, body) {
|
|
@@ -2223,15 +2010,17 @@ var app11 = new Hono11().post("/:name/chat", zValidator4("json", chatSchema), as
|
|
|
2223
2010
|
}
|
|
2224
2011
|
}
|
|
2225
2012
|
if (!conversationId) {
|
|
2226
|
-
const
|
|
2013
|
+
const conv2 = await createConversation(baseName, "volute", {
|
|
2227
2014
|
userId: user.id !== 0 ? user.id : void 0,
|
|
2228
2015
|
title,
|
|
2229
2016
|
participantIds
|
|
2230
2017
|
});
|
|
2231
|
-
conversationId =
|
|
2018
|
+
conversationId = conv2.id;
|
|
2232
2019
|
}
|
|
2233
2020
|
}
|
|
2234
|
-
const
|
|
2021
|
+
const conv = await getConversation(conversationId);
|
|
2022
|
+
const convTitle = conv?.title;
|
|
2023
|
+
const channel = convTitle ? `volute:${slugify(convTitle)}` : `volute:${conversationId}`;
|
|
2235
2024
|
const contentBlocks = [];
|
|
2236
2025
|
if (body.message) {
|
|
2237
2026
|
contentBlocks.push({ type: "text", text: body.message });
|
|
@@ -2245,13 +2034,20 @@ var app11 = new Hono11().post("/:name/chat", zValidator4("json", chatSchema), as
|
|
|
2245
2034
|
const participants = await getParticipants(conversationId);
|
|
2246
2035
|
const agentParticipants = participants.filter((p) => p.userType === "agent");
|
|
2247
2036
|
const participantNames = participants.map((p) => p.username);
|
|
2248
|
-
const { getAgentManager: getAgentManager2 } = await import("./agent-manager-
|
|
2037
|
+
const { getAgentManager: getAgentManager2 } = await import("./agent-manager-IMZ7ZMBF.js");
|
|
2249
2038
|
const manager = getAgentManager2();
|
|
2250
2039
|
const runningAgents = agentParticipants.map((ap) => {
|
|
2251
2040
|
const agentKey = ap.username === baseName ? name : ap.username;
|
|
2252
2041
|
return manager.isRunning(agentKey) ? ap.username : null;
|
|
2253
2042
|
}).filter((n) => n !== null && n !== senderName);
|
|
2254
2043
|
const isDM = participants.length === 2;
|
|
2044
|
+
const dir = agentDir(baseName);
|
|
2045
|
+
writeChannelEntry(dir, channel, {
|
|
2046
|
+
platformId: conversationId,
|
|
2047
|
+
platform: "volute",
|
|
2048
|
+
name: convTitle ?? void 0,
|
|
2049
|
+
type: isDM ? "dm" : "group"
|
|
2050
|
+
});
|
|
2255
2051
|
const typingMap = getTypingMap();
|
|
2256
2052
|
const currentlyTyping = typingMap.get(channel);
|
|
2257
2053
|
const payload = JSON.stringify({
|
|
@@ -2548,20 +2344,20 @@ async function startServer({
|
|
|
2548
2344
|
hostname = "127.0.0.1"
|
|
2549
2345
|
}) {
|
|
2550
2346
|
let assetsDir = "";
|
|
2551
|
-
let searchDir =
|
|
2347
|
+
let searchDir = dirname2(new URL(import.meta.url).pathname);
|
|
2552
2348
|
for (let i = 0; i < 5; i++) {
|
|
2553
|
-
const candidate =
|
|
2554
|
-
if (
|
|
2349
|
+
const candidate = resolve8(searchDir, "dist", "web-assets");
|
|
2350
|
+
if (existsSync6(candidate)) {
|
|
2555
2351
|
assetsDir = candidate;
|
|
2556
2352
|
break;
|
|
2557
2353
|
}
|
|
2558
|
-
searchDir =
|
|
2354
|
+
searchDir = dirname2(searchDir);
|
|
2559
2355
|
}
|
|
2560
2356
|
if (assetsDir) {
|
|
2561
2357
|
app_default.get("*", async (c) => {
|
|
2562
2358
|
const urlPath = new URL(c.req.url).pathname;
|
|
2563
2359
|
if (urlPath.startsWith("/api/")) return c.notFound();
|
|
2564
|
-
const filePath =
|
|
2360
|
+
const filePath = resolve8(assetsDir, urlPath.slice(1));
|
|
2565
2361
|
if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
|
|
2566
2362
|
const s = await stat(filePath).catch(() => null);
|
|
2567
2363
|
if (s?.isFile()) {
|
|
@@ -2570,7 +2366,7 @@ async function startServer({
|
|
|
2570
2366
|
const body = await readFile2(filePath);
|
|
2571
2367
|
return c.body(body, 200, { "Content-Type": mime });
|
|
2572
2368
|
}
|
|
2573
|
-
const indexPath =
|
|
2369
|
+
const indexPath = resolve8(assetsDir, "index.html");
|
|
2574
2370
|
const indexStat = await stat(indexPath).catch(() => null);
|
|
2575
2371
|
if (indexStat?.isFile()) {
|
|
2576
2372
|
const body = await readFile2(indexPath, "utf-8");
|
|
@@ -2580,10 +2376,10 @@ async function startServer({
|
|
|
2580
2376
|
});
|
|
2581
2377
|
}
|
|
2582
2378
|
const server = serve({ fetch: app_default.fetch, port, hostname });
|
|
2583
|
-
await new Promise((
|
|
2379
|
+
await new Promise((resolve10, reject) => {
|
|
2584
2380
|
server.on("listening", () => {
|
|
2585
2381
|
logger_default.info("Volute UI running", { hostname, port });
|
|
2586
|
-
|
|
2382
|
+
resolve10();
|
|
2587
2383
|
});
|
|
2588
2384
|
server.on("error", (err) => {
|
|
2589
2385
|
reject(err);
|
|
@@ -2594,14 +2390,14 @@ async function startServer({
|
|
|
2594
2390
|
|
|
2595
2391
|
// src/daemon.ts
|
|
2596
2392
|
if (!process.env.VOLUTE_HOME) {
|
|
2597
|
-
process.env.VOLUTE_HOME =
|
|
2393
|
+
process.env.VOLUTE_HOME = resolve9(homedir(), ".volute");
|
|
2598
2394
|
}
|
|
2599
2395
|
async function startDaemon(opts) {
|
|
2600
2396
|
const { port, hostname } = opts;
|
|
2601
2397
|
const myPid = String(process.pid);
|
|
2602
2398
|
const home = voluteHome();
|
|
2603
2399
|
if (!opts.foreground) {
|
|
2604
|
-
const log2 = new RotatingLog(
|
|
2400
|
+
const log2 = new RotatingLog(resolve9(home, "daemon.log"));
|
|
2605
2401
|
const write2 = (...args) => log2.write(`${format(...args)}
|
|
2606
2402
|
`);
|
|
2607
2403
|
console.log = write2;
|
|
@@ -2609,8 +2405,8 @@ async function startDaemon(opts) {
|
|
|
2609
2405
|
console.warn = write2;
|
|
2610
2406
|
console.info = write2;
|
|
2611
2407
|
}
|
|
2612
|
-
const DAEMON_PID_PATH =
|
|
2613
|
-
const DAEMON_JSON_PATH =
|
|
2408
|
+
const DAEMON_PID_PATH = resolve9(home, "daemon.pid");
|
|
2409
|
+
const DAEMON_JSON_PATH = resolve9(home, "daemon.json");
|
|
2614
2410
|
mkdirSync2(home, { recursive: true });
|
|
2615
2411
|
const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes(32).toString("hex");
|
|
2616
2412
|
process.env.VOLUTE_DAEMON_TOKEN = token;
|