hermes-web-ui 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/assets/{Add-HK51AOcE.js → Add-CYFVC6GK.js} +1 -1
- package/dist/client/assets/{Button-sy1PzWPU.js → Button-Bls2FkVh.js} +1 -1
- package/dist/client/assets/{ChannelsView-Do43S3tP.css → ChannelsView-CSo2o-P4.css} +1 -1
- package/dist/client/assets/ChannelsView-hQeWN-ve.js +1 -0
- package/dist/client/assets/{ChatView-BZljWOsk.js → ChatView-C67INFi3.js} +2 -2
- package/dist/client/assets/{ChatView-DWJ1E8rg.css → ChatView-CtLv9X8G.css} +1 -1
- package/dist/client/assets/{Close-h76fWaJi.js → Close-CkAmZwHA.js} +1 -1
- package/dist/client/assets/{FormItem-DAkggFjx.js → FormItem-CO8nEllS.js} +1 -1
- package/dist/client/assets/{Input-BgeYIOdH.js → Input-CmTdqaW1.js} +1 -1
- package/dist/client/assets/{InputNumber-CP0Q1JN_.js → InputNumber-BVqiFQ5W.js} +1 -1
- package/dist/client/assets/JobsView-B0LZ2Ep0.js +2 -0
- package/dist/client/assets/{JobsView-CvuV9mZY.css → JobsView-CVx2Yv-y.css} +1 -1
- package/dist/client/assets/{LoginView-DR64ehSS.js → LoginView-BjqBXdDl.js} +1 -1
- package/dist/client/assets/{LogsView-De8hT0ry.js → LogsView-CXiJ_mte.js} +1 -1
- package/dist/client/assets/{MarkdownRenderer-CgO4HMET.js → MarkdownRenderer-CtI0yse1.js} +1 -1
- package/dist/client/assets/{MemoryView-vo6uIeGe.js → MemoryView-CjPn1pVR.js} +1 -1
- package/dist/client/assets/{Modal-D0bHwidv.js → Modal-apmj2qGK.js} +1 -1
- package/dist/client/assets/ModelsView-DXvahVC_.js +1 -0
- package/dist/client/assets/{Popconfirm-C4L6j7Ed.js → Popconfirm-B9XSMaYA.js} +1 -1
- package/dist/client/assets/{Popover-CSVNytD9.js → Popover-CjCb_fJl.js} +1 -1
- package/dist/client/assets/{ProfilesView-5N8GD-OY.js → ProfilesView-CmMfNg5X.js} +1 -1
- package/dist/client/assets/{Scrollbar-CP3UrDPW.js → Scrollbar-v6Ok23iG.js} +1 -1
- package/dist/client/assets/{Select-BX8K2ITf.js → Select-CDF2CEro.js} +1 -1
- package/dist/client/assets/{SettingRow-Dj1WGKUP.js → SettingRow-CSjwu__h.js} +1 -1
- package/dist/client/assets/{SettingsView-C78xbLXK.css → SettingsView-BIEQOPzq.css} +1 -1
- package/dist/client/assets/{SettingsView-8WKddMDg.js → SettingsView-BYedQhU5.js} +2 -2
- package/dist/client/assets/{SkillsView-huWlVVSd.js → SkillsView-B_MA4How.js} +1 -1
- package/dist/client/assets/{Spin-7qVct-fX.js → Spin-UqA8uGuf.js} +1 -1
- package/dist/client/assets/{Suffix-CTB2TVbZ.js → Suffix-iRME2DUp.js} +1 -1
- package/dist/client/assets/{Switch-DznAKpSq.js → Switch-B4za8e-x.js} +1 -1
- package/dist/client/assets/{TerminalView-D8h6hUON.js → TerminalView-C0xlWgsR.js} +1 -1
- package/dist/client/assets/{Tooltip-hZdU3QDl.js → Tooltip-C9kFaGpi.js} +1 -1
- package/dist/client/assets/{UsageView-c67PH6UD.js → UsageView-Df6TKjYG.js} +1 -1
- package/dist/client/assets/{Warning-ajVqmXLg.js → Warning-C--exCXL.js} +1 -1
- package/dist/client/assets/{_plugin-vue_export-helper-Cla2Sei2.js → _plugin-vue_export-helper-BPCSidQI.js} +1 -1
- package/dist/client/assets/{app-Dn_xFNgc.js → app-BEBfTlZP.js} +1 -1
- package/dist/client/assets/app-DoAgSphx.js +1 -0
- package/dist/client/assets/{browser-Bj_pylgC.js → browser-OtgUKGth.js} +1 -1
- package/dist/client/assets/{chat-oRYxV4zZ.js → chat-B8_g1FhX.js} +2 -2
- package/dist/client/assets/composables-VZZHak9F.js +1 -0
- package/dist/client/assets/{fade-in-scale-up.cssr-A5vydVRa.js → fade-in-scale-up.cssr-BbYEGcju.js} +1 -1
- package/dist/client/assets/index-DY7SeRWD.js +284 -0
- package/dist/client/assets/index-JeutuTe0.css +1 -0
- package/dist/client/assets/{jobs-D6sYt3p2.js → jobs-BRLhuQpK.js} +1 -1
- package/dist/client/assets/{light-s39H4IqC.js → light-8G-BZ0JM.js} +1 -1
- package/dist/client/assets/{light-BlRycys6.js → light-B3QvGN97.js} +1 -1
- package/dist/client/assets/{light-2H7dwk18.js → light-B83Z4vA9.js} +1 -1
- package/dist/client/assets/{light-BRnwbni5.js → light-Bmu6b0jg.js} +1 -1
- package/dist/client/assets/{light-DyxaUrhN.js → light-BtLlDltU.js} +1 -1
- package/dist/client/assets/{light-DTze2Byq.js → light-DDEUT7ek.js} +1 -1
- package/dist/client/assets/{pinia-0T1SpgZT.js → pinia-F-uLzgMS.js} +1 -1
- package/dist/client/assets/{profiles-CXj2WAET.js → profiles-DIJT1P0i.js} +1 -1
- package/dist/client/assets/{router-k7Mt11r-.js → router-Drg4uUER.js} +2 -2
- package/dist/client/assets/{sessions-C04iLbID.js → sessions-BwtYroiN.js} +1 -1
- package/dist/client/assets/{skills-CrJMmxLv.js → skills-BLhNwqgu.js} +1 -1
- package/dist/client/assets/use-compitable-BgSV79Sl.js +1 -0
- package/dist/client/assets/{use-message-kLSX34Jy.js → use-message-xhQoRXQV.js} +1 -1
- package/dist/client/assets/{useTheme-OKrDn5ib.js → useTheme-Dd5YNF4O.js} +1 -1
- package/dist/client/index.html +28 -28
- package/dist/server/index.js +2 -2
- package/dist/server/routes/hermes/config.js +15 -3
- package/dist/server/routes/hermes/filesystem.js +25 -5
- package/dist/server/routes/hermes/logs.js +1 -1
- package/dist/server/routes/hermes/profiles.js +1 -1
- package/dist/server/routes/hermes/sessions.js +1 -1
- package/dist/server/routes/hermes/weixin.js +2 -2
- package/dist/server/routes/webhook.js +1 -1
- package/dist/server/services/hermes/hermes-cli.d.ts +125 -0
- package/dist/server/services/hermes/hermes-cli.js +488 -0
- package/dist/server/services/hermes/hermes-profile.d.ts +22 -0
- package/dist/server/services/hermes/hermes-profile.js +60 -0
- package/dist/server/services/hermes/hermes.d.ts +40 -0
- package/dist/server/services/hermes/hermes.js +118 -0
- package/dist/server/shared/providers.js +2 -2
- package/package.json +4 -1
- package/dist/client/assets/ChannelsView-B3Iv1qGF.js +0 -1
- package/dist/client/assets/JobsView-C3MddyvL.js +0 -2
- package/dist/client/assets/ModelsView-Czh0QZMT.js +0 -1
- package/dist/client/assets/app-DuW413U3.js +0 -1
- package/dist/client/assets/composables-NK3hMwZN.js +0 -1
- package/dist/client/assets/index-8Iu2oDQ9.css +0 -1
- package/dist/client/assets/index-CNVL9pSf.js +0 -284
- package/dist/client/assets/use-compitable-CBi_h52X.js +0 -1
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listSessions = listSessions;
|
|
4
|
+
exports.getSession = getSession;
|
|
5
|
+
exports.deleteSession = deleteSession;
|
|
6
|
+
exports.renameSession = renameSession;
|
|
7
|
+
exports.getVersion = getVersion;
|
|
8
|
+
exports.startGateway = startGateway;
|
|
9
|
+
exports.startGatewayBackground = startGatewayBackground;
|
|
10
|
+
exports.restartGateway = restartGateway;
|
|
11
|
+
exports.stopGateway = stopGateway;
|
|
12
|
+
exports.listLogFiles = listLogFiles;
|
|
13
|
+
exports.readLogs = readLogs;
|
|
14
|
+
exports.listProfiles = listProfiles;
|
|
15
|
+
exports.getProfile = getProfile;
|
|
16
|
+
exports.createProfile = createProfile;
|
|
17
|
+
exports.deleteProfile = deleteProfile;
|
|
18
|
+
exports.renameProfile = renameProfile;
|
|
19
|
+
exports.useProfile = useProfile;
|
|
20
|
+
exports.exportProfile = exportProfile;
|
|
21
|
+
exports.setupReset = setupReset;
|
|
22
|
+
exports.importProfile = importProfile;
|
|
23
|
+
const child_process_1 = require("child_process");
|
|
24
|
+
const fs_1 = require("fs");
|
|
25
|
+
const util_1 = require("util");
|
|
26
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
27
|
+
const execOpts = { windowsHide: true };
|
|
28
|
+
const isDocker = (0, fs_1.existsSync)('/.dockerenv');
|
|
29
|
+
function resolveHermesBin() {
|
|
30
|
+
const envBin = process.env.HERMES_BIN?.trim();
|
|
31
|
+
if (envBin)
|
|
32
|
+
return envBin;
|
|
33
|
+
return 'hermes';
|
|
34
|
+
}
|
|
35
|
+
const HERMES_BIN = resolveHermesBin();
|
|
36
|
+
/**
|
|
37
|
+
* List sessions from Hermes CLI (without messages)
|
|
38
|
+
*/
|
|
39
|
+
async function listSessions(source, limit) {
|
|
40
|
+
const args = ['sessions', 'export', '-'];
|
|
41
|
+
if (source)
|
|
42
|
+
args.push('--source', source);
|
|
43
|
+
try {
|
|
44
|
+
const { stdout } = await execFileAsync(HERMES_BIN, args, {
|
|
45
|
+
maxBuffer: 50 * 1024 * 1024, // 50MB
|
|
46
|
+
timeout: 30000,
|
|
47
|
+
...execOpts,
|
|
48
|
+
});
|
|
49
|
+
const lines = stdout.trim().split('\n').filter(Boolean);
|
|
50
|
+
const sessions = [];
|
|
51
|
+
for (const line of lines) {
|
|
52
|
+
try {
|
|
53
|
+
const raw = JSON.parse(line);
|
|
54
|
+
let title = raw.title;
|
|
55
|
+
if (!title && raw.messages) {
|
|
56
|
+
const firstUser = raw.messages.find((m) => m.role === 'user');
|
|
57
|
+
if (firstUser?.content) {
|
|
58
|
+
const t = String(firstUser.content).slice(0, 40);
|
|
59
|
+
title = t + (String(firstUser.content).length > 40 ? '...' : '');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
sessions.push({
|
|
63
|
+
id: raw.id,
|
|
64
|
+
source: raw.source,
|
|
65
|
+
user_id: raw.user_id,
|
|
66
|
+
model: raw.model,
|
|
67
|
+
title,
|
|
68
|
+
started_at: raw.started_at,
|
|
69
|
+
ended_at: raw.ended_at,
|
|
70
|
+
end_reason: raw.end_reason,
|
|
71
|
+
message_count: raw.message_count,
|
|
72
|
+
tool_call_count: raw.tool_call_count,
|
|
73
|
+
input_tokens: raw.input_tokens,
|
|
74
|
+
output_tokens: raw.output_tokens,
|
|
75
|
+
cache_read_tokens: raw.cache_read_tokens || 0,
|
|
76
|
+
cache_write_tokens: raw.cache_write_tokens || 0,
|
|
77
|
+
reasoning_tokens: raw.reasoning_tokens || 0,
|
|
78
|
+
billing_provider: raw.billing_provider,
|
|
79
|
+
estimated_cost_usd: raw.estimated_cost_usd,
|
|
80
|
+
actual_cost_usd: raw.actual_cost_usd ?? null,
|
|
81
|
+
cost_status: raw.cost_status || '',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch { /* skip malformed lines */ }
|
|
85
|
+
}
|
|
86
|
+
// Sort by started_at descending
|
|
87
|
+
sessions.sort((a, b) => b.started_at - a.started_at);
|
|
88
|
+
if (limit && limit > 0) {
|
|
89
|
+
return sessions.slice(0, limit);
|
|
90
|
+
}
|
|
91
|
+
return sessions;
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
console.error('[Hermes CLI] sessions export failed:', err.message);
|
|
95
|
+
throw new Error(`Failed to list sessions: ${err.message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get a single session with messages from Hermes CLI
|
|
100
|
+
*/
|
|
101
|
+
async function getSession(id) {
|
|
102
|
+
const args = ['sessions', 'export', '-', '--session-id', id];
|
|
103
|
+
try {
|
|
104
|
+
const { stdout } = await execFileAsync(HERMES_BIN, args, {
|
|
105
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
106
|
+
timeout: 30000,
|
|
107
|
+
...execOpts,
|
|
108
|
+
});
|
|
109
|
+
const lines = stdout.trim().split('\n').filter(Boolean);
|
|
110
|
+
if (lines.length === 0)
|
|
111
|
+
return null;
|
|
112
|
+
if (!lines[0].startsWith('{'))
|
|
113
|
+
return null;
|
|
114
|
+
const raw = JSON.parse(lines[0]);
|
|
115
|
+
return {
|
|
116
|
+
id: raw.id,
|
|
117
|
+
source: raw.source,
|
|
118
|
+
user_id: raw.user_id,
|
|
119
|
+
model: raw.model,
|
|
120
|
+
title: raw.title,
|
|
121
|
+
started_at: raw.started_at,
|
|
122
|
+
ended_at: raw.ended_at,
|
|
123
|
+
end_reason: raw.end_reason,
|
|
124
|
+
message_count: raw.message_count,
|
|
125
|
+
tool_call_count: raw.tool_call_count,
|
|
126
|
+
input_tokens: raw.input_tokens,
|
|
127
|
+
output_tokens: raw.output_tokens,
|
|
128
|
+
cache_read_tokens: raw.cache_read_tokens || 0,
|
|
129
|
+
cache_write_tokens: raw.cache_write_tokens || 0,
|
|
130
|
+
reasoning_tokens: raw.reasoning_tokens || 0,
|
|
131
|
+
billing_provider: raw.billing_provider,
|
|
132
|
+
estimated_cost_usd: raw.estimated_cost_usd,
|
|
133
|
+
actual_cost_usd: raw.actual_cost_usd ?? null,
|
|
134
|
+
cost_status: raw.cost_status || '',
|
|
135
|
+
messages: raw.messages,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
if (err.code === 1 || err.status === 1)
|
|
140
|
+
return null;
|
|
141
|
+
console.error('[Hermes CLI] session export failed:', err.message);
|
|
142
|
+
throw new Error(`Failed to get session: ${err.message}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Delete a session from Hermes CLI
|
|
147
|
+
*/
|
|
148
|
+
async function deleteSession(id) {
|
|
149
|
+
try {
|
|
150
|
+
await execFileAsync(HERMES_BIN, ['sessions', 'delete', id, '--yes'], {
|
|
151
|
+
timeout: 10000,
|
|
152
|
+
...execOpts,
|
|
153
|
+
});
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
console.error('[Hermes CLI] session delete failed:', err.message);
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Rename a session title via Hermes CLI
|
|
163
|
+
*/
|
|
164
|
+
async function renameSession(id, title) {
|
|
165
|
+
try {
|
|
166
|
+
await execFileAsync(HERMES_BIN, ['sessions', 'rename', id, title], {
|
|
167
|
+
timeout: 10000,
|
|
168
|
+
...execOpts,
|
|
169
|
+
});
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
console.error('[Hermes CLI] session rename failed:', err.message);
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get Hermes version
|
|
179
|
+
*/
|
|
180
|
+
async function getVersion() {
|
|
181
|
+
try {
|
|
182
|
+
const { stdout } = await execFileAsync(HERMES_BIN, ['--version'], { timeout: 5000, ...execOpts });
|
|
183
|
+
return stdout.trim();
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return '';
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Start Hermes gateway (uses launchd/systemd)
|
|
191
|
+
*/
|
|
192
|
+
async function startGateway() {
|
|
193
|
+
if (isDocker) {
|
|
194
|
+
const pid = await startGatewayBackground();
|
|
195
|
+
return pid ? `Gateway started (PID: ${pid})` : 'Gateway start triggered';
|
|
196
|
+
}
|
|
197
|
+
const { stdout, stderr } = await execFileAsync(HERMES_BIN, ['gateway', 'start'], {
|
|
198
|
+
timeout: 30000,
|
|
199
|
+
...execOpts,
|
|
200
|
+
});
|
|
201
|
+
return stdout || stderr;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Start Hermes gateway in background (for WSL where launchd/systemd is unavailable)
|
|
205
|
+
* Uses "hermes gateway run" as a detached background process
|
|
206
|
+
*/
|
|
207
|
+
async function startGatewayBackground() {
|
|
208
|
+
const { spawn } = require('child_process');
|
|
209
|
+
const child = spawn(HERMES_BIN, ['gateway', 'run'], {
|
|
210
|
+
detached: true,
|
|
211
|
+
stdio: 'ignore',
|
|
212
|
+
windowsHide: true,
|
|
213
|
+
});
|
|
214
|
+
child.unref();
|
|
215
|
+
return child.pid ?? null;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Restart Hermes gateway
|
|
219
|
+
*/
|
|
220
|
+
async function restartGateway() {
|
|
221
|
+
if (isDocker) {
|
|
222
|
+
try {
|
|
223
|
+
await stopGateway();
|
|
224
|
+
}
|
|
225
|
+
catch { }
|
|
226
|
+
const pid = await startGatewayBackground();
|
|
227
|
+
return pid ? `Gateway restarted (PID: ${pid})` : 'Gateway restart triggered';
|
|
228
|
+
}
|
|
229
|
+
const { stdout, stderr } = await execFileAsync(HERMES_BIN, ['gateway', 'restart'], {
|
|
230
|
+
timeout: 30000,
|
|
231
|
+
...execOpts,
|
|
232
|
+
});
|
|
233
|
+
return stdout || stderr;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Stop Hermes gateway
|
|
237
|
+
*/
|
|
238
|
+
async function stopGateway() {
|
|
239
|
+
const { stdout, stderr } = await execFileAsync(HERMES_BIN, ['gateway', 'stop'], {
|
|
240
|
+
timeout: 30000,
|
|
241
|
+
...execOpts,
|
|
242
|
+
});
|
|
243
|
+
return stdout || stderr;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* List available log files
|
|
247
|
+
*/
|
|
248
|
+
async function listLogFiles() {
|
|
249
|
+
try {
|
|
250
|
+
const { stdout } = await execFileAsync(HERMES_BIN, ['logs', 'list'], {
|
|
251
|
+
timeout: 10000,
|
|
252
|
+
...execOpts,
|
|
253
|
+
});
|
|
254
|
+
const files = [];
|
|
255
|
+
const lines = stdout.trim().split('\n').filter(l => l.includes('.log'));
|
|
256
|
+
for (const line of lines) {
|
|
257
|
+
const match = line.match(/^\s+(\S+)\s+([\d.]+\w+)\s+(.+)$/);
|
|
258
|
+
if (match) {
|
|
259
|
+
const rawName = match[1];
|
|
260
|
+
const name = rawName.replace(/\.log$/, '');
|
|
261
|
+
if (['agent', 'errors', 'gateway'].includes(name)) {
|
|
262
|
+
files.push({ name, size: match[2], modified: match[3].trim() });
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return files;
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
console.error('[Hermes CLI] logs list failed:', err.message);
|
|
270
|
+
return [];
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Read log lines
|
|
275
|
+
*/
|
|
276
|
+
async function readLogs(logName = 'agent', lines = 100, level, session, since) {
|
|
277
|
+
const args = ['logs', logName, '-n', String(lines)];
|
|
278
|
+
if (level)
|
|
279
|
+
args.push('--level', level);
|
|
280
|
+
if (session)
|
|
281
|
+
args.push('--session', session);
|
|
282
|
+
if (since)
|
|
283
|
+
args.push('--since', since);
|
|
284
|
+
try {
|
|
285
|
+
const { stdout } = await execFileAsync(HERMES_BIN, args, {
|
|
286
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
287
|
+
timeout: 15000,
|
|
288
|
+
...execOpts,
|
|
289
|
+
});
|
|
290
|
+
return stdout;
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
console.error('[Hermes CLI] logs read failed:', err.message);
|
|
294
|
+
throw new Error(`Failed to read logs: ${err.message}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* List all profiles
|
|
299
|
+
*/
|
|
300
|
+
async function listProfiles() {
|
|
301
|
+
try {
|
|
302
|
+
const { stdout } = await execFileAsync(HERMES_BIN, ['profile', 'list'], {
|
|
303
|
+
timeout: 10000,
|
|
304
|
+
...execOpts,
|
|
305
|
+
});
|
|
306
|
+
const lines = stdout.trim().split('\n').filter(Boolean);
|
|
307
|
+
const profiles = [];
|
|
308
|
+
// Skip header lines (starts with " Profile" or " ─")
|
|
309
|
+
for (const line of lines) {
|
|
310
|
+
if (line.startsWith(' Profile') || line.match(/^ ─/))
|
|
311
|
+
continue;
|
|
312
|
+
const match = line.match(/^\s+(◆)?(\S+)\s{2,}(\S+)\s{2,}(\S+)\s{2,}(.*)$/);
|
|
313
|
+
if (match) {
|
|
314
|
+
profiles.push({
|
|
315
|
+
name: match[2],
|
|
316
|
+
active: !!match[1],
|
|
317
|
+
model: match[3],
|
|
318
|
+
gateway: match[4],
|
|
319
|
+
alias: match[5].trim() === '—' ? '' : match[5].trim(),
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return profiles;
|
|
324
|
+
}
|
|
325
|
+
catch (err) {
|
|
326
|
+
console.error('[Hermes CLI] profile list failed:', err.message);
|
|
327
|
+
throw new Error(`Failed to list profiles: ${err.message}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Get profile details
|
|
332
|
+
*/
|
|
333
|
+
async function getProfile(name) {
|
|
334
|
+
try {
|
|
335
|
+
const { stdout } = await execFileAsync(HERMES_BIN, ['profile', 'show', name], {
|
|
336
|
+
timeout: 10000,
|
|
337
|
+
...execOpts,
|
|
338
|
+
});
|
|
339
|
+
const result = {};
|
|
340
|
+
for (const line of stdout.trim().split('\n')) {
|
|
341
|
+
const match = line.match(/^(\w[\w\s]*?):\s+(.+)$/);
|
|
342
|
+
if (match) {
|
|
343
|
+
result[match[1].trim().toLowerCase().replace(/\s+/g, '_')] = match[2].trim();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
const modelFull = result.model || '';
|
|
347
|
+
const providerMatch = modelFull.match(/\((.+)\)/);
|
|
348
|
+
const model = providerMatch ? modelFull.replace(/\s*\(.+\)/, '').trim() : modelFull;
|
|
349
|
+
return {
|
|
350
|
+
name: result.profile || name,
|
|
351
|
+
path: result.path || '',
|
|
352
|
+
model,
|
|
353
|
+
provider: providerMatch ? providerMatch[1] : '',
|
|
354
|
+
gateway: result.gateway || '',
|
|
355
|
+
skills: parseInt(result.skills || '0', 10),
|
|
356
|
+
hasEnv: result['.env'] === 'exists',
|
|
357
|
+
hasSoulMd: result.soul_md === 'exists',
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
catch (err) {
|
|
361
|
+
if (err.code === 1 || err.status === 1) {
|
|
362
|
+
throw new Error(`Profile "${name}" not found`);
|
|
363
|
+
}
|
|
364
|
+
console.error('[Hermes CLI] profile show failed:', err.message);
|
|
365
|
+
throw new Error(`Failed to get profile: ${err.message}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Create a new profile
|
|
370
|
+
*/
|
|
371
|
+
async function createProfile(name, clone) {
|
|
372
|
+
const args = ['profile', 'create', name];
|
|
373
|
+
if (clone)
|
|
374
|
+
args.push('--clone');
|
|
375
|
+
try {
|
|
376
|
+
const { stdout, stderr } = await execFileAsync(HERMES_BIN, args, {
|
|
377
|
+
timeout: 15000,
|
|
378
|
+
...execOpts,
|
|
379
|
+
});
|
|
380
|
+
return stdout || stderr;
|
|
381
|
+
}
|
|
382
|
+
catch (err) {
|
|
383
|
+
console.error('[Hermes CLI] profile create failed:', err.message);
|
|
384
|
+
throw new Error(`Failed to create profile: ${err.message}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Delete a profile
|
|
389
|
+
*/
|
|
390
|
+
async function deleteProfile(name) {
|
|
391
|
+
try {
|
|
392
|
+
await execFileAsync(HERMES_BIN, ['profile', 'delete', name, '--yes'], {
|
|
393
|
+
timeout: 10000,
|
|
394
|
+
...execOpts,
|
|
395
|
+
});
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
catch (err) {
|
|
399
|
+
console.error('[Hermes CLI] profile delete failed:', err.message);
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Rename a profile
|
|
405
|
+
*/
|
|
406
|
+
async function renameProfile(oldName, newName) {
|
|
407
|
+
try {
|
|
408
|
+
await execFileAsync(HERMES_BIN, ['profile', 'rename', oldName, newName], {
|
|
409
|
+
timeout: 10000,
|
|
410
|
+
...execOpts,
|
|
411
|
+
});
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
catch (err) {
|
|
415
|
+
console.error('[Hermes CLI] profile rename failed:', err.message);
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Switch active profile
|
|
421
|
+
*/
|
|
422
|
+
async function useProfile(name) {
|
|
423
|
+
try {
|
|
424
|
+
const { stdout, stderr } = await execFileAsync(HERMES_BIN, ['profile', 'use', name], {
|
|
425
|
+
timeout: 10000,
|
|
426
|
+
...execOpts,
|
|
427
|
+
});
|
|
428
|
+
return stdout || stderr;
|
|
429
|
+
}
|
|
430
|
+
catch (err) {
|
|
431
|
+
console.error('[Hermes CLI] profile use failed:', err.message);
|
|
432
|
+
throw new Error(`Failed to switch profile: ${err.message}`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Export profile to archive
|
|
437
|
+
*/
|
|
438
|
+
async function exportProfile(name, outputPath) {
|
|
439
|
+
const args = ['profile', 'export', name];
|
|
440
|
+
if (outputPath)
|
|
441
|
+
args.push('--output', outputPath);
|
|
442
|
+
try {
|
|
443
|
+
const { stdout, stderr } = await execFileAsync(HERMES_BIN, args, {
|
|
444
|
+
timeout: 60000,
|
|
445
|
+
...execOpts,
|
|
446
|
+
});
|
|
447
|
+
return stdout || stderr;
|
|
448
|
+
}
|
|
449
|
+
catch (err) {
|
|
450
|
+
console.error('[Hermes CLI] profile export failed:', err.message);
|
|
451
|
+
throw new Error(`Failed to export profile: ${err.message}`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Run hermes setup --non-interactive --reset to generate default config for current profile
|
|
456
|
+
*/
|
|
457
|
+
async function setupReset() {
|
|
458
|
+
try {
|
|
459
|
+
const { stdout, stderr } = await execFileAsync(HERMES_BIN, ['setup', '--non-interactive', '--reset'], {
|
|
460
|
+
timeout: 30000,
|
|
461
|
+
...execOpts,
|
|
462
|
+
});
|
|
463
|
+
return stdout || stderr;
|
|
464
|
+
}
|
|
465
|
+
catch (err) {
|
|
466
|
+
console.error('[Hermes CLI] setup reset failed:', err.message);
|
|
467
|
+
throw new Error(`Failed to reset config: ${err.message}`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Import profile from archive
|
|
472
|
+
*/
|
|
473
|
+
async function importProfile(archivePath, name) {
|
|
474
|
+
const args = ['profile', 'import', archivePath];
|
|
475
|
+
if (name)
|
|
476
|
+
args.push('--name', name);
|
|
477
|
+
try {
|
|
478
|
+
const { stdout, stderr } = await execFileAsync(HERMES_BIN, args, {
|
|
479
|
+
timeout: 60000,
|
|
480
|
+
...execOpts,
|
|
481
|
+
});
|
|
482
|
+
return stdout || stderr;
|
|
483
|
+
}
|
|
484
|
+
catch (err) {
|
|
485
|
+
console.error('[Hermes CLI] profile import failed:', err.message);
|
|
486
|
+
throw new Error(`Failed to import profile: ${err.message}`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the active profile's home directory.
|
|
3
|
+
* default → ~/.hermes/
|
|
4
|
+
* other → ~/.hermes/profiles/{name}/
|
|
5
|
+
*/
|
|
6
|
+
export declare function getActiveProfileDir(): string;
|
|
7
|
+
/**
|
|
8
|
+
* Get the active profile's config.yaml path.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getActiveConfigPath(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Get the active profile's auth.json path.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getActiveAuthPath(): string;
|
|
15
|
+
/**
|
|
16
|
+
* Get the active profile's .env path.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getActiveEnvPath(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Get the active profile name.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getActiveProfileName(): string;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getActiveProfileDir = getActiveProfileDir;
|
|
4
|
+
exports.getActiveConfigPath = getActiveConfigPath;
|
|
5
|
+
exports.getActiveAuthPath = getActiveAuthPath;
|
|
6
|
+
exports.getActiveEnvPath = getActiveEnvPath;
|
|
7
|
+
exports.getActiveProfileName = getActiveProfileName;
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const os_1 = require("os");
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const HERMES_BASE = (0, path_1.resolve)((0, os_1.homedir)(), '.hermes');
|
|
12
|
+
/**
|
|
13
|
+
* Get the active profile's home directory.
|
|
14
|
+
* default → ~/.hermes/
|
|
15
|
+
* other → ~/.hermes/profiles/{name}/
|
|
16
|
+
*/
|
|
17
|
+
function getActiveProfileDir() {
|
|
18
|
+
const activeFile = (0, path_1.join)(HERMES_BASE, 'active_profile');
|
|
19
|
+
try {
|
|
20
|
+
const name = (0, fs_1.readFileSync)(activeFile, 'utf-8').trim();
|
|
21
|
+
if (name && name !== 'default') {
|
|
22
|
+
const dir = (0, path_1.join)(HERMES_BASE, 'profiles', name);
|
|
23
|
+
if ((0, fs_1.existsSync)(dir))
|
|
24
|
+
return dir;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch { }
|
|
28
|
+
return HERMES_BASE;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get the active profile's config.yaml path.
|
|
32
|
+
*/
|
|
33
|
+
function getActiveConfigPath() {
|
|
34
|
+
return (0, path_1.join)(getActiveProfileDir(), 'config.yaml');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the active profile's auth.json path.
|
|
38
|
+
*/
|
|
39
|
+
function getActiveAuthPath() {
|
|
40
|
+
return (0, path_1.join)(getActiveProfileDir(), 'auth.json');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get the active profile's .env path.
|
|
44
|
+
*/
|
|
45
|
+
function getActiveEnvPath() {
|
|
46
|
+
return (0, path_1.join)(getActiveProfileDir(), '.env');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the active profile name.
|
|
50
|
+
*/
|
|
51
|
+
function getActiveProfileName() {
|
|
52
|
+
const activeFile = (0, path_1.join)(HERMES_BASE, 'active_profile');
|
|
53
|
+
try {
|
|
54
|
+
const name = (0, fs_1.readFileSync)(activeFile, 'utf-8').trim();
|
|
55
|
+
return name || 'default';
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return 'default';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Send an instruction to Hermes Agent via /v1/runs
|
|
3
|
+
*/
|
|
4
|
+
export declare function sendInstruction(params: {
|
|
5
|
+
input: string | any[];
|
|
6
|
+
instructions?: string;
|
|
7
|
+
conversationHistory?: any[];
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
authToken?: string;
|
|
10
|
+
}): Promise<{
|
|
11
|
+
run_id: string;
|
|
12
|
+
status: string;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Get run status (poll /v1/runs/:id if supported)
|
|
16
|
+
*/
|
|
17
|
+
export declare function getRunStatus(runId: string): Promise<any>;
|
|
18
|
+
/**
|
|
19
|
+
* Subscribe to SSE events for a run
|
|
20
|
+
*/
|
|
21
|
+
export declare function streamRunEvents(runId: string, authToken?: string): AsyncGenerator<any>;
|
|
22
|
+
/**
|
|
23
|
+
* Health check
|
|
24
|
+
*/
|
|
25
|
+
export declare function healthCheck(): Promise<{
|
|
26
|
+
status: string;
|
|
27
|
+
version?: string;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Fetch available models
|
|
31
|
+
*/
|
|
32
|
+
export declare function fetchModels(): Promise<{
|
|
33
|
+
data: Array<{
|
|
34
|
+
id: string;
|
|
35
|
+
}>;
|
|
36
|
+
}>;
|
|
37
|
+
type WebhookCallback = (payload: any) => void | Promise<void>;
|
|
38
|
+
export declare function onWebhook(callback: WebhookCallback): void;
|
|
39
|
+
export declare function emitWebhook(payload: any): void;
|
|
40
|
+
export {};
|