hermes-launch 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/server.js +64 -12
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -20,6 +20,36 @@ const HERMES_HOME = IS_WIN
|
|
|
20
20
|
const CONFIG_PATH = resolve(HERMES_HOME, 'config.yaml');
|
|
21
21
|
const INSTALL_URL = 'https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh';
|
|
22
22
|
|
|
23
|
+
function curlOpts() {
|
|
24
|
+
// Windows: curl.exe -s -o nul; macOS/Linux: curl -s -o /dev/null
|
|
25
|
+
if (IS_WIN) return { silent: 'curl.exe -s -o nul -w "%{http_code}"', devnull: 'nul 2>nul' };
|
|
26
|
+
return { silent: 'curl -s -o /dev/null -w "%{http_code}"', devnull: '/dev/null 2>/dev/null' };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function curlHealth(port) {
|
|
30
|
+
const c = curlOpts();
|
|
31
|
+
return `${c.silent} http://127.0.0.1:${port}/ ${c.devnull} || echo 0`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function hermesBin() {
|
|
35
|
+
// Resolve hermes command — on Windows it's hermes.exe in Python Scripts
|
|
36
|
+
if (!IS_WIN) return 'hermes';
|
|
37
|
+
// Add common Python Scripts paths to PATH for this process
|
|
38
|
+
const scriptsDirs = [
|
|
39
|
+
resolve(process.env.APPDATA || '', 'Python', 'Python312', 'Scripts'),
|
|
40
|
+
resolve(process.env.APPDATA || '', 'Python', 'Python311', 'Scripts'),
|
|
41
|
+
resolve(process.env.LOCALAPPDATA || '', 'Programs', 'Python', 'Python312', 'Scripts'),
|
|
42
|
+
resolve(homedir(), 'AppData', 'Local', 'Programs', 'Python', 'Python312', 'Scripts'),
|
|
43
|
+
];
|
|
44
|
+
for (const d of scriptsDirs) {
|
|
45
|
+
if (existsSync(resolve(d, 'hermes.exe'))) {
|
|
46
|
+
process.env.PATH = `${d};${process.env.PATH}`;
|
|
47
|
+
return resolve(d, 'hermes.exe');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return 'hermes'; // fallback
|
|
51
|
+
}
|
|
52
|
+
|
|
23
53
|
// ——— helpers ———
|
|
24
54
|
|
|
25
55
|
function run(cmd, opts = {}) {
|
|
@@ -52,7 +82,7 @@ api.status = async () => {
|
|
|
52
82
|
}
|
|
53
83
|
|
|
54
84
|
// Check dashboard
|
|
55
|
-
const dashRunning = run(
|
|
85
|
+
const dashRunning = run(curlHealth(9119), { silent: true }).out === '200';
|
|
56
86
|
|
|
57
87
|
const tools = ['web', 'terminal', 'file', 'skills', 'session_search', 'delegate_task', 'memory', 'vision', 'tts', 'clarify'];
|
|
58
88
|
|
|
@@ -120,24 +150,39 @@ api.enableTools = async (tools) => {
|
|
|
120
150
|
};
|
|
121
151
|
|
|
122
152
|
api.startDashboard = async () => {
|
|
123
|
-
const running = run(
|
|
153
|
+
const running = run(curlHealth(9119), { silent: true });
|
|
124
154
|
if (running.out === '200') return { ok: true, alreadyRunning: true, url: 'http://localhost:9119' };
|
|
125
155
|
|
|
126
|
-
const
|
|
127
|
-
|
|
156
|
+
const hbin = hermesBin();
|
|
157
|
+
|
|
158
|
+
// Collect stderr for error reporting
|
|
159
|
+
const proc = spawn(hbin, ['dashboard', '--port', '9119', '--tui', '--no-open', '--skip-build'], {
|
|
160
|
+
stdio: ['ignore', 'ignore', 'pipe'],
|
|
128
161
|
detached: true,
|
|
129
162
|
shell: IS_WIN,
|
|
130
163
|
env: { ...process.env },
|
|
131
164
|
});
|
|
132
|
-
|
|
165
|
+
|
|
166
|
+
let errMsg = '';
|
|
167
|
+
proc.stderr.setEncoding('utf-8');
|
|
168
|
+
proc.stderr.on('data', d => errMsg += d);
|
|
169
|
+
proc.on('error', e => errMsg += e.message);
|
|
170
|
+
|
|
171
|
+
// Don't wait for child — it runs independently
|
|
133
172
|
if (proc.unref) proc.unref();
|
|
134
173
|
|
|
135
|
-
// Wait for it to come up
|
|
136
|
-
|
|
174
|
+
// Wait for it to come up (longer on Windows)
|
|
175
|
+
const maxWait = IS_WIN ? 30 : 15;
|
|
176
|
+
for (let i = 0; i < maxWait; i++) {
|
|
137
177
|
await new Promise(r => setTimeout(r, 1000));
|
|
138
|
-
const check = run(
|
|
178
|
+
const check = run(curlHealth(9119), { silent: true });
|
|
139
179
|
if (check.out === '200') return { ok: true, alreadyRunning: false, url: 'http://localhost:9119' };
|
|
140
180
|
}
|
|
181
|
+
|
|
182
|
+
// Report any captured errors
|
|
183
|
+
if (errMsg) {
|
|
184
|
+
return { ok: false, msg: `Dashboard failed to start: ${errMsg.substring(0, 500)}` };
|
|
185
|
+
}
|
|
141
186
|
return { ok: true, alreadyRunning: false, url: 'http://localhost:9119', note: 'started — may take a moment' };
|
|
142
187
|
};
|
|
143
188
|
|
|
@@ -334,10 +379,17 @@ const STEPS = [
|
|
|
334
379
|
if (btn) btn.disabled = true;
|
|
335
380
|
st.innerHTML = '⏳ Starting dashboard... <span class="spinner"></span>';
|
|
336
381
|
const r = await api('/api/start-dashboard');
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
382
|
+
if (r.ok) {
|
|
383
|
+
st.innerHTML = '✅ Running at <a href="http://localhost:9119" class="link" target="_blank">localhost:9119</a>';
|
|
384
|
+
document.getElementById('dash-url').textContent = 'http://localhost:9119';
|
|
385
|
+
document.getElementById('dash-area').style.display = 'block';
|
|
386
|
+
return true;
|
|
387
|
+
} else {
|
|
388
|
+
st.innerHTML = '❌ Failed: ' + (r.msg || 'Could not start dashboard').replace(/</g, '<');
|
|
389
|
+
st.className = 'status fail';
|
|
390
|
+
if (btn) btn.disabled = false;
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
341
393
|
}},
|
|
342
394
|
];
|
|
343
395
|
|