hermes-web-ui 0.2.2 → 0.2.3
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 +30 -6
- package/bin/hermes-web-ui.mjs +34 -4
- package/dist/assets/Button-CQLKwjHl.js +109 -0
- package/dist/assets/ChannelsView-Bdv3P2Rv.js +1 -0
- package/dist/assets/ChatView-BGSDL0hI.js +142 -0
- package/dist/assets/{ChatView-BVHQ6KhU.css → ChatView-CGsFaSiv.css} +1 -1
- package/dist/assets/Close-inn9RP7R.js +45 -0
- package/dist/assets/FormItem-BvJieJmq.js +110 -0
- package/dist/assets/Input-edKmVCeM.js +234 -0
- package/dist/assets/InputNumber-BpYEJnKY.js +13 -0
- package/dist/assets/JobsView-Dx4HmGC6.js +2 -0
- package/dist/assets/LoginView-BHThbj0n.css +1 -0
- package/dist/assets/LoginView-CIQSZ6bh.js +1 -0
- package/dist/assets/LogsView-nn7t6RGX.js +1 -0
- package/dist/assets/{MarkdownRenderer-C2pkccH2.js → MarkdownRenderer-Yw5JS7CE.js} +9 -9
- package/dist/assets/MemoryView-CE9P7mef.js +5 -0
- package/dist/assets/Modal-CDRYujZp.js +232 -0
- package/dist/assets/ModelsView-B72PAvvd.js +1 -0
- package/dist/assets/Popover-CRhyj79I.js +117 -0
- package/dist/assets/Select-CXQmv_5e.js +340 -0
- package/dist/assets/SettingRow-B3O4TYKh.js +1 -0
- package/dist/assets/SettingsView-BF2Uh-Eo.js +352 -0
- package/dist/assets/SkillsView-Abm6Dt2r.css +1 -0
- package/dist/assets/SkillsView-CeUPV9g8.js +1 -0
- package/dist/assets/Spin-COypV4Iq.js +43 -0
- package/dist/assets/Suffix-Bs0SC_yA.js +101 -0
- package/dist/assets/Switch-BcUqwhfi.js +102 -0
- package/dist/assets/Tag-CVO-_zgr.js +71 -0
- package/dist/assets/Tooltip-BljrRE17.js +1 -0
- package/dist/assets/UsageView-CFH6hwxE.js +1 -0
- package/dist/assets/_plugin-vue_export-helper-DJRCopG_.js +3 -0
- package/dist/assets/app-BcCNNvPk.js +1 -0
- package/dist/assets/app-CMJknO_z.js +1 -0
- package/dist/assets/browser-BuJOvks2.js +47 -0
- package/dist/assets/chat-DIeO-6BT.js +6 -0
- package/dist/assets/context-C8Jv60vX.js +1 -0
- package/dist/assets/index-BZ3NfTDJ.css +1 -0
- package/dist/assets/index-Bj9YOu02.js +306 -0
- package/dist/assets/jobs-CnB9OiiZ.js +1 -0
- package/dist/assets/logo-CiQBpLPw.js +1 -0
- package/dist/assets/pinia-YU9i-6Bb.js +1 -0
- package/dist/assets/router--r9mOZY5.js +4 -0
- package/dist/assets/{sessions-DYkP_X2v.js → sessions-COjIc6fz.js} +1 -1
- package/dist/assets/{skills-C6QBmS9j.js → skills-C4yD0aCK.js} +1 -1
- package/dist/assets/use-message-D8bO1GLN.js +1 -0
- package/dist/index.html +18 -18
- package/dist/server/index.js +104 -61
- package/dist/server/routes/filesystem.js +38 -0
- package/dist/server/services/auth.d.ts +9 -0
- package/dist/server/services/auth.js +65 -0
- package/dist/server/services/hermes-cli.js +13 -1
- package/package.json +2 -2
- package/dist/assets/Button-CpNld4Mc.js +0 -109
- package/dist/assets/ChannelsView-BGXB46ZU.js +0 -1
- package/dist/assets/ChatView-CaO-j1NR.js +0 -142
- package/dist/assets/Close-BAvirVyH.js +0 -45
- package/dist/assets/FormItem-DUC1YCrh.js +0 -110
- package/dist/assets/Input-CCmp4iGM.js +0 -234
- package/dist/assets/InputNumber-DpIdrMEW.js +0 -13
- package/dist/assets/JobsView-t5o1pB0r.js +0 -2
- package/dist/assets/LogsView-QqOV3ZEf.js +0 -1
- package/dist/assets/MemoryView-oeAn8ZfB.js +0 -5
- package/dist/assets/Modal-BljFqAJF.js +0 -232
- package/dist/assets/ModelsView-DvK44HBy.js +0 -1
- package/dist/assets/Popover-BQMR8Xxo.js +0 -117
- package/dist/assets/Select-D33SMWcz.js +0 -340
- package/dist/assets/SettingRow-BxCsRfGG.js +0 -102
- package/dist/assets/SettingsView-CK9ArFcg.js +0 -352
- package/dist/assets/SkillsView-BvNhRbMq.css +0 -1
- package/dist/assets/SkillsView-_z2SQ9kJ.js +0 -1
- package/dist/assets/Spin-CwbBDHwW.js +0 -43
- package/dist/assets/Suffix-CKUJBJSi.js +0 -101
- package/dist/assets/Tag-87KswiOb.js +0 -71
- package/dist/assets/Tooltip-CuLVJgy8.js +0 -1
- package/dist/assets/UsageView-COiUupLe.js +0 -1
- package/dist/assets/_plugin-vue_export-helper-C7dadZ10.js +0 -49
- package/dist/assets/app-DX-WvBe8.js +0 -1
- package/dist/assets/app-DwI_Lyfm.js +0 -1
- package/dist/assets/chat-De2jGIM6.js +0 -6
- package/dist/assets/client-D-w1KhaU.js +0 -1
- package/dist/assets/context-vjXbZCu8.js +0 -1
- package/dist/assets/index-D3MGnlpF.js +0 -307
- package/dist/assets/index-DCNlSGk-.css +0 -1
- package/dist/assets/jobs-B2WdYQNb.js +0 -1
- package/dist/assets/pinia-B4dETPKk.js +0 -1
- package/dist/assets/preload-helper-D4M6sveU.js +0 -1
- package/dist/assets/use-message-BeTKmVAO.js +0 -1
- package/dist/assets/vue.runtime.esm-bundler-BoqZ7fRe.js +0 -3
- /package/dist/{assets/logo-BAarh-tH.png → logo.png} +0 -0
package/dist/server/index.js
CHANGED
|
@@ -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
|
-
//
|
|
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 {
|
|
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
|
|
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') &&
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
|
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('
|
|
197
|
+
console.log('✗ config.yaml not found');
|
|
125
198
|
return;
|
|
126
199
|
}
|
|
127
200
|
const content = readFileSync(configPath, 'utf-8');
|
|
128
|
-
const
|
|
129
|
-
if (!
|
|
130
|
-
|
|
131
|
-
if (!
|
|
132
|
-
|
|
133
|
-
const api =
|
|
134
|
-
let
|
|
135
|
-
for (const [
|
|
136
|
-
if (api[
|
|
137
|
-
api[
|
|
138
|
-
|
|
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 (!
|
|
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
|
-
|
|
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('
|
|
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
|
-
|
|
231
|
+
catch { }
|
|
232
|
+
console.log('⚠ Gateway not running, starting...');
|
|
189
233
|
try {
|
|
190
|
-
|
|
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(
|
|
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('
|
|
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,65 @@
|
|
|
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 ') ? auth.slice(7) : '';
|
|
57
|
+
if (!provided || provided !== token) {
|
|
58
|
+
ctx.status = 401;
|
|
59
|
+
ctx.set('Content-Type', 'application/json');
|
|
60
|
+
ctx.body = { error: 'Unauthorized' };
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
await next();
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -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.
|
|
3
|
+
"version": "0.2.3",
|
|
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
|
|
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,109 +0,0 @@
|
|
|
1
|
-
import{$ as e,E as t,M as n,S as r,k as i,m as a,n as o,r as s,rt as c,w as l}from"./vue.runtime.esm-bundler-BoqZ7fRe.js";import{$ as u,B as d,J as f,Q as p,V as m,W as h,d as g,dt as _,f as v,ft as y,i as b,l as x,lt as S,n as C,nt as w,o as T,ot as E,q as D,r as O,rt as k,s as A,st as j,tt as M,u as N,ut as P,z as F}from"./_plugin-vue_export-helper-C7dadZ10.js";function I(e){return e.replace(/#|\(|\)|,|\s|\./g,`_`)}var L=r({name:`FadeInExpandTransition`,props:{appear:Boolean,group:Boolean,mode:String,onLeave:Function,onAfterLeave:Function,onAfterEnter:Function,width:Boolean,reverse:Boolean},setup(e,{slots:t}){function n(t){e.width?t.style.maxWidth=`${t.offsetWidth}px`:t.style.maxHeight=`${t.offsetHeight}px`,t.offsetWidth}function r(t){e.width?t.style.maxWidth=`0`:t.style.maxHeight=`0`,t.offsetWidth;let{onLeave:n}=e;n&&n()}function i(t){e.width?t.style.maxWidth=``:t.style.maxHeight=``;let{onAfterLeave:n}=e;n&&n()}function a(t){if(t.style.transition=`none`,e.width){let e=t.offsetWidth;t.style.maxWidth=`0`,t.offsetWidth,t.style.transition=``,t.style.maxWidth=`${e}px`}else if(e.reverse)t.style.maxHeight=`${t.offsetHeight}px`,t.offsetHeight,t.style.transition=``,t.style.maxHeight=`0`;else{let e=t.offsetHeight;t.style.maxHeight=`0`,t.offsetWidth,t.style.transition=``,t.style.maxHeight=`${e}px`}t.offsetWidth}function c(t){var n;e.width?t.style.maxWidth=``:e.reverse||(t.style.maxHeight=``),(n=e.onAfterEnter)==null||n.call(e)}return()=>{let{group:u,width:d,appear:f,mode:p}=e,m=u?s:o,h={name:d?`fade-in-width-expand-transition`:`fade-in-height-expand-transition`,appear:f,onEnter:a,onAfterEnter:c,onBeforeLeave:n,onLeave:r,onAfterLeave:i};return u||(h.mode=p),l(m,h,t)}}}),{cubicBezierEaseInOut:R}=g;function z({duration:e=`.2s`,delay:t=`.1s`}={}){return[E(`&.fade-in-width-expand-transition-leave-from, &.fade-in-width-expand-transition-enter-to`,{opacity:1}),E(`&.fade-in-width-expand-transition-leave-to, &.fade-in-width-expand-transition-enter-from`,`
|
|
2
|
-
opacity: 0!important;
|
|
3
|
-
margin-left: 0!important;
|
|
4
|
-
margin-right: 0!important;
|
|
5
|
-
`),E(`&.fade-in-width-expand-transition-leave-active`,`
|
|
6
|
-
overflow: hidden;
|
|
7
|
-
transition:
|
|
8
|
-
opacity ${e} ${R},
|
|
9
|
-
max-width ${e} ${R} ${t},
|
|
10
|
-
margin-left ${e} ${R} ${t},
|
|
11
|
-
margin-right ${e} ${R} ${t};
|
|
12
|
-
`),E(`&.fade-in-width-expand-transition-enter-active`,`
|
|
13
|
-
overflow: hidden;
|
|
14
|
-
transition:
|
|
15
|
-
opacity ${e} ${R} ${t},
|
|
16
|
-
max-width ${e} ${R},
|
|
17
|
-
margin-left ${e} ${R},
|
|
18
|
-
margin-right ${e} ${R};
|
|
19
|
-
`)]}var B=j(`base-wave`,`
|
|
20
|
-
position: absolute;
|
|
21
|
-
left: 0;
|
|
22
|
-
right: 0;
|
|
23
|
-
top: 0;
|
|
24
|
-
bottom: 0;
|
|
25
|
-
border-radius: inherit;
|
|
26
|
-
`),V=r({name:`BaseWave`,props:{clsPrefix:{type:String,required:!0}},setup(t){N(`-base-wave`,B,c(t,`clsPrefix`));let r=e(null),a=e(!1),o=null;return n(()=>{o!==null&&window.clearTimeout(o)}),{active:a,selfRef:r,play(){o!==null&&(window.clearTimeout(o),a.value=!1,o=null),i(()=>{var e;(e=r.value)==null||e.offsetHeight,a.value=!0,o=window.setTimeout(()=>{a.value=!1,o=null},1e3)})}}},render(){let{clsPrefix:e}=this;return l(`div`,{ref:`selfRef`,"aria-hidden":!0,class:[`${e}-base-wave`,this.active&&`${e}-base-wave--active`]})}});function H(e){return k(e,[255,255,255,.16])}function U(e){return k(e,[0,0,0,.12])}var W=u(`n-button-group`),G={paddingTiny:`0 6px`,paddingSmall:`0 10px`,paddingMedium:`0 14px`,paddingLarge:`0 18px`,paddingRoundTiny:`0 10px`,paddingRoundSmall:`0 14px`,paddingRoundMedium:`0 18px`,paddingRoundLarge:`0 22px`,iconMarginTiny:`6px`,iconMarginSmall:`6px`,iconMarginMedium:`6px`,iconMarginLarge:`6px`,iconSizeTiny:`14px`,iconSizeSmall:`18px`,iconSizeMedium:`18px`,iconSizeLarge:`20px`,rippleDuration:`.6s`};function K(e){let{heightTiny:t,heightSmall:n,heightMedium:r,heightLarge:i,borderRadius:a,fontSizeTiny:o,fontSizeSmall:s,fontSizeMedium:c,fontSizeLarge:l,opacityDisabled:u,textColor2:d,textColor3:f,primaryColorHover:p,primaryColorPressed:m,borderColor:h,primaryColor:g,baseColor:_,infoColor:v,infoColorHover:y,infoColorPressed:b,successColor:x,successColorHover:S,successColorPressed:C,warningColor:w,warningColorHover:T,warningColorPressed:E,errorColor:D,errorColorHover:O,errorColorPressed:k,fontWeight:A,buttonColor2:j,buttonColor2Hover:M,buttonColor2Pressed:N,fontWeightStrong:P}=e;return Object.assign(Object.assign({},G),{heightTiny:t,heightSmall:n,heightMedium:r,heightLarge:i,borderRadiusTiny:a,borderRadiusSmall:a,borderRadiusMedium:a,borderRadiusLarge:a,fontSizeTiny:o,fontSizeSmall:s,fontSizeMedium:c,fontSizeLarge:l,opacityDisabled:u,colorOpacitySecondary:`0.16`,colorOpacitySecondaryHover:`0.22`,colorOpacitySecondaryPressed:`0.28`,colorSecondary:j,colorSecondaryHover:M,colorSecondaryPressed:N,colorTertiary:j,colorTertiaryHover:M,colorTertiaryPressed:N,colorQuaternary:`#0000`,colorQuaternaryHover:M,colorQuaternaryPressed:N,color:`#0000`,colorHover:`#0000`,colorPressed:`#0000`,colorFocus:`#0000`,colorDisabled:`#0000`,textColor:d,textColorTertiary:f,textColorHover:p,textColorPressed:m,textColorFocus:p,textColorDisabled:d,textColorText:d,textColorTextHover:p,textColorTextPressed:m,textColorTextFocus:p,textColorTextDisabled:d,textColorGhost:d,textColorGhostHover:p,textColorGhostPressed:m,textColorGhostFocus:p,textColorGhostDisabled:d,border:`1px solid ${h}`,borderHover:`1px solid ${p}`,borderPressed:`1px solid ${m}`,borderFocus:`1px solid ${p}`,borderDisabled:`1px solid ${h}`,rippleColor:g,colorPrimary:g,colorHoverPrimary:p,colorPressedPrimary:m,colorFocusPrimary:p,colorDisabledPrimary:g,textColorPrimary:_,textColorHoverPrimary:_,textColorPressedPrimary:_,textColorFocusPrimary:_,textColorDisabledPrimary:_,textColorTextPrimary:g,textColorTextHoverPrimary:p,textColorTextPressedPrimary:m,textColorTextFocusPrimary:p,textColorTextDisabledPrimary:d,textColorGhostPrimary:g,textColorGhostHoverPrimary:p,textColorGhostPressedPrimary:m,textColorGhostFocusPrimary:p,textColorGhostDisabledPrimary:g,borderPrimary:`1px solid ${g}`,borderHoverPrimary:`1px solid ${p}`,borderPressedPrimary:`1px solid ${m}`,borderFocusPrimary:`1px solid ${p}`,borderDisabledPrimary:`1px solid ${g}`,rippleColorPrimary:g,colorInfo:v,colorHoverInfo:y,colorPressedInfo:b,colorFocusInfo:y,colorDisabledInfo:v,textColorInfo:_,textColorHoverInfo:_,textColorPressedInfo:_,textColorFocusInfo:_,textColorDisabledInfo:_,textColorTextInfo:v,textColorTextHoverInfo:y,textColorTextPressedInfo:b,textColorTextFocusInfo:y,textColorTextDisabledInfo:d,textColorGhostInfo:v,textColorGhostHoverInfo:y,textColorGhostPressedInfo:b,textColorGhostFocusInfo:y,textColorGhostDisabledInfo:v,borderInfo:`1px solid ${v}`,borderHoverInfo:`1px solid ${y}`,borderPressedInfo:`1px solid ${b}`,borderFocusInfo:`1px solid ${y}`,borderDisabledInfo:`1px solid ${v}`,rippleColorInfo:v,colorSuccess:x,colorHoverSuccess:S,colorPressedSuccess:C,colorFocusSuccess:S,colorDisabledSuccess:x,textColorSuccess:_,textColorHoverSuccess:_,textColorPressedSuccess:_,textColorFocusSuccess:_,textColorDisabledSuccess:_,textColorTextSuccess:x,textColorTextHoverSuccess:S,textColorTextPressedSuccess:C,textColorTextFocusSuccess:S,textColorTextDisabledSuccess:d,textColorGhostSuccess:x,textColorGhostHoverSuccess:S,textColorGhostPressedSuccess:C,textColorGhostFocusSuccess:S,textColorGhostDisabledSuccess:x,borderSuccess:`1px solid ${x}`,borderHoverSuccess:`1px solid ${S}`,borderPressedSuccess:`1px solid ${C}`,borderFocusSuccess:`1px solid ${S}`,borderDisabledSuccess:`1px solid ${x}`,rippleColorSuccess:x,colorWarning:w,colorHoverWarning:T,colorPressedWarning:E,colorFocusWarning:T,colorDisabledWarning:w,textColorWarning:_,textColorHoverWarning:_,textColorPressedWarning:_,textColorFocusWarning:_,textColorDisabledWarning:_,textColorTextWarning:w,textColorTextHoverWarning:T,textColorTextPressedWarning:E,textColorTextFocusWarning:T,textColorTextDisabledWarning:d,textColorGhostWarning:w,textColorGhostHoverWarning:T,textColorGhostPressedWarning:E,textColorGhostFocusWarning:T,textColorGhostDisabledWarning:w,borderWarning:`1px solid ${w}`,borderHoverWarning:`1px solid ${T}`,borderPressedWarning:`1px solid ${E}`,borderFocusWarning:`1px solid ${T}`,borderDisabledWarning:`1px solid ${w}`,rippleColorWarning:w,colorError:D,colorHoverError:O,colorPressedError:k,colorFocusError:O,colorDisabledError:D,textColorError:_,textColorHoverError:_,textColorPressedError:_,textColorFocusError:_,textColorDisabledError:_,textColorTextError:D,textColorTextHoverError:O,textColorTextPressedError:k,textColorTextFocusError:O,textColorTextDisabledError:d,textColorGhostError:D,textColorGhostHoverError:O,textColorGhostPressedError:k,textColorGhostFocusError:O,textColorGhostDisabledError:D,borderError:`1px solid ${D}`,borderHoverError:`1px solid ${O}`,borderPressedError:`1px solid ${k}`,borderFocusError:`1px solid ${O}`,borderDisabledError:`1px solid ${D}`,rippleColorError:D,waveOpacity:`0.6`,fontWeight:A,fontWeightStrong:P})}var q={name:`Button`,common:O,self:K},J=E([j(`button`,`
|
|
27
|
-
margin: 0;
|
|
28
|
-
font-weight: var(--n-font-weight);
|
|
29
|
-
line-height: 1;
|
|
30
|
-
font-family: inherit;
|
|
31
|
-
padding: var(--n-padding);
|
|
32
|
-
height: var(--n-height);
|
|
33
|
-
font-size: var(--n-font-size);
|
|
34
|
-
border-radius: var(--n-border-radius);
|
|
35
|
-
color: var(--n-text-color);
|
|
36
|
-
background-color: var(--n-color);
|
|
37
|
-
width: var(--n-width);
|
|
38
|
-
white-space: nowrap;
|
|
39
|
-
outline: none;
|
|
40
|
-
position: relative;
|
|
41
|
-
z-index: auto;
|
|
42
|
-
border: none;
|
|
43
|
-
display: inline-flex;
|
|
44
|
-
flex-wrap: nowrap;
|
|
45
|
-
flex-shrink: 0;
|
|
46
|
-
align-items: center;
|
|
47
|
-
justify-content: center;
|
|
48
|
-
user-select: none;
|
|
49
|
-
-webkit-user-select: none;
|
|
50
|
-
text-align: center;
|
|
51
|
-
cursor: pointer;
|
|
52
|
-
text-decoration: none;
|
|
53
|
-
transition:
|
|
54
|
-
color .3s var(--n-bezier),
|
|
55
|
-
background-color .3s var(--n-bezier),
|
|
56
|
-
opacity .3s var(--n-bezier),
|
|
57
|
-
border-color .3s var(--n-bezier);
|
|
58
|
-
`,[P(`color`,[S(`border`,{borderColor:`var(--n-border-color)`}),P(`disabled`,[S(`border`,{borderColor:`var(--n-border-color-disabled)`})]),_(`disabled`,[E(`&:focus`,[S(`state-border`,{borderColor:`var(--n-border-color-focus)`})]),E(`&:hover`,[S(`state-border`,{borderColor:`var(--n-border-color-hover)`})]),E(`&:active`,[S(`state-border`,{borderColor:`var(--n-border-color-pressed)`})]),P(`pressed`,[S(`state-border`,{borderColor:`var(--n-border-color-pressed)`})])])]),P(`disabled`,{backgroundColor:`var(--n-color-disabled)`,color:`var(--n-text-color-disabled)`},[S(`border`,{border:`var(--n-border-disabled)`})]),_(`disabled`,[E(`&:focus`,{backgroundColor:`var(--n-color-focus)`,color:`var(--n-text-color-focus)`},[S(`state-border`,{border:`var(--n-border-focus)`})]),E(`&:hover`,{backgroundColor:`var(--n-color-hover)`,color:`var(--n-text-color-hover)`},[S(`state-border`,{border:`var(--n-border-hover)`})]),E(`&:active`,{backgroundColor:`var(--n-color-pressed)`,color:`var(--n-text-color-pressed)`},[S(`state-border`,{border:`var(--n-border-pressed)`})]),P(`pressed`,{backgroundColor:`var(--n-color-pressed)`,color:`var(--n-text-color-pressed)`},[S(`state-border`,{border:`var(--n-border-pressed)`})])]),P(`loading`,`cursor: wait;`),j(`base-wave`,`
|
|
59
|
-
pointer-events: none;
|
|
60
|
-
top: 0;
|
|
61
|
-
right: 0;
|
|
62
|
-
bottom: 0;
|
|
63
|
-
left: 0;
|
|
64
|
-
animation-iteration-count: 1;
|
|
65
|
-
animation-duration: var(--n-ripple-duration);
|
|
66
|
-
animation-timing-function: var(--n-bezier-ease-out), var(--n-bezier-ease-out);
|
|
67
|
-
`,[P(`active`,{zIndex:1,animationName:`button-wave-spread, button-wave-opacity`})]),p&&`MozBoxSizing`in document.createElement(`div`).style?E(`&::moz-focus-inner`,{border:0}):null,S(`border, state-border`,`
|
|
68
|
-
position: absolute;
|
|
69
|
-
left: 0;
|
|
70
|
-
top: 0;
|
|
71
|
-
right: 0;
|
|
72
|
-
bottom: 0;
|
|
73
|
-
border-radius: inherit;
|
|
74
|
-
transition: border-color .3s var(--n-bezier);
|
|
75
|
-
pointer-events: none;
|
|
76
|
-
`),S(`border`,`
|
|
77
|
-
border: var(--n-border);
|
|
78
|
-
`),S(`state-border`,`
|
|
79
|
-
border: var(--n-border);
|
|
80
|
-
border-color: #0000;
|
|
81
|
-
z-index: 1;
|
|
82
|
-
`),S(`icon`,`
|
|
83
|
-
margin: var(--n-icon-margin);
|
|
84
|
-
margin-left: 0;
|
|
85
|
-
height: var(--n-icon-size);
|
|
86
|
-
width: var(--n-icon-size);
|
|
87
|
-
max-width: var(--n-icon-size);
|
|
88
|
-
font-size: var(--n-icon-size);
|
|
89
|
-
position: relative;
|
|
90
|
-
flex-shrink: 0;
|
|
91
|
-
`,[j(`icon-slot`,`
|
|
92
|
-
height: var(--n-icon-size);
|
|
93
|
-
width: var(--n-icon-size);
|
|
94
|
-
position: absolute;
|
|
95
|
-
left: 0;
|
|
96
|
-
top: 50%;
|
|
97
|
-
transform: translateY(-50%);
|
|
98
|
-
display: flex;
|
|
99
|
-
align-items: center;
|
|
100
|
-
justify-content: center;
|
|
101
|
-
`,[T({top:`50%`,originalTransform:`translateY(-50%)`})]),z()]),S(`content`,`
|
|
102
|
-
display: flex;
|
|
103
|
-
align-items: center;
|
|
104
|
-
flex-wrap: nowrap;
|
|
105
|
-
min-width: 0;
|
|
106
|
-
`,[E(`~`,[S(`icon`,{margin:`var(--n-icon-margin)`,marginRight:0})])]),P(`block`,`
|
|
107
|
-
display: flex;
|
|
108
|
-
width: 100%;
|
|
109
|
-
`),P(`dashed`,[S(`border, state-border`,{borderStyle:`dashed !important`})]),P(`disabled`,{cursor:`not-allowed`,opacity:`var(--n-opacity-disabled)`})]),E(`@keyframes button-wave-spread`,{from:{boxShadow:`0 0 0.5px 0 var(--n-ripple-color)`},to:{boxShadow:`0 0 0.5px 4.5px var(--n-ripple-color)`}}),E(`@keyframes button-wave-opacity`,{from:{opacity:`var(--n-wave-opacity)`},to:{opacity:0}})]),Y=r({name:`Button`,props:Object.assign(Object.assign({},x.props),{color:String,textColor:String,text:Boolean,block:Boolean,loading:Boolean,disabled:Boolean,circle:Boolean,size:String,ghost:Boolean,round:Boolean,secondary:Boolean,tertiary:Boolean,quaternary:Boolean,strong:Boolean,focusable:{type:Boolean,default:!0},keyboard:{type:Boolean,default:!0},tag:{type:String,default:`button`},type:{type:String,default:`default`},dashed:Boolean,renderIcon:Function,iconPlacement:{type:String,default:`left`},attrType:{type:String,default:`button`},bordered:{type:Boolean,default:!0},onClick:[Function,Array],nativeFocusBehavior:{type:Boolean,default:!C},spinProps:Object}),slots:Object,setup(n){let r=e(null),i=e(null),o=e(!1),s=M(()=>!n.quaternary&&!n.tertiary&&!n.secondary&&!n.text&&(!n.color||n.ghost||n.dashed)&&n.bordered),c=t(W,{}),{inlineThemeDisabled:l,mergedClsPrefixRef:u,mergedRtlRef:p,mergedComponentPropsRef:h}=m(n),{mergedSizeRef:g}=F({},{defaultSize:`medium`,mergedSize:e=>{let{size:t}=n;if(t)return t;let{size:r}=c;if(r)return r;let{mergedSize:i}=e||{};return i?i.value:h?.value?.Button?.size||`medium`}}),_=a(()=>n.focusable&&!n.disabled),b=e=>{var t;_.value||e.preventDefault(),!n.nativeFocusBehavior&&(e.preventDefault(),!n.disabled&&_.value&&((t=r.value)==null||t.focus({preventScroll:!0})))},S=e=>{var t;if(!n.disabled&&!n.loading){let{onClick:r}=n;r&&f(r,e),n.text||(t=i.value)==null||t.play()}},C=e=>{switch(e.key){case`Enter`:if(!n.keyboard)return;o.value=!1}},T=e=>{switch(e.key){case`Enter`:if(!n.keyboard||n.loading){e.preventDefault();return}o.value=!0}},E=()=>{o.value=!1},D=x(`Button`,`-button`,J,q,n,u),O=v(`Button`,p,u),k=a(()=>{let{common:{cubicBezierEaseInOut:e,cubicBezierEaseOut:t},self:r}=D.value,{rippleDuration:i,opacityDisabled:a,fontWeight:o,fontWeightStrong:s}=r,c=g.value,{dashed:l,type:u,ghost:d,text:f,color:p,round:m,circle:h,textColor:_,secondary:v,tertiary:b,quaternary:x,strong:S}=n,C={"--n-font-weight":S?s:o},T={"--n-color":`initial`,"--n-color-hover":`initial`,"--n-color-pressed":`initial`,"--n-color-focus":`initial`,"--n-color-disabled":`initial`,"--n-ripple-color":`initial`,"--n-text-color":`initial`,"--n-text-color-hover":`initial`,"--n-text-color-pressed":`initial`,"--n-text-color-focus":`initial`,"--n-text-color-disabled":`initial`},E=u===`tertiary`,O=u===`default`,k=E?`default`:u;if(f){let e=_||p;T={"--n-color":`#0000`,"--n-color-hover":`#0000`,"--n-color-pressed":`#0000`,"--n-color-focus":`#0000`,"--n-color-disabled":`#0000`,"--n-ripple-color":`#0000`,"--n-text-color":e||r[y(`textColorText`,k)],"--n-text-color-hover":e?H(e):r[y(`textColorTextHover`,k)],"--n-text-color-pressed":e?U(e):r[y(`textColorTextPressed`,k)],"--n-text-color-focus":e?H(e):r[y(`textColorTextHover`,k)],"--n-text-color-disabled":e||r[y(`textColorTextDisabled`,k)]}}else if(d||l){let e=_||p;T={"--n-color":`#0000`,"--n-color-hover":`#0000`,"--n-color-pressed":`#0000`,"--n-color-focus":`#0000`,"--n-color-disabled":`#0000`,"--n-ripple-color":p||r[y(`rippleColor`,k)],"--n-text-color":e||r[y(`textColorGhost`,k)],"--n-text-color-hover":e?H(e):r[y(`textColorGhostHover`,k)],"--n-text-color-pressed":e?U(e):r[y(`textColorGhostPressed`,k)],"--n-text-color-focus":e?H(e):r[y(`textColorGhostHover`,k)],"--n-text-color-disabled":e||r[y(`textColorGhostDisabled`,k)]}}else if(v){let e=O?r.textColor:E?r.textColorTertiary:r[y(`color`,k)],t=p||e,n=u!==`default`&&u!==`tertiary`;T={"--n-color":n?w(t,{alpha:Number(r.colorOpacitySecondary)}):r.colorSecondary,"--n-color-hover":n?w(t,{alpha:Number(r.colorOpacitySecondaryHover)}):r.colorSecondaryHover,"--n-color-pressed":n?w(t,{alpha:Number(r.colorOpacitySecondaryPressed)}):r.colorSecondaryPressed,"--n-color-focus":n?w(t,{alpha:Number(r.colorOpacitySecondaryHover)}):r.colorSecondaryHover,"--n-color-disabled":r.colorSecondary,"--n-ripple-color":`#0000`,"--n-text-color":t,"--n-text-color-hover":t,"--n-text-color-pressed":t,"--n-text-color-focus":t,"--n-text-color-disabled":t}}else if(b||x){let e=O?r.textColor:E?r.textColorTertiary:r[y(`color`,k)],t=p||e;b?(T[`--n-color`]=r.colorTertiary,T[`--n-color-hover`]=r.colorTertiaryHover,T[`--n-color-pressed`]=r.colorTertiaryPressed,T[`--n-color-focus`]=r.colorSecondaryHover,T[`--n-color-disabled`]=r.colorTertiary):(T[`--n-color`]=r.colorQuaternary,T[`--n-color-hover`]=r.colorQuaternaryHover,T[`--n-color-pressed`]=r.colorQuaternaryPressed,T[`--n-color-focus`]=r.colorQuaternaryHover,T[`--n-color-disabled`]=r.colorQuaternary),T[`--n-ripple-color`]=`#0000`,T[`--n-text-color`]=t,T[`--n-text-color-hover`]=t,T[`--n-text-color-pressed`]=t,T[`--n-text-color-focus`]=t,T[`--n-text-color-disabled`]=t}else T={"--n-color":p||r[y(`color`,k)],"--n-color-hover":p?H(p):r[y(`colorHover`,k)],"--n-color-pressed":p?U(p):r[y(`colorPressed`,k)],"--n-color-focus":p?H(p):r[y(`colorFocus`,k)],"--n-color-disabled":p||r[y(`colorDisabled`,k)],"--n-ripple-color":p||r[y(`rippleColor`,k)],"--n-text-color":_||(p?r.textColorPrimary:E?r.textColorTertiary:r[y(`textColor`,k)]),"--n-text-color-hover":_||(p?r.textColorHoverPrimary:r[y(`textColorHover`,k)]),"--n-text-color-pressed":_||(p?r.textColorPressedPrimary:r[y(`textColorPressed`,k)]),"--n-text-color-focus":_||(p?r.textColorFocusPrimary:r[y(`textColorFocus`,k)]),"--n-text-color-disabled":_||(p?r.textColorDisabledPrimary:r[y(`textColorDisabled`,k)])};let A={"--n-border":`initial`,"--n-border-hover":`initial`,"--n-border-pressed":`initial`,"--n-border-focus":`initial`,"--n-border-disabled":`initial`};A=f?{"--n-border":`none`,"--n-border-hover":`none`,"--n-border-pressed":`none`,"--n-border-focus":`none`,"--n-border-disabled":`none`}:{"--n-border":r[y(`border`,k)],"--n-border-hover":r[y(`borderHover`,k)],"--n-border-pressed":r[y(`borderPressed`,k)],"--n-border-focus":r[y(`borderFocus`,k)],"--n-border-disabled":r[y(`borderDisabled`,k)]};let{[y(`height`,c)]:j,[y(`fontSize`,c)]:M,[y(`padding`,c)]:N,[y(`paddingRound`,c)]:P,[y(`iconSize`,c)]:F,[y(`borderRadius`,c)]:I,[y(`iconMargin`,c)]:L,waveOpacity:R}=r,z={"--n-width":h&&!f?j:`initial`,"--n-height":f?`initial`:j,"--n-font-size":M,"--n-padding":h||f?`initial`:m?P:N,"--n-icon-size":F,"--n-icon-margin":L,"--n-border-radius":f?`initial`:h||m?j:I};return Object.assign(Object.assign(Object.assign(Object.assign({"--n-bezier":e,"--n-bezier-ease-out":t,"--n-ripple-duration":i,"--n-opacity-disabled":a,"--n-wave-opacity":R},C),T),A),z)}),A=l?d(`button`,a(()=>{let e=``,{dashed:t,type:r,ghost:i,text:a,color:o,round:s,circle:c,textColor:l,secondary:u,tertiary:d,quaternary:f,strong:p}=n;t&&(e+=`a`),i&&(e+=`b`),a&&(e+=`c`),s&&(e+=`d`),c&&(e+=`e`),u&&(e+=`f`),d&&(e+=`g`),f&&(e+=`h`),p&&(e+=`i`),o&&(e+=`j${I(o)}`),l&&(e+=`k${I(l)}`);let{value:m}=g;return e+=`l${m[0]}`,e+=`m${r[0]}`,e}),k,n):void 0;return{selfElRef:r,waveElRef:i,mergedClsPrefix:u,mergedFocusable:_,mergedSize:g,showBorder:s,enterPressed:o,rtlEnabled:O,handleMousedown:b,handleKeydown:T,handleBlur:E,handleKeyup:C,handleClick:S,customColorCssVars:a(()=>{let{color:e}=n;if(!e)return null;let t=H(e);return{"--n-border-color":e,"--n-border-color-hover":t,"--n-border-color-pressed":U(e),"--n-border-color-focus":t,"--n-border-color-disabled":e}}),cssVars:l?void 0:k,themeClass:A?.themeClass,onRender:A?.onRender}},render(){let{mergedClsPrefix:e,tag:t,onRender:n}=this;n?.();let r=D(this.$slots.default,t=>t&&l(`span`,{class:`${e}-button__content`},t));return l(t,{ref:`selfElRef`,class:[this.themeClass,`${e}-button`,`${e}-button--${this.type}-type`,`${e}-button--${this.mergedSize}-type`,this.rtlEnabled&&`${e}-button--rtl`,this.disabled&&`${e}-button--disabled`,this.block&&`${e}-button--block`,this.enterPressed&&`${e}-button--pressed`,!this.text&&this.dashed&&`${e}-button--dashed`,this.color&&`${e}-button--color`,this.secondary&&`${e}-button--secondary`,this.loading&&`${e}-button--loading`,this.ghost&&`${e}-button--ghost`],tabindex:this.mergedFocusable?0:-1,type:this.attrType,style:this.cssVars,disabled:this.disabled,onClick:this.handleClick,onBlur:this.handleBlur,onMousedown:this.handleMousedown,onKeyup:this.handleKeyup,onKeydown:this.handleKeydown},this.iconPlacement===`right`&&r,l(L,{width:!0},{default:()=>D(this.$slots.icon,t=>(this.loading||this.renderIcon||t)&&l(`span`,{class:`${e}-button__icon`,style:{margin:h(this.$slots.default)?`0`:``}},l(A,null,{default:()=>this.loading?l(b,Object.assign({clsPrefix:e,key:`loading`,class:`${e}-icon-slot`,strokeWidth:20},this.spinProps)):l(`div`,{key:`icon`,class:`${e}-icon-slot`,role:`none`},this.renderIcon?this.renderIcon():t)})))}),this.iconPlacement===`left`&&r,this.text?null:l(V,{ref:`waveElRef`,clsPrefix:e}),this.showBorder?l(`div`,{"aria-hidden":!0,class:`${e}-button__border`,style:this.customColorCssVars}):null,this.showBorder?l(`div`,{"aria-hidden":!0,class:`${e}-button__state-border`,style:this.customColorCssVars}):null)}}),X=Y;export{I as a,L as i,X as n,q as r,Y as t};
|