robot-resources 1.3.4 → 1.3.6

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.
@@ -23,6 +23,6 @@ export async function setupRouter() {
23
23
  }
24
24
 
25
25
  const venvPython = ensureVenv(python.bin);
26
- installRouter();
26
+ await installRouter();
27
27
  return { venvPython, pythonVersion: python.version };
28
28
  }
package/lib/wizard.js CHANGED
@@ -30,6 +30,71 @@ export async function runWizard({ nonInteractive = false } = {}) {
30
30
  mcp: [],
31
31
  };
32
32
 
33
+ // ── Step 0: Provision API key (before anything else) ────────────────────
34
+ //
35
+ // Provision early so config.json exists before any tool installs.
36
+ // If the session dies later, telemetry still works for all tools.
37
+ // Single fetch() with 10s timeout — no prompts, no browser.
38
+
39
+ {
40
+ const config = readConfig();
41
+ if (!config.api_key && !process.env.RR_API_KEY) {
42
+ try {
43
+ const { hostname } = await import('node:os');
44
+ const { join } = await import('node:path');
45
+ const { homedir } = await import('node:os');
46
+ const { readFileSync, writeFileSync, mkdirSync } = await import('node:fs');
47
+ const { randomUUID } = await import('node:crypto');
48
+
49
+ const rrDir = join(homedir(), '.robot-resources');
50
+ const machineIdPath = join(rrDir, '.machine-id');
51
+ let machineId;
52
+ try {
53
+ machineId = readFileSync(machineIdPath, 'utf-8').trim();
54
+ } catch {
55
+ machineId = randomUUID();
56
+ try {
57
+ mkdirSync(rrDir, { recursive: true });
58
+ writeFileSync(machineIdPath, machineId, 'utf-8');
59
+ } catch { /* non-fatal */ }
60
+ }
61
+
62
+ const platformUrl = process.env.RR_PLATFORM_URL || 'https://api.robotresources.ai';
63
+ const res = await fetch(`${platformUrl}/v1/auth/signup`, {
64
+ method: 'POST',
65
+ headers: { 'Content-Type': 'application/json' },
66
+ body: JSON.stringify({
67
+ agent_name: hostname(),
68
+ platform: 'cli',
69
+ machine_id: machineId,
70
+ }),
71
+ signal: AbortSignal.timeout(10_000),
72
+ });
73
+
74
+ if (res.ok) {
75
+ const { data } = await res.json();
76
+ if (data.api_key !== 'existing') {
77
+ writeConfig({
78
+ api_key: data.api_key,
79
+ key_id: data.key_id,
80
+ claim_url: data.claim_url,
81
+ signup_source: 'auto',
82
+ });
83
+ }
84
+ results.auth = true;
85
+ results.authMethod = 'auto';
86
+ results.claimUrl = data.claim_url;
87
+ }
88
+ } catch {
89
+ // Non-fatal — tools work without telemetry
90
+ }
91
+ } else {
92
+ results.auth = true;
93
+ results.authMethod = config.api_key ? 'config' : 'apikey';
94
+ results.claimUrl = config.claim_url || null;
95
+ }
96
+ }
97
+
33
98
  // ── Step 1: Router Installation ─────────────────────────────────────────
34
99
 
35
100
  step('Checking Router...');
@@ -225,96 +290,15 @@ export async function runWizard({ nonInteractive = false } = {}) {
225
290
 
226
291
  summary(lines);
227
292
 
228
- // ── Step 5: Dashboard silent provisioning + claim link ────────────────
229
- //
230
- // Silently call the platform API to create a placeholder account.
231
- // This gives us an API key (telemetry starts flowing immediately)
232
- // and a claim URL (human clicks to adopt the dashboard).
233
- // No prompts, no browser, no blocking.
293
+ // ── Claim link output (provisioning already happened at Step 1.5) ─────
234
294
 
235
295
  if (somethingInstalled) {
236
296
  blank();
237
-
238
- const config = readConfig();
239
- if (config.api_key) {
240
- // Already provisioned from a previous run
241
- success(`Dashboard: API key configured`);
242
- if (config.claim_url) {
243
- info(`Claim your dashboard: ${config.claim_url}`);
244
- }
245
- results.auth = true;
246
- results.authMethod = 'config';
247
- } else if (process.env.RR_API_KEY) {
248
- const envKey = process.env.RR_API_KEY;
249
- if (envKey.startsWith('rr_live_')) {
250
- writeConfig({ api_key: envKey, signup_source: 'agent' });
251
- success('Dashboard: API key loaded from RR_API_KEY');
252
- results.auth = true;
253
- results.authMethod = 'apikey';
254
- }
297
+ const claimUrl = results.claimUrl || readConfig().claim_url;
298
+ if (claimUrl) {
299
+ info(`Claim your dashboard: ${claimUrl}`);
255
300
  } else {
256
- // Silent provisioning — no prompt, no browser
257
- // Use a stable machine ID so re-runs don't create duplicate accounts
258
- try {
259
- const { hostname } = await import('node:os');
260
- const { join } = await import('node:path');
261
- const { homedir } = await import('node:os');
262
- const { readFileSync, writeFileSync, mkdirSync } = await import('node:fs');
263
- const { randomUUID } = await import('node:crypto');
264
-
265
- const rrDir = join(homedir(), '.robot-resources');
266
- const machineIdPath = join(rrDir, '.machine-id');
267
- let machineId;
268
- try {
269
- machineId = readFileSync(machineIdPath, 'utf-8').trim();
270
- } catch {
271
- machineId = randomUUID();
272
- try {
273
- mkdirSync(rrDir, { recursive: true });
274
- writeFileSync(machineIdPath, machineId, 'utf-8');
275
- } catch { /* non-fatal */ }
276
- }
277
-
278
- const platformUrl = process.env.RR_PLATFORM_URL || 'https://api.robotresources.ai';
279
- const res = await fetch(`${platformUrl}/v1/auth/signup`, {
280
- method: 'POST',
281
- headers: { 'Content-Type': 'application/json' },
282
- body: JSON.stringify({
283
- agent_name: hostname(),
284
- platform: 'cli',
285
- machine_id: machineId,
286
- }),
287
- signal: AbortSignal.timeout(10_000),
288
- });
289
-
290
- if (res.ok) {
291
- const { data } = await res.json();
292
- if (data.api_key === 'existing') {
293
- // Machine already provisioned in a previous run
294
- success('Dashboard: already provisioned');
295
- } else {
296
- writeConfig({
297
- api_key: data.api_key,
298
- key_id: data.key_id,
299
- claim_url: data.claim_url,
300
- signup_source: 'auto',
301
- });
302
- success('Dashboard: API key provisioned (telemetry active)');
303
- }
304
- results.auth = true;
305
- results.authMethod = 'auto';
306
- results.claimUrl = data.claim_url;
307
- if (data.claim_url) {
308
- info(`Claim your dashboard: ${data.claim_url}`);
309
- }
310
- } else {
311
- // Non-fatal — router works without telemetry
312
- info('Dashboard: https://robotresources.ai/dashboard');
313
- }
314
- } catch {
315
- // Network error, timeout, etc. — non-fatal
316
- info('Dashboard: https://robotresources.ai/dashboard');
317
- }
301
+ info('Dashboard: https://robotresources.ai/dashboard');
318
302
  }
319
303
  }
320
304
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robot-resources",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "description": "Robot Resources — AI agent runtime tools. One command to install everything.",
5
5
  "type": "module",
6
6
  "bin": {