@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 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
- // Hermes is always standalone check first
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 NemoClaw binary
219
+ // Check for OpenClaw binary
205
220
  try {
206
- execSync('nemoclaw --version', { stdio: 'pipe' });
207
- return 'nemoclaw';
221
+ execSync('openclaw --version', { stdio: 'pipe' });
222
+ return 'openclaw';
208
223
  } catch {}
209
224
 
210
- // Check for NemoClaw directory
211
- const nemoclawDir = join(homedir(), '.nemoclaw');
212
- if (existsSync(nemoclawDir)) return 'nemoclaw';
225
+ // Check for OpenClaw directory (fallback)
226
+ const openclawDir = join(homedir(), '.openclaw');
227
+ if (existsSync(openclawDir)) return 'openclaw';
213
228
 
214
- // Fall back to OpenClaw
215
- return 'openclaw';
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
- const runtime = options.runtimeOverride || await detectRuntime();
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbiesrobotics/alice-agents",
3
- "version": "1.5.10",
3
+ "version": "1.5.11",
4
4
  "description": "A.L.I.C.E. — 31 AI agents for OpenClaw. One conversation, one team.",
5
5
  "bin": {
6
6
  "alice-agents": "bin/alice-install.mjs",