robot-resources 1.3.3 → 1.3.5

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.
Files changed (2) hide show
  1. package/lib/wizard.js +70 -61
  2. package/package.json +1 -1
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,71 +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
- try {
258
- const hostname = (await import('node:os')).hostname();
259
- const platformUrl = process.env.RR_PLATFORM_URL || 'https://api.robotresources.ai';
260
- const res = await fetch(`${platformUrl}/v1/auth/signup`, {
261
- method: 'POST',
262
- headers: { 'Content-Type': 'application/json' },
263
- body: JSON.stringify({
264
- agent_name: hostname,
265
- platform: 'cli',
266
- }),
267
- signal: AbortSignal.timeout(10_000),
268
- });
269
-
270
- if (res.ok) {
271
- const { data } = await res.json();
272
- writeConfig({
273
- api_key: data.api_key,
274
- key_id: data.key_id,
275
- claim_url: data.claim_url,
276
- signup_source: 'auto',
277
- });
278
- results.auth = true;
279
- results.authMethod = 'auto';
280
- results.claimUrl = data.claim_url;
281
- success('Dashboard: API key provisioned (telemetry active)');
282
- if (data.claim_url) {
283
- info(`Claim your dashboard: ${data.claim_url}`);
284
- }
285
- } else {
286
- // Non-fatal — router works without telemetry
287
- info('Dashboard: https://robotresources.ai/dashboard');
288
- }
289
- } catch {
290
- // Network error, timeout, etc. — non-fatal
291
- info('Dashboard: https://robotresources.ai/dashboard');
292
- }
301
+ info('Dashboard: https://robotresources.ai/dashboard');
293
302
  }
294
303
  }
295
304
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robot-resources",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "Robot Resources — AI agent runtime tools. One command to install everything.",
5
5
  "type": "module",
6
6
  "bin": {