hermes-launch 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -0
- package/bin/hermes-launch.js +447 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# 🐚 Hermes Launch
|
|
2
|
+
|
|
3
|
+
**One command. Zero to AI agent.**
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx hermes-launch
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Hermes Launch installs, configures, and starts [Hermes Agent](https://github.com/NousResearch/hermes-agent) — the open-source AI agent framework by Nous Research. No faffing with Python venvs, curl pipes, or config files.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Full interactive setup (recommended for first use)
|
|
13
|
+
npx hermes-launch
|
|
14
|
+
|
|
15
|
+
# Non-interactive — smart defaults, go fast
|
|
16
|
+
npx hermes-launch --quick
|
|
17
|
+
|
|
18
|
+
# Just start the web dashboard if Hermes is already installed
|
|
19
|
+
npx hermes-launch --dashboard
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## What you get
|
|
23
|
+
|
|
24
|
+
After running `npx hermes-launch`:
|
|
25
|
+
|
|
26
|
+
- **Hermes Agent CLI** — `hermes` in your terminal. Chat, code, research, automate.
|
|
27
|
+
- **Web dashboard** at `http://localhost:9119` — manage config, API keys, sessions.
|
|
28
|
+
- **Tool sets** enabled out of the box: web search, terminal, file ops, skills, memory, vision, TTS, subagent delegation, cross-session search.
|
|
29
|
+
- **Streaming** enabled — see responses as they generate.
|
|
30
|
+
- **Zero config** — the setup wizard walks you through model/provider selection.
|
|
31
|
+
|
|
32
|
+
## After setup
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
hermes # start a conversation
|
|
36
|
+
hermes chat -q "analyze this repo" # one-shot
|
|
37
|
+
hermes model # change provider/model
|
|
38
|
+
hermes gateway setup # connect Telegram/Discord/Slack
|
|
39
|
+
hermes tools list # see what tools are available
|
|
40
|
+
hermes dashboard # open the web UI
|
|
41
|
+
hermes doctor # health check
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## What's under the hood
|
|
45
|
+
|
|
46
|
+
Hermes Launch is a thin wrapper — it:
|
|
47
|
+
|
|
48
|
+
1. Checks prerequisites (Python 3.10+, curl, git)
|
|
49
|
+
2. Installs Hermes Agent via the official install script if missing
|
|
50
|
+
3. Guides you through `hermes setup` to pick a model provider
|
|
51
|
+
4. Enables the core toolsets
|
|
52
|
+
5. Starts `hermes dashboard --tui` on port 9119
|
|
53
|
+
6. Prints next steps
|
|
54
|
+
|
|
55
|
+
Everything lives in `~/.hermes/` — config, sessions, logs, skills.
|
|
56
|
+
|
|
57
|
+
## Requirements
|
|
58
|
+
|
|
59
|
+
- **Node.js** 18+ (comes with npx)
|
|
60
|
+
- **Python** 3.10+ (system or homebrew)
|
|
61
|
+
- **curl**, **git**
|
|
62
|
+
- macOS, Linux, or WSL
|
|
63
|
+
|
|
64
|
+
## Why not just curl the install script?
|
|
65
|
+
|
|
66
|
+
You can! `curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash` works great. Hermes Launch adds:
|
|
67
|
+
|
|
68
|
+
- Prerequisite checking with clear error messages
|
|
69
|
+
- Interactive setup flow with prompts
|
|
70
|
+
- Smart defaults for tool enablement
|
|
71
|
+
- Dashboard auto-start
|
|
72
|
+
- A clean post-install summary
|
|
73
|
+
- No pipe-to-bash pattern (safer for enterprise environments)
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
MIT
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* hermes-launch — one command to install, configure, and run Hermes Agent.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx hermes-launch # full interactive flow
|
|
7
|
+
* npx hermes-launch --quick # skip prompts, use smart defaults
|
|
8
|
+
* npx hermes-launch --dashboard # just start the web dashboard
|
|
9
|
+
* npx hermes-launch --help # this message
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { execSync, spawn } from 'child_process';
|
|
13
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'fs';
|
|
14
|
+
import { homedir, platform, hostname } from 'os';
|
|
15
|
+
import { resolve } from 'path';
|
|
16
|
+
import { createInterface } from 'readline';
|
|
17
|
+
|
|
18
|
+
const HERMES_HOME = resolve(homedir(), '.hermes');
|
|
19
|
+
const CONFIG_PATH = resolve(HERMES_HOME, 'config.yaml');
|
|
20
|
+
const INSTALL_URL = 'https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh';
|
|
21
|
+
|
|
22
|
+
const BOLD = '\x1b[1m';
|
|
23
|
+
const DIM = '\x1b[2m';
|
|
24
|
+
const GREEN = '\x1b[32m';
|
|
25
|
+
const YELLOW = '\x1b[33m';
|
|
26
|
+
const RED = '\x1b[31m';
|
|
27
|
+
const CYAN = '\x1b[36m';
|
|
28
|
+
const RESET = '\x1b[0m';
|
|
29
|
+
const CLEAR_LINE = '\x1b[K';
|
|
30
|
+
|
|
31
|
+
// ——— helpers ———
|
|
32
|
+
|
|
33
|
+
function printBanner() {
|
|
34
|
+
const banner = `
|
|
35
|
+
╔════════════════════════════════════════╗
|
|
36
|
+
║ ${CYAN}🐚 Hermes Launch ${RESET} ║
|
|
37
|
+
║ ${DIM}zero-to-AI-agent in seconds${RESET} ║
|
|
38
|
+
╚════════════════════════════════════════╝
|
|
39
|
+
`;
|
|
40
|
+
console.log(banner);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function ask(query) {
|
|
44
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
45
|
+
return new Promise(resolve => rl.question(query, ans => { rl.close(); resolve(ans.trim()); }));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function run(cmd, opts = {}) {
|
|
49
|
+
const defaults = { stdio: opts.silent ? 'pipe' : 'inherit', timeout: 120_000, ...opts };
|
|
50
|
+
try {
|
|
51
|
+
const out = execSync(cmd, defaults);
|
|
52
|
+
return { ok: true, out: out?.toString()?.trim() || '' };
|
|
53
|
+
} catch (e) {
|
|
54
|
+
return { ok: false, out: e.stderr?.toString()?.trim() || e.message };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function spinner(ms) {
|
|
59
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function step(msg) {
|
|
63
|
+
process.stdout.write(` ${CYAN}→${RESET} ${msg} ... `);
|
|
64
|
+
return {
|
|
65
|
+
ok: () => { process.stdout.write(`${GREEN}done${RESET}\n`); },
|
|
66
|
+
skip: (reason) => { process.stdout.write(`${YELLOW}skipped${RESET} (${reason})\n`); },
|
|
67
|
+
fail: (err) => { process.stdout.write(`${RED}failed${RESET}\n ${DIM}${err}${RESET}\n`); },
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function printSummary(info) {
|
|
72
|
+
console.log(`\n${BOLD}${GREEN} ✅ Hermes Agent is live!${RESET}\n`);
|
|
73
|
+
console.log(` ${BOLD}Web Dashboard${RESET}`);
|
|
74
|
+
console.log(` ${CYAN}http://localhost:${info.port || 9119}${RESET}\n`);
|
|
75
|
+
console.log(` ${BOLD}CLI${RESET}`);
|
|
76
|
+
console.log(` ${CYAN}hermes${RESET} interactive chat`);
|
|
77
|
+
console.log(` ${CYAN}hermes chat -q "..."${RESET} one-shot query`);
|
|
78
|
+
console.log(` ${CYAN}hermes --continue${RESET} resume last session\n`);
|
|
79
|
+
console.log(` ${BOLD}Key commands${RESET}`);
|
|
80
|
+
console.log(` ${CYAN}hermes model${RESET} change model/provider`);
|
|
81
|
+
console.log(` ${CYAN}hermes gateway setup${RESET} connect Telegram/Discord`);
|
|
82
|
+
console.log(` ${CYAN}hermes tools list${RESET} see available tools`);
|
|
83
|
+
console.log(` ${CYAN}hermes cron${RESET} schedule recurring tasks`);
|
|
84
|
+
console.log(` ${CYAN}hermes doctor${RESET} health check\n`);
|
|
85
|
+
console.log(` ${BOLD}Docs${RESET}`);
|
|
86
|
+
console.log(` ${CYAN}https://hermes-agent.nousresearch.com/docs${RESET}\n`);
|
|
87
|
+
if (info.messaging) {
|
|
88
|
+
console.log(` ${BOLD}Messaging${RESET}`);
|
|
89
|
+
for (const [platform, status] of Object.entries(info.messaging)) {
|
|
90
|
+
console.log(` ${platform}: ${status}`);
|
|
91
|
+
}
|
|
92
|
+
console.log();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function printMiniBanner() {
|
|
97
|
+
console.log(`
|
|
98
|
+
${CYAN} 🐚 Hermes Launch${RESET} ${DIM}— zero-to-agent${RESET}
|
|
99
|
+
`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ——— core steps ———
|
|
103
|
+
|
|
104
|
+
async function checkPrereqs() {
|
|
105
|
+
const s = step('Checking prerequisites');
|
|
106
|
+
const checks = {
|
|
107
|
+
node: run('node --version', { silent: true }).ok,
|
|
108
|
+
python3: run('python3 --version', { silent: true }).ok,
|
|
109
|
+
curl: run('curl --version', { silent: true }).ok,
|
|
110
|
+
git: run('git --version', { silent: true }).ok,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const missing = Object.entries(checks).filter(([, ok]) => !ok).map(([name]) => name);
|
|
114
|
+
if (missing.length) {
|
|
115
|
+
s.fail(`Missing: ${missing.join(', ')}`);
|
|
116
|
+
console.log(` Install missing tools and try again.`);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Check Python version >= 3.10 — try multiple binaries
|
|
121
|
+
const pyCandidates = ['python3.11', 'python3.12', 'python3.13', 'python3.14', 'python3.10', 'python3'];
|
|
122
|
+
let pyVer = '';
|
|
123
|
+
let pyBin = 'python3';
|
|
124
|
+
for (const bin of pyCandidates) {
|
|
125
|
+
const r = run(`${bin} --version`, { silent: true });
|
|
126
|
+
if (r.ok) {
|
|
127
|
+
pyVer = r.out;
|
|
128
|
+
pyBin = bin;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const match = pyVer.match(/(\d+)\.(\d+)/);
|
|
134
|
+
if (match) {
|
|
135
|
+
const major = parseInt(match[1]), minor = parseInt(match[2]);
|
|
136
|
+
if (major < 3 || (major === 3 && minor < 10)) {
|
|
137
|
+
s.fail(`Python 3.10+ required, got ${major}.${minor} (${pyBin})`);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
s.ok();
|
|
143
|
+
checks.pythonBin = pyBin;
|
|
144
|
+
return checks;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function installHermes(quick) {
|
|
148
|
+
const s = step('Checking Hermes installation');
|
|
149
|
+
const hasHermes = run('hermes --version', { silent: true }).ok;
|
|
150
|
+
|
|
151
|
+
if (hasHermes) {
|
|
152
|
+
const ver = run('hermes --version', { silent: true }).out;
|
|
153
|
+
s.skip(`v${ver} already installed`);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!quick) {
|
|
158
|
+
console.log();
|
|
159
|
+
const ans = await ask(` Hermes not found. Install it now? [Y/n] `);
|
|
160
|
+
if (ans.toLowerCase() === 'n') {
|
|
161
|
+
console.log(` ${YELLOW}Aborted. Install manually: curl -fsSL ${INSTALL_URL} | bash${RESET}`);
|
|
162
|
+
process.exit(0);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const si = step('Downloading and installing Hermes');
|
|
167
|
+
try {
|
|
168
|
+
const cmd = `curl -fsSL ${INSTALL_URL} | bash`;
|
|
169
|
+
const result = run(cmd, { timeout: 180_000, silent: false });
|
|
170
|
+
if (!result.ok) {
|
|
171
|
+
si.fail(result.out);
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
si.ok();
|
|
175
|
+
return true;
|
|
176
|
+
} catch (e) {
|
|
177
|
+
si.fail(e.message);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function checkConfig(quick) {
|
|
183
|
+
const s = step('Checking Hermes configuration');
|
|
184
|
+
|
|
185
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
186
|
+
s.skip('no config yet — will be generated');
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const raw = readFileSync(CONFIG_PATH, 'utf-8');
|
|
191
|
+
|
|
192
|
+
// Check if config has a model set (not commented out)
|
|
193
|
+
const hasModel = /^model:\s*\n/m.test(raw);
|
|
194
|
+
|
|
195
|
+
if (!hasModel || raw.includes('default: ""') || raw.includes("default: ''")) {
|
|
196
|
+
s.skip('needs model configuration');
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
s.ok();
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function runSetup(quick) {
|
|
205
|
+
if (quick) {
|
|
206
|
+
const s = step('Running headless setup');
|
|
207
|
+
// For quick mode, just enable the gateway and set up with defaults
|
|
208
|
+
const setCmds = [
|
|
209
|
+
'hermes tools enable web terminal file skills session_search delegate_task memory clarify vision 2>/dev/null || true',
|
|
210
|
+
`hermes config set display.streaming.enabled true 2>/dev/null || true`,
|
|
211
|
+
];
|
|
212
|
+
for (const cmd of setCmds) run(cmd, { silent: true });
|
|
213
|
+
s.ok();
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Interactive: guide the user through setup
|
|
218
|
+
console.log(`\n ${BOLD}Let's configure your Hermes Agent.${RESET}\n`);
|
|
219
|
+
console.log(` ${DIM}(You can skip any step and configure later with \`hermes setup\`)${RESET}\n`);
|
|
220
|
+
|
|
221
|
+
const doSetup = await ask(` Run the Hermes setup wizard? (recommended) [Y/n] `);
|
|
222
|
+
if (doSetup.toLowerCase() !== 'n') {
|
|
223
|
+
const s = step('Running setup wizard');
|
|
224
|
+
try {
|
|
225
|
+
const result = run('hermes setup', { stdio: 'inherit', timeout: 300_000 });
|
|
226
|
+
if (!result.ok) {
|
|
227
|
+
s.fail(result.out);
|
|
228
|
+
} else {
|
|
229
|
+
s.ok();
|
|
230
|
+
}
|
|
231
|
+
} catch (e) {
|
|
232
|
+
s.fail(e.message);
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
// Minimal quick config
|
|
236
|
+
const s = step('Applying minimal configuration');
|
|
237
|
+
run('hermes tools enable web terminal file skills session_search delegate_task memory 2>/dev/null || true', { silent: true });
|
|
238
|
+
s.skip('minimal config applied');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function enableToolsets(quick) {
|
|
243
|
+
const s = step('Enabling tool sets');
|
|
244
|
+
|
|
245
|
+
// Core toolsets that make Hermes useful
|
|
246
|
+
const toolsets = [
|
|
247
|
+
'web', // web search + content extraction
|
|
248
|
+
'terminal', // shell commands
|
|
249
|
+
'file', // file read/write/search
|
|
250
|
+
'skills', // skill management
|
|
251
|
+
'session_search', // cross-session recall
|
|
252
|
+
'delegate_task', // spawn subagents
|
|
253
|
+
'memory', // cross-session memory
|
|
254
|
+
'vision', // image analysis
|
|
255
|
+
'tts', // text-to-speech
|
|
256
|
+
'clarify', // ask questions
|
|
257
|
+
];
|
|
258
|
+
|
|
259
|
+
let ok = true;
|
|
260
|
+
for (const t of toolsets) {
|
|
261
|
+
const r = run(`hermes tools enable ${t}`, { silent: true });
|
|
262
|
+
if (!r.ok) ok = false;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (ok) {
|
|
266
|
+
s.ok();
|
|
267
|
+
} else {
|
|
268
|
+
// Some may have failed if already enabled — that's fine
|
|
269
|
+
s.ok();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Enable gateway streaming
|
|
273
|
+
run('hermes config set display.streaming.enabled true 2>/dev/null || true', { silent: true });
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async function startDashboard(quick) {
|
|
277
|
+
const s = step('Starting web dashboard');
|
|
278
|
+
const port = quick ? '9119' : '9119';
|
|
279
|
+
|
|
280
|
+
// Check if dashboard is already running
|
|
281
|
+
const statusCheck = run('hermes dashboard --status', { silent: true });
|
|
282
|
+
if (statusCheck.ok && statusCheck.out.length > 0 && !statusCheck.out.includes('No running')) {
|
|
283
|
+
s.skip('already running');
|
|
284
|
+
return { port, alreadyRunning: true };
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
const proc = spawn(
|
|
289
|
+
'hermes',
|
|
290
|
+
['dashboard', '--port', port, '--tui', quick ? '--no-open' : ''],
|
|
291
|
+
{
|
|
292
|
+
stdio: 'inherit',
|
|
293
|
+
detached: false,
|
|
294
|
+
env: { ...process.env },
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
// Give it a moment to start
|
|
299
|
+
await spinner(3000);
|
|
300
|
+
|
|
301
|
+
// Verify it's up
|
|
302
|
+
const verify = run(`curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:${port}/ 2>/dev/null || echo "0"`, { silent: true });
|
|
303
|
+
if (verify.out === '0') {
|
|
304
|
+
s.skip('dashboard launched in background');
|
|
305
|
+
} else {
|
|
306
|
+
s.ok();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return { port, alreadyRunning: false };
|
|
310
|
+
} catch (e) {
|
|
311
|
+
s.fail(e.message);
|
|
312
|
+
return { port, alreadyRunning: false, error: e.message };
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function checkGatewayStatus() {
|
|
317
|
+
const s = step('Checking messaging gateway');
|
|
318
|
+
const result = run('hermes gateway status', { silent: true });
|
|
319
|
+
if (result.ok) {
|
|
320
|
+
const out = result.out;
|
|
321
|
+
const hasTelegram = out.includes('telegram') && (out.includes('running') || out.includes('connected'));
|
|
322
|
+
const hasDiscord = out.includes('discord') && (out.includes('running') || out.includes('connected'));
|
|
323
|
+
const platforms = [];
|
|
324
|
+
if (hasTelegram) platforms.push('telegram');
|
|
325
|
+
if (hasDiscord) platforms.push('discord');
|
|
326
|
+
if (platforms.length > 0) {
|
|
327
|
+
s.ok();
|
|
328
|
+
return platforms;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
s.skip('not configured');
|
|
332
|
+
return [];
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
async function showQuickStart() {
|
|
336
|
+
console.log(`\n ${BOLD}${GREEN}Hermes Agent is ready to use!${RESET}\n`);
|
|
337
|
+
|
|
338
|
+
console.log(` ${BOLD}Start a conversation:${RESET}`);
|
|
339
|
+
console.log(` ${CYAN}hermes${RESET} interactive chat`);
|
|
340
|
+
console.log(` ${CYAN}hermes -q "summarize my repo"${RESET} one-shot query\n`);
|
|
341
|
+
|
|
342
|
+
console.log(` ${BOLD}First things to try:${RESET}`);
|
|
343
|
+
console.log(` • ${CYAN}hermes model${RESET} — pick your LLM provider`);
|
|
344
|
+
console.log(` • ${CYAN}hermes gateway setup${RESET} — connect Telegram/Discord`);
|
|
345
|
+
console.log(` • ${CYAN}hermes dashboard${RESET} — open the web UI`);
|
|
346
|
+
console.log(` • ${CYAN}hermes skills browse${RESET} — discover skills\n`);
|
|
347
|
+
|
|
348
|
+
console.log(` ${BOLD}Pro tips:${RESET}`);
|
|
349
|
+
console.log(` • ${DIM}Your config lives at ~/.hermes/config.yaml${RESET}`);
|
|
350
|
+
console.log(` • ${DIM}API keys go in ~/.hermes/.env${RESET}`);
|
|
351
|
+
console.log(` • ${DIM}Type /help in a session for all slash commands${RESET}`);
|
|
352
|
+
console.log(` • ${DIM}Run \`hermes doctor\` if something isn't working${RESET}`);
|
|
353
|
+
console.log();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// ——— main ———
|
|
357
|
+
|
|
358
|
+
async function main() {
|
|
359
|
+
const args = process.argv.slice(2);
|
|
360
|
+
const flags = {
|
|
361
|
+
quick: args.includes('--quick') || args.includes('-q'),
|
|
362
|
+
dashboard: args.includes('--dashboard'),
|
|
363
|
+
help: args.includes('--help') || args.includes('-h'),
|
|
364
|
+
version: args.includes('--version') || args.includes('-v'),
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
if (flags.help) {
|
|
368
|
+
console.log(`
|
|
369
|
+
${BOLD}hermes-launch${RESET} — one command to install and run Hermes Agent
|
|
370
|
+
|
|
371
|
+
${BOLD}Usage:${RESET}
|
|
372
|
+
npx hermes-launch full interactive setup
|
|
373
|
+
npx hermes-launch --quick non-interactive, smart defaults
|
|
374
|
+
npx hermes-launch --dashboard just start the web dashboard
|
|
375
|
+
npx hermes-launch --help this message
|
|
376
|
+
|
|
377
|
+
${BOLD}What it does:${RESET}
|
|
378
|
+
1. Check prerequisites (Python, curl, git)
|
|
379
|
+
2. Install Hermes Agent (if not present)
|
|
380
|
+
3. Run setup wizard to configure model/tools
|
|
381
|
+
4. Enable useful toolsets
|
|
382
|
+
5. Start the web dashboard on port 9119
|
|
383
|
+
6. Print next steps
|
|
384
|
+
|
|
385
|
+
${BOLD}After launch:${RESET}
|
|
386
|
+
hermes start chatting
|
|
387
|
+
hermes gateway setup add Telegram/Discord
|
|
388
|
+
hermes model change AI provider
|
|
389
|
+
`);
|
|
390
|
+
process.exit(0);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (flags.version) {
|
|
394
|
+
const pkg = JSON.parse(readFileSync(resolve(import.meta.dirname, '../package.json'), 'utf-8'));
|
|
395
|
+
console.log(`hermes-launch v${pkg.version}`);
|
|
396
|
+
process.exit(0);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (flags.dashboard) {
|
|
400
|
+
printMiniBanner();
|
|
401
|
+
const result = await startDashboard(true);
|
|
402
|
+
if (result.error) {
|
|
403
|
+
process.exit(1);
|
|
404
|
+
}
|
|
405
|
+
printSummary({ port: result.port, messaging: {} });
|
|
406
|
+
process.exit(0);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// ——— full flow ———
|
|
410
|
+
printBanner();
|
|
411
|
+
|
|
412
|
+
// 1. Prerequisites
|
|
413
|
+
await checkPrereqs();
|
|
414
|
+
|
|
415
|
+
// 2. Install
|
|
416
|
+
await installHermes(flags.quick);
|
|
417
|
+
|
|
418
|
+
// 3. Check config
|
|
419
|
+
const needsSetup = await checkConfig(flags.quick);
|
|
420
|
+
|
|
421
|
+
// 4. Setup if needed
|
|
422
|
+
if (!needsSetup) {
|
|
423
|
+
await runSetup(flags.quick);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// 5. Enable tools
|
|
427
|
+
await enableToolsets(flags.quick);
|
|
428
|
+
|
|
429
|
+
// 6. Start dashboard
|
|
430
|
+
const dashResult = await startDashboard(flags.quick);
|
|
431
|
+
|
|
432
|
+
// 7. Check gateway
|
|
433
|
+
const platforms = await checkGatewayStatus();
|
|
434
|
+
|
|
435
|
+
// 8. Show summary
|
|
436
|
+
printSummary({
|
|
437
|
+
port: dashResult.port,
|
|
438
|
+
messaging: platforms.length > 0
|
|
439
|
+
? Object.fromEntries(platforms.map(p => [p, `${GREEN}connected${RESET}`]))
|
|
440
|
+
: { none: `${YELLOW}not configured${RESET} (run \`hermes gateway setup\`)` },
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
main().catch(e => {
|
|
445
|
+
console.error(`${RED}Error:${RESET}`, e.message);
|
|
446
|
+
process.exit(1);
|
|
447
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hermes-launch",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "One command to launch Hermes Agent — zero-to-AI-agent in seconds",
|
|
5
|
+
"bin": {
|
|
6
|
+
"hermes-launch": "./bin/hermes-launch.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"src/",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"hermes",
|
|
15
|
+
"ai-agent",
|
|
16
|
+
"claude-code",
|
|
17
|
+
"codex",
|
|
18
|
+
"opencode",
|
|
19
|
+
"llm",
|
|
20
|
+
"agent",
|
|
21
|
+
"nous-research"
|
|
22
|
+
],
|
|
23
|
+
"type": "module",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/NousResearch/hermes-launch"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/NousResearch/hermes-launch",
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"preferGlobal": true
|
|
34
|
+
}
|