@robbiesrobotics/alice-agents 1.5.6 → 1.5.8
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/bin/alice-cloud.cjs +71 -55
- package/lib/installer.mjs +15 -10
- package/package.json +1 -1
package/bin/alice-cloud.cjs
CHANGED
|
@@ -50,10 +50,34 @@ function runCommand(cmd, args) {
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/** Fetch JSON helper — replaces `got` with native fetch (Node 18+) */
|
|
54
|
+
async function fetchJson(url, options = {}) {
|
|
55
|
+
const { method = 'GET', json, headers = {}, timeoutMs = 15000 } = options;
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
58
|
+
try {
|
|
59
|
+
const fetchOpts = {
|
|
60
|
+
method,
|
|
61
|
+
headers: { ...headers },
|
|
62
|
+
signal: controller.signal,
|
|
63
|
+
};
|
|
64
|
+
if (json !== undefined) {
|
|
65
|
+
fetchOpts.headers['Content-Type'] = 'application/json';
|
|
66
|
+
fetchOpts.body = JSON.stringify(json);
|
|
67
|
+
}
|
|
68
|
+
const res = await fetch(url, fetchOpts);
|
|
69
|
+
const text = await res.text();
|
|
70
|
+
let data;
|
|
71
|
+
try { data = JSON.parse(text); } catch (_) { data = text; }
|
|
72
|
+
return { ok: res.ok, status: res.status, data };
|
|
73
|
+
} finally {
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
53
78
|
// ── Login ──────────────────────────────────────────────────────────────────────
|
|
54
79
|
async function login(args) {
|
|
55
80
|
const open = (await import('open')).default;
|
|
56
|
-
const got = (await import('got')).default;
|
|
57
81
|
|
|
58
82
|
// Non-interactive mode: use token from env
|
|
59
83
|
if (NON_INTERACTIVE) {
|
|
@@ -63,15 +87,15 @@ async function login(args) {
|
|
|
63
87
|
process.exit(1);
|
|
64
88
|
}
|
|
65
89
|
try {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
})
|
|
90
|
+
const supabaseUrl = process.env.ALICE_SUPABASE_URL || 'https://xxxgvtwnlbtdgmlgccee.supabase.co';
|
|
91
|
+
const { ok, data } = await fetchJson(`${supabaseUrl}/auth/v1/user`, {
|
|
92
|
+
headers: { Authorization: `Bearer ${token}`, apikey: token },
|
|
93
|
+
});
|
|
70
94
|
const config = loadConfig();
|
|
71
95
|
config.supabaseToken = token;
|
|
72
|
-
config.user =
|
|
96
|
+
config.user = data;
|
|
73
97
|
saveConfig(config);
|
|
74
|
-
console.log('✅ Logged in as',
|
|
98
|
+
console.log('✅ Logged in as', data.email || data.user_metadata?.user_name || 'unknown');
|
|
75
99
|
return;
|
|
76
100
|
} catch (err) {
|
|
77
101
|
console.error('❌ Token validation failed:', err.message);
|
|
@@ -80,15 +104,13 @@ async function login(args) {
|
|
|
80
104
|
}
|
|
81
105
|
|
|
82
106
|
console.log('🔐 A.L.I.C.E. Cloud login');
|
|
83
|
-
console.log(' Opening browser for
|
|
107
|
+
console.log(' Opening browser for login…');
|
|
84
108
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
console.log(' Browser opened. Complete login in your browser.');
|
|
91
|
-
console.log(' After login, paste your Supabase access token here:');
|
|
109
|
+
const loginUrl = `${API_BASE.replace('/api/cloud', '')}/login?cli=1`;
|
|
110
|
+
try { await open(loginUrl); } catch (_) {
|
|
111
|
+
console.log(` Could not open browser. Visit: ${loginUrl}`);
|
|
112
|
+
}
|
|
113
|
+
console.log(' After login, copy the access token and paste it here:');
|
|
92
114
|
process.stdout.write(' > ');
|
|
93
115
|
|
|
94
116
|
return new Promise((resolve, reject) => {
|
|
@@ -99,15 +121,15 @@ async function login(args) {
|
|
|
99
121
|
token = token.trim();
|
|
100
122
|
if (!token) { reject(new Error('No token provided')); return; }
|
|
101
123
|
try {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
})
|
|
124
|
+
const supabaseUrl = process.env.ALICE_SUPABASE_URL || 'https://xxxgvtwnlbtdgmlgccee.supabase.co';
|
|
125
|
+
const { ok, data } = await fetchJson(`${supabaseUrl}/auth/v1/user`, {
|
|
126
|
+
headers: { Authorization: `Bearer ${token}`, apikey: token },
|
|
127
|
+
});
|
|
106
128
|
const config = loadConfig();
|
|
107
129
|
config.supabaseToken = token;
|
|
108
|
-
config.user =
|
|
130
|
+
config.user = data;
|
|
109
131
|
saveConfig(config);
|
|
110
|
-
console.log(' ✅ Logged in as',
|
|
132
|
+
console.log(' ✅ Logged in as', data.email || data.user_metadata?.user_name || 'unknown');
|
|
111
133
|
resolve();
|
|
112
134
|
} catch (err) {
|
|
113
135
|
reject(new Error('Token validation failed: ' + err.message));
|
|
@@ -118,11 +140,10 @@ async function login(args) {
|
|
|
118
140
|
|
|
119
141
|
// ── Register ───────────────────────────────────────────────────────────────────
|
|
120
142
|
async function detectGatewayUrl() {
|
|
121
|
-
const got = (await import('got')).default;
|
|
122
143
|
const candidates = ['https://localhost:18789', 'http://localhost:18789'];
|
|
123
144
|
for (const url of candidates) {
|
|
124
145
|
try {
|
|
125
|
-
|
|
146
|
+
const { ok } = await fetchJson(url, { timeoutMs: 2000 });
|
|
126
147
|
return url;
|
|
127
148
|
} catch (_) {}
|
|
128
149
|
}
|
|
@@ -144,7 +165,6 @@ async function getOpenClawVersion() {
|
|
|
144
165
|
}
|
|
145
166
|
|
|
146
167
|
async function register(args) {
|
|
147
|
-
const got = (await import('got')).default;
|
|
148
168
|
const config = loadConfig();
|
|
149
169
|
|
|
150
170
|
if (!config.supabaseToken) {
|
|
@@ -165,11 +185,12 @@ async function register(args) {
|
|
|
165
185
|
let lastError;
|
|
166
186
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
167
187
|
try {
|
|
168
|
-
const
|
|
188
|
+
const { ok, status, data } = await fetchJson(`${API_BASE}/register`, {
|
|
189
|
+
method: 'POST',
|
|
169
190
|
json: { gatewayUrl, gatewayToken, hostname, version },
|
|
170
191
|
headers: { Authorization: `Bearer ${config.supabaseToken}` },
|
|
171
|
-
|
|
172
|
-
}
|
|
192
|
+
});
|
|
193
|
+
if (!ok) throw new Error(`HTTP ${status}: ${typeof data === 'string' ? data : JSON.stringify(data)}`);
|
|
173
194
|
config.registration = { gatewayUrl, hostname, version, registeredAt: new Date().toISOString() };
|
|
174
195
|
saveConfig(config);
|
|
175
196
|
console.log(' ✅ Gateway registered!');
|
|
@@ -187,7 +208,6 @@ async function register(args) {
|
|
|
187
208
|
|
|
188
209
|
// ── Status ─────────────────────────────────────────────────────────────────────
|
|
189
210
|
async function status(args) {
|
|
190
|
-
const got = (await import('got')).default;
|
|
191
211
|
const config = loadConfig();
|
|
192
212
|
|
|
193
213
|
if (!config.supabaseToken) {
|
|
@@ -196,12 +216,16 @@ async function status(args) {
|
|
|
196
216
|
}
|
|
197
217
|
|
|
198
218
|
try {
|
|
199
|
-
const data = await
|
|
219
|
+
const { ok, status: httpStatus, data } = await fetchJson(`${API_BASE}/status`, {
|
|
200
220
|
headers: { Authorization: `Bearer ${config.supabaseToken}` },
|
|
201
|
-
|
|
202
|
-
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
if (httpStatus === 401) {
|
|
224
|
+
console.error('❌ Session expired. Run `alice-cloud login` again.');
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
203
227
|
|
|
204
|
-
if (!data.registered) {
|
|
228
|
+
if (!ok || !data.registered) {
|
|
205
229
|
console.log('⚪ No gateway registered.');
|
|
206
230
|
console.log(' Run `alice-cloud register` to connect your gateway.');
|
|
207
231
|
return;
|
|
@@ -214,18 +238,13 @@ async function status(args) {
|
|
|
214
238
|
console.log(` Last heartbeat: ${data.lastHeartbeat ? new Date(data.lastHeartbeat).toLocaleString() : 'Never'}`);
|
|
215
239
|
console.log(` Version : ${data.version}`);
|
|
216
240
|
} catch (err) {
|
|
217
|
-
|
|
218
|
-
console.error('❌ Session expired. Run `alice-cloud login` again.');
|
|
219
|
-
} else {
|
|
220
|
-
console.error('❌ Status check failed:', err.message);
|
|
221
|
-
}
|
|
241
|
+
console.error('❌ Status check failed:', err.message);
|
|
222
242
|
process.exit(1);
|
|
223
243
|
}
|
|
224
244
|
}
|
|
225
245
|
|
|
226
246
|
// ── Unregister ─────────────────────────────────────────────────────────────────
|
|
227
247
|
async function unregister(args) {
|
|
228
|
-
const got = (await import('got')).default;
|
|
229
248
|
const config = loadConfig();
|
|
230
249
|
|
|
231
250
|
if (!config.supabaseToken) {
|
|
@@ -235,35 +254,33 @@ async function unregister(args) {
|
|
|
235
254
|
|
|
236
255
|
console.log('🗑️ Unregistering gateway…');
|
|
237
256
|
try {
|
|
238
|
-
await
|
|
257
|
+
const { ok, status } = await fetchJson(`${API_BASE}/status`, {
|
|
258
|
+
method: 'DELETE',
|
|
239
259
|
headers: { Authorization: `Bearer ${config.supabaseToken}` },
|
|
240
|
-
throwHttpErrors: false,
|
|
241
260
|
});
|
|
242
|
-
|
|
243
|
-
saveConfig(config);
|
|
244
|
-
console.log(' ✅ Gateway unregistered.');
|
|
245
|
-
} catch (err) {
|
|
246
|
-
if (err.response?.statusCode === 404) {
|
|
261
|
+
if (status === 404) {
|
|
247
262
|
console.log(' ℹ️ No gateway was registered.');
|
|
248
263
|
} else {
|
|
249
|
-
|
|
250
|
-
|
|
264
|
+
delete config.registration;
|
|
265
|
+
saveConfig(config);
|
|
266
|
+
console.log(' ✅ Gateway unregistered.');
|
|
251
267
|
}
|
|
268
|
+
} catch (err) {
|
|
269
|
+
console.error('❌ Unregister failed:', err.message);
|
|
270
|
+
process.exit(1);
|
|
252
271
|
}
|
|
253
272
|
}
|
|
254
273
|
|
|
255
274
|
// ── Watch (daemon) ─────────────────────────────────────────────────────────────
|
|
256
275
|
async function checkGatewayUp(gatewayUrl) {
|
|
257
|
-
const got = (await import('got')).default;
|
|
258
276
|
try {
|
|
259
|
-
|
|
277
|
+
const { ok } = await fetchJson(gatewayUrl, { timeoutMs: 3000 });
|
|
260
278
|
return true;
|
|
261
279
|
} catch (_) {}
|
|
262
280
|
return false;
|
|
263
281
|
}
|
|
264
282
|
|
|
265
283
|
async function startHeartbeatLoop(config) {
|
|
266
|
-
const got = (await import('got')).default;
|
|
267
284
|
const gatewayUrl = config.registration?.gatewayUrl || 'https://localhost:18789';
|
|
268
285
|
|
|
269
286
|
async function heartbeat() {
|
|
@@ -273,10 +290,11 @@ async function startHeartbeatLoop(config) {
|
|
|
273
290
|
console.log('[watch] Gateway down, attempting restart…');
|
|
274
291
|
try { await runCommand('openclaw', ['gateway', 'start']); await sleep(3000); } catch (_) {}
|
|
275
292
|
}
|
|
276
|
-
await
|
|
293
|
+
await fetchJson(`${API_BASE}/heartbeat`, {
|
|
294
|
+
method: 'POST',
|
|
277
295
|
json: { hostname: os.hostname(), connected: await checkGatewayUp(gatewayUrl), timestamp: new Date().toISOString() },
|
|
278
296
|
headers: { Authorization: `Bearer ${config.supabaseToken}` },
|
|
279
|
-
|
|
297
|
+
timeoutMs: 10000,
|
|
280
298
|
});
|
|
281
299
|
console.log(`[${new Date().toLocaleTimeString()}] heartbeat sent (gateway: ${isUp ? 'up' : 'down'})`);
|
|
282
300
|
} catch (err) {
|
|
@@ -312,7 +330,6 @@ async function watch(args) {
|
|
|
312
330
|
}
|
|
313
331
|
|
|
314
332
|
// ── Programmatic API exports ───────────────────────────────────────────────────
|
|
315
|
-
// Allow ESM callers to import these via createRequire or spawn as child process.
|
|
316
333
|
module.exports = {
|
|
317
334
|
login,
|
|
318
335
|
register,
|
|
@@ -328,13 +345,12 @@ module.exports = {
|
|
|
328
345
|
};
|
|
329
346
|
|
|
330
347
|
// ── CLI dispatcher ─────────────────────────────────────────────────────────────
|
|
331
|
-
// Only run as CLI when this file is the main module (not when required/imported)
|
|
332
348
|
if (require.main === module) {
|
|
333
349
|
const commands = { login, register, status, unregister, watch };
|
|
334
350
|
const cmd = process.argv[2];
|
|
335
351
|
|
|
336
352
|
if (!cmd) {
|
|
337
|
-
console.log(`alice-cloud v1.0
|
|
353
|
+
console.log(`alice-cloud v1.1.0 — A.L.I.C.E. | Control Cloud CLI
|
|
338
354
|
|
|
339
355
|
Usage: alice-cloud <command> [options]
|
|
340
356
|
|
package/lib/installer.mjs
CHANGED
|
@@ -447,7 +447,7 @@ function printBanner() {
|
|
|
447
447
|
console.log(` ${dim('│')} ${dim('Adaptive Learning & Intelligent Coordination')} ${dim('│')}`);
|
|
448
448
|
console.log(` ${dim('│')} ${dim('Engine — Multi-Agent Orchestration')} ${dim('│')}`);
|
|
449
449
|
console.log(` ${dim('│')} ${dim('│')}`);
|
|
450
|
-
console.log(` ${dim('│')} ${dim('v' + version)} ${green('●')} ${dim('
|
|
450
|
+
console.log(` ${dim('│')} ${dim('v' + version)} ${green('●')} ${dim('31 AI agents, one team')} ${dim('│')}`);
|
|
451
451
|
console.log(` ${dim('│')} ${dim('│')}`);
|
|
452
452
|
console.log(` ${dim('╰──────────────────────────────────────────────╯')}`);
|
|
453
453
|
console.log('');
|
|
@@ -479,7 +479,7 @@ function printSummaryWithOptions(mode, tier, agents, preset, userInfo, detectedM
|
|
|
479
479
|
`${dim('Model:')} ${green(modelLabel)}`,
|
|
480
480
|
`${dim('User:')} ${green(userInfo.name)}`,
|
|
481
481
|
`${dim('Timezone:')} ${green(userInfo.timezone)}`,
|
|
482
|
-
`${dim('Cloud:')} ${
|
|
482
|
+
`${dim('Cloud:')} ${missionControl?.enabled ? (isCloudAuthenticated() ? green('connected') : yellow('enabled (setup pending)')) : dim('local only')}`,
|
|
483
483
|
...(missionControl?.enabled
|
|
484
484
|
? [
|
|
485
485
|
`${dim('Dashboard:')} ${green(missionControl.dashboardUrl)}`,
|
|
@@ -526,20 +526,18 @@ async function _runCloudOnboarding(auto, options, existingMissionControl) {
|
|
|
526
526
|
writeCloudJson(cloudData);
|
|
527
527
|
printStepDone('Cloud token saved');
|
|
528
528
|
} else if (!auto) {
|
|
529
|
-
// Interactive: open
|
|
530
|
-
console.log(` ${dim('A.L.I.C.E.
|
|
531
|
-
console.log(` ${dim('We\'ll open
|
|
529
|
+
// Interactive: open the dashboard login page and prompt for token
|
|
530
|
+
console.log(` ${dim('Sign in to A.L.I.C.E. | Control to connect your local gateway.')}`);
|
|
531
|
+
console.log(` ${dim('We\'ll open the login page — after signing in, copy the access token shown.')}`);
|
|
532
532
|
console.log('');
|
|
533
533
|
|
|
534
534
|
try {
|
|
535
535
|
const open = (await import('open')).default;
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
await open(oauthUrl);
|
|
539
|
-
console.log(` ${green('Browser opened!')} Sign in with GitHub and copy the token shown.`);
|
|
536
|
+
await open('https://alice.av3.ai/login?cli=1');
|
|
537
|
+
console.log(` ${green('Browser opened!')} Sign in and copy the access token shown.`);
|
|
540
538
|
} catch {
|
|
541
539
|
console.log(` ${yellow('Could not open browser.')} Visit this URL to sign in:`);
|
|
542
|
-
console.log(` ${cyan('https://alice.av3.ai/login')}`);
|
|
540
|
+
console.log(` ${cyan('https://alice.av3.ai/login?cli=1')}`);
|
|
543
541
|
}
|
|
544
542
|
console.log('');
|
|
545
543
|
|
|
@@ -1003,9 +1001,16 @@ export async function runInstall(options = {}) {
|
|
|
1003
1001
|
console.log(` ${icons.info} ${dim('Runtime: OpenClaw')}`);
|
|
1004
1002
|
}
|
|
1005
1003
|
console.log('');
|
|
1004
|
+
if (missionControl?.enabled && !isCloudAuthenticated()) {
|
|
1005
|
+
console.log(` ${yellow('☁️ Cloud setup pending:')} ${cyan('alice-cloud login && alice-cloud register')}`);
|
|
1006
|
+
console.log('');
|
|
1007
|
+
}
|
|
1006
1008
|
console.log(` ${dim('Manage skills:')} ${cyan('npx @robbiesrobotics/alice-agents --skills')}`);
|
|
1007
1009
|
console.log(` ${dim('Health check:')} ${cyan('npx @robbiesrobotics/alice-agents --doctor')}`);
|
|
1008
1010
|
console.log(` ${dim('Restart runtime:')} ${cyan('openclaw gateway restart')}`);
|
|
1011
|
+
if (missionControl?.enabled) {
|
|
1012
|
+
console.log(` ${dim('Cloud dashboard:')} ${cyan('https://alice.av3.ai')}`);
|
|
1013
|
+
}
|
|
1009
1014
|
console.log('');
|
|
1010
1015
|
printSeparator();
|
|
1011
1016
|
console.log('');
|