@robbiesrobotics/alice-agents 1.5.10 → 1.5.11
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/lib/installer.mjs +55 -10
- package/lib/runtime-installer.mjs +314 -0
- package/package.json +1 -1
package/lib/installer.mjs
CHANGED
|
@@ -14,6 +14,11 @@ import {
|
|
|
14
14
|
isCloudRegistered,
|
|
15
15
|
configureCloudFromSupabase,
|
|
16
16
|
} from './mission-control.mjs';
|
|
17
|
+
import {
|
|
18
|
+
promptAndInstallRuntime,
|
|
19
|
+
printNoRuntimeDetected,
|
|
20
|
+
getRuntimeInfo,
|
|
21
|
+
} from './runtime-installer.mjs';
|
|
17
22
|
import {
|
|
18
23
|
promptInstallMode,
|
|
19
24
|
promptUserInfo,
|
|
@@ -191,7 +196,17 @@ function checkLinuxDockerPermissions() {
|
|
|
191
196
|
}
|
|
192
197
|
|
|
193
198
|
async function detectRuntime() {
|
|
194
|
-
//
|
|
199
|
+
// Check for NemoClaw binary first (most specific)
|
|
200
|
+
try {
|
|
201
|
+
execSync('nemoclaw --version', { stdio: 'pipe' });
|
|
202
|
+
return 'nemoclaw';
|
|
203
|
+
} catch {}
|
|
204
|
+
|
|
205
|
+
// Check for NemoClaw directory
|
|
206
|
+
const nemoclawDir = join(homedir(), '.nemoclaw');
|
|
207
|
+
if (existsSync(nemoclawDir)) return 'nemoclaw';
|
|
208
|
+
|
|
209
|
+
// Hermes is always standalone — check next
|
|
195
210
|
const hermesDir = join(homedir(), '.hermes');
|
|
196
211
|
const hermesConfig = join(hermesDir, 'config.yaml');
|
|
197
212
|
if (existsSync(hermesConfig)) {
|
|
@@ -201,18 +216,18 @@ async function detectRuntime() {
|
|
|
201
216
|
} catch {}
|
|
202
217
|
}
|
|
203
218
|
|
|
204
|
-
// Check for
|
|
219
|
+
// Check for OpenClaw binary
|
|
205
220
|
try {
|
|
206
|
-
execSync('
|
|
207
|
-
return '
|
|
221
|
+
execSync('openclaw --version', { stdio: 'pipe' });
|
|
222
|
+
return 'openclaw';
|
|
208
223
|
} catch {}
|
|
209
224
|
|
|
210
|
-
// Check for
|
|
211
|
-
const
|
|
212
|
-
if (existsSync(
|
|
225
|
+
// Check for OpenClaw directory (fallback)
|
|
226
|
+
const openclawDir = join(homedir(), '.openclaw');
|
|
227
|
+
if (existsSync(openclawDir)) return 'openclaw';
|
|
213
228
|
|
|
214
|
-
//
|
|
215
|
-
return
|
|
229
|
+
// Nothing found
|
|
230
|
+
return null;
|
|
216
231
|
}
|
|
217
232
|
|
|
218
233
|
function getOpenClawVersion() {
|
|
@@ -741,7 +756,37 @@ export async function runInstall(options = {}) {
|
|
|
741
756
|
checkLinuxDockerPermissions();
|
|
742
757
|
|
|
743
758
|
// 1. Detect runtime — Hermes, NemoClaw, OpenClaw, or none
|
|
744
|
-
|
|
759
|
+
let runtime = options.runtimeOverride || await detectRuntime();
|
|
760
|
+
|
|
761
|
+
// 1b. No runtime detected — offer to install one
|
|
762
|
+
if (!runtime) {
|
|
763
|
+
printNoRuntimeDetected();
|
|
764
|
+
const installed = await promptAndInstallRuntime();
|
|
765
|
+
if (!installed) {
|
|
766
|
+
// User skipped or install failed
|
|
767
|
+
console.log(` ${dim('Install a runtime manually, then re-run:')} ${cyan('npx @robbiesrobotics/alice-agents')}`);
|
|
768
|
+
console.log('');
|
|
769
|
+
process.exit(1);
|
|
770
|
+
}
|
|
771
|
+
runtime = installed;
|
|
772
|
+
// Re-check model after install
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// 1c. User specified --runtime X but it's not installed
|
|
776
|
+
if (options.runtimeOverride && runtime !== options.runtimeOverride) {
|
|
777
|
+
const rtInfo = getRuntimeInfo(options.runtimeOverride);
|
|
778
|
+
if (rtInfo) {
|
|
779
|
+
console.log(` ${icons.info} ${dim(`You specified --runtime ${options.runtimeOverride} but ${rtInfo.name} is not installed.`)}`);
|
|
780
|
+
console.log('');
|
|
781
|
+
const installed = await promptAndInstallRuntime(options.runtimeOverride);
|
|
782
|
+
if (!installed) {
|
|
783
|
+
console.log(` ${dim('Install manually, then re-run:')} ${cyan('npx @robbiesrobotics/alice-agents --runtime ' + options.runtimeOverride)}`);
|
|
784
|
+
console.log('');
|
|
785
|
+
process.exit(1);
|
|
786
|
+
}
|
|
787
|
+
runtime = installed;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
745
790
|
|
|
746
791
|
// ── HERMES-ONLY PATH ──────────────────────────────────────────────────────
|
|
747
792
|
if (runtime === 'hermes') {
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* runtime-installer.mjs — Auto-install missing runtimes for A.L.I.C.E.
|
|
3
|
+
*
|
|
4
|
+
* Handles detecting, offering to install, and installing:
|
|
5
|
+
* - Hermes Agent (Nous Research)
|
|
6
|
+
* - OpenClaw
|
|
7
|
+
* - NemoClaw (NVIDIA)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { execSync } from 'node:child_process';
|
|
11
|
+
import { existsSync } from 'node:fs';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { confirm, choose } from './prompter.mjs';
|
|
15
|
+
|
|
16
|
+
// ── Colors / icons (duplicated from installer.mjs to avoid circular imports) ──
|
|
17
|
+
const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
|
|
18
|
+
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
19
|
+
const greenBold = (s) => `\x1b[1m\x1b[32m${s}\x1b[0m`;
|
|
20
|
+
const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
|
|
21
|
+
const red = (s) => `\x1b[31m${s}\x1b[0m`;
|
|
22
|
+
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
23
|
+
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
24
|
+
const icons = { ok: '✔', fail: '✗', info: 'ℹ', warn: '⚠' };
|
|
25
|
+
|
|
26
|
+
// ── Runtime definitions ──────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
const RUNTIMES = {
|
|
29
|
+
hermes: {
|
|
30
|
+
name: 'Hermes Agent',
|
|
31
|
+
maker: 'Nous Research',
|
|
32
|
+
emoji: '🧠',
|
|
33
|
+
tagline: 'Self-improving personal AI agent',
|
|
34
|
+
description: [
|
|
35
|
+
'Lightweight — runs on laptops, VPS, even Android.',
|
|
36
|
+
'Self-improving — creates skills from experience, remembers across sessions.',
|
|
37
|
+
'A.L.I.C.E. becomes a team of Hermes skills.',
|
|
38
|
+
],
|
|
39
|
+
installTime: '~2 minutes',
|
|
40
|
+
platforms: ['Linux', 'macOS', 'WSL2', 'Android/Termux'],
|
|
41
|
+
requiresDocker: false,
|
|
42
|
+
modelCommand: 'hermes model',
|
|
43
|
+
docsUrl: 'https://hermes-agent.nousresearch.com/docs/',
|
|
44
|
+
getInstallCommand() {
|
|
45
|
+
return 'curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash';
|
|
46
|
+
},
|
|
47
|
+
isInstalled() {
|
|
48
|
+
const hermesConfig = join(homedir(), '.hermes', 'config.yaml');
|
|
49
|
+
if (!existsSync(hermesConfig)) return false;
|
|
50
|
+
try {
|
|
51
|
+
execSync('hermes version', { stdio: 'pipe' });
|
|
52
|
+
return true;
|
|
53
|
+
} catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
getPostInstallSteps() {
|
|
58
|
+
return [
|
|
59
|
+
`Reload your shell: ${cyan('source ~/.bashrc')} ${dim('(or ~/.zshrc)')}`,
|
|
60
|
+
`Pick a model: ${cyan('hermes model')}`,
|
|
61
|
+
`Re-run A.L.I.C.E.: ${cyan('npx @robbiesrobotics/alice-agents')}`,
|
|
62
|
+
];
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
openclaw: {
|
|
67
|
+
name: 'OpenClaw',
|
|
68
|
+
maker: 'OpenClaw',
|
|
69
|
+
emoji: '🤖',
|
|
70
|
+
tagline: 'Mature multi-agent orchestration platform',
|
|
71
|
+
description: [
|
|
72
|
+
'Full agent workspaces, subagent spawning, cron, MCP support.',
|
|
73
|
+
'15+ messaging platforms. Mature ecosystem with ClawHub skills.',
|
|
74
|
+
'A.L.I.C.E. becomes an agent workspace tree.',
|
|
75
|
+
],
|
|
76
|
+
installTime: '~3 minutes',
|
|
77
|
+
platforms: ['Linux', 'macOS', 'Windows', 'WSL2'],
|
|
78
|
+
requiresDocker: false,
|
|
79
|
+
modelCommand: 'openclaw configure',
|
|
80
|
+
docsUrl: 'https://docs.openclaw.ai',
|
|
81
|
+
getInstallCommand() {
|
|
82
|
+
return 'npm install -g openclaw';
|
|
83
|
+
},
|
|
84
|
+
isInstalled() {
|
|
85
|
+
try {
|
|
86
|
+
execSync('openclaw --version', { stdio: 'pipe' });
|
|
87
|
+
return true;
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
getPostInstallSteps() {
|
|
93
|
+
return [
|
|
94
|
+
`Set up your model: ${cyan('openclaw configure')}`,
|
|
95
|
+
`Re-run A.L.I.C.E.: ${cyan('npx @robbiesrobotics/alice-agents')}`,
|
|
96
|
+
];
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
nemoclaw: {
|
|
101
|
+
name: 'NemoClaw',
|
|
102
|
+
maker: 'NVIDIA',
|
|
103
|
+
emoji: '🛡️',
|
|
104
|
+
tagline: 'Enterprise-grade agents with sandboxing',
|
|
105
|
+
description: [
|
|
106
|
+
'Agents run isolated — Landlock + seccomp + network namespace sandboxing.',
|
|
107
|
+
'Built on OpenClaw, hardened by NVIDIA. Best for sensitive data.',
|
|
108
|
+
'A.L.I.C.E. runs inside the OpenShell sandbox.',
|
|
109
|
+
],
|
|
110
|
+
installTime: '~20-30 minutes',
|
|
111
|
+
platforms: ['Linux', 'macOS (Docker)', 'DGX Spark', 'WSL2'],
|
|
112
|
+
requiresDocker: true,
|
|
113
|
+
modelCommand: '(configured during install)',
|
|
114
|
+
docsUrl: 'https://docs.nvidia.com/nemoclaw/latest/',
|
|
115
|
+
getInstallCommand() {
|
|
116
|
+
return 'curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash';
|
|
117
|
+
},
|
|
118
|
+
isInstalled() {
|
|
119
|
+
try {
|
|
120
|
+
execSync('nemoclaw --version', { stdio: 'pipe' });
|
|
121
|
+
return true;
|
|
122
|
+
} catch {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
getPostInstallSteps() {
|
|
127
|
+
return [
|
|
128
|
+
`NemoClaw configures your model during onboard.`,
|
|
129
|
+
`Connect: ${cyan('nemoclaw <name> connect')}`,
|
|
130
|
+
`Re-run A.L.I.C.E.: ${cyan('npx @robbiesrobotics/alice-agents --runtime nemoclaw')}`,
|
|
131
|
+
];
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// ── Public API ───────────────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Show the runtime selection wizard and install the chosen runtime.
|
|
140
|
+
* Returns the runtime key ('hermes' | 'openclaw' | 'nemoclaw') or null if user skips.
|
|
141
|
+
*/
|
|
142
|
+
export async function promptAndInstallRuntime(forceRuntime = null) {
|
|
143
|
+
// If user specified --runtime X but it's not installed, install that one
|
|
144
|
+
if (forceRuntime && RUNTIMES[forceRuntime]) {
|
|
145
|
+
return await installSpecificRuntime(forceRuntime);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// No runtime at all — show the full wizard
|
|
149
|
+
printRuntimeWizard();
|
|
150
|
+
|
|
151
|
+
const choice = await choose(
|
|
152
|
+
' Which runtime do you want to install?',
|
|
153
|
+
['1', '2', '3', 'skip'],
|
|
154
|
+
'1'
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const map = { '1': 'hermes', '2': 'openclaw', '3': 'nemoclaw' };
|
|
158
|
+
const picked = map[choice];
|
|
159
|
+
|
|
160
|
+
if (!picked) {
|
|
161
|
+
console.log(`\n ${dim('Skipped. Install a runtime manually and re-run this installer.')}\n`);
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return await installSpecificRuntime(picked);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Install a specific runtime, show progress, verify, and return the key.
|
|
170
|
+
*/
|
|
171
|
+
async function installSpecificRuntime(key) {
|
|
172
|
+
const rt = RUNTIMES[key];
|
|
173
|
+
if (!rt) return null;
|
|
174
|
+
|
|
175
|
+
// Pre-flight checks
|
|
176
|
+
if (rt.requiresDocker) {
|
|
177
|
+
const dockerOk = checkDockerAvailable();
|
|
178
|
+
if (!dockerOk) {
|
|
179
|
+
console.log(`\n ${icons.warn} ${yellow('Docker is required for ' + rt.name + ' but does not appear to be running.')}`);
|
|
180
|
+
console.log(` Start Docker (or Colima on macOS) and try again.\n`);
|
|
181
|
+
console.log(` ${dim('Docs: ' + rt.docsUrl)}\n`);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (key === 'nemoclaw') {
|
|
187
|
+
const platform = process.platform;
|
|
188
|
+
if (platform === 'darwin') {
|
|
189
|
+
console.log(`\n ${icons.warn} ${yellow('NemoClaw on macOS requires Docker Desktop or Colima.')}`);
|
|
190
|
+
console.log(` ${dim('Make sure one is running before proceeding.')}`);
|
|
191
|
+
const ok = await confirm(' Continue with NemoClaw install?', false);
|
|
192
|
+
if (!ok) return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Confirm
|
|
197
|
+
console.log(`\n ${bold(rt.emoji + ' Installing ' + rt.name + ' (' + rt.installTime + ')')}\n`);
|
|
198
|
+
console.log(` ${dim(rt.getInstallCommand())}\n`);
|
|
199
|
+
|
|
200
|
+
const ok = await confirm(' Proceed?', true);
|
|
201
|
+
if (!ok) return null;
|
|
202
|
+
|
|
203
|
+
// Run install
|
|
204
|
+
console.log('');
|
|
205
|
+
try {
|
|
206
|
+
execSync(rt.getInstallCommand(), { stdio: 'inherit', timeout: 10 * 60 * 1000 }); // 10 min timeout
|
|
207
|
+
} catch (err) {
|
|
208
|
+
console.log(`\n ${icons.fail} ${red('Installation failed.')}`);
|
|
209
|
+
console.log(` Install manually: ${cyan(rt.getInstallCommand())}`);
|
|
210
|
+
console.log(` Docs: ${dim(rt.docsUrl)}\n`);
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Verify
|
|
215
|
+
console.log('');
|
|
216
|
+
if (rt.isInstalled()) {
|
|
217
|
+
console.log(` ${icons.ok} ${green(rt.name + ' installed successfully!')}`);
|
|
218
|
+
} else {
|
|
219
|
+
console.log(` ${icons.warn} ${yellow('Install completed but ' + rt.name + ' not detected in PATH.')}`);
|
|
220
|
+
console.log(` You may need to reload your shell: ${cyan('source ~/.bashrc')}`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Post-install steps
|
|
224
|
+
const steps = rt.getPostInstallSteps();
|
|
225
|
+
if (steps.length) {
|
|
226
|
+
console.log(`\n ${bold('Next steps:')}`);
|
|
227
|
+
for (const step of steps) {
|
|
228
|
+
console.log(` ${step}`);
|
|
229
|
+
}
|
|
230
|
+
console.log('');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return key;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Check if Docker is available and running.
|
|
238
|
+
*/
|
|
239
|
+
function checkDockerAvailable() {
|
|
240
|
+
try {
|
|
241
|
+
execSync('docker info', { stdio: 'pipe' });
|
|
242
|
+
return true;
|
|
243
|
+
} catch {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Check if any supported runtime is installed.
|
|
250
|
+
* Returns the runtime key or null.
|
|
251
|
+
*/
|
|
252
|
+
export function detectAnyRuntime() {
|
|
253
|
+
for (const [key, rt] of Object.entries(RUNTIMES)) {
|
|
254
|
+
if (rt.isInstalled()) return key;
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Get runtime info object.
|
|
261
|
+
*/
|
|
262
|
+
export function getRuntimeInfo(key) {
|
|
263
|
+
return RUNTIMES[key] || null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Print the runtime selection wizard.
|
|
268
|
+
*/
|
|
269
|
+
function printRuntimeWizard() {
|
|
270
|
+
console.log('');
|
|
271
|
+
console.log(' ╭─ Choose Your Runtime ───────────────────────────────────────╮');
|
|
272
|
+
console.log(' │ │');
|
|
273
|
+
console.log(' │ A.L.I.C.E. needs a runtime to manage your agent team. │');
|
|
274
|
+
console.log(' │ │');
|
|
275
|
+
console.log(' │ Three options — they work great together too: │');
|
|
276
|
+
console.log(' │ │');
|
|
277
|
+
console.log(' │ 1. 🧠 Hermes Agent (recommended) │');
|
|
278
|
+
console.log(' │ Self-improving personal AI agent by Nous Research. │');
|
|
279
|
+
console.log(' │ Lightweight, runs anywhere — laptop, VPS, phone. │');
|
|
280
|
+
console.log(' │ A.L.I.C.E. becomes a team of Hermes skills. │');
|
|
281
|
+
console.log(' │ Install: ~2 minutes │');
|
|
282
|
+
console.log(' │ │');
|
|
283
|
+
console.log(' │ 2. 🤖 OpenClaw │');
|
|
284
|
+
console.log(' │ Mature multi-agent orchestration platform. │');
|
|
285
|
+
console.log(' │ Agent workspaces, subagent spawning, cron, MCP. │');
|
|
286
|
+
console.log(' │ A.L.I.C.E. becomes an agent workspace tree. │');
|
|
287
|
+
console.log(' │ Install: ~3 minutes │');
|
|
288
|
+
console.log(' │ │');
|
|
289
|
+
console.log(' │ 3. 🛡️ NemoClaw (NVIDIA) │');
|
|
290
|
+
console.log(' │ Enterprise-grade OpenClaw with OpenShell sandboxing. │');
|
|
291
|
+
console.log(' │ Agents run isolated — Landlock + seccomp + netns. │');
|
|
292
|
+
console.log(' │ Best for teams handling sensitive data. │');
|
|
293
|
+
console.log(' │ Requires Docker · Install: ~20-30 minutes │');
|
|
294
|
+
console.log(' │ │');
|
|
295
|
+
console.log(' │ Not sure? Start with Hermes — it\'s the fastest path. │');
|
|
296
|
+
console.log(' │ You can add OpenClaw or NemoClaw later. │');
|
|
297
|
+
console.log(' │ │');
|
|
298
|
+
console.log(' ╰─────────────────────────────────────────────────────────────╯');
|
|
299
|
+
console.log('');
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Print "runtime not detected" message (used before the wizard).
|
|
304
|
+
*/
|
|
305
|
+
export function printNoRuntimeDetected() {
|
|
306
|
+
console.log('');
|
|
307
|
+
console.log(` ${icons.warn} ${yellow('No supported runtime detected')}`);
|
|
308
|
+
console.log('');
|
|
309
|
+
console.log(' A.L.I.C.E. requires one of:');
|
|
310
|
+
console.log(` ${cyan('1.')} Hermes Agent ${dim('— personal AI agent, self-improving')}`);
|
|
311
|
+
console.log(` ${cyan('2.')} OpenClaw ${dim('— multi-agent orchestration, mature ecosystem')}`);
|
|
312
|
+
console.log(` ${cyan('3.')} NemoClaw ${dim('— enterprise sandboxed agents (NVIDIA)')}`);
|
|
313
|
+
console.log('');
|
|
314
|
+
}
|