hermes-web-ui 0.2.2 → 0.2.4

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.
Files changed (99) hide show
  1. package/README.md +30 -6
  2. package/bin/hermes-web-ui.mjs +34 -4
  3. package/dist/assets/{Button-CpNld4Mc.js → Button-sJ2BpaPl.js} +14 -14
  4. package/dist/assets/{ChannelsView-BWEvTQwM.css → ChannelsView-C2h4_vNn.css} +1 -1
  5. package/dist/assets/ChannelsView-CD_79lUP.js +1 -0
  6. package/dist/assets/ChatView-CLIjlJ1x.js +142 -0
  7. package/dist/assets/ChatView-CX_ZYhvz.css +1 -0
  8. package/dist/assets/Close-2w73mIOt.js +45 -0
  9. package/dist/assets/FormItem-XpOdWzQ0.js +110 -0
  10. package/dist/assets/Input-BzhYBEbH.js +234 -0
  11. package/dist/assets/InputNumber-8txyKuLX.js +13 -0
  12. package/dist/assets/JobsView-C-1FgnDL.js +2 -0
  13. package/dist/assets/{JobsView-DkwaDky6.css → JobsView-OYrxaGgM.css} +1 -1
  14. package/dist/assets/LoginView-BD15AZNF.js +1 -0
  15. package/dist/assets/LoginView-BHThbj0n.css +1 -0
  16. package/dist/assets/LogsView-DmQ4ttpe.js +1 -0
  17. package/dist/assets/LogsView-DzYGlYxF.css +1 -0
  18. package/dist/assets/{MarkdownRenderer-C2pkccH2.js → MarkdownRenderer-DJm5zGZj.js} +2 -2
  19. package/dist/assets/MemoryView-DBtvO2X2.js +5 -0
  20. package/dist/assets/MemoryView-WR7DvkW0.css +1 -0
  21. package/dist/assets/Modal-D421R1s7.js +232 -0
  22. package/dist/assets/{ModelsView-CLdtVeiJ.css → ModelsView-Dm1vBT2p.css} +1 -1
  23. package/dist/assets/ModelsView-Dt3deKCr.js +1 -0
  24. package/dist/assets/Popover-pOQtxFC1.js +117 -0
  25. package/dist/assets/Select-rOqAn7Lj.js +340 -0
  26. package/dist/assets/SettingRow-CndAlF8Z.js +1 -0
  27. package/dist/assets/SettingsView-CIcrKeJw.css +1 -0
  28. package/dist/assets/SettingsView-CxEQl8Fh.js +352 -0
  29. package/dist/assets/SkillsView-4FLTf1XD.css +1 -0
  30. package/dist/assets/SkillsView-BopVAaC6.js +1 -0
  31. package/dist/assets/Spin-CaLC5eru.js +43 -0
  32. package/dist/assets/Suffix-C1X_jn5E.js +101 -0
  33. package/dist/assets/Switch-BeZgnVyD.js +102 -0
  34. package/dist/assets/Tag-DFrN7AVl.js +71 -0
  35. package/dist/assets/Tooltip-ClSL1Ac2.js +1 -0
  36. package/dist/assets/{UsageView-CXSijPwc.css → UsageView-Bdck_cnA.css} +1 -1
  37. package/dist/assets/UsageView-BvGRIGlC.js +1 -0
  38. package/dist/assets/_plugin-vue_export-helper-DQGaK6t5.js +3 -0
  39. package/dist/assets/app-DHhjDueA.js +1 -0
  40. package/dist/assets/app-DqRfMAIZ.js +1 -0
  41. package/dist/assets/browser-Bf2Q3p4g.js +47 -0
  42. package/dist/assets/chat-B0V07VGa.js +6 -0
  43. package/dist/assets/context-Bm7UPqDk.js +1 -0
  44. package/dist/assets/index-BR3ulF5g.css +1 -0
  45. package/dist/assets/index-Bdq3IZmO.js +306 -0
  46. package/dist/assets/jobs-QM3wEm9o.js +1 -0
  47. package/dist/assets/logo-CiQBpLPw.js +1 -0
  48. package/dist/assets/pinia-bZ6_VpBU.js +1 -0
  49. package/dist/assets/router-Ddepf70Q.js +4 -0
  50. package/dist/assets/{sessions-DYkP_X2v.js → sessions-r2FX4lYx.js} +1 -1
  51. package/dist/assets/{skills-C6QBmS9j.js → skills-DtNdlEJd.js} +1 -1
  52. package/dist/assets/use-message-DAtcV1hg.js +1 -0
  53. package/dist/index.html +18 -18
  54. package/dist/server/index.js +104 -61
  55. package/dist/server/routes/filesystem.js +38 -0
  56. package/dist/server/services/auth.d.ts +9 -0
  57. package/dist/server/services/auth.js +67 -0
  58. package/dist/server/services/hermes-cli.js +13 -1
  59. package/package.json +2 -2
  60. package/dist/assets/ChannelsView-BGXB46ZU.js +0 -1
  61. package/dist/assets/ChatView-BVHQ6KhU.css +0 -1
  62. package/dist/assets/ChatView-CaO-j1NR.js +0 -142
  63. package/dist/assets/Close-BAvirVyH.js +0 -45
  64. package/dist/assets/FormItem-DUC1YCrh.js +0 -110
  65. package/dist/assets/Input-CCmp4iGM.js +0 -234
  66. package/dist/assets/InputNumber-DpIdrMEW.js +0 -13
  67. package/dist/assets/JobsView-t5o1pB0r.js +0 -2
  68. package/dist/assets/LogsView-B2TeFIUX.css +0 -1
  69. package/dist/assets/LogsView-QqOV3ZEf.js +0 -1
  70. package/dist/assets/MemoryView-CHeaa1-C.css +0 -1
  71. package/dist/assets/MemoryView-oeAn8ZfB.js +0 -5
  72. package/dist/assets/Modal-BljFqAJF.js +0 -232
  73. package/dist/assets/ModelsView-DvK44HBy.js +0 -1
  74. package/dist/assets/Popover-BQMR8Xxo.js +0 -117
  75. package/dist/assets/Select-D33SMWcz.js +0 -340
  76. package/dist/assets/SettingRow-BxCsRfGG.js +0 -102
  77. package/dist/assets/SettingsView-CK9ArFcg.js +0 -352
  78. package/dist/assets/SettingsView-Cl1ts-YY.css +0 -1
  79. package/dist/assets/SkillsView-BvNhRbMq.css +0 -1
  80. package/dist/assets/SkillsView-_z2SQ9kJ.js +0 -1
  81. package/dist/assets/Spin-CwbBDHwW.js +0 -43
  82. package/dist/assets/Suffix-CKUJBJSi.js +0 -101
  83. package/dist/assets/Tag-87KswiOb.js +0 -71
  84. package/dist/assets/Tooltip-CuLVJgy8.js +0 -1
  85. package/dist/assets/UsageView-COiUupLe.js +0 -1
  86. package/dist/assets/_plugin-vue_export-helper-C7dadZ10.js +0 -49
  87. package/dist/assets/app-DX-WvBe8.js +0 -1
  88. package/dist/assets/app-DwI_Lyfm.js +0 -1
  89. package/dist/assets/chat-De2jGIM6.js +0 -6
  90. package/dist/assets/client-D-w1KhaU.js +0 -1
  91. package/dist/assets/context-vjXbZCu8.js +0 -1
  92. package/dist/assets/index-D3MGnlpF.js +0 -307
  93. package/dist/assets/index-DCNlSGk-.css +0 -1
  94. package/dist/assets/jobs-B2WdYQNb.js +0 -1
  95. package/dist/assets/pinia-B4dETPKk.js +0 -1
  96. package/dist/assets/preload-helper-D4M6sveU.js +0 -1
  97. package/dist/assets/use-message-BeTKmVAO.js +0 -1
  98. package/dist/assets/vue.runtime.esm-bundler-BoqZ7fRe.js +0 -3
  99. /package/dist/{assets/logo-BAarh-tH.png → logo.png} +0 -0
@@ -54,13 +54,24 @@ const filesystem_1 = require("./routes/filesystem");
54
54
  const config_2 = require("./routes/config");
55
55
  const weixin_1 = require("./routes/weixin");
56
56
  const hermesCli = __importStar(require("./services/hermes-cli"));
57
+ const auth_1 = require("./services/auth");
58
+ const app = new koa_1.default();
57
59
  const { restartGateway, startGateway, startGatewayBackground, getVersion } = hermesCli;
60
+ let server = null;
61
+ let isShuttingDown = false;
62
+ // 👉 如果你有子进程,一定要存
63
+ let gatewayPid = null;
58
64
  async function bootstrap() {
59
65
  await (0, promises_1.mkdir)(config_1.config.uploadDir, { recursive: true });
60
66
  await (0, promises_1.mkdir)(config_1.config.dataDir, { recursive: true });
67
+ // Auth (after mkdir so data dir exists)
68
+ const authToken = await (0, auth_1.getToken)();
69
+ if (authToken) {
70
+ app.use(await (0, auth_1.authMiddleware)(authToken));
71
+ console.log(`🔐 Auth enabled — token: ${authToken}`);
72
+ }
61
73
  await ensureApiServerConfig();
62
74
  await ensureGatewayRunning();
63
- const app = new koa_1.default();
64
75
  app.use((0, cors_1.default)({ origin: config_1.config.corsOrigins }));
65
76
  app.use((0, bodyparser_1.default)());
66
77
  app.use(webhook_1.webhookRoutes.routes());
@@ -70,7 +81,7 @@ async function bootstrap() {
70
81
  app.use(filesystem_1.fsRoutes.routes());
71
82
  app.use(config_2.configRoutes.routes());
72
83
  app.use(weixin_1.weixinRoutes.routes());
73
- // Health endpoint: check CLI version + gateway connectivity
84
+ // health
74
85
  app.use(async (ctx, next) => {
75
86
  if (ctx.path === '/health') {
76
87
  const raw = await getVersion();
@@ -82,7 +93,7 @@ async function bootstrap() {
82
93
  });
83
94
  gatewayOk = res.ok;
84
95
  }
85
- catch { /* not reachable */ }
96
+ catch { }
86
97
  ctx.body = {
87
98
  status: gatewayOk ? 'ok' : 'error',
88
99
  platform: 'hermes-agent',
@@ -94,25 +105,87 @@ async function bootstrap() {
94
105
  await next();
95
106
  });
96
107
  app.use(proxy_1.proxyRoutes.routes());
97
- // SPA fallback
108
+ // SPA
98
109
  const distDir = (0, path_1.resolve)(__dirname, '..');
99
110
  app.use((0, koa_static_1.default)(distDir));
100
111
  app.use(async (ctx) => {
101
- if (!ctx.path.startsWith('/api') && !ctx.path.startsWith('/v1') && ctx.path !== '/health' && ctx.path !== '/upload' && ctx.path !== '/webhook') {
112
+ if (!ctx.path.startsWith('/api') &&
113
+ !ctx.path.startsWith('/v1') &&
114
+ ctx.path !== '/health' &&
115
+ ctx.path !== '/upload' &&
116
+ ctx.path !== '/webhook') {
102
117
  await (0, koa_send_1.default)(ctx, 'index.html', { root: distDir });
103
118
  }
104
119
  });
105
- app.listen(config_1.config.port, '0.0.0.0', () => {
106
- console.log(` ➜ Hermes BFF Server: http://localhost:${config_1.config.port}`);
107
- console.log(` ➜ Upstream: ${config_1.config.upstream}`);
120
+ // 🚀 启动服务
121
+ server = app.listen(config_1.config.port, '0.0.0.0');
122
+ server.on('listening', () => {
123
+ console.log(`➜ Server: http://localhost:${config_1.config.port}`);
124
+ console.log(`➜ Upstream: ${config_1.config.upstream}`);
125
+ });
126
+ server.on('error', (err) => {
127
+ console.error('Server error:', err.message);
108
128
  });
129
+ // 👇 绑定退出信号
130
+ bindShutdown();
109
131
  }
132
+ // ============================
133
+ // ✅ 统一关闭逻辑(核心)
134
+ // ============================
135
+ function bindShutdown() {
136
+ const shutdown = async (signal) => {
137
+ if (isShuttingDown)
138
+ return;
139
+ isShuttingDown = true;
140
+ console.log(`\n[${signal}] shutting down...`);
141
+ try {
142
+ // ✅ 1. 关闭 HTTP server
143
+ if (server) {
144
+ await new Promise((resolve) => {
145
+ server.close(() => {
146
+ console.log('✓ http server closed');
147
+ resolve();
148
+ });
149
+ });
150
+ }
151
+ // ✅ 2. 关闭子进程(如果有)
152
+ if (gatewayPid) {
153
+ try {
154
+ process.kill(gatewayPid);
155
+ console.log(`✓ gateway process killed: ${gatewayPid}`);
156
+ }
157
+ catch { }
158
+ }
159
+ }
160
+ catch (err) {
161
+ console.error('shutdown error:', err);
162
+ }
163
+ process.exit(0);
164
+ };
165
+ // 👉 nodemon 专用(必须 once)
166
+ process.once('SIGUSR2', shutdown);
167
+ // 👉 正常退出
168
+ process.on('SIGINT', shutdown);
169
+ process.on('SIGTERM', shutdown);
170
+ // 👉 防止异常退出没处理
171
+ process.on('uncaughtException', (err) => {
172
+ console.error('uncaughtException:', err);
173
+ shutdown('uncaughtException');
174
+ });
175
+ process.on('unhandledRejection', (err) => {
176
+ console.error('unhandledRejection:', err);
177
+ shutdown('unhandledRejection');
178
+ });
179
+ }
180
+ // ============================
181
+ // 你的原逻辑(基本不动)
182
+ // ============================
110
183
  async function ensureApiServerConfig() {
111
184
  const { homedir } = await Promise.resolve().then(() => __importStar(require('os')));
112
185
  const { readFileSync, writeFileSync, existsSync, copyFileSync } = await Promise.resolve().then(() => __importStar(require('fs')));
113
186
  const yaml = (await Promise.resolve().then(() => __importStar(require('js-yaml')))).default;
114
187
  const configPath = (0, path_1.resolve)(homedir(), '.hermes/config.yaml');
115
- const apiServerDefaults = {
188
+ const defaults = {
116
189
  enabled: true,
117
190
  host: '127.0.0.1',
118
191
  port: 8642,
@@ -121,83 +194,53 @@ async function ensureApiServerConfig() {
121
194
  };
122
195
  try {
123
196
  if (!existsSync(configPath)) {
124
- console.log(' ✗ config.yaml not found, run "hermes setup" first');
197
+ console.log('✗ config.yaml not found');
125
198
  return;
126
199
  }
127
200
  const content = readFileSync(configPath, 'utf-8');
128
- const config = yaml.load(content) || {};
129
- if (!config.platforms)
130
- config.platforms = {};
131
- if (!config.platforms.api_server)
132
- config.platforms.api_server = {};
133
- const api = config.platforms.api_server;
134
- let needsUpdate = false;
135
- for (const [key, value] of Object.entries(apiServerDefaults)) {
136
- if (api[key] === undefined || api[key] === null) {
137
- api[key] = value;
138
- needsUpdate = true;
201
+ const cfg = yaml.load(content) || {};
202
+ if (!cfg.platforms)
203
+ cfg.platforms = {};
204
+ if (!cfg.platforms.api_server)
205
+ cfg.platforms.api_server = {};
206
+ const api = cfg.platforms.api_server;
207
+ let changed = false;
208
+ for (const [k, v] of Object.entries(defaults)) {
209
+ if (api[k] != null && api[k] !== v) {
210
+ api[k] = v;
211
+ changed = true;
139
212
  }
140
213
  }
141
- if (!needsUpdate) {
142
- console.log(' ✓ api_server config is correct');
214
+ if (!changed)
143
215
  return;
144
- }
145
- // Backup before modifying
146
216
  copyFileSync(configPath, configPath + '.bak');
147
- const updated = yaml.dump(config, { lineWidth: -1, noRefs: true, quotingType: '"' });
148
- writeFileSync(configPath, updated, 'utf-8');
149
- console.log(' ✓ api_server config ensured (backup saved to config.yaml.bak)');
217
+ writeFileSync(configPath, yaml.dump(cfg), 'utf-8');
150
218
  await restartGateway();
151
219
  }
152
220
  catch (err) {
153
- console.error(' Failed to update config:', err.message);
221
+ console.error('config error:', err.message);
154
222
  }
155
223
  }
156
224
  async function ensureGatewayRunning() {
157
225
  const upstream = config_1.config.upstream.replace(/\/$/, '');
158
226
  try {
159
227
  const res = await fetch(`${upstream}/health`, { signal: AbortSignal.timeout(5000) });
160
- if (res.ok) {
161
- console.log(' ✓ Gateway is running');
228
+ if (res.ok)
162
229
  return;
163
- }
164
- }
165
- catch {
166
- // Gateway not reachable
167
- }
168
- // Detect WSL — no launchd/systemd, hermes gateway start won't work
169
- const { existsSync, readFileSync } = await Promise.resolve().then(() => __importStar(require('fs')));
170
- const isWSL = existsSync('/proc/version') && readFileSync('/proc/version', 'utf-8').toLowerCase().includes('microsoft');
171
- if (isWSL) {
172
- console.log(' ⚠ WSL detected — Gateway not reachable, starting in background...');
173
- try {
174
- const pid = await startGatewayBackground();
175
- await new Promise(r => setTimeout(r, 3000));
176
- const res = await fetch(`${upstream}/health`, { signal: AbortSignal.timeout(5000) });
177
- if (res.ok) {
178
- console.log(` ✓ Gateway started in background (PID: ${pid})`);
179
- return;
180
- }
181
- console.log(' ✗ Gateway start attempted but still not reachable');
182
- }
183
- catch (err) {
184
- console.error(' ✗ Failed to start gateway:', err.message);
185
- }
186
- return;
187
230
  }
188
- console.log(' ⚠ Gateway not reachable, starting...');
231
+ catch { }
232
+ console.log('⚠ Gateway not running, starting...');
189
233
  try {
190
- await startGateway();
234
+ // 👉 关键:保存 PID
235
+ gatewayPid = await startGatewayBackground();
191
236
  await new Promise(r => setTimeout(r, 3000));
192
237
  const res = await fetch(`${upstream}/health`, { signal: AbortSignal.timeout(5000) });
193
238
  if (res.ok) {
194
- console.log(' ✓ Gateway started successfully');
195
- return;
239
+ console.log(`✓ Gateway started (PID: ${gatewayPid})`);
196
240
  }
197
- console.log(' ✗ Gateway start attempted but still not reachable');
198
241
  }
199
242
  catch (err) {
200
- console.error(' Failed to start gateway:', err.message);
243
+ console.error('gateway start failed:', err.message);
201
244
  }
202
245
  }
203
246
  bootstrap();
@@ -116,6 +116,9 @@ async function writeConfigYaml(config) {
116
116
  exports.fsRoutes.get('/api/skills', async (ctx) => {
117
117
  const skillsDir = (0, path_1.join)(hermesDir, 'skills');
118
118
  try {
119
+ // Read disabled skills list from config.yaml
120
+ const config = await readConfigYaml();
121
+ const disabledList = config.skills?.disabled || [];
119
122
  const entries = await (0, promises_1.readdir)(skillsDir, { withFileTypes: true });
120
123
  const categories = [];
121
124
  for (const entry of entries) {
@@ -134,6 +137,7 @@ exports.fsRoutes.get('/api/skills', async (ctx) => {
134
137
  skills.push({
135
138
  name: se.name,
136
139
  description: extractDescription(skillMd),
140
+ enabled: !disabledList.includes(se.name),
137
141
  });
138
142
  }
139
143
  }
@@ -152,6 +156,40 @@ exports.fsRoutes.get('/api/skills', async (ctx) => {
152
156
  ctx.body = { error: `Failed to read skills directory: ${err.message}` };
153
157
  }
154
158
  });
159
+ // Toggle skill enabled/disabled via config.yaml skills.disabled
160
+ exports.fsRoutes.put('/api/skills/toggle', async (ctx) => {
161
+ const { name, enabled } = ctx.request.body;
162
+ if (!name || typeof enabled !== 'boolean') {
163
+ ctx.status = 400;
164
+ ctx.body = { error: 'Missing name or enabled flag' };
165
+ return;
166
+ }
167
+ try {
168
+ const config = await readConfigYaml();
169
+ if (!config.skills)
170
+ config.skills = {};
171
+ if (!Array.isArray(config.skills.disabled))
172
+ config.skills.disabled = [];
173
+ const disabled = config.skills.disabled;
174
+ const idx = disabled.indexOf(name);
175
+ if (enabled) {
176
+ // Enable: remove from disabled list
177
+ if (idx !== -1)
178
+ disabled.splice(idx, 1);
179
+ }
180
+ else {
181
+ // Disable: add to disabled list
182
+ if (idx === -1)
183
+ disabled.push(name);
184
+ }
185
+ await writeConfigYaml(config);
186
+ ctx.body = { success: true };
187
+ }
188
+ catch (err) {
189
+ ctx.status = 500;
190
+ ctx.body = { error: err.message };
191
+ }
192
+ });
155
193
  // List files in a skill directory
156
194
  async function listFilesRecursive(dir, prefix) {
157
195
  const result = [];
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Get or create the auth token. Returns null if auth is disabled.
3
+ */
4
+ export declare function getToken(): Promise<string | null>;
5
+ /**
6
+ * Koa middleware: check Authorization header for API routes.
7
+ * Skips /health, /webhook, and static file requests.
8
+ */
9
+ export declare function authMiddleware(token: string | null): Promise<(ctx: any, next: () => Promise<void>) => Promise<void>>;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getToken = getToken;
4
+ exports.authMiddleware = authMiddleware;
5
+ const promises_1 = require("fs/promises");
6
+ const path_1 = require("path");
7
+ const crypto_1 = require("crypto");
8
+ const config_1 = require("../config");
9
+ // Token stored in project data directory
10
+ const TOKEN_FILE = (0, path_1.join)(config_1.config.dataDir, '.token');
11
+ function generateToken() {
12
+ return (0, crypto_1.randomBytes)(32).toString('hex');
13
+ }
14
+ /**
15
+ * Get or create the auth token. Returns null if auth is disabled.
16
+ */
17
+ async function getToken() {
18
+ // Auth can be disabled via env var
19
+ if (process.env.AUTH_DISABLED === '1' || process.env.AUTH_DISABLED === 'true') {
20
+ return null;
21
+ }
22
+ // Custom token via env var
23
+ if (process.env.AUTH_TOKEN) {
24
+ return process.env.AUTH_TOKEN;
25
+ }
26
+ try {
27
+ const token = await (0, promises_1.readFile)(TOKEN_FILE, 'utf-8');
28
+ return token.trim();
29
+ }
30
+ catch {
31
+ // Generate a new token
32
+ const token = generateToken();
33
+ await (0, promises_1.writeFile)(TOKEN_FILE, token + '\n', { mode: 0o600 });
34
+ return token;
35
+ }
36
+ }
37
+ /**
38
+ * Koa middleware: check Authorization header for API routes.
39
+ * Skips /health, /webhook, and static file requests.
40
+ */
41
+ async function authMiddleware(token) {
42
+ return async (ctx, next) => {
43
+ // If auth is disabled, skip
44
+ if (!token) {
45
+ await next();
46
+ return;
47
+ }
48
+ // Skip non-API paths (static files, health check, SPA)
49
+ const path = ctx.path;
50
+ if (path === '/health' ||
51
+ (!path.startsWith('/api') && !path.startsWith('/v1') && path !== '/upload' && path !== '/webhook')) {
52
+ await next();
53
+ return;
54
+ }
55
+ const auth = ctx.headers.authorization || '';
56
+ const provided = auth.startsWith('Bearer ')
57
+ ? auth.slice(7)
58
+ : ctx.query.token || '';
59
+ if (!provided || provided !== token) {
60
+ ctx.status = 401;
61
+ ctx.set('Content-Type', 'application/json');
62
+ ctx.body = { error: 'Unauthorized' };
63
+ return;
64
+ }
65
+ await next();
66
+ };
67
+ }
@@ -13,6 +13,7 @@ exports.readLogs = readLogs;
13
13
  const child_process_1 = require("child_process");
14
14
  const util_1 = require("util");
15
15
  const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
16
+ const execOpts = { windowsHide: true };
16
17
  /**
17
18
  * List sessions from Hermes CLI (without messages)
18
19
  */
@@ -24,6 +25,7 @@ async function listSessions(source, limit) {
24
25
  const { stdout } = await execFileAsync('hermes', args, {
25
26
  maxBuffer: 50 * 1024 * 1024, // 50MB
26
27
  timeout: 30000,
28
+ ...execOpts,
27
29
  });
28
30
  const lines = stdout.trim().split('\n').filter(Boolean);
29
31
  const sessions = [];
@@ -83,10 +85,13 @@ async function getSession(id) {
83
85
  const { stdout } = await execFileAsync('hermes', args, {
84
86
  maxBuffer: 50 * 1024 * 1024,
85
87
  timeout: 30000,
88
+ ...execOpts,
86
89
  });
87
90
  const lines = stdout.trim().split('\n').filter(Boolean);
88
91
  if (lines.length === 0)
89
92
  return null;
93
+ if (!lines[0].startsWith('{'))
94
+ return null;
90
95
  const raw = JSON.parse(lines[0]);
91
96
  return {
92
97
  id: raw.id,
@@ -125,6 +130,7 @@ async function deleteSession(id) {
125
130
  try {
126
131
  await execFileAsync('hermes', ['sessions', 'delete', id, '--yes'], {
127
132
  timeout: 10000,
133
+ ...execOpts,
128
134
  });
129
135
  return true;
130
136
  }
@@ -140,6 +146,7 @@ async function renameSession(id, title) {
140
146
  try {
141
147
  await execFileAsync('hermes', ['sessions', 'rename', id, title], {
142
148
  timeout: 10000,
149
+ ...execOpts,
143
150
  });
144
151
  return true;
145
152
  }
@@ -153,7 +160,7 @@ async function renameSession(id, title) {
153
160
  */
154
161
  async function getVersion() {
155
162
  try {
156
- const { stdout } = await execFileAsync('hermes', ['--version'], { timeout: 5000 });
163
+ const { stdout } = await execFileAsync('hermes', ['--version'], { timeout: 5000, ...execOpts });
157
164
  return stdout.trim();
158
165
  }
159
166
  catch {
@@ -166,6 +173,7 @@ async function getVersion() {
166
173
  async function startGateway() {
167
174
  const { stdout, stderr } = await execFileAsync('hermes', ['gateway', 'start'], {
168
175
  timeout: 30000,
176
+ ...execOpts,
169
177
  });
170
178
  return stdout || stderr;
171
179
  }
@@ -178,6 +186,7 @@ async function startGatewayBackground() {
178
186
  const child = spawn('hermes', ['gateway', 'run'], {
179
187
  detached: true,
180
188
  stdio: 'ignore',
189
+ windowsHide: true,
181
190
  });
182
191
  child.unref();
183
192
  return child.pid ?? null;
@@ -188,6 +197,7 @@ async function startGatewayBackground() {
188
197
  async function restartGateway() {
189
198
  const { stdout, stderr } = await execFileAsync('hermes', ['gateway', 'restart'], {
190
199
  timeout: 30000,
200
+ ...execOpts,
191
201
  });
192
202
  return stdout || stderr;
193
203
  }
@@ -198,6 +208,7 @@ async function listLogFiles() {
198
208
  try {
199
209
  const { stdout } = await execFileAsync('hermes', ['logs', 'list'], {
200
210
  timeout: 10000,
211
+ ...execOpts,
201
212
  });
202
213
  const files = [];
203
214
  const lines = stdout.trim().split('\n').filter(l => l.includes('.log'));
@@ -233,6 +244,7 @@ async function readLogs(logName = 'agent', lines = 100, level, session, since) {
233
244
  const { stdout } = await execFileAsync('hermes', args, {
234
245
  maxBuffer: 10 * 1024 * 1024,
235
246
  timeout: 15000,
247
+ ...execOpts,
236
248
  });
237
249
  return stdout;
238
250
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hermes-web-ui",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Hermes Agent Web UI - Chat and Job Management Dashboard",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,7 +15,7 @@
15
15
  "start": "vite --host --port 8648",
16
16
  "dev": "concurrently \"npm run dev:server\" \"npm run dev:client\"",
17
17
  "dev:client": "vite --host",
18
- "dev:server": "nodemon --watch server/src --ext ts --exec node -r ts-node/register server/src/index.ts",
18
+ "dev:server": "nodemon --signal SIGTERM --watch server/src -e ts,tsx --exec node -r ts-node/register server/src/index.ts",
19
19
  "build": "vue-tsc -b && vite build && tsc -p server/tsconfig.json",
20
20
  "preview": "vite preview"
21
21
  },
@@ -1 +0,0 @@
1
- import{$ as e,F as t,I as n,P as r,R as i,S as a,U as o,_ as s,at as c,b as l,ct as u,g as d,h as f,m as p,ot as m,u as h,v as g,x as _,z as v}from"./vue.runtime.esm-bundler-BoqZ7fRe.js";import{t as y,vt as b}from"./_plugin-vue_export-helper-C7dadZ10.js";import{t as x}from"./Button-CpNld4Mc.js";import{t as S}from"./Input-CCmp4iGM.js";import{t as C}from"./Tag-87KswiOb.js";import{t as w}from"./use-message-BeTKmVAO.js";import{t as T}from"./Spin-CwbBDHwW.js";import{a as E,i as D,n as O,o as k,r as A,s as j,t as M}from"./SettingRow-BxCsRfGG.js";var N={class:`platform-info`},P=[`innerHTML`],F={class:`platform-name`},I={key:0,class:`platform-card-body`},L=y(a({__name:`PlatformCard`,props:{name:{},icon:{},config:{},credentials:{}},setup(t){let r=t,i=e(!0),{t:a}=b(),d=p(()=>{let e=r.credentials;if(!e)return!1;let t=[`token`,`api_key`,`app_id`,`client_id`,`secret`,`app_secret`,`client_secret`,`access_token`,`bot_id`,`account_id`,`enabled`];return[e,e.extra].filter(Boolean).some(e=>t.some(t=>{let n=e[t];return n!=null&&n!==``&&n!==!1}))});return(e,r)=>(n(),g(`div`,{class:m([`platform-card`,{configured:d.value}])},[f(`div`,{class:`platform-card-header`,onClick:r[0]||=e=>i.value=!i.value},[f(`div`,N,[f(`span`,{class:`platform-icon`,innerHTML:t.icon},null,8,P),f(`span`,F,u(t.name),1),_(c(C),{type:d.value?`success`:`default`,size:`small`,round:``},{default:o(()=>[l(u(d.value?c(a)(`common.configured`):c(a)(`common.notConfigured`)),1)]),_:1},8,[`type`])]),f(`span`,{class:m([`expand-icon`,{expanded:i.value}])},`▾`,2)]),i.value?(n(),g(`div`,I,[v(e.$slots,`default`,{},void 0,!0)])):s(``,!0)],2))}}),[[`__scopeId`,`data-v-ee5f4168`]]),R={class:`settings-section`},z={class:`weixin-qr-section`},B={key:1,class:`weixin-qr-loading`},V={key:2,class:`weixin-qr-hint`},H=y(a({__name:`PlatformSettings`,setup(r){let a=O(),p=w(),{t:m}=b();async function v(e,t){try{await a.saveSection(e,t),p.success(m(`settings.saved`))}catch{p.error(m(`settings.saveFailed`))}}async function y(e,t){try{await E(e,t),await a.fetchSettings(),p.success(m(`settings.saved`))}catch{p.error(m(`settings.saveFailed`))}}function C(e){return a.platforms[e]||{}}let N=e(``),P=e(``),F=e(`idle`),I=null;async function H(){F.value=`loading`,N.value=``,P.value=``,W();try{let e=await A();P.value=e.qrcode,N.value=e.qrcode_url,window.open(e.qrcode_url,`_blank`),F.value=`waiting`,U()}catch(e){F.value=`error`,p.error(e.message||`Failed to get QR code`)}}function U(){P.value&&(I=setTimeout(async()=>{try{let e=await D(P.value);e.status===`wait`?U():e.status===`scaned`?(F.value=`scaned`,U()):e.status===`expired`?F.value=`expired`:e.status===`confirmed`&&(F.value=`confirmed`,await k({account_id:e.account_id,token:e.token,base_url:e.base_url}),await a.fetchSettings(),p.success(m(`settings.saved`)))}catch{U()}},3e3))}function W(){I&&=(clearTimeout(I),null)}t(()=>{W()});let G=[{key:`telegram`,name:`Telegram`,icon:`<svg viewBox="0 0 24 24" fill="currentColor"><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.479.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/></svg>`},{key:`discord`,name:`Discord`,icon:`<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189z"/></svg>`},{key:`slack`,name:`Slack`,icon:`<svg viewBox="0 0 24 24" fill="currentColor"><path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zm1.271 0a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zm0 1.271a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zm10.122 0a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V5.042zm-1.27 0a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zm0-1.27a2.527 2.527 0 0 1 2.523-2.52h6.313A2.528 2.528 0 0 1 24 18.956a2.528 2.528 0 0 1-2.522 2.523h-6.313z"/></svg>`},{key:`whatsapp`,name:`WhatsApp`,icon:`<svg viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>`},{key:`matrix`,name:`Matrix`,icon:`<svg viewBox="0 0 24 24" fill="currentColor"><path d="M.632.55v22.9H2.28V24H0V0h2.28v.55zm7.043 7.26v1.157h.033c.309-.443.683-.784 1.117-1.024.433-.245.936-.365 1.5-.365.54 0 1.033.107 1.48.324.448.217.786.619 1.017 1.205.24-.376.558-.702.956-.98.398-.277.872-.414 1.424-.414.41 0 .784.065 1.122.194.34.13.629.325.87.588.241.263.428.59.56.984.132.393.198.85.198 1.368v5.89h-2.49v-4.893c0-.268-.016-.525-.048-.77a1.627 1.627 0 00-.2-.63 1.028 1.028 0 00-.392-.426 1.294 1.294 0 00-.616-.134c-.277 0-.508.05-.693.15a1.043 1.043 0 00-.43.41 1.768 1.768 0 00-.214.616 4.15 4.15 0 00-.06.74v4.937H9.29v-4.937c0-.25-.01-.498-.032-.742a1.84 1.84 0 00-.166-.638.998.998 0 00-.363-.448 1.206 1.206 0 00-.624-.154c-.26 0-.483.048-.67.144a1.055 1.055 0 00-.436.402 1.744 1.744 0 00-.227.616 4.108 4.108 0 00-.063.74v4.937H5.21V7.81zm15.693 15.64V.55H21.72V0H24v24h-2.28v-.55z"/></svg>`},{key:`feishu`,name:`Feishu`,icon:`<svg viewBox="0 0 24 24" fill="currentColor"><path d="M6.59 3.41a2.25 2.25 0 0 1 3.182 0L13.5 7.14l-3.182 3.182L6.59 7.59a2.25 2.25 0 0 1 0-3.182zm5.303 5.303L15.075 5.53a2.25 2.25 0 0 1 3.182 3.182L15.075 11.894 11.893 8.713zM3.41 6.59a2.25 2.25 0 0 1 3.182 0l3.182 3.182-3.182 3.182a2.25 2.25 0 0 1-3.182-3.182L3.41 6.59zm5.303 5.303L11.894 15.075a2.25 2.25 0 0 1-3.182 3.182L5.53 15.075 8.713 11.893zm5.303-5.303L17.478 9.778a2.25 2.25 0 0 1-3.182 3.182L10.53 10.075l3.182-3.182 0 .023z"/></svg>`},{key:`weixin`,name:`Weixin`,icon:`<svg viewBox="0 0 24 24" fill="currentColor"><path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 01.213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 00.167-.054l1.903-1.114a.864.864 0 01.717-.098 10.16 10.16 0 002.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 01-1.162 1.178A1.17 1.17 0 014.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 01-1.162 1.178 1.17 1.17 0 01-1.162-1.178c0-.651.52-1.18 1.162-1.18zm3.68 4.025c-3.694 0-6.69 2.462-6.69 5.496 0 3.034 2.996 5.496 6.69 5.496.753 0 1.477-.1 2.158-.28a.66.66 0 01.548.074l1.46.854a.25.25 0 00.127.041.224.224 0 00.221-.225c0-.055-.022-.109-.037-.162l-.298-1.131a.453.453 0 01.163-.509C21.81 18.613 22.77 16.973 22.77 15.512c0-3.034-2.996-5.496-6.69-5.496h.198zm-2.454 3.347c.491 0 .889.404.889.902a.896.896 0 01-.889.903.896.896 0 01-.889-.903c0-.498.398-.902.889-.902zm4.912 0c.491 0 .889.404.889.902a.896.896 0 01-.889.903.896.896 0 01-.889-.903c0-.498.398-.902.889-.902z"/></svg>`},{key:`wecom`,name:`WeCom`,icon:`<svg viewBox="0 0 24 24" fill="currentColor"><path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 01.213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 00.167-.054l1.903-1.114a.864.864 0 01.717-.098 10.16 10.16 0 002.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 01-1.162 1.178A1.17 1.17 0 014.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 01-1.162 1.178 1.17 1.17 0 01-1.162-1.178c0-.651.52-1.18 1.162-1.18zm3.68 4.025c-3.694 0-6.69 2.462-6.69 5.496 0 3.034 2.996 5.496 6.69 5.496.753 0 1.477-.1 2.158-.28a.66.66 0 01.548.074l1.46.854a.25.25 0 00.127.041.224.224 0 00.221-.225c0-.055-.022-.109-.037-.162l-.298-1.131a.453.453 0 01.163-.509C21.81 18.613 22.77 16.973 22.77 15.512c0-3.034-2.996-5.496-6.69-5.496h.198zm-2.454 3.347c.491 0 .889.404.889.902a.896.896 0 01-.889.903.896.896 0 01-.889-.903c0-.498.398-.902.889-.902zm4.912 0c.491 0 .889.404.889.902a.896.896 0 01-.889.903.896.896 0 01-.889-.903c0-.498.398-.902.889-.902z"/></svg>`}];return(e,t)=>(n(),g(`section`,R,[(n(),g(h,null,i(G,e=>_(L,{key:e.key,name:e.name,icon:e.icon,config:c(a)[e.key],credentials:C(e.key)},{default:o(()=>[e.key===`telegram`?(n(),g(h,{key:0},[_(M,{label:c(m)(`platform.botToken`),hint:c(m)(`platform.botTokenHint`)},{default:o(()=>[_(c(S),{value:C(`telegram`).token||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`123456:ABC-DEF...`,"onUpdate:value":t[0]||=e=>y(`telegram`,{token:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.requireMention`),hint:c(m)(`platform.requireMentionGroup`)},{default:o(()=>[_(c(j),{value:c(a).telegram.require_mention,"onUpdate:value":t[1]||=e=>v(`telegram`,{require_mention:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.reactions`),hint:c(m)(`platform.reactionsHint`)},{default:o(()=>[_(c(j),{value:c(a).telegram.reactions,"onUpdate:value":t[2]||=e=>v(`telegram`,{reactions:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.freeResponseChats`),hint:c(m)(`platform.freeResponseChatsHint`)},{default:o(()=>[_(c(S),{value:c(a).telegram.free_response_chats||``,size:`small`,placeholder:`chat_id1,chat_id2`,"onUpdate:value":t[3]||=e=>v(`telegram`,{free_response_chats:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.mentionPatterns`),hint:c(m)(`platform.mentionPatternsHint`)},{default:o(()=>[_(c(S),{value:(c(a).telegram.mention_patterns||[]).join(`, `),size:`small`,placeholder:`pattern1, pattern2`,"onUpdate:value":t[4]||=e=>v(`telegram`,{mention_patterns:e?e.split(`,`).map(e=>e.trim()):[]})},null,8,[`value`])]),_:1},8,[`label`,`hint`])],64)):s(``,!0),e.key===`discord`?(n(),g(h,{key:1},[_(M,{label:c(m)(`platform.botToken`),hint:c(m)(`platform.botTokenHint`)},{default:o(()=>[_(c(S),{value:C(`discord`).token||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`Bot token...`,"onUpdate:value":t[5]||=e=>y(`discord`,{token:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.requireMention`),hint:c(m)(`platform.requireMentionChannel`)},{default:o(()=>[_(c(j),{value:c(a).discord.require_mention,"onUpdate:value":t[6]||=e=>v(`discord`,{require_mention:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.autoThread`),hint:c(m)(`platform.autoThreadHint`)},{default:o(()=>[_(c(j),{value:c(a).discord.auto_thread,"onUpdate:value":t[7]||=e=>v(`discord`,{auto_thread:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.reactions`),hint:c(m)(`platform.reactionsHint`)},{default:o(()=>[_(c(j),{value:c(a).discord.reactions,"onUpdate:value":t[8]||=e=>v(`discord`,{reactions:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.freeResponseChannels`),hint:c(m)(`platform.freeResponseChannelsHint`)},{default:o(()=>[_(c(S),{value:c(a).discord.free_response_channels||``,size:`small`,placeholder:`channel_id1,channel_id2`,"onUpdate:value":t[9]||=e=>v(`discord`,{free_response_channels:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.allowedChannels`),hint:c(m)(`platform.allowedChannelsHint`)},{default:o(()=>[_(c(S),{value:c(a).discord.allowed_channels||``,size:`small`,placeholder:`channel_id1,channel_id2`,"onUpdate:value":t[10]||=e=>v(`discord`,{allowed_channels:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.ignoredChannels`),hint:c(m)(`platform.ignoredChannelsHint`)},{default:o(()=>[_(c(S),{value:c(a).discord.ignored_channels||``,size:`small`,placeholder:`channel_id1,channel_id2`,"onUpdate:value":t[11]||=e=>v(`discord`,{ignored_channels:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.noThreadChannels`),hint:c(m)(`platform.noThreadChannelsHint`)},{default:o(()=>[_(c(S),{value:c(a).discord.no_thread_channels||``,size:`small`,placeholder:`channel_id1,channel_id2`,"onUpdate:value":t[12]||=e=>v(`discord`,{no_thread_channels:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`])],64)):s(``,!0),e.key===`slack`?(n(),g(h,{key:2},[_(M,{label:c(m)(`platform.botToken`),hint:c(m)(`platform.botTokenHint`)},{default:o(()=>[_(c(S),{value:C(`slack`).token||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`xoxb-...`,"onUpdate:value":t[13]||=e=>y(`slack`,{token:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.requireMention`),hint:c(m)(`platform.requireMentionChannel`)},{default:o(()=>[_(c(j),{value:c(a).slack.require_mention,"onUpdate:value":t[14]||=e=>v(`slack`,{require_mention:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.allowBots`),hint:c(m)(`platform.allowBotsHint`)},{default:o(()=>[_(c(j),{value:c(a).slack.allow_bots,"onUpdate:value":t[15]||=e=>v(`slack`,{allow_bots:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.freeResponseChannels`),hint:c(m)(`platform.freeResponseChannelsHint`)},{default:o(()=>[_(c(S),{value:c(a).slack.free_response_channels||``,size:`small`,placeholder:`channel_id1,channel_id2`,"onUpdate:value":t[16]||=e=>v(`slack`,{free_response_channels:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`])],64)):s(``,!0),e.key===`whatsapp`?(n(),g(h,{key:3},[_(M,{label:c(m)(`platform.waEnabled`),hint:c(m)(`platform.waEnabledHint`)},{default:o(()=>[_(c(j),{value:C(`whatsapp`).enabled,"onUpdate:value":t[17]||=e=>y(`whatsapp`,{enabled:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.requireMention`),hint:c(m)(`platform.requireMentionGroup`)},{default:o(()=>[_(c(j),{value:c(a).whatsapp.require_mention,"onUpdate:value":t[18]||=e=>v(`whatsapp`,{require_mention:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.freeResponseChats`),hint:c(m)(`platform.freeResponseChatsHint`)},{default:o(()=>[_(c(S),{value:c(a).whatsapp.free_response_chats||``,size:`small`,placeholder:`chat_id1,chat_id2`,"onUpdate:value":t[19]||=e=>v(`whatsapp`,{free_response_chats:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.mentionPatterns`),hint:c(m)(`platform.mentionPatternsHint`)},{default:o(()=>[_(c(S),{value:(c(a).whatsapp.mention_patterns||[]).join(`, `),size:`small`,placeholder:`pattern1, pattern2`,"onUpdate:value":t[20]||=e=>v(`whatsapp`,{mention_patterns:e?e.split(`,`).map(e=>e.trim()):[]})},null,8,[`value`])]),_:1},8,[`label`,`hint`])],64)):s(``,!0),e.key===`matrix`?(n(),g(h,{key:4},[_(M,{label:c(m)(`platform.accessToken`),hint:c(m)(`platform.accessTokenHint`)},{default:o(()=>[_(c(S),{value:C(`matrix`).token||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`syt_...`,"onUpdate:value":t[21]||=e=>y(`matrix`,{token:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.homeserver`),hint:c(m)(`platform.homeserverHint`)},{default:o(()=>[_(c(S),{value:C(`matrix`).extra?.homeserver||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`https://matrix.org`,"onUpdate:value":t[22]||=e=>y(`matrix`,{extra:{...C(`matrix`).extra,homeserver:e}})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.requireMention`),hint:c(m)(`platform.requireMentionRoom`)},{default:o(()=>[_(c(j),{value:c(a).matrix.require_mention,"onUpdate:value":t[23]||=e=>v(`matrix`,{require_mention:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.autoThread`),hint:c(m)(`platform.autoThreadHintRoom`)},{default:o(()=>[_(c(j),{value:c(a).matrix.auto_thread,"onUpdate:value":t[24]||=e=>v(`matrix`,{auto_thread:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.dmMentionThreads`),hint:c(m)(`platform.dmMentionThreadsHint`)},{default:o(()=>[_(c(j),{value:c(a).matrix.dm_mention_threads,"onUpdate:value":t[25]||=e=>v(`matrix`,{dm_mention_threads:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.freeResponseRooms`),hint:c(m)(`platform.freeResponseRoomsHint`)},{default:o(()=>[_(c(S),{value:c(a).matrix.free_response_rooms||``,size:`small`,placeholder:`room_id1,room_id2`,"onUpdate:value":t[26]||=e=>v(`matrix`,{free_response_rooms:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`])],64)):s(``,!0),e.key===`feishu`?(n(),g(h,{key:5},[_(M,{label:c(m)(`platform.appId`),hint:c(m)(`platform.appIdHint`)},{default:o(()=>[_(c(S),{value:C(`feishu`).extra?.app_id||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`cli_...`,"onUpdate:value":t[27]||=e=>y(`feishu`,{extra:{...C(`feishu`).extra,app_id:e}})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.appSecret`),hint:c(m)(`platform.appSecretHint`)},{default:o(()=>[_(c(S),{value:C(`feishu`).extra?.app_secret||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`App Secret`,"onUpdate:value":t[28]||=e=>y(`feishu`,{extra:{...C(`feishu`).extra,app_secret:e}})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.requireMention`),hint:c(m)(`platform.requireMentionGroup`)},{default:o(()=>[_(c(j),{value:c(a).feishu.require_mention,"onUpdate:value":t[29]||=e=>v(`feishu`,{require_mention:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.freeResponseChats`),hint:c(m)(`platform.freeResponseChatsHint`)},{default:o(()=>[_(c(S),{value:c(a).feishu.free_response_chats||``,size:`small`,placeholder:`chat_id1,chat_id2`,"onUpdate:value":t[30]||=e=>v(`feishu`,{free_response_chats:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`])],64)):s(``,!0),e.key===`dingtalk`?(n(),g(h,{key:6},[_(M,{label:c(m)(`platform.clientId`),hint:c(m)(`platform.clientIdHint`)},{default:o(()=>[_(c(S),{value:C(`dingtalk`).extra?.client_id||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`Client ID`,"onUpdate:value":t[31]||=e=>y(`dingtalk`,{extra:{...C(`dingtalk`).extra,client_id:e}})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.clientSecret`),hint:c(m)(`platform.clientSecretHint`)},{default:o(()=>[_(c(S),{value:C(`dingtalk`).extra?.client_secret||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`Client Secret`,"onUpdate:value":t[32]||=e=>y(`dingtalk`,{extra:{...C(`dingtalk`).extra,client_secret:e}})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.requireMention`),hint:c(m)(`platform.requireMentionGroup`)},{default:o(()=>[_(c(j),{value:c(a).dingtalk.require_mention,"onUpdate:value":t[33]||=e=>v(`dingtalk`,{require_mention:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.freeResponseChats`),hint:c(m)(`platform.freeResponseChatsHint`)},{default:o(()=>[_(c(S),{value:c(a).dingtalk.free_response_chats||``,size:`small`,placeholder:`chat_id1,chat_id2`,"onUpdate:value":t[34]||=e=>v(`dingtalk`,{free_response_chats:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`])],64)):s(``,!0),e.key===`weixin`?(n(),g(h,{key:7},[f(`div`,z,[F.value===`idle`||F.value===`error`||F.value===`expired`||F.value===`confirmed`?(n(),d(c(x),{key:0,type:`primary`,size:`small`,onClick:H},{default:o(()=>[l(u(F.value===`confirmed`?c(m)(`platform.qrRelogin`):c(m)(`platform.qrLogin`)),1)]),_:1})):s(``,!0),F.value===`loading`?(n(),g(`div`,B,[_(c(T),{size:`small`}),f(`span`,null,u(c(m)(`platform.qrFetching`)),1)])):s(``,!0),F.value===`waiting`||F.value===`scaned`?(n(),g(`div`,V,u(F.value===`scaned`?c(m)(`platform.qrScanedHint`):c(m)(`platform.qrScanHint`)),1)):s(``,!0)]),_(M,{label:c(m)(`platform.weixinToken`),hint:c(m)(`platform.weixinTokenHint`)},{default:o(()=>[_(c(S),{value:C(`weixin`).token||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`Token`,"onUpdate:value":t[35]||=e=>y(`weixin`,{token:e})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.accountId`),hint:c(m)(`platform.accountIdHint`)},{default:o(()=>[_(c(S),{value:C(`weixin`).extra?.account_id||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`Account ID`,"onUpdate:value":t[36]||=e=>y(`weixin`,{extra:{...C(`weixin`).extra,account_id:e}})},null,8,[`value`])]),_:1},8,[`label`,`hint`])],64)):s(``,!0),e.key===`wecom`?(n(),g(h,{key:8},[_(M,{label:c(m)(`platform.botId`),hint:c(m)(`platform.botIdHint`)},{default:o(()=>[_(c(S),{value:C(`wecom`).extra?.bot_id||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`Bot ID`,"onUpdate:value":t[37]||=e=>y(`wecom`,{extra:{...C(`wecom`).extra,bot_id:e}})},null,8,[`value`])]),_:1},8,[`label`,`hint`]),_(M,{label:c(m)(`platform.appSecret`),hint:c(m)(`platform.wecomSecretHint`)},{default:o(()=>[_(c(S),{value:C(`wecom`).extra?.secret||``,clearable:``,size:`small`,style:{width:`300px`},placeholder:`Secret`,"onUpdate:value":t[38]||=e=>y(`wecom`,{extra:{...C(`wecom`).extra,secret:e}})},null,8,[`value`])]),_:1},8,[`label`,`hint`])],64)):s(``,!0)]),_:2},1032,[`name`,`icon`,`config`,`credentials`])),64))]))}}),[[`__scopeId`,`data-v-afd5f277`]]),U={class:`channels-view`},W={class:`channels-header`},G={class:`header-title`},K={class:`channels-content`},q=y(a({__name:`ChannelsView`,setup(e){let t=O(),{t:i}=b();return r(()=>{t.fetchSettings()}),(e,r)=>(n(),g(`div`,U,[f(`header`,W,[f(`h2`,G,u(c(i)(`sidebar.channels`)),1)]),f(`div`,K,[_(c(T),{show:c(t).loading},{default:o(()=>[_(H)]),_:1},8,[`show`])])]))}}),[[`__scopeId`,`data-v-ceb983fe`]]);export{q as default};
@@ -1 +0,0 @@
1
- .chat-input-area[data-v-9ceae9e7]{border-top:1px solid #e0e0e0;flex-shrink:0;padding:12px 20px 16px}.attachment-previews[data-v-9ceae9e7]{flex-wrap:wrap;gap:8px;padding:0 0 10px;display:flex}.attachment-preview[data-v-9ceae9e7]{background-color:#f0f0f0;border:1px solid #e0e0e0;border-radius:6px;position:relative;overflow:hidden}.attachment-preview.image[data-v-9ceae9e7]{width:64px;height:64px}.attachment-thumb[data-v-9ceae9e7]{object-fit:cover;width:100%;height:100%}.attachment-file[data-v-9ceae9e7]{color:#666;flex-direction:column;justify-content:center;align-items:center;gap:2px;min-width:80px;max-width:140px;padding:8px 12px;display:flex}.attachment-file .file-name[data-v-9ceae9e7]{white-space:nowrap;text-overflow:ellipsis;max-width:100%;font-size:11px;overflow:hidden}.attachment-file .file-size[data-v-9ceae9e7]{color:#999;font-size:10px}.attachment-remove[data-v-9ceae9e7]{color:#fff;cursor:pointer;opacity:0;background:#00000080;border:none;border-radius:50%;justify-content:center;align-items:center;width:18px;height:18px;transition:opacity .15s;display:flex;position:absolute;top:2px;right:2px}.attachment-preview:hover .attachment-remove[data-v-9ceae9e7]{opacity:1}.file-input-hidden[data-v-9ceae9e7]{display:none}.input-wrapper[data-v-9ceae9e7]{background-color:#fff;border:1px solid #e0e0e0;border-radius:10px;align-items:center;gap:10px;padding:10px 12px;transition:border-color .15s;display:flex}.input-wrapper[data-v-9ceae9e7]:focus-within{border-color:#333}.input-textarea[data-v-9ceae9e7]{color:#1a1a1a;resize:none;background:0 0;border:none;outline:none;flex:1;min-height:20px;max-height:100px;font-family:Inter,system-ui,-apple-system,sans-serif;font-size:14px;line-height:1.5;overflow-y:auto}.input-textarea[data-v-9ceae9e7]::placeholder{color:#999}.input-actions[data-v-9ceae9e7]{flex-shrink:0;align-items:center;gap:6px;display:flex}.input-wrapper.drag-over[data-v-9ceae9e7]{background-color:#4a90d90a;border-style:dashed;border-color:#4a90d9}.message[data-v-ccf3ecc4]{flex-direction:column;display:flex}.message.user[data-v-ccf3ecc4]{align-items:flex-end}.message.user .msg-body[data-v-ccf3ecc4]{max-width:75%}.message.user .msg-content.user[data-v-ccf3ecc4]{align-items:flex-end}.message.user .message-bubble[data-v-ccf3ecc4]{background-color:#e8e8e8;border-radius:10px 10px 4px}.message.assistant[data-v-ccf3ecc4]{flex-direction:row;align-items:flex-start;gap:8px}.message.assistant .msg-body[data-v-ccf3ecc4]{max-width:80%}.message.assistant .msg-avatar[data-v-ccf3ecc4]{flex-shrink:0;width:40px;height:40px;margin-top:2px}.message.assistant .message-bubble[data-v-ccf3ecc4]{background-color:#f5f5f5;border-radius:10px 10px 10px 4px}.message.tool[data-v-ccf3ecc4],.message.system[data-v-ccf3ecc4]{align-items:flex-start}.message.system .message-bubble.system[data-v-ccf3ecc4]{background-color:#f57f170f;border-left:3px solid #f57f17;border-radius:6px;max-width:80%}.msg-body[data-v-ccf3ecc4]{align-items:flex-start;gap:8px;max-width:85%;display:flex}.msg-content[data-v-ccf3ecc4]{flex-direction:column;min-width:0;display:flex}.message-bubble[data-v-ccf3ecc4]{word-break:break-word;padding:10px 14px;font-size:14px;line-height:1.65}.msg-attachments[data-v-ccf3ecc4]{flex-wrap:wrap;gap:8px;margin-bottom:8px;display:flex}.msg-attachment[data-v-ccf3ecc4]{background-color:#0000000a;border:1px solid #ebebeb;border-radius:6px;overflow:hidden}.msg-attachment.image[data-v-ccf3ecc4]{max-width:200px}.msg-attachment-thumb[data-v-ccf3ecc4]{object-fit:contain;max-width:200px;max-height:160px;display:block}.msg-attachment-file[data-v-ccf3ecc4]{color:#666;align-items:center;gap:6px;padding:6px 10px;font-size:12px;display:flex}.msg-attachment-file .att-name[data-v-ccf3ecc4]{white-space:nowrap;text-overflow:ellipsis;max-width:160px;overflow:hidden}.msg-attachment-file .att-size[data-v-ccf3ecc4]{color:#999;flex-shrink:0;font-size:11px}.message-time[data-v-ccf3ecc4]{color:#999;margin-top:4px;padding:0 4px;font-size:11px}.tool-line[data-v-ccf3ecc4]{color:#999;border-radius:6px;align-items:center;gap:6px;padding:2px 4px;font-size:11px;display:flex}.tool-line.expandable[data-v-ccf3ecc4]{cursor:pointer}.tool-line.expandable[data-v-ccf3ecc4]:hover{background:#00000008}.tool-line .tool-name[data-v-ccf3ecc4]{flex-shrink:0;font-family:JetBrains Mono,Fira Code,Consolas,monospace}.tool-line .tool-preview[data-v-ccf3ecc4]{text-overflow:ellipsis;white-space:nowrap;max-width:400px;overflow:hidden}.tool-chevron[data-v-ccf3ecc4]{flex-shrink:0;transition:transform .15s}.tool-chevron.rotated[data-v-ccf3ecc4]{transform:rotate(90deg)}.tool-spinner[data-v-ccf3ecc4]{border:1.5px solid #999;border-top-color:#0000;border-radius:50%;flex-shrink:0;width:10px;height:10px;animation:.6s linear infinite spin-ccf3ecc4}.tool-error-badge[data-v-ccf3ecc4]{color:#c62828;background:#c6282814;border-radius:3px;padding:0 4px;font-size:9px;line-height:14px}.tool-details[data-v-ccf3ecc4]{border-left:2px solid #ebebeb;margin-top:2px;margin-left:16px;padding-left:10px}.tool-detail-section[data-v-ccf3ecc4]{margin-bottom:6px}.tool-detail-label[data-v-ccf3ecc4]{color:#999;text-transform:uppercase;letter-spacing:.3px;margin-bottom:2px;font-size:10px;font-weight:600}.tool-detail-code[data-v-ccf3ecc4]{color:#666;white-space:pre-wrap;word-break:break-all;background:#f4f4f4;border-radius:6px;max-height:300px;margin:0;padding:6px 8px;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:11px;line-height:1.5;overflow:auto}@keyframes spin-ccf3ecc4{to{transform:rotate(360deg)}}.streaming-cursor[data-v-ccf3ecc4]{vertical-align:text-bottom;background-color:#999;width:2px;height:1em;margin-left:2px;animation:.8s infinite blink-ccf3ecc4;display:inline-block}.streaming-dots[data-v-ccf3ecc4]{gap:4px;padding:4px 0;display:flex}.streaming-dots span[data-v-ccf3ecc4]{background-color:#999;border-radius:50%;width:6px;height:6px;animation:1.4s ease-in-out infinite pulse-ccf3ecc4}.streaming-dots span[data-v-ccf3ecc4]:nth-child(2){animation-delay:.2s}.streaming-dots span[data-v-ccf3ecc4]:nth-child(3){animation-delay:.4s}@keyframes blink-ccf3ecc4{0%,50%{opacity:1}51%,to{opacity:0}}@keyframes pulse-ccf3ecc4{0%,80%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}.message-list[data-v-77d56b6f]{background-color:#fff;flex-direction:column;flex:1;gap:16px;padding:20px;display:flex;overflow-y:auto}.empty-state[data-v-77d56b6f]{color:#999;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;display:flex}.empty-state .empty-logo[data-v-77d56b6f]{opacity:.25;width:48px;height:48px}.empty-state p[data-v-77d56b6f]{font-size:14px}.fade-enter-active[data-v-77d56b6f],.fade-leave-active[data-v-77d56b6f]{transition:opacity .4s}.fade-enter-from[data-v-77d56b6f],.fade-leave-to[data-v-77d56b6f]{opacity:0}.streaming-indicator[data-v-77d56b6f]{align-items:flex-start;gap:12px;padding:4px;display:flex}.streaming-indicator .thinking-video[data-v-77d56b6f]{object-fit:contain;border-radius:10px;flex-shrink:0;width:120px;height:120px}.tool-calls-panel[data-v-77d56b6f]{scrollbar-width:none;-ms-overflow-style:none;flex-direction:column;gap:4px;max-height:120px;padding-top:4px;display:flex;overflow-y:auto}.tool-calls-panel[data-v-77d56b6f]::-webkit-scrollbar{display:none}.tool-call-item[data-v-77d56b6f]{color:#666;background:#00000008;border-radius:6px;align-items:center;gap:6px;padding:3px 8px;font-size:11px;display:flex}.tool-call-item .tool-call-icon[data-v-77d56b6f]{color:#999;flex-shrink:0}.tool-call-item .tool-call-name[data-v-77d56b6f]{flex-shrink:0;font-family:JetBrains Mono,Fira Code,Consolas,monospace}.tool-call-item .tool-call-preview[data-v-77d56b6f]{text-overflow:ellipsis;white-space:nowrap;color:#999;max-width:300px;overflow:hidden}.tool-call-spinner[data-v-77d56b6f]{border:1.5px solid #999;border-top-color:#0000;border-radius:50%;flex-shrink:0;width:10px;height:10px;animation:.6s linear infinite spin-77d56b6f}.tool-call-error[data-v-77d56b6f]{color:#c62828;background:#c6282814;border-radius:3px;padding:0 4px;font-size:9px;line-height:14px}@keyframes spin-77d56b6f{to{transform:rotate(360deg)}}.chat-panel[data-v-3849a23e]{height:100%;display:flex}.session-list[data-v-3849a23e]{border-right:1px solid #e0e0e0;flex-direction:column;flex-shrink:0;width:220px;transition:width .25s,opacity .25s;display:flex;overflow:hidden}.session-list.collapsed[data-v-3849a23e]{opacity:0;pointer-events:none;border-right:none;width:0}.session-list-header[data-v-3849a23e]{flex-shrink:0;justify-content:space-between;align-items:center;padding:12px;display:flex}.session-list-title[data-v-3849a23e]{color:#999;text-transform:uppercase;letter-spacing:.5px;font-size:12px;font-weight:600}.session-group-header[data-v-3849a23e]{cursor:pointer;-webkit-user-select:none;user-select:none;align-items:center;gap:4px;padding:6px 10px 4px;display:flex}.group-chevron[data-v-3849a23e]{flex-shrink:0;transition:transform .15s;transform:rotate(90deg)}.group-chevron.collapsed[data-v-3849a23e]{transform:rotate(0)}.session-group-label[data-v-3849a23e]{color:#999;text-transform:uppercase;letter-spacing:.5px;font-size:10px;font-weight:600}.session-group-count[data-v-3849a23e]{color:#999;font-size:10px;font-weight:400}.session-items[data-v-3849a23e]{flex:1;padding:0 6px 12px;overflow-y:auto}.session-loading[data-v-3849a23e],.session-empty[data-v-3849a23e]{color:#999;text-align:center;padding:16px 10px;font-size:12px}.session-item[data-v-3849a23e]{cursor:pointer;text-align:left;color:#666;background:0 0;border:none;border-radius:6px;justify-content:space-between;align-items:center;width:100%;margin-bottom:2px;padding:8px 10px;transition:all .15s;display:flex}.session-item[data-v-3849a23e]:hover{color:#1a1a1a;background:#3333330f}.session-item:hover .session-item-delete[data-v-3849a23e]{opacity:1}.session-item.active[data-v-3849a23e]{color:#1a1a1a;background:#3333331a;font-weight:500}.session-item-content[data-v-3849a23e]{flex:1;overflow:hidden}.session-item-title[data-v-3849a23e]{white-space:nowrap;text-overflow:ellipsis;font-size:13px;display:block;overflow:hidden}.session-item-time[data-v-3849a23e]{color:#999;font-size:11px}.session-item-meta[data-v-3849a23e]{align-items:center;gap:6px;margin-top:2px;display:flex}.session-item-model[data-v-3849a23e]{color:#333;text-overflow:ellipsis;white-space:nowrap;background:#33333314;border-radius:3px;flex-shrink:0;max-width:100px;padding:0 5px;font-size:10px;line-height:16px;overflow:hidden}.session-item-delete[data-v-3849a23e]{opacity:0;color:#999;cursor:pointer;background:0 0;border:none;border-radius:3px;flex-shrink:0;padding:2px;transition:all .15s}.session-item-delete[data-v-3849a23e]:hover{color:#c62828;background:#c628281a}.chat-main[data-v-3849a23e]{flex-direction:column;flex:1;min-width:0;display:flex;overflow:hidden}.chat-header[data-v-3849a23e]{border-bottom:1px solid #e0e0e0;flex-shrink:0;justify-content:space-between;align-items:center;padding:12px 16px;display:flex}.header-left[data-v-3849a23e]{flex:1;align-items:center;gap:8px;min-width:0;display:flex;overflow:hidden}.header-session-title[data-v-3849a23e]{color:#1a1a1a;white-space:nowrap;text-overflow:ellipsis;font-size:14px;font-weight:500;overflow:hidden}.source-badge[data-v-3849a23e]{color:#999;white-space:nowrap;background:#9999991f;border-radius:8px;flex-shrink:0;padding:1px 7px;font-size:10px;line-height:16px}.header-actions[data-v-3849a23e]{flex-shrink:0;align-items:center;gap:4px;display:flex}.context-info[data-v-3849a23e]{color:#999;flex-shrink:0;padding:0 20px 4px;font-size:11px}.chat-view[data-v-d35d4d9c]{flex-direction:column;height:100vh;display:flex}