hermes-web-ui 0.3.7 → 0.4.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 +28 -12
- package/dist/client/assets/{Add-Cc7cgBoB.js → Add-BChxDDdy.js} +1 -1
- package/dist/client/assets/{Button-EoeZgIFH.js → Button-uvjCWO-i.js} +1 -1
- package/dist/client/assets/{ChannelsView-Bfbq3w7n.js → ChannelsView-D3a0g0rb.js} +1 -1
- package/dist/client/assets/{ChatView-Vfi_jEpI.css → ChatView-DI3XN8vz.css} +1 -1
- package/dist/client/assets/ChatView-T8LH7dwU.js +127 -0
- package/dist/client/assets/{Close-CKHcXisf.js → Close-DbXijZpL.js} +1 -1
- package/dist/client/assets/{FormItem-CvZvjrtr.js → FormItem-BRiLD3TC.js} +1 -1
- package/dist/client/assets/{GatewaysView-Dp4-TFPE.js → GatewaysView-rfzh1nqy.js} +1 -1
- package/dist/client/assets/{Input-Bk7XdoG-.js → Input-CjlUbV0M.js} +1 -1
- package/dist/client/assets/{InputNumber-Dn0EHi-K.js → InputNumber-CPEjoOAv.js} +1 -1
- package/dist/client/assets/{JobsView-D4JN73Zz.js → JobsView-D6AFr9Xe.js} +2 -2
- package/dist/client/assets/{LoginView--hy5CI5O.js → LoginView-DJB_TSHN.js} +1 -1
- package/dist/client/assets/{LogsView-Dz2ZeYad.js → LogsView-Ul8pAp42.js} +1 -1
- package/dist/client/assets/{MarkdownRenderer-BbedVxvo.js → MarkdownRenderer-CY7d2L7Z.js} +1 -1
- package/dist/client/assets/{MemoryView-D2EHM35l.js → MemoryView-BR5Dl_fa.js} +1 -1
- package/dist/client/assets/{Modal-C5-Iw50K.js → Modal-DDUFP8vh.js} +1 -1
- package/dist/client/assets/{ModelsView-CtrRf4vK.js → ModelsView-DAi9Jdmk.js} +1 -1
- package/dist/client/assets/{Popconfirm-C-M2anVL.js → Popconfirm-Cnb_uQVo.js} +1 -1
- package/dist/client/assets/{Popover-mIRPCy7U.js → Popover-DiVI0l6E.js} +1 -1
- package/dist/client/assets/{ProfilesView-Dy9PivgB.js → ProfilesView-BB0Zrfhi.js} +1 -1
- package/dist/client/assets/{Select-uZBC8HC2.js → Select-BqUA1wxE.js} +1 -1
- package/dist/client/assets/{SettingRow-D9R65bDj.js → SettingRow-CK0bHtaz.js} +1 -1
- package/dist/client/assets/{SettingsView-DWEEXqSY.js → SettingsView-BKKk44FG.js} +1 -1
- package/dist/client/assets/{SkillsView-CdZSRy9_.js → SkillsView-whSlyc23.js} +1 -1
- package/dist/client/assets/{Spin-ChbFBUOD.js → Spin-DwHJdgNz.js} +1 -1
- package/dist/client/assets/{Suffix-DgzfIwzx.js → Suffix-D6x-7akR.js} +1 -1
- package/dist/client/assets/{Switch--HhY1uSh.js → Switch-BvHRSSqt.js} +1 -1
- package/dist/client/assets/{Tag-B2zrHMmZ.js → Tag-BMMlXaEi.js} +1 -1
- package/dist/client/assets/{TerminalView-BwfnH803.js → TerminalView-el6o2Q0a.js} +1 -1
- package/dist/client/assets/{Tooltip-9tdvSKGi.js → Tooltip-BM4wl764.js} +1 -1
- package/dist/client/assets/{UsageView-zL3a7F86.js → UsageView-DQ_YKoEV.js} +1 -1
- package/dist/client/assets/{Warning-CXXqHzLa.js → Warning-CEC7rgvY.js} +1 -1
- package/dist/client/assets/{_plugin-vue_export-helper-Cnn0Z73x.js → _plugin-vue_export-helper-DgUZPfuZ.js} +1 -1
- package/dist/client/assets/app-DPUhLGXq.js +1 -0
- package/dist/client/assets/{app-BMobzABI.js → app-DUt8TNq3.js} +1 -1
- package/dist/client/assets/{browser-CQRjhbaB.js → browser-vxCOMmsq.js} +1 -1
- package/dist/client/assets/chat-i_Ge_Lfr.js +6 -0
- package/dist/client/assets/composables-jrQPIjcq.js +1 -0
- package/dist/client/assets/{fade-in.cssr-lwO9nLky.js → fade-in.cssr-DVg2CkO3.js} +1 -1
- package/dist/client/assets/{index-Tg6M43Om.js → index-COwJ2oY0.js} +1 -1
- package/dist/client/assets/{jobs-Z2HS0j2d.js → jobs-Czr1RcSG.js} +1 -1
- package/dist/client/assets/{light-DgIst23O.js → light-3rSjNeC-.js} +1 -1
- package/dist/client/assets/{light-oE8MEiWL.js → light-CKDlpgGU.js} +1 -1
- package/dist/client/assets/{light-Dx6qj2pM.js → light-CiIDFs7y.js} +1 -1
- package/dist/client/assets/{light-DZ0Ns16h.js → light-CoJqT8Vu.js} +1 -1
- package/dist/client/assets/{light-CjCy-Dkn.js → light-DPRJ1OEN.js} +1 -1
- package/dist/client/assets/{light-DzpNsLai.js → light-vTpJevRf.js} +1 -1
- package/dist/client/assets/{models-DLQiHB7r.js → models-BzEeJuoO.js} +1 -1
- package/dist/client/assets/{pinia-Dp_b1vdW.js → pinia-BoNLlsLy.js} +1 -1
- package/dist/client/assets/{profiles-CNTHYFZE.js → profiles-B-DFTmc2.js} +1 -1
- package/dist/client/assets/{router-Dj-Nmg7q.js → router-HHMeDEaP.js} +2 -2
- package/dist/client/assets/{sessions-C0kvgvBm.js → sessions-BmxS_BoH.js} +1 -1
- package/dist/client/assets/{skills-G7EoEvdS.js → skills-Be8Mzr1r.js} +1 -1
- package/dist/client/assets/{use-message-BgToAqhv.js → use-message-DBTY4945.js} +1 -1
- package/dist/client/assets/{useTheme-BUShiwRu.js → useTheme-D58Cg7k2.js} +1 -1
- package/dist/client/index.html +27 -27
- package/dist/server/index.js +19 -194
- package/dist/server/routes/health.d.ts +4 -0
- package/dist/server/routes/health.js +109 -0
- package/dist/server/routes/hermes/group-chat.d.ts +4 -0
- package/dist/server/routes/hermes/group-chat.js +146 -0
- package/dist/server/routes/update.d.ts +2 -0
- package/dist/server/routes/update.js +69 -0
- package/dist/server/routes/upload.js +41 -11
- package/dist/server/services/auth.js +1 -1
- package/dist/server/services/gateway-bootstrap.d.ts +2 -0
- package/dist/server/services/gateway-bootstrap.js +51 -0
- package/dist/server/services/group-chat/coordinator.d.ts +14 -0
- package/dist/server/services/group-chat/coordinator.js +230 -0
- package/dist/server/services/group-chat/index.d.ts +5 -0
- package/dist/server/services/group-chat/index.js +115 -0
- package/dist/server/services/group-chat/rooms-db.d.ts +56 -0
- package/dist/server/services/group-chat/rooms-db.js +199 -0
- package/dist/server/services/hermes/group-chat/agent-clients.d.ts +133 -0
- package/dist/server/services/hermes/group-chat/agent-clients.js +364 -0
- package/dist/server/services/hermes/group-chat/index.d.ts +72 -0
- package/dist/server/services/hermes/group-chat/index.js +307 -0
- package/dist/server/services/shutdown.d.ts +1 -0
- package/dist/server/services/shutdown.js +37 -0
- package/package.json +1 -1
- package/dist/client/assets/ChatView-CDdyTo72.js +0 -127
- package/dist/client/assets/app-Bqu9Uz-1.js +0 -1
- package/dist/client/assets/chat-BIdq6ZXF.js +0 -6
- package/dist/client/assets/composables-ClIU-Ad1.js +0 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Server } from 'socket.io';
|
|
2
|
+
import type { Server as HttpServer } from 'http';
|
|
3
|
+
import { AgentClients } from './agent-clients';
|
|
4
|
+
interface ChatMessage {
|
|
5
|
+
id: string;
|
|
6
|
+
roomId: string;
|
|
7
|
+
senderId: string;
|
|
8
|
+
senderName: string;
|
|
9
|
+
content: string;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
}
|
|
12
|
+
interface RoomAgent {
|
|
13
|
+
id: string;
|
|
14
|
+
roomId: string;
|
|
15
|
+
agentId: string;
|
|
16
|
+
profile: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
invited: number;
|
|
20
|
+
}
|
|
21
|
+
declare class ChatStorage {
|
|
22
|
+
private db;
|
|
23
|
+
constructor(dbPath: string);
|
|
24
|
+
getRoom(roomId: string): {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
inviteCode: string | null;
|
|
28
|
+
} | undefined;
|
|
29
|
+
getRoomByInviteCode(code: string): {
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
inviteCode: string | null;
|
|
33
|
+
} | undefined;
|
|
34
|
+
getAllRooms(): {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
inviteCode: string | null;
|
|
38
|
+
}[];
|
|
39
|
+
saveRoom(id: string, name: string, inviteCode?: string): void;
|
|
40
|
+
updateRoomInviteCode(roomId: string, inviteCode: string): void;
|
|
41
|
+
getMessages(roomId: string, limit?: number): ChatMessage[];
|
|
42
|
+
addMessage(msg: ChatMessage): void;
|
|
43
|
+
pruneMessages(roomId: string, keep?: number): void;
|
|
44
|
+
getRoomAgents(roomId: string): RoomAgent[];
|
|
45
|
+
addRoomAgent(roomId: string, agentId: string, profile: string, name: string, description: string, invited: number): RoomAgent;
|
|
46
|
+
removeRoomAgent(agentId: string): void;
|
|
47
|
+
close(): void;
|
|
48
|
+
}
|
|
49
|
+
export declare class GroupChatServer {
|
|
50
|
+
private io;
|
|
51
|
+
private storage;
|
|
52
|
+
private rooms;
|
|
53
|
+
private userNames;
|
|
54
|
+
readonly agentClients: AgentClients;
|
|
55
|
+
private gatewayManager;
|
|
56
|
+
setGatewayManager(manager: any): void;
|
|
57
|
+
constructor(httpServer: HttpServer);
|
|
58
|
+
getIO(): Server;
|
|
59
|
+
getStorage(): ChatStorage;
|
|
60
|
+
getRoomIds(): string[];
|
|
61
|
+
private restoreAgents;
|
|
62
|
+
private authMiddleware;
|
|
63
|
+
private onConnection;
|
|
64
|
+
private handleJoin;
|
|
65
|
+
private handleMessage;
|
|
66
|
+
private handleTyping;
|
|
67
|
+
private handleStopTyping;
|
|
68
|
+
private handleDisconnect;
|
|
69
|
+
private leaveAllRooms;
|
|
70
|
+
private generateId;
|
|
71
|
+
}
|
|
72
|
+
export {};
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GroupChatServer = void 0;
|
|
4
|
+
const node_sqlite_1 = require("node:sqlite");
|
|
5
|
+
const socket_io_1 = require("socket.io");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const auth_1 = require("../../auth");
|
|
9
|
+
const config_1 = require("../../../config");
|
|
10
|
+
const agent_clients_1 = require("./agent-clients");
|
|
11
|
+
// ─── SQLite Storage ───────────────────────────────────────────
|
|
12
|
+
class ChatStorage {
|
|
13
|
+
db;
|
|
14
|
+
constructor(dbPath) {
|
|
15
|
+
this.db = new node_sqlite_1.DatabaseSync(dbPath);
|
|
16
|
+
this.db.exec(`
|
|
17
|
+
CREATE TABLE IF NOT EXISTS rooms (
|
|
18
|
+
id TEXT PRIMARY KEY,
|
|
19
|
+
name TEXT NOT NULL,
|
|
20
|
+
inviteCode TEXT UNIQUE
|
|
21
|
+
)
|
|
22
|
+
`);
|
|
23
|
+
this.db.exec(`
|
|
24
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
25
|
+
id TEXT PRIMARY KEY,
|
|
26
|
+
roomId TEXT NOT NULL,
|
|
27
|
+
senderId TEXT NOT NULL,
|
|
28
|
+
senderName TEXT NOT NULL,
|
|
29
|
+
content TEXT NOT NULL,
|
|
30
|
+
timestamp INTEGER NOT NULL,
|
|
31
|
+
FOREIGN KEY (roomId) REFERENCES rooms(id)
|
|
32
|
+
)
|
|
33
|
+
`);
|
|
34
|
+
this.db.exec('CREATE INDEX IF NOT EXISTS idx_messages_room ON messages(roomId, timestamp)');
|
|
35
|
+
this.db.exec(`
|
|
36
|
+
CREATE TABLE IF NOT EXISTS room_agents (
|
|
37
|
+
id TEXT PRIMARY KEY,
|
|
38
|
+
roomId TEXT NOT NULL,
|
|
39
|
+
agentId TEXT NOT NULL,
|
|
40
|
+
profile TEXT NOT NULL,
|
|
41
|
+
name TEXT NOT NULL,
|
|
42
|
+
description TEXT NOT NULL DEFAULT '',
|
|
43
|
+
invited INTEGER NOT NULL DEFAULT 0,
|
|
44
|
+
FOREIGN KEY (roomId) REFERENCES rooms(id)
|
|
45
|
+
)
|
|
46
|
+
`);
|
|
47
|
+
this.db.exec('CREATE INDEX IF NOT EXISTS idx_room_agents_room ON room_agents(roomId)');
|
|
48
|
+
}
|
|
49
|
+
// ─── Rooms ────────────────────────────────────────────────
|
|
50
|
+
getRoom(roomId) {
|
|
51
|
+
return this.db.prepare('SELECT id, name, inviteCode FROM rooms WHERE id = ?').get(roomId);
|
|
52
|
+
}
|
|
53
|
+
getRoomByInviteCode(code) {
|
|
54
|
+
return this.db.prepare('SELECT id, name, inviteCode FROM rooms WHERE inviteCode = ?').get(code);
|
|
55
|
+
}
|
|
56
|
+
getAllRooms() {
|
|
57
|
+
return this.db.prepare('SELECT id, name, inviteCode FROM rooms ORDER BY id').all();
|
|
58
|
+
}
|
|
59
|
+
saveRoom(id, name, inviteCode) {
|
|
60
|
+
this.db.prepare('INSERT OR IGNORE INTO rooms (id, name, inviteCode) VALUES (?, ?, ?)').run(id, name, inviteCode || null);
|
|
61
|
+
}
|
|
62
|
+
updateRoomInviteCode(roomId, inviteCode) {
|
|
63
|
+
this.db.prepare('UPDATE rooms SET inviteCode = ? WHERE id = ?').run(inviteCode, roomId);
|
|
64
|
+
}
|
|
65
|
+
// ─── Messages ─────────────────────────────────────────────
|
|
66
|
+
getMessages(roomId, limit = 500) {
|
|
67
|
+
const rows = this.db.prepare('SELECT id, roomId, senderId, senderName, content, timestamp FROM messages WHERE roomId = ? ORDER BY timestamp DESC LIMIT ?').all(roomId, limit);
|
|
68
|
+
return rows.reverse(); // return in chronological order
|
|
69
|
+
}
|
|
70
|
+
addMessage(msg) {
|
|
71
|
+
this.db.prepare('INSERT INTO messages (id, roomId, senderId, senderName, content, timestamp) VALUES (?, ?, ?, ?, ?, ?)').run(msg.id, msg.roomId, msg.senderId, msg.senderName, msg.content, msg.timestamp);
|
|
72
|
+
}
|
|
73
|
+
pruneMessages(roomId, keep = 500) {
|
|
74
|
+
const count = this.db.prepare('SELECT COUNT(*) as c FROM messages WHERE roomId = ?').get(roomId).c;
|
|
75
|
+
if (count > keep) {
|
|
76
|
+
const cutoff = this.db.prepare('SELECT timestamp FROM messages WHERE roomId = ? ORDER BY timestamp DESC LIMIT 1 OFFSET ?').get(roomId, keep - 1);
|
|
77
|
+
if (cutoff) {
|
|
78
|
+
this.db.prepare('DELETE FROM messages WHERE roomId = ? AND timestamp < ?').run(roomId, cutoff.timestamp);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// ─── Room Agents ──────────────────────────────────────────
|
|
83
|
+
getRoomAgents(roomId) {
|
|
84
|
+
return this.db.prepare('SELECT id, roomId, agentId, profile, name, description, invited FROM room_agents WHERE roomId = ?').all(roomId);
|
|
85
|
+
}
|
|
86
|
+
addRoomAgent(roomId, agentId, profile, name, description, invited) {
|
|
87
|
+
const id = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
88
|
+
this.db.prepare('INSERT INTO room_agents (id, roomId, agentId, profile, name, description, invited) VALUES (?, ?, ?, ?, ?, ?, ?)').run(id, roomId, agentId, profile, name, description, invited);
|
|
89
|
+
return { id, roomId, agentId, profile, name, description, invited };
|
|
90
|
+
}
|
|
91
|
+
removeRoomAgent(agentId) {
|
|
92
|
+
this.db.prepare('DELETE FROM room_agents WHERE id = ?').run(agentId);
|
|
93
|
+
}
|
|
94
|
+
close() {
|
|
95
|
+
this.db.close();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// ─── ChatRoom (in-memory, for online members) ─────────────────
|
|
99
|
+
class ChatRoom {
|
|
100
|
+
id;
|
|
101
|
+
name;
|
|
102
|
+
members = new Map();
|
|
103
|
+
constructor(id, name) {
|
|
104
|
+
this.id = id;
|
|
105
|
+
this.name = name || id;
|
|
106
|
+
}
|
|
107
|
+
addMember(id, name) {
|
|
108
|
+
const member = { id, name, joinedAt: Date.now() };
|
|
109
|
+
this.members.set(id, member);
|
|
110
|
+
return member;
|
|
111
|
+
}
|
|
112
|
+
removeMember(id) {
|
|
113
|
+
const member = this.members.get(id);
|
|
114
|
+
this.members.delete(id);
|
|
115
|
+
return member;
|
|
116
|
+
}
|
|
117
|
+
getMembersList() {
|
|
118
|
+
return Array.from(this.members.values());
|
|
119
|
+
}
|
|
120
|
+
hasMember(id) {
|
|
121
|
+
return this.members.has(id);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// ─── GroupChat Server ────────────────────────────────────────
|
|
125
|
+
class GroupChatServer {
|
|
126
|
+
io;
|
|
127
|
+
storage;
|
|
128
|
+
rooms = new Map();
|
|
129
|
+
userNames = new Map();
|
|
130
|
+
agentClients = new agent_clients_1.AgentClients();
|
|
131
|
+
gatewayManager = null;
|
|
132
|
+
setGatewayManager(manager) {
|
|
133
|
+
this.gatewayManager = manager;
|
|
134
|
+
this.agentClients.setGatewayManager(manager);
|
|
135
|
+
}
|
|
136
|
+
constructor(httpServer) {
|
|
137
|
+
const dbPath = (0, path_1.join)(config_1.config.dataDir, 'webui.db');
|
|
138
|
+
(0, fs_1.mkdirSync)(config_1.config.dataDir, { recursive: true });
|
|
139
|
+
this.storage = new ChatStorage(dbPath);
|
|
140
|
+
this.io = new socket_io_1.Server(httpServer, {
|
|
141
|
+
path: '/api/hermes/group-chat',
|
|
142
|
+
cors: { origin: '*', methods: ['GET', 'POST'] },
|
|
143
|
+
});
|
|
144
|
+
this.io.use(this.authMiddleware.bind(this));
|
|
145
|
+
this.io.on('connection', this.onConnection.bind(this));
|
|
146
|
+
// Restore persisted rooms into memory
|
|
147
|
+
this.storage.getAllRooms().forEach((row) => {
|
|
148
|
+
this.rooms.set(row.id, new ChatRoom(row.id, row.name));
|
|
149
|
+
});
|
|
150
|
+
console.log('[GroupChat] Socket.IO ready at /group-chat');
|
|
151
|
+
// Restore agent connections from SQLite
|
|
152
|
+
this.restoreAgents();
|
|
153
|
+
}
|
|
154
|
+
getIO() {
|
|
155
|
+
return this.io;
|
|
156
|
+
}
|
|
157
|
+
getStorage() {
|
|
158
|
+
return this.storage;
|
|
159
|
+
}
|
|
160
|
+
getRoomIds() {
|
|
161
|
+
return Array.from(this.rooms.keys());
|
|
162
|
+
}
|
|
163
|
+
// ─── Restore Agents ─────────────────────────────────────────
|
|
164
|
+
async restoreAgents() {
|
|
165
|
+
const rooms = this.storage.getAllRooms();
|
|
166
|
+
let total = 0;
|
|
167
|
+
for (const room of rooms) {
|
|
168
|
+
const agents = this.storage.getRoomAgents(room.id);
|
|
169
|
+
for (const agent of agents) {
|
|
170
|
+
try {
|
|
171
|
+
const client = await this.agentClients.createAgent({
|
|
172
|
+
profile: agent.profile,
|
|
173
|
+
name: agent.name,
|
|
174
|
+
description: agent.description,
|
|
175
|
+
invited: agent.invited,
|
|
176
|
+
});
|
|
177
|
+
await this.agentClients.addAgentToRoom(room.id, client);
|
|
178
|
+
total++;
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
console.error(`[GroupChat] Failed to restore agent ${agent.name} in room ${room.id}: ${err.message}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (total > 0) {
|
|
186
|
+
console.log(`[GroupChat] Restored ${total} agent(s) across ${rooms.length} room(s)`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// ─── Auth ───────────────────────────────────────────────────
|
|
190
|
+
async authMiddleware(socket, next) {
|
|
191
|
+
const authToken = await (0, auth_1.getToken)();
|
|
192
|
+
if (authToken) {
|
|
193
|
+
const token = socket.handshake.auth.token || socket.handshake.query.token || '';
|
|
194
|
+
if (token !== authToken) {
|
|
195
|
+
return next(new Error('Unauthorized'));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
next();
|
|
199
|
+
}
|
|
200
|
+
// ─── Connection ─────────────────────────────────────────────
|
|
201
|
+
onConnection(socket) {
|
|
202
|
+
const userId = socket.id;
|
|
203
|
+
const userName = socket.handshake.auth.name || `User-${userId.slice(0, 6)}`;
|
|
204
|
+
this.userNames.set(userId, userName);
|
|
205
|
+
console.log(`[GroupChat] Connected: ${userName} (${userId})`);
|
|
206
|
+
socket.on('join', (data, ack) => this.handleJoin(socket, data, ack));
|
|
207
|
+
socket.on('message', (data, ack) => this.handleMessage(socket, data, ack));
|
|
208
|
+
socket.on('typing', (data) => this.handleTyping(socket, data));
|
|
209
|
+
socket.on('stop_typing', (data) => this.handleStopTyping(socket, data));
|
|
210
|
+
socket.on('disconnect', () => this.handleDisconnect(socket));
|
|
211
|
+
}
|
|
212
|
+
// ─── Handlers ───────────────────────────────────────────────
|
|
213
|
+
handleJoin(socket, data, ack) {
|
|
214
|
+
const userId = socket.id;
|
|
215
|
+
if (data.name)
|
|
216
|
+
this.userNames.set(userId, data.name);
|
|
217
|
+
const userName = this.userNames.get(userId);
|
|
218
|
+
const roomId = data.roomId || 'general';
|
|
219
|
+
let room = this.rooms.get(roomId);
|
|
220
|
+
if (!room) {
|
|
221
|
+
room = new ChatRoom(roomId);
|
|
222
|
+
this.rooms.set(roomId, room);
|
|
223
|
+
this.storage.saveRoom(roomId, roomId);
|
|
224
|
+
}
|
|
225
|
+
room.addMember(userId, userName);
|
|
226
|
+
socket.join(roomId);
|
|
227
|
+
socket.to(roomId).emit('member_joined', {
|
|
228
|
+
roomId,
|
|
229
|
+
memberId: userId,
|
|
230
|
+
memberName: userName,
|
|
231
|
+
members: room.getMembersList(),
|
|
232
|
+
});
|
|
233
|
+
// Load history from SQLite
|
|
234
|
+
const messages = this.storage.getMessages(roomId);
|
|
235
|
+
ack?.({
|
|
236
|
+
roomId,
|
|
237
|
+
roomName: room.name,
|
|
238
|
+
members: room.getMembersList(),
|
|
239
|
+
messages,
|
|
240
|
+
rooms: this.getRoomIds(),
|
|
241
|
+
});
|
|
242
|
+
console.log(`[GroupChat] ${userName} joined room: ${roomId}`);
|
|
243
|
+
}
|
|
244
|
+
handleMessage(socket, data, ack) {
|
|
245
|
+
const userId = socket.id;
|
|
246
|
+
const roomId = data.roomId || 'general';
|
|
247
|
+
const room = this.rooms.get(roomId);
|
|
248
|
+
if (!room || !room.hasMember(userId)) {
|
|
249
|
+
ack?.({ error: 'Not in room' });
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const msg = {
|
|
253
|
+
id: this.generateId(),
|
|
254
|
+
roomId,
|
|
255
|
+
senderId: userId,
|
|
256
|
+
senderName: this.userNames.get(userId),
|
|
257
|
+
content: data.content,
|
|
258
|
+
timestamp: Date.now(),
|
|
259
|
+
};
|
|
260
|
+
this.storage.addMessage(msg);
|
|
261
|
+
this.storage.pruneMessages(roomId);
|
|
262
|
+
this.io.to(roomId).emit('message', msg);
|
|
263
|
+
ack?.({ id: msg.id });
|
|
264
|
+
}
|
|
265
|
+
handleTyping(socket, data) {
|
|
266
|
+
const roomId = data.roomId || 'general';
|
|
267
|
+
socket.to(roomId).emit('typing', {
|
|
268
|
+
roomId,
|
|
269
|
+
userId: socket.id,
|
|
270
|
+
userName: this.userNames.get(socket.id),
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
handleStopTyping(socket, data) {
|
|
274
|
+
const roomId = data.roomId || 'general';
|
|
275
|
+
socket.to(roomId).emit('stop_typing', {
|
|
276
|
+
roomId,
|
|
277
|
+
userId: socket.id,
|
|
278
|
+
userName: this.userNames.get(socket.id),
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
handleDisconnect(socket) {
|
|
282
|
+
const userId = socket.id;
|
|
283
|
+
const userName = this.userNames.get(userId);
|
|
284
|
+
console.log(`[GroupChat] Disconnected: ${userName} (${userId})`);
|
|
285
|
+
this.leaveAllRooms(socket, userId, userName || userId);
|
|
286
|
+
this.userNames.delete(userId);
|
|
287
|
+
}
|
|
288
|
+
// ─── Helpers ────────────────────────────────────────────────
|
|
289
|
+
leaveAllRooms(socket, userId, userName) {
|
|
290
|
+
this.rooms.forEach((room, rid) => {
|
|
291
|
+
if (room.hasMember(userId)) {
|
|
292
|
+
room.removeMember(userId);
|
|
293
|
+
socket.leave(rid);
|
|
294
|
+
this.io.to(rid).emit('member_left', {
|
|
295
|
+
roomId: rid,
|
|
296
|
+
memberId: userId,
|
|
297
|
+
memberName: userName,
|
|
298
|
+
members: room.getMembersList(),
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
generateId() {
|
|
304
|
+
return Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
exports.GroupChatServer = GroupChatServer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function bindShutdown(server: any): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bindShutdown = bindShutdown;
|
|
4
|
+
function bindShutdown(server) {
|
|
5
|
+
let isShuttingDown = false;
|
|
6
|
+
const shutdown = async (signal) => {
|
|
7
|
+
if (isShuttingDown)
|
|
8
|
+
return;
|
|
9
|
+
isShuttingDown = true;
|
|
10
|
+
console.log(`\n[${signal}] shutting down...`);
|
|
11
|
+
try {
|
|
12
|
+
if (server) {
|
|
13
|
+
await new Promise((resolve) => {
|
|
14
|
+
server.close(() => {
|
|
15
|
+
console.log('✓ http server closed');
|
|
16
|
+
resolve();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
console.error('shutdown error:', err);
|
|
23
|
+
}
|
|
24
|
+
process.exit(0);
|
|
25
|
+
};
|
|
26
|
+
process.once('SIGUSR2', shutdown);
|
|
27
|
+
process.on('SIGINT', shutdown);
|
|
28
|
+
process.on('SIGTERM', shutdown);
|
|
29
|
+
process.on('uncaughtException', (err) => {
|
|
30
|
+
console.error('uncaughtException:', err);
|
|
31
|
+
shutdown('uncaughtException');
|
|
32
|
+
});
|
|
33
|
+
process.on('unhandledRejection', (err) => {
|
|
34
|
+
console.error('unhandledRejection:', err);
|
|
35
|
+
shutdown('unhandledRejection');
|
|
36
|
+
});
|
|
37
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hermes-web-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Web dashboard for Hermes Agent — multi-platform AI chat, session management, scheduled jobs, usage analytics & channel configuration (Telegram, Discord, Slack, WhatsApp)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import{$ as e,A as t,B as n,C as r,D as i,E as a,F as o,G as s,K as c,L as l,N as u,Q as d,R as f,T as p,U as m,V as h,W as g,X as _,_ as v,ct as y,d as b,dt as x,g as S,gt as C,j as w,k as T,m as E,mt as D,ot as O,pt as k,q as A,st as j,w as M,y as N}from"./router-Dj-Nmg7q.js";import{r as P,t as F}from"./_plugin-vue_export-helper-Cnn0Z73x.js";import{t as I}from"./logo-Cd-t_oGE.js";import{$ as L,B as R,X as z,c as B,ct as V,dt as H,ft as U,pt as W,q as G,st as K,tt as q,ut as J,z as ee}from"./browser-CQRjhbaB.js";import{C as te,E as Y,N as ne,S as X,T as Z,c as Q,g as re,k as ie,l as ae,m as oe,n as se,o as ce,r as le,t as ue}from"./Popover-mIRPCy7U.js";import{r as de,t as fe}from"./create-5zWq3BEB.js";import{d as pe,f as me,p as he,r as ge}from"./Suffix-DgzfIwzx.js";import{t as _e}from"./Modal-C5-Iw50K.js";import{t as $}from"./Button-EoeZgIFH.js";import{t as ve}from"./Input-Bk7XdoG-.js";import{i as ye,n as be,t as xe}from"./chat-BIdq6ZXF.js";import{t as Se}from"./Tooltip-9tdvSKGi.js";import{t as Ce}from"./use-message-BgToAqhv.js";import{t as we}from"./Popconfirm-C-M2anVL.js";import{t as Te}from"./useTheme-BUShiwRu.js";import{t as Ee}from"./app-BMobzABI.js";import{t as De}from"./profiles-CNTHYFZE.js";import{i as Oe}from"./sessions-C0kvgvBm.js";import{t as ke}from"./MarkdownRenderer-BbedVxvo.js";function Ae(e={},t){let r=O({ctrl:!1,command:!1,win:!1,shift:!1,tab:!1}),{keydown:i,keyup:a}=e,o=e=>{switch(e.key){case`Control`:r.ctrl=!0;break;case`Meta`:r.command=!0,r.win=!0;break;case`Shift`:r.shift=!0;break;case`Tab`:r.tab=!0;break}i!==void 0&&Object.keys(i).forEach(t=>{if(t!==e.key)return;let n=i[t];if(typeof n==`function`)n(e);else{let{stop:t=!1,prevent:r=!1}=n;t&&e.stopPropagation(),r&&e.preventDefault(),n.handler(e)}})},s=e=>{switch(e.key){case`Control`:r.ctrl=!1;break;case`Meta`:r.command=!1,r.win=!1;break;case`Shift`:r.shift=!1;break;case`Tab`:r.tab=!1;break}a!==void 0&&Object.keys(a).forEach(t=>{if(t!==e.key)return;let n=a[t];if(typeof n==`function`)n(e);else{let{stop:t=!1,prevent:r=!1}=n;t&&e.stopPropagation(),r&&e.preventDefault(),n.handler(e)}})},c=()=>{(t===void 0||t.value)&&(he(`keydown`,document,o),he(`keyup`,document,s)),t!==void 0&&_(t,e=>{e?(he(`keydown`,document,o),he(`keyup`,document,s)):(me(`keydown`,document,o),me(`keyup`,document,s))})};return ne()?(n(c),h(()=>{(t===void 0||t.value)&&(me(`keydown`,document,o),me(`keyup`,document,s))})):c(),j(r)}function je(e,t,n){if(!t)return e;let r=y(e.value),i=null;return _(e,e=>{i!==null&&window.clearTimeout(i),e===!0?n&&!n.value?r.value=!0:i=window.setTimeout(()=>{r.value=!0},t):r.value=!1}),r}function Me(e){return t=>{t?e.value=t.$el:e.value=null}}var Ne=w({name:`ChevronRight`,render(){return u(`svg`,{viewBox:`0 0 16 16`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`},u(`path`,{d:`M5.64645 3.14645C5.45118 3.34171 5.45118 3.65829 5.64645 3.85355L9.79289 8L5.64645 12.1464C5.45118 12.3417 5.45118 12.6583 5.64645 12.8536C5.84171 13.0488 6.15829 13.0488 6.35355 12.8536L10.8536 8.35355C11.0488 8.15829 11.0488 7.84171 10.8536 7.64645L6.35355 3.14645C6.15829 2.95118 5.84171 2.95118 5.64645 3.14645Z`,fill:`currentColor`}))}}),Pe=L(`n-dropdown-menu`),Fe=L(`n-dropdown`),Ie=L(`n-dropdown-option`),Le=w({name:`DropdownDivider`,props:{clsPrefix:{type:String,required:!0}},render(){return u(`div`,{class:`${this.clsPrefix}-dropdown-divider`})}}),Re=w({name:`DropdownGroupHeader`,props:{clsPrefix:{type:String,required:!0},tmNode:{type:Object,required:!0}},setup(){let{showIconRef:e,hasSubmenuRef:t}=o(Pe),{renderLabelRef:n,labelFieldRef:r,nodePropsRef:i,renderOptionRef:a}=o(Fe);return{labelField:r,showIcon:e,hasSubmenu:t,renderLabel:n,nodeProps:i,renderOption:a}},render(){let{clsPrefix:e,hasSubmenu:t,showIcon:n,nodeProps:r,renderLabel:i,renderOption:a}=this,{rawNode:o}=this.tmNode,s=u(`div`,Object.assign({class:`${e}-dropdown-option`},r?.(o)),u(`div`,{class:`${e}-dropdown-option-body ${e}-dropdown-option-body--group`},u(`div`,{"data-dropdown-option":!0,class:[`${e}-dropdown-option-body__prefix`,n&&`${e}-dropdown-option-body__prefix--show-icon`]},Q(o.icon)),u(`div`,{class:`${e}-dropdown-option-body__label`,"data-dropdown-option":!0},i?i(o):Q(o.title??o[this.labelField])),u(`div`,{class:[`${e}-dropdown-option-body__suffix`,t&&`${e}-dropdown-option-body__suffix--has-submenu`],"data-dropdown-option":!0})));return a?a({node:s,option:o}):s}}),ze=V(`icon`,`
|
|
2
|
-
height: 1em;
|
|
3
|
-
width: 1em;
|
|
4
|
-
line-height: 1em;
|
|
5
|
-
text-align: center;
|
|
6
|
-
display: inline-block;
|
|
7
|
-
position: relative;
|
|
8
|
-
fill: currentColor;
|
|
9
|
-
`,[H(`color-transition`,{transition:`color .3s var(--n-bezier)`}),H(`depth`,{color:`var(--n-color)`},[K(`svg`,{opacity:`var(--n-opacity)`,transition:`opacity .3s var(--n-bezier)`})]),K(`svg`,{height:`1em`,width:`1em`})]),Be=w({_n_icon__:!0,name:`Icon`,inheritAttrs:!1,props:Object.assign(Object.assign({},B.props),{depth:[String,Number],size:[Number,String],color:String,component:[Object,Function]}),setup(e){let{mergedClsPrefixRef:t,inlineThemeDisabled:n}=R(e),i=B(`Icon`,`-icon`,ze,be,e,t),a=r(()=>{let{depth:t}=e,{common:{cubicBezierEaseInOut:n},self:r}=i.value;if(t!==void 0){let{color:e,[`opacity${t}Depth`]:i}=r;return{"--n-bezier":n,"--n-color":e,"--n-opacity":i}}return{"--n-bezier":n,"--n-color":``,"--n-opacity":``}}),o=n?ee(`icon`,r(()=>`${e.depth||`d`}`),a,e):void 0;return{mergedClsPrefix:t,mergedStyle:r(()=>{let{size:t,color:n}=e;return{fontSize:oe(t),color:n}}),cssVars:n?void 0:a,themeClass:o?.themeClass,onRender:o?.onRender}},render(){let{$parent:e,depth:t,mergedClsPrefix:n,component:r,onRender:i,themeClass:a}=this;return e?.$options?._n_icon__&&z(`icon`,"don't wrap `n-icon` inside `n-icon`"),i?.(),u(`i`,l(this.$attrs,{role:`img`,class:[`${n}-icon`,a,{[`${n}-icon--depth`]:t,[`${n}-icon--color-transition`]:t!==void 0}],style:[this.cssVars,this.mergedStyle]}),r?u(r):this.$slots)}});function Ve(e,t){return e.type===`submenu`||e.type===void 0&&e[t]!==void 0}function He(e){return e.type===`group`}function Ue(e){return e.type===`divider`}function We(e){return e.type===`render`}var Ge=w({name:`DropdownOption`,props:{clsPrefix:{type:String,required:!0},tmNode:{type:Object,required:!0},parentKey:{type:[String,Number],default:null},placement:{type:String,default:`right-start`},props:Object,scrollable:Boolean},setup(e){let t=o(Fe),{hoverKeyRef:n,keyboardKeyRef:i,lastToggledSubmenuKeyRef:a,pendingKeyPathRef:s,activeKeyPathRef:l,animatedRef:u,mergedShowRef:d,renderLabelRef:f,renderIconRef:p,labelFieldRef:m,childrenFieldRef:h,renderOptionRef:g,nodePropsRef:_,menuPropsRef:v}=t,b=o(Ie,null),x=o(Pe),S=o(Z),C=r(()=>e.tmNode.rawNode),w=r(()=>{let{value:t}=h;return Ve(e.tmNode.rawNode,t)}),T=r(()=>{let{disabled:t}=e.tmNode;return t}),E=je(r(()=>{if(!w.value)return!1;let{key:t,disabled:r}=e.tmNode;if(r)return!1;let{value:o}=n,{value:c}=i,{value:l}=a,{value:u}=s;return o===null?c===null?l===null?!1:u.includes(t):u.includes(t)&&u[u.length-1]!==t:u.includes(t)}),300,r(()=>i.value===null&&!u.value)),D=r(()=>!!b?.enteringSubmenuRef.value),O=y(!1);c(Ie,{enteringSubmenuRef:O});function k(){O.value=!0}function A(){O.value=!1}function j(){let{parentKey:t,tmNode:r}=e;r.disabled||d.value&&(a.value=t,i.value=null,n.value=r.key)}function M(){let{tmNode:t}=e;t.disabled||d.value&&n.value!==t.key&&j()}function N(t){if(e.tmNode.disabled||!d.value)return;let{relatedTarget:r}=t;r&&!de({target:r},`dropdownOption`)&&!de({target:r},`scrollbarRail`)&&(n.value=null)}function P(){let{value:n}=w,{tmNode:r}=e;d.value&&!n&&!r.disabled&&(t.doSelect(r.key,r.rawNode),t.doUpdateShow(!1))}return{labelField:m,renderLabel:f,renderIcon:p,siblingHasIcon:x.showIconRef,siblingHasSubmenu:x.hasSubmenuRef,menuProps:v,popoverBody:S,animated:u,mergedShowSubmenu:r(()=>E.value&&!D.value),rawNode:C,hasSubmenu:w,pending:q(()=>{let{value:t}=s,{key:n}=e.tmNode;return t.includes(n)}),childActive:q(()=>{let{value:t}=l,{key:n}=e.tmNode,r=t.findIndex(e=>n===e);return r===-1?!1:r<t.length-1}),active:q(()=>{let{value:t}=l,{key:n}=e.tmNode,r=t.findIndex(e=>n===e);return r===-1?!1:r===t.length-1}),mergedDisabled:T,renderOption:g,nodeProps:_,handleClick:P,handleMouseMove:M,handleMouseEnter:j,handleMouseLeave:N,handleSubmenuBeforeEnter:k,handleSubmenuAfterEnter:A}},render(){let{animated:e,rawNode:t,mergedShowSubmenu:n,clsPrefix:r,siblingHasIcon:i,siblingHasSubmenu:a,renderLabel:o,renderIcon:s,renderOption:c,nodeProps:d,props:f,scrollable:p}=this,m=null;if(n){let e=this.menuProps?.call(this,t,t.children);m=u(Je,Object.assign({},e,{clsPrefix:r,scrollable:this.scrollable,tmNodes:this.tmNode.children,parentKey:this.tmNode.key}))}let h={class:[`${r}-dropdown-option-body`,this.pending&&`${r}-dropdown-option-body--pending`,this.active&&`${r}-dropdown-option-body--active`,this.childActive&&`${r}-dropdown-option-body--child-active`,this.mergedDisabled&&`${r}-dropdown-option-body--disabled`],onMousemove:this.handleMouseMove,onMouseenter:this.handleMouseEnter,onMouseleave:this.handleMouseLeave,onClick:this.handleClick},g=d?.(t),_=u(`div`,Object.assign({class:[`${r}-dropdown-option`,g?.class],"data-dropdown-option":!0},g),u(`div`,l(h,f),[u(`div`,{class:[`${r}-dropdown-option-body__prefix`,i&&`${r}-dropdown-option-body__prefix--show-icon`]},[s?s(t):Q(t.icon)]),u(`div`,{"data-dropdown-option":!0,class:`${r}-dropdown-option-body__label`},o?o(t):Q(t[this.labelField]??t.title)),u(`div`,{"data-dropdown-option":!0,class:[`${r}-dropdown-option-body__suffix`,a&&`${r}-dropdown-option-body__suffix--has-submenu`]},this.hasSubmenu?u(Be,null,{default:()=>u(Ne,null)}):null)]),this.hasSubmenu?u(te,null,{default:()=>[u(X,null,{default:()=>u(`div`,{class:`${r}-dropdown-offset-container`},u(re,{show:this.mergedShowSubmenu,placement:this.placement,to:p&&this.popoverBody||void 0,teleportDisabled:!p},{default:()=>u(`div`,{class:`${r}-dropdown-menu-wrapper`},e?u(b,{onBeforeEnter:this.handleSubmenuBeforeEnter,onAfterEnter:this.handleSubmenuAfterEnter,name:`fade-in-scale-up-transition`,appear:!0},{default:()=>m}):m)}))})]}):null);return c?c({node:_,option:t}):_}}),Ke=w({name:`NDropdownGroup`,props:{clsPrefix:{type:String,required:!0},tmNode:{type:Object,required:!0},parentKey:{type:[String,Number],default:null}},render(){let{tmNode:e,parentKey:t,clsPrefix:n}=this,{children:r}=e;return u(N,null,u(Re,{clsPrefix:n,tmNode:e,key:e.key}),r?.map(e=>{let{rawNode:r}=e;return r.show===!1?null:Ue(r)?u(Le,{clsPrefix:n,key:e.key}):e.isGroup?(z(`dropdown`,"`group` node is not allowed to be put in `group` node."),null):u(Ge,{clsPrefix:n,tmNode:e,parentKey:t,key:e.key})}))}}),qe=w({name:`DropdownRenderOption`,props:{tmNode:{type:Object,required:!0}},render(){let{rawNode:{render:e,props:t}}=this.tmNode;return u(`div`,t,[e?.()])}}),Je=w({name:`DropdownMenu`,props:{scrollable:Boolean,showArrow:Boolean,arrowStyle:[String,Object],clsPrefix:{type:String,required:!0},tmNodes:{type:Array,default:()=>[]},parentKey:{type:[String,Number],default:null}},setup(e){let{renderIconRef:t,childrenFieldRef:n}=o(Fe);c(Pe,{showIconRef:r(()=>{let n=t.value;return e.tmNodes.some(e=>{if(e.isGroup)return e.children?.some(({rawNode:e})=>n?n(e):e.icon);let{rawNode:t}=e;return n?n(t):t.icon})}),hasSubmenuRef:r(()=>{let{value:t}=n;return e.tmNodes.some(e=>{if(e.isGroup)return e.children?.some(({rawNode:e})=>Ve(e,t));let{rawNode:n}=e;return Ve(n,t)})})});let i=y(null);return c(Y,null),c(ie,null),c(Z,i),{bodyRef:i}},render(){let{parentKey:e,clsPrefix:t,scrollable:n}=this,r=this.tmNodes.map(r=>{let{rawNode:i}=r;return i.show===!1?null:We(i)?u(qe,{tmNode:r,key:r.key}):Ue(i)?u(Le,{clsPrefix:t,key:r.key}):He(i)?u(Ke,{clsPrefix:t,tmNode:r,parentKey:e,key:r.key}):u(Ge,{clsPrefix:t,tmNode:r,parentKey:e,key:r.key,props:i.props,scrollable:n})});return u(`div`,{class:[`${t}-dropdown-menu`,n&&`${t}-dropdown-menu--scrollable`],ref:`bodyRef`},n?u(ge,{contentClass:`${t}-dropdown-menu__content`},{default:()=>r}):r,this.showArrow?le({clsPrefix:t,arrowStyle:this.arrowStyle,arrowClass:void 0,arrowWrapperClass:void 0,arrowWrapperStyle:void 0}):null)}}),Ye=V(`dropdown-menu`,`
|
|
10
|
-
transform-origin: var(--v-transform-origin);
|
|
11
|
-
background-color: var(--n-color);
|
|
12
|
-
border-radius: var(--n-border-radius);
|
|
13
|
-
box-shadow: var(--n-box-shadow);
|
|
14
|
-
position: relative;
|
|
15
|
-
transition:
|
|
16
|
-
background-color .3s var(--n-bezier),
|
|
17
|
-
box-shadow .3s var(--n-bezier);
|
|
18
|
-
`,[ce(),V(`dropdown-option`,`
|
|
19
|
-
position: relative;
|
|
20
|
-
`,[K(`a`,`
|
|
21
|
-
text-decoration: none;
|
|
22
|
-
color: inherit;
|
|
23
|
-
outline: none;
|
|
24
|
-
`,[K(`&::before`,`
|
|
25
|
-
content: "";
|
|
26
|
-
position: absolute;
|
|
27
|
-
left: 0;
|
|
28
|
-
right: 0;
|
|
29
|
-
top: 0;
|
|
30
|
-
bottom: 0;
|
|
31
|
-
`)]),V(`dropdown-option-body`,`
|
|
32
|
-
display: flex;
|
|
33
|
-
cursor: pointer;
|
|
34
|
-
position: relative;
|
|
35
|
-
height: var(--n-option-height);
|
|
36
|
-
line-height: var(--n-option-height);
|
|
37
|
-
font-size: var(--n-font-size);
|
|
38
|
-
color: var(--n-option-text-color);
|
|
39
|
-
transition: color .3s var(--n-bezier);
|
|
40
|
-
`,[K(`&::before`,`
|
|
41
|
-
content: "";
|
|
42
|
-
position: absolute;
|
|
43
|
-
top: 0;
|
|
44
|
-
bottom: 0;
|
|
45
|
-
left: 4px;
|
|
46
|
-
right: 4px;
|
|
47
|
-
transition: background-color .3s var(--n-bezier);
|
|
48
|
-
border-radius: var(--n-border-radius);
|
|
49
|
-
`),U(`disabled`,[H(`pending`,`
|
|
50
|
-
color: var(--n-option-text-color-hover);
|
|
51
|
-
`,[J(`prefix, suffix`,`
|
|
52
|
-
color: var(--n-option-text-color-hover);
|
|
53
|
-
`),K(`&::before`,`background-color: var(--n-option-color-hover);`)]),H(`active`,`
|
|
54
|
-
color: var(--n-option-text-color-active);
|
|
55
|
-
`,[J(`prefix, suffix`,`
|
|
56
|
-
color: var(--n-option-text-color-active);
|
|
57
|
-
`),K(`&::before`,`background-color: var(--n-option-color-active);`)]),H(`child-active`,`
|
|
58
|
-
color: var(--n-option-text-color-child-active);
|
|
59
|
-
`,[J(`prefix, suffix`,`
|
|
60
|
-
color: var(--n-option-text-color-child-active);
|
|
61
|
-
`)])]),H(`disabled`,`
|
|
62
|
-
cursor: not-allowed;
|
|
63
|
-
opacity: var(--n-option-opacity-disabled);
|
|
64
|
-
`),H(`group`,`
|
|
65
|
-
font-size: calc(var(--n-font-size) - 1px);
|
|
66
|
-
color: var(--n-group-header-text-color);
|
|
67
|
-
`,[J(`prefix`,`
|
|
68
|
-
width: calc(var(--n-option-prefix-width) / 2);
|
|
69
|
-
`,[H(`show-icon`,`
|
|
70
|
-
width: calc(var(--n-option-icon-prefix-width) / 2);
|
|
71
|
-
`)])]),J(`prefix`,`
|
|
72
|
-
width: var(--n-option-prefix-width);
|
|
73
|
-
display: flex;
|
|
74
|
-
justify-content: center;
|
|
75
|
-
align-items: center;
|
|
76
|
-
color: var(--n-prefix-color);
|
|
77
|
-
transition: color .3s var(--n-bezier);
|
|
78
|
-
z-index: 1;
|
|
79
|
-
`,[H(`show-icon`,`
|
|
80
|
-
width: var(--n-option-icon-prefix-width);
|
|
81
|
-
`),V(`icon`,`
|
|
82
|
-
font-size: var(--n-option-icon-size);
|
|
83
|
-
`)]),J(`label`,`
|
|
84
|
-
white-space: nowrap;
|
|
85
|
-
flex: 1;
|
|
86
|
-
z-index: 1;
|
|
87
|
-
`),J(`suffix`,`
|
|
88
|
-
box-sizing: border-box;
|
|
89
|
-
flex-grow: 0;
|
|
90
|
-
flex-shrink: 0;
|
|
91
|
-
display: flex;
|
|
92
|
-
justify-content: flex-end;
|
|
93
|
-
align-items: center;
|
|
94
|
-
min-width: var(--n-option-suffix-width);
|
|
95
|
-
padding: 0 8px;
|
|
96
|
-
transition: color .3s var(--n-bezier);
|
|
97
|
-
color: var(--n-suffix-color);
|
|
98
|
-
z-index: 1;
|
|
99
|
-
`,[H(`has-submenu`,`
|
|
100
|
-
width: var(--n-option-icon-suffix-width);
|
|
101
|
-
`),V(`icon`,`
|
|
102
|
-
font-size: var(--n-option-icon-size);
|
|
103
|
-
`)]),V(`dropdown-menu`,`pointer-events: all;`)]),V(`dropdown-offset-container`,`
|
|
104
|
-
pointer-events: none;
|
|
105
|
-
position: absolute;
|
|
106
|
-
left: 0;
|
|
107
|
-
right: 0;
|
|
108
|
-
top: -4px;
|
|
109
|
-
bottom: -4px;
|
|
110
|
-
`)]),V(`dropdown-divider`,`
|
|
111
|
-
transition: background-color .3s var(--n-bezier);
|
|
112
|
-
background-color: var(--n-divider-color);
|
|
113
|
-
height: 1px;
|
|
114
|
-
margin: 4px 0;
|
|
115
|
-
`),V(`dropdown-menu-wrapper`,`
|
|
116
|
-
transform-origin: var(--v-transform-origin);
|
|
117
|
-
width: fit-content;
|
|
118
|
-
`),K(`>`,[V(`scrollbar`,`
|
|
119
|
-
height: inherit;
|
|
120
|
-
max-height: inherit;
|
|
121
|
-
`)]),U(`scrollable`,`
|
|
122
|
-
padding: var(--n-padding);
|
|
123
|
-
`),H(`scrollable`,[J(`content`,`
|
|
124
|
-
padding: var(--n-padding);
|
|
125
|
-
`)])]),Xe={animated:{type:Boolean,default:!0},keyboard:{type:Boolean,default:!0},size:String,inverted:Boolean,placement:{type:String,default:`bottom`},onSelect:[Function,Array],options:{type:Array,default:()=>[]},menuProps:Function,showArrow:Boolean,renderLabel:Function,renderIcon:Function,renderOption:Function,nodeProps:Function,labelField:{type:String,default:`label`},keyField:{type:String,default:`key`},childrenField:{type:String,default:`children`},value:[String,Number]},Ze=Object.keys(se),Qe=w({name:`Dropdown`,inheritAttrs:!1,props:Object.assign(Object.assign(Object.assign({},se),Xe),B.props),setup(e){let t=y(!1),n=pe(x(e,`show`),t),i=r(()=>{let{keyField:t,childrenField:n}=e;return fe(e.options,{getKey(e){return e[t]},getDisabled(e){return e.disabled===!0},getIgnored(e){return e.type===`divider`||e.type===`render`},getChildren(e){return e[n]}})}),a=r(()=>i.value.treeNodes),o=y(null),s=y(null),l=y(null),u=r(()=>o.value??s.value??l.value??null),d=r(()=>i.value.getPath(u.value).keyPath),f=r(()=>i.value.getPath(e.value).keyPath),p=q(()=>e.keyboard&&n.value);Ae({keydown:{ArrowUp:{prevent:!0,handler:O},ArrowRight:{prevent:!0,handler:D},ArrowDown:{prevent:!0,handler:k},ArrowLeft:{prevent:!0,handler:E},Enter:{prevent:!0,handler:A},Escape:T}},p);let{mergedClsPrefixRef:m,inlineThemeDisabled:h,mergedComponentPropsRef:g}=R(e),v=r(()=>e.size||g?.value?.Dropdown?.size||`medium`),b=B(`Dropdown`,`-dropdown`,Ye,ye,e,m);c(Fe,{labelFieldRef:x(e,`labelField`),childrenFieldRef:x(e,`childrenField`),renderLabelRef:x(e,`renderLabel`),renderIconRef:x(e,`renderIcon`),hoverKeyRef:o,keyboardKeyRef:s,lastToggledSubmenuKeyRef:l,pendingKeyPathRef:d,activeKeyPathRef:f,animatedRef:x(e,`animated`),mergedShowRef:n,nodePropsRef:x(e,`nodeProps`),renderOptionRef:x(e,`renderOption`),menuPropsRef:x(e,`menuProps`),doSelect:S,doUpdateShow:C}),_(n,t=>{!e.animated&&!t&&w()});function S(t,n){let{onSelect:r}=e;r&&G(r,t,n)}function C(n){let{"onUpdate:show":r,onUpdateShow:i}=e;r&&G(r,n),i&&G(i,n),t.value=n}function w(){o.value=null,s.value=null,l.value=null}function T(){C(!1)}function E(){M(`left`)}function D(){M(`right`)}function O(){M(`up`)}function k(){M(`down`)}function A(){let e=j();e?.isLeaf&&n.value&&(S(e.key,e.rawNode),C(!1))}function j(){let{value:e}=i,{value:t}=u;return!e||t===null?null:e.getNode(t)??null}function M(e){let{value:t}=u,{value:{getFirstAvailableNode:n}}=i,r=null;if(t===null){let e=n();e!==null&&(r=e.key)}else{let t=j();if(t){let n;switch(e){case`down`:n=t.getNext();break;case`up`:n=t.getPrev();break;case`right`:n=t.getChild();break;case`left`:n=t.getParent();break}n&&(r=n.key)}}r!==null&&(o.value=null,s.value=r)}let N=r(()=>{let{inverted:t}=e,n=v.value,{common:{cubicBezierEaseInOut:r},self:i}=b.value,{padding:a,dividerColor:o,borderRadius:s,optionOpacityDisabled:c,[W(`optionIconSuffixWidth`,n)]:l,[W(`optionSuffixWidth`,n)]:u,[W(`optionIconPrefixWidth`,n)]:d,[W(`optionPrefixWidth`,n)]:f,[W(`fontSize`,n)]:p,[W(`optionHeight`,n)]:m,[W(`optionIconSize`,n)]:h}=i,g={"--n-bezier":r,"--n-font-size":p,"--n-padding":a,"--n-border-radius":s,"--n-option-height":m,"--n-option-prefix-width":f,"--n-option-icon-prefix-width":d,"--n-option-suffix-width":u,"--n-option-icon-suffix-width":l,"--n-option-icon-size":h,"--n-divider-color":o,"--n-option-opacity-disabled":c};return t?(g[`--n-color`]=i.colorInverted,g[`--n-option-color-hover`]=i.optionColorHoverInverted,g[`--n-option-color-active`]=i.optionColorActiveInverted,g[`--n-option-text-color`]=i.optionTextColorInverted,g[`--n-option-text-color-hover`]=i.optionTextColorHoverInverted,g[`--n-option-text-color-active`]=i.optionTextColorActiveInverted,g[`--n-option-text-color-child-active`]=i.optionTextColorChildActiveInverted,g[`--n-prefix-color`]=i.prefixColorInverted,g[`--n-suffix-color`]=i.suffixColorInverted,g[`--n-group-header-text-color`]=i.groupHeaderTextColorInverted):(g[`--n-color`]=i.color,g[`--n-option-color-hover`]=i.optionColorHover,g[`--n-option-color-active`]=i.optionColorActive,g[`--n-option-text-color`]=i.optionTextColor,g[`--n-option-text-color-hover`]=i.optionTextColorHover,g[`--n-option-text-color-active`]=i.optionTextColorActive,g[`--n-option-text-color-child-active`]=i.optionTextColorChildActive,g[`--n-prefix-color`]=i.prefixColor,g[`--n-suffix-color`]=i.suffixColor,g[`--n-group-header-text-color`]=i.groupHeaderTextColor),g}),P=h?ee(`dropdown`,r(()=>`${v.value[0]}${e.inverted?`i`:``}`),N,e):void 0;return{mergedClsPrefix:m,mergedTheme:b,mergedSize:v,tmNodes:a,mergedShow:n,handleAfterLeave:()=>{e.animated&&w()},doUpdateShow:C,cssVars:h?void 0:N,themeClass:P?.themeClass,onRender:P?.onRender}},render(){let e=(e,t,n,r,i)=>{var a;let{mergedClsPrefix:o,menuProps:s}=this;(a=this.onRender)==null||a.call(this);let c=s?.(void 0,this.tmNodes.map(e=>e.rawNode))||{},d={ref:Me(t),class:[e,`${o}-dropdown`,`${o}-dropdown--${this.mergedSize}-size`,this.themeClass],clsPrefix:o,tmNodes:this.tmNodes,style:[...n,this.cssVars],showArrow:this.showArrow,arrowStyle:this.arrowStyle,scrollable:this.scrollable,onMouseenter:r,onMouseleave:i};return u(Je,l(this.$attrs,d,c))},{mergedTheme:t}=this,n={show:this.mergedShow,theme:t.peers.Popover,themeOverrides:t.peerOverrides.Popover,internalOnAfterLeave:this.handleAfterLeave,internalRenderBody:e,onUpdateShow:this.doUpdateShow,"onUpdate:show":void 0};return u(ue,Object.assign({},ae(this.$props,Ze),n),{trigger:()=>{var e;return(e=this.$slots).default?.call(e)}})}}),$e={class:`chat-input-area`},et={key:0,class:`attachment-previews`},tt=[`src`,`alt`],nt={key:1,class:`attachment-file`},rt={class:`file-name`},it={class:`file-size`},at=[`onClick`],ot=[`placeholder`],st={class:`input-actions`},ct=F(w({__name:`ChatInput`,setup(n){let o=xe(),{t:c}=P(),l=y(``),u=y(),f=y(),m=y([]),h=y(!1),g=y(0),_=y(!1),v=r(()=>l.value.trim()||m.value.length>0);function b(e){if(m.value.find(t=>t.name===e.name))return;let t=Date.now().toString(36)+Math.random().toString(36).slice(2,8),n=URL.createObjectURL(e);m.value.push({id:t,name:e.name,type:e.type,size:e.size,url:n,file:e})}function x(){f.value?.click()}function S(e){let t=e.target;if(t.files){for(let e of t.files)b(e);t.value=``}}function w(e){let t=Array.from(e.clipboardData?.items||[]).filter(e=>e.type.startsWith(`image/`));if(t.length){e.preventDefault();for(let e of t){let t=e.getAsFile();if(!t)continue;let n=e.type.split(`/`)[1]||`png`;b(new File([t],`pasted-${Date.now()}.${n}`,{type:e.type}))}}}function O(e){e.preventDefault()}function j(e){e.preventDefault(),e.dataTransfer?.types.includes(`Files`)&&(g.value++,h.value=!0)}function F(){g.value--,g.value<=0&&(g.value=0,h.value=!1)}function I(e){e.preventDefault(),g.value=0,h.value=!1;let t=Array.from(e.dataTransfer?.files||[]);if(t.length){for(let e of t)b(e);u.value?.focus()}}function L(){let e=l.value.trim();!e&&m.value.length===0||(o.sendMessage(e,m.value.length>0?m.value:void 0),l.value=``,m.value=[],u.value&&(u.value.style.height=`auto`))}function R(){_.value=!0}function z(){requestAnimationFrame(()=>{_.value=!1})}function B(e){return _.value||e.isComposing||e.keyCode===229}function V(e){e.key!==`Enter`||e.shiftKey||B(e)||(e.preventDefault(),L())}function H(e){let t=e.target;t.style.height=`auto`,t.style.height=Math.min(t.scrollHeight,100)+`px`}function U(e){let t=m.value.findIndex(t=>t.id===e);t!==-1&&(URL.revokeObjectURL(m.value[t].url),m.value.splice(t,1))}function W(e){return e<1024?e+` B`:e<1024*1024?(e/1024).toFixed(1)+` KB`:(e/(1024*1024)).toFixed(1)+` MB`}function G(e){return e.startsWith(`image/`)}return(n,r)=>(s(),i(`div`,$e,[m.value.length>0?(s(),i(`div`,et,[(s(!0),i(N,null,A(m.value,e=>(s(),i(`div`,{key:e.id,class:D([`attachment-preview`,{image:G(e.type)}])},[G(e.type)?(s(),i(`img`,{key:0,src:e.url,alt:e.name,class:`attachment-thumb`},null,8,tt)):(s(),i(`div`,nt,[r[2]||=M(`svg`,{width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`},[M(`path`,{d:`M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z`}),M(`polyline`,{points:`14 2 14 8 20 8`})],-1),M(`span`,rt,C(e.name),1),M(`span`,it,C(W(e.size)),1)])),M(`button`,{class:`attachment-remove`,onClick:t=>U(e.id)},[...r[3]||=[M(`svg`,{width:`12`,height:`12`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`},[M(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),M(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,at)],2))),128))])):a(``,!0),M(`div`,{class:D([`input-wrapper`,{"drag-over":h.value}]),onDragover:O,onDragenter:j,onDragleave:F,onDrop:I},[M(`input`,{ref_key:`fileInputRef`,ref:f,type:`file`,multiple:``,class:`file-input-hidden`,onChange:S},null,544),e(M(`textarea`,{ref_key:`textareaRef`,ref:u,"onUpdate:modelValue":r[0]||=e=>l.value=e,class:`input-textarea`,placeholder:k(c)(`chat.inputPlaceholder`),rows:`1`,onKeydown:V,onCompositionstart:R,onCompositionend:z,onInput:H,onPaste:w},null,40,ot),[[E,l.value]]),M(`div`,st,[t(k(Se),{trigger:`hover`},{trigger:d(()=>[t(k($),{quaternary:``,size:`small`,onClick:x,circle:``},{icon:d(()=>[...r[4]||=[M(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`},[M(`path`,{d:`M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48`})],-1)]]),_:1})]),default:d(()=>[T(` `+C(k(c)(`chat.attachFiles`)),1)]),_:1}),k(o).isStreaming?(s(),p(k($),{key:0,size:`small`,type:`error`,onClick:r[1]||=e=>k(o).stopStreaming()},{default:d(()=>[T(C(k(c)(`chat.stop`)),1)]),_:1})):a(``,!0),t(k($),{size:`small`,type:`primary`,disabled:!v.value||k(o).isStreaming,onClick:L},{icon:d(()=>[...r[5]||=[M(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`},[M(`line`,{x1:`22`,y1:`2`,x2:`11`,y2:`13`}),M(`polygon`,{points:`22 2 15 22 11 13 2 9 22 2`})],-1)]]),default:d(()=>[T(` `+C(k(c)(`chat.send`)),1)]),_:1},8,[`disabled`])])],34)]))}}),[[`__scopeId`,`data-v-4c2b3ca2`]]),lt={key:1,width:`12`,height:`12`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`,class:`tool-icon`},ut={class:`tool-name`},dt={key:2,class:`tool-preview`},ft={key:3,class:`tool-spinner`},pt={key:4,class:`tool-error-badge`},mt={key:0,class:`tool-details`},ht={key:0,class:`tool-detail-section`},gt={class:`tool-detail-label`},_t={class:`tool-detail-code`},vt={key:1,class:`tool-detail-section`},yt={class:`tool-detail-label`},bt={class:`tool-detail-code`},xt={key:1,class:`msg-body`},St={key:0,src:I,alt:`Hermes`,class:`msg-avatar`},Ct={key:0,class:`msg-attachments`},wt=[`src`,`alt`],Tt={key:1,class:`msg-attachment-file`},Et={class:`att-name`},Dt={class:`att-size`},Ot={key:2,class:`streaming-dots`},kt={class:`message-time`},At=F(w({__name:`MessageItem`,props:{message:{}},setup(e){let t=e,{t:n}=P(),o=r(()=>t.message.role===`system`),c=y(!1),l=r(()=>new Date(t.message.timestamp).toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`}));function u(e){return e.startsWith(`image/`)}function d(e){return e<1024?e+` B`:e<1024*1024?(e/1024).toFixed(1)+` KB`:(e/(1024*1024)).toFixed(1)+` MB`}let f=r(()=>(t.message.attachments?.length??0)>0),m=r(()=>!!(t.message.toolArgs||t.message.toolResult)),h=r(()=>{if(!t.message.toolArgs)return``;try{return JSON.stringify(JSON.parse(t.message.toolArgs),null,2)}catch{return t.message.toolArgs}}),g=r(()=>{if(!t.message.toolResult)return``;try{let e=JSON.parse(t.message.toolResult),r=JSON.stringify(e,null,2);return r.length>2e3?r.slice(0,2e3)+`
|
|
126
|
-
`+n(`chat.truncated`):r}catch{let e=t.message.toolResult;return e.length>2e3?e.slice(0,2e3)+`
|
|
127
|
-
`+n(`chat.truncated`):e}});return(t,r)=>(s(),i(`div`,{class:D([`message`,[e.message.role]])},[e.message.role===`tool`?(s(),i(N,{key:0},[M(`div`,{class:D([`tool-line`,{expandable:m.value}]),onClick:r[0]||=e=>m.value&&(c.value=!c.value)},[m.value?(s(),i(`svg`,{key:0,width:`10`,height:`10`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,class:D([`tool-chevron`,{rotated:c.value}])},[...r[1]||=[M(`polyline`,{points:`9 18 15 12 9 6`},null,-1)]],2)):(s(),i(`svg`,lt,[...r[2]||=[M(`path`,{d:`M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z`},null,-1)]])),M(`span`,ut,C(e.message.toolName),1),e.message.toolPreview&&!c.value?(s(),i(`span`,dt,C(e.message.toolPreview),1)):a(``,!0),e.message.toolStatus===`running`?(s(),i(`span`,ft)):a(``,!0),e.message.toolStatus===`error`?(s(),i(`span`,pt,C(k(n)(`chat.error`)),1)):a(``,!0)],2),c.value&&m.value?(s(),i(`div`,mt,[h.value?(s(),i(`div`,ht,[M(`div`,gt,C(k(n)(`chat.arguments`)),1),M(`pre`,_t,C(h.value),1)])):a(``,!0),g.value?(s(),i(`div`,vt,[M(`div`,yt,C(k(n)(`chat.result`)),1),M(`pre`,bt,C(g.value),1)])):a(``,!0)])):a(``,!0)],64)):(s(),i(`div`,xt,[e.message.role===`assistant`?(s(),i(`img`,St)):a(``,!0),M(`div`,{class:D([`msg-content`,e.message.role])},[M(`div`,{class:D([`message-bubble`,{system:o.value}])},[f.value?(s(),i(`div`,Ct,[(s(!0),i(N,null,A(e.message.attachments,e=>(s(),i(`div`,{key:e.id,class:D([`msg-attachment`,{image:u(e.type)}])},[u(e.type)&&e.url?(s(),i(`img`,{key:0,src:e.url,alt:e.name,class:`msg-attachment-thumb`},null,8,wt)):(s(),i(`div`,Tt,[r[3]||=M(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`},[M(`path`,{d:`M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z`}),M(`polyline`,{points:`14 2 14 8 20 8`})],-1),M(`span`,Et,C(e.name),1),M(`span`,Dt,C(d(e.size)),1)]))],2))),128))])):a(``,!0),e.message.content?(s(),p(ke,{key:1,content:e.message.content},null,8,[`content`])):a(``,!0),e.message.isStreaming&&!e.message.content?(s(),i(`span`,Ot,[...r[4]||=[M(`span`,null,null,-1),M(`span`,null,null,-1),M(`span`,null,null,-1)]])):a(``,!0)],2),M(`div`,kt,C(l.value),1)],2)]))],2))}}),[[`__scopeId`,`data-v-5923b714`]]),jt=`/assets/thinking-light-BjeGd2gJ.mp4`,Mt=`/assets/thinking-dark-yYkYRZLs.mp4`,Nt={key:0,class:`empty-state`},Pt={key:0,class:`streaming-indicator`},Ft=[`src`],It={key:0,class:`tool-calls-panel`},Lt={class:`tool-call-name`},Rt={key:0,class:`tool-call-preview`},zt={key:1,class:`tool-call-spinner`},Bt={key:2,class:`tool-call-error`},Vt=F(w({__name:`MessageList`,setup(e){let n=xe(),{t:o}=P(),{isDark:c}=Te(),l=y(),u=r(()=>n.messages.filter(e=>e.role!==`tool`)),m=r(()=>{let e=n.messages,t=-1;for(let n=e.length-1;n>=0;n--)if(e[n].role===`user`){t=n;break}return[...e.filter((e,n)=>e.role===`tool`&&n>t)].reverse()});function h(e=200){let t=l.value;return t?t.scrollHeight-t.scrollTop-t.clientHeight<e:!0}function g(){f(()=>{l.value&&(l.value.scrollTop=l.value.scrollHeight)})}return _(()=>n.activeSessionId,e=>{e&&g()},{immediate:!0}),_(()=>n.isRunActive,e=>{e&&g()}),_(()=>n.messages[n.messages.length-1]?.content,()=>{if(!n.isStreaming){g();return}h()&&g()}),_(m,()=>{if(!n.isStreaming){g();return}h()&&g()}),(e,r)=>(s(),i(`div`,{ref_key:`listRef`,ref:l,class:`message-list`},[k(n).messages.length===0?(s(),i(`div`,Nt,[r[0]||=M(`img`,{src:`/logo.png`,alt:`Hermes`,class:`empty-logo`},null,-1),M(`p`,null,C(k(o)(`chat.emptyState`)),1)])):a(``,!0),(s(!0),i(N,null,A(u.value,e=>(s(),p(At,{key:e.id,message:e},null,8,[`message`]))),128)),t(b,{name:`fade`},{default:d(()=>[k(n).isRunActive?(s(),i(`div`,Pt,[M(`video`,{src:k(c)?k(Mt):k(jt),autoplay:``,loop:``,muted:``,playsinline:``,class:`thinking-video`},null,8,Ft),m.value.length>0?(s(),i(`div`,It,[(s(!0),i(N,null,A(m.value,e=>(s(),i(`div`,{key:e.id,class:`tool-call-item`},[r[1]||=M(`svg`,{width:`12`,height:`12`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`,class:`tool-call-icon`},[M(`path`,{d:`M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z`})],-1),M(`span`,Lt,C(e.toolName),1),e.toolPreview?(s(),i(`span`,Rt,C(e.toolPreview),1)):a(``,!0),e.toolStatus===`running`?(s(),i(`span`,zt)):a(``,!0),e.toolStatus===`error`?(s(),i(`span`,Bt,C(k(o)(`chat.error`)),1)):a(``,!0)]))),128))])):a(``,!0)])):a(``,!0)]),_:1})],512))}}),[[`__scopeId`,`data-v-9cc7b1be`]]),Ht={class:`chat-panel`},Ut={class:`session-list-header`},Wt={key:0,class:`session-list-title`},Gt={class:`session-list-actions`},Kt={key:0,class:`session-items`},qt={key:0,class:`session-loading`},Jt={key:1,class:`session-empty`},Yt=[`onClick`],Xt={class:`session-group-label`},Zt={class:`session-group-count`},Qt=[`onClick`,`onContextmenu`],$t={class:`session-item-content`},en={class:`session-item-title`},tn={class:`session-item-meta`},nn={key:0,class:`session-item-model`},rn={class:`session-item-time`},an={class:`chat-main`},on={class:`chat-header`},sn={class:`header-left`},cn={class:`header-session-title`},ln={key:0,class:`source-badge`},un={class:`header-actions`},dn={key:0,class:`context-info`},fn=F(w({__name:`ChatPanel`,setup(e){let n=xe(),o=Ce(),{t:c}=P(),l=y(typeof window>`u`||!window.matchMedia(`(max-width: 768px)`).matches),u=null;function h(e){n.switchSession(e),u?.matches&&(l.value=!1)}function b(e){e.matches&&l.value&&(l.value=!1)}m(()=>{u=window.matchMedia(`(max-width: 768px)`),b(u),u.addEventListener(`change`,b)}),g(()=>{u?.removeEventListener(`change`,b)});let x=y(!1),w=y(``),E=y(null),O=y(null),j=y(new Set(JSON.parse(localStorage.getItem(`hermes_collapsed_groups`)||`[]`))),F={telegram:`Telegram`,api_server:`API Server`,cli:`CLI`,discord:`Discord`,slack:`Slack`,matrix:`Matrix`,whatsapp:`WhatsApp`,signal:`Signal`,email:`Email`,sms:`SMS`,dingtalk:`DingTalk`,feishu:`Feishu`,wecom:`WeCom`,weixin:`WeChat`,bluebubbles:`iMessage`,mattermost:`Mattermost`,cron:`Cron`};function I(e){return e?F[e]||e:``}function L(e){return e===`api_server`?-1:e===`cron`?999:0}let R=r(()=>{let e=[...n.sessions].sort((e,t)=>t.createdAt-e.createdAt),t=new Map;for(let n of e){let e=n.source||``;t.has(e)||t.set(e,[]),t.get(e).push(n)}return[...t.keys()].sort((e,t)=>{let n=L(e),r=L(t);return n===r?e.localeCompare(t):n-r}).map(e=>({source:e,label:e?I(e):c(`chat.other`),sessions:t.get(e)}))});function z(e){if(!j.value.has(e))j.value=new Set([...j.value,e]);else{j.value=new Set(R.value.map(e=>e.source).filter(t=>t!==e));let t=R.value.find(t=>t.source===e);t?.sessions.length&&n.switchSession(t.sessions[0].id)}localStorage.setItem(`hermes_collapsed_groups`,JSON.stringify([...j.value]))}_(R,e=>{if(localStorage.getItem(`hermes_collapsed_groups`)!==null){let e=n.activeSession?.source;e&&j.value.has(e)&&(j.value=new Set([...j.value].filter(t=>t!==e)),localStorage.setItem(`hermes_collapsed_groups`,JSON.stringify([...j.value])));return}j.value=new Set(e.slice(1).map(e=>e.source)),localStorage.setItem(`hermes_collapsed_groups`,JSON.stringify([...j.value]))},{once:!0});let B=r(()=>n.activeSession?.title||c(`chat.newChat`)),V=r(()=>(n.activeSession?.inputTokens??0)+(n.activeSession?.outputTokens??0)),H={"claude-opus-4":2e5,"claude-sonnet-4":2e5,"claude-haiku-4":2e5,"claude-3.5-sonnet":2e5,"claude-3.5-haiku":2e5,"claude-3-opus":2e5,"claude-3-sonnet":2e5,"claude-3-haiku":2e5,"gpt-4o":128e3,"gpt-4o-mini":128e3,"gpt-4-turbo":128e3,"gpt-4":8192,"gpt-3.5-turbo":16385,o1:2e5,"o1-mini":128e3,o3:2e5,"o3-mini":2e5,"o4-mini":2e5,"deepseek-chat":65536,"deepseek-reasoner":65536,"gemini-2.5-pro":1e6,"gemini-2.5-flash":1e6,"gemini-2.0-flash":1e6,"glm-4-plus":128e3,"glm-4":128e3,"qwen-max":128e3,"qwen-plus":128e3,"qwen-turbo":128e3},U=r(()=>{let e=n.activeSession?.model||``;for(let[t,n]of Object.entries(H))if(e.includes(t))return n;return null});function W(e){return e>=1e6?(e/1e6).toFixed(1)+`M`:e>=1e3?(e/1e3).toFixed(1)+`k`:String(e)}let G=r(()=>n.activeSession?.source||``);function K(){n.newChat()}function q(e){let t=e||n.activeSessionId;t&&(navigator.clipboard.writeText(t),o.success(c(`common.copied`)))}function J(e){n.deleteSession(e),o.success(c(`chat.sessionDeleted`))}function ee(e){let t=new Date(e),n=new Date;return t.toDateString()===n.toDateString()?t.toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`}):t.toLocaleDateString([],{month:`short`,day:`numeric`})}let te=r(()=>[{label:c(`chat.rename`),key:`rename`},{label:c(`chat.copySessionId`),key:`copy-id`}]),Y=y(null);function ne(e,t){e.preventDefault(),Y.value=t,X.value=!0,Z.value=e.clientX,Q.value=e.clientY}let X=y(!1),Z=y(0),Q=y(0);function re(e){if(X.value=!1,Y.value){if(e===`copy-id`)q(Y.value);else if(e===`rename`){let e=n.sessions.find(e=>e.id===Y.value);E.value=Y.value,w.value=e?.title||``,x.value=!0,f(()=>{O.value?.focus()})}}}function ie(){X.value=!1}async function ae(){if(!(!E.value||!w.value.trim())){if(await Oe(E.value,w.value.trim())){let e=n.sessions.find(e=>e.id===E.value);e&&(e.title=w.value.trim()),n.activeSession?.id===E.value&&(n.activeSession.title=w.value.trim()),o.success(c(`chat.renamed`))}else o.error(c(`chat.renameFailed`));x.value=!1}}return(e,r)=>(s(),i(`div`,Ht,[M(`div`,{class:D([`session-backdrop`,{active:l.value}]),onClick:r[0]||=e=>l.value=!1},null,2),M(`aside`,{class:D([`session-list`,{collapsed:!l.value}])},[M(`div`,Ut,[l.value?(s(),i(`span`,Wt,C(k(c)(`chat.sessions`)),1)):a(``,!0),M(`div`,Gt,[M(`button`,{class:`session-close-btn`,onClick:r[1]||=e=>l.value=!1},[...r[7]||=[M(`svg`,{width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`},[M(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),M(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]]),t(k($),{quaternary:``,size:`tiny`,onClick:K,circle:``},{icon:d(()=>[...r[8]||=[M(`svg`,{width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`},[M(`line`,{x1:`12`,y1:`5`,x2:`12`,y2:`19`}),M(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`})],-1)]]),_:1})])]),l.value?(s(),i(`div`,Kt,[k(n).isLoadingSessions&&k(n).sessions.length===0?(s(),i(`div`,qt,C(k(c)(`common.loading`)),1)):k(n).sessions.length===0?(s(),i(`div`,Jt,C(k(c)(`chat.noSessions`)),1)):a(``,!0),(s(!0),i(N,null,A(R.value,e=>(s(),i(N,{key:e.source},[M(`div`,{class:`session-group-header`,onClick:t=>z(e.source)},[(s(),i(`svg`,{width:`10`,height:`10`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,class:D([`group-chevron`,{collapsed:j.value.has(e.source)}])},[...r[9]||=[M(`polyline`,{points:`9 18 15 12 9 6`},null,-1)]],2)),M(`span`,Xt,C(e.label),1),M(`span`,Zt,C(e.sessions.length),1)],8,Yt),j.value.has(e.source)?a(``,!0):(s(!0),i(N,{key:0},A(e.sessions,e=>(s(),i(`button`,{key:e.id,class:D([`session-item`,{active:e.id===k(n).activeSessionId}]),onClick:t=>h(e.id),onContextmenu:t=>ne(t,e.id)},[M(`div`,$t,[M(`span`,en,C(e.title),1),M(`span`,tn,[e.model?(s(),i(`span`,nn,C(e.model),1)):a(``,!0),M(`span`,rn,C(ee(e.createdAt)),1)])]),e.id!==k(n).activeSessionId||k(n).sessions.length>1?(s(),p(k(we),{key:0,onPositiveClick:t=>J(e.id)},{trigger:d(()=>[M(`button`,{class:`session-item-delete`,onClick:r[2]||=v(()=>{},[`stop`])},[...r[10]||=[M(`svg`,{width:`12`,height:`12`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`},[M(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),M(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]])]),default:d(()=>[T(` `+C(k(c)(`chat.deleteSession`)),1)]),_:1},8,[`onPositiveClick`])):a(``,!0)],42,Qt))),128))],64))),128))])):a(``,!0)],2),t(k(Qe),{placement:`bottom-start`,trigger:`manual`,x:Z.value,y:Q.value,options:te.value,show:X.value,onSelect:re,onClickoutside:ie},null,8,[`x`,`y`,`options`,`show`]),t(k(_e),{show:x.value,"onUpdate:show":r[4]||=e=>x.value=e,preset:`dialog`,title:k(c)(`chat.renameSession`),"positive-text":k(c)(`common.ok`),"negative-text":k(c)(`common.cancel`),onPositiveClick:ae},{default:d(()=>[t(k(ve),{ref_key:`renameInputRef`,ref:O,value:w.value,"onUpdate:value":r[3]||=e=>w.value=e,placeholder:k(c)(`chat.enterNewTitle`),onKeydown:S(ae,[`enter`])},null,8,[`value`,`placeholder`])]),_:1},8,[`show`,`title`,`positive-text`,`negative-text`]),M(`div`,an,[M(`header`,on,[M(`div`,sn,[t(k($),{quaternary:``,size:`small`,onClick:r[5]||=e=>l.value=!l.value,circle:``},{icon:d(()=>[...r[11]||=[M(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`},[M(`rect`,{x:`3`,y:`3`,width:`7`,height:`7`}),M(`rect`,{x:`14`,y:`3`,width:`7`,height:`7`}),M(`rect`,{x:`3`,y:`14`,width:`7`,height:`7`}),M(`rect`,{x:`14`,y:`14`,width:`7`,height:`7`})],-1)]]),_:1}),M(`span`,cn,C(B.value),1),G.value?(s(),i(`span`,ln,C(I(G.value)),1)):a(``,!0)]),M(`div`,un,[t(k(Se),{trigger:`hover`},{trigger:d(()=>[t(k($),{quaternary:``,size:`small`,onClick:r[6]||=e=>q(),circle:``},{icon:d(()=>[...r[12]||=[M(`svg`,{width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`},[M(`rect`,{x:`9`,y:`9`,width:`13`,height:`13`,rx:`2`,ry:`2`}),M(`path`,{d:`M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1`})],-1)]]),_:1})]),default:d(()=>[T(` `+C(k(c)(`chat.copySessionId`)),1)]),_:1}),t(k($),{size:`small`,onClick:K},{icon:d(()=>[...r[13]||=[M(`svg`,{width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`},[M(`line`,{x1:`12`,y1:`5`,x2:`12`,y2:`19`}),M(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`})],-1)]]),default:d(()=>[T(` `+C(k(c)(`chat.newChat`)),1)]),_:1})])]),t(Vt),U.value===null?a(``,!0):(s(),i(`div`,dn,[M(`span`,null,C(W(V.value))+` / `+C(W(U.value)),1)])),t(ct)])]))}}),[[`__scopeId`,`data-v-563d6965`]]),pn={class:`chat-view`},mn=F(w({__name:`ChatView`,setup(e){let n=Ee(),r=xe(),a=De();return m(async()=>{n.loadModels(),await a.fetchProfiles(),r.loadSessions()}),(e,n)=>(s(),i(`div`,pn,[t(fn)]))}}),[[`__scopeId`,`data-v-6dae3628`]]);export{mn as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./app-BMobzABI.js";export{e as useAppStore};
|