robot-resources 1.3.0 → 1.3.2

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/detect.js CHANGED
@@ -156,6 +156,21 @@ export function getOpenClawAuthMode() {
156
156
  return 'apikey';
157
157
  }
158
158
 
159
+ /**
160
+ * Detect if the environment is headless (no browser available).
161
+ * On headless servers, login() tries xdg-open which fails silently,
162
+ * then hangs for 120s waiting for a callback that never comes.
163
+ */
164
+ export function isHeadless() {
165
+ // SSH session — no local browser
166
+ if (process.env.SSH_CONNECTION || process.env.SSH_CLIENT) return true;
167
+ // Linux without a display server
168
+ if (process.platform === 'linux' && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) return true;
169
+ // Docker / container
170
+ if (process.env.container || process.env.DOCKER_CONTAINER) return true;
171
+ return false;
172
+ }
173
+
159
174
  /**
160
175
  * Check if the router service is already registered.
161
176
  */
package/lib/wizard.js CHANGED
@@ -1,11 +1,10 @@
1
1
  import { readConfig, writeConfig } from '@robot-resources/cli-core/config.mjs';
2
- import { login } from '@robot-resources/cli-core/login.mjs';
3
- import { findPython, isPortAvailable } from './detect.js';
2
+ import { findPython, isPortAvailable, isHeadless } from './detect.js';
4
3
  import { setupRouter, isRouterInstalled, getVenvPythonPath } from './python-bridge.js';
5
4
  import { installService, isServiceRunning, isServiceInstalled } from './service.js';
6
5
  import { configureAgentMCP } from './mcp-config.js';
7
6
  import { configureToolRouting } from './tool-config.js';
8
- import { header, step, success, warn, error, info, blank, summary, confirm, prompt } from './ui.js';
7
+ import { header, step, success, warn, error, info, blank, summary } from './ui.js';
9
8
 
10
9
  /**
11
10
  * Main setup wizard. Handles the full onboarding flow:
@@ -193,19 +192,23 @@ export async function runWizard({ nonInteractive = false } = {}) {
193
192
 
194
193
  summary(lines);
195
194
 
196
- // ── Step 5: Dashboard login (optional, always last) ────────────────────
195
+ // ── Step 5: Dashboard silent provisioning + claim link ────────────────
197
196
  //
198
- // Auth is deliberately at the end. The router works fully without it.
199
- // Dashboard is for humans agents should skip this and tell their
200
- // human to run the login command later if they want monitoring.
197
+ // Silently call the platform API to create a placeholder account.
198
+ // This gives us an API key (telemetry starts flowing immediately)
199
+ // and a claim URL (human clicks to adopt the dashboard).
200
+ // No prompts, no browser, no blocking.
201
201
 
202
202
  if (somethingInstalled) {
203
203
  blank();
204
204
 
205
- // Check if already authenticated (from a previous run)
206
205
  const config = readConfig();
207
206
  if (config.api_key) {
208
- success(`Dashboard: logged in as ${config.user_name || config.user_email || 'unknown'}`);
207
+ // Already provisioned from a previous run
208
+ success(`Dashboard: API key configured`);
209
+ if (config.claim_url) {
210
+ info(`Claim your dashboard: ${config.claim_url}`);
211
+ }
209
212
  results.auth = true;
210
213
  results.authMethod = 'config';
211
214
  } else if (process.env.RR_API_KEY) {
@@ -216,28 +219,43 @@ export async function runWizard({ nonInteractive = false } = {}) {
216
219
  results.auth = true;
217
220
  results.authMethod = 'apikey';
218
221
  }
219
- }
220
-
221
- if (!results.auth) {
222
- if (nonInteractive) {
223
- // Agent flow: don't prompt, just tell the agent what to relay
224
- info('Dashboard (optional): run "npx robot-resources login" to claim your dashboard');
225
- } else {
226
- // Interactive flow: offer login but don't block on "no"
227
- const shouldLogin = await confirm('Claim your dashboard? (optional)', { defaultYes: false, nonInteractive });
228
- if (shouldLogin) {
229
- try {
230
- await login();
231
- results.auth = true;
232
- results.authMethod = 'github';
233
- success('Dashboard claimed');
234
- } catch (err) {
235
- error(`Login failed: ${err.message}`);
236
- info('You can claim later: npx robot-resources login');
222
+ } else {
223
+ // Silent provisioning — no prompt, no browser
224
+ try {
225
+ const hostname = (await import('node:os')).hostname();
226
+ const platformUrl = process.env.RR_PLATFORM_URL || 'https://api.robotresources.ai';
227
+ const res = await fetch(`${platformUrl}/v1/auth/signup`, {
228
+ method: 'POST',
229
+ headers: { 'Content-Type': 'application/json' },
230
+ body: JSON.stringify({
231
+ agent_name: hostname,
232
+ platform: 'cli',
233
+ }),
234
+ signal: AbortSignal.timeout(10_000),
235
+ });
236
+
237
+ if (res.ok) {
238
+ const { data } = await res.json();
239
+ writeConfig({
240
+ api_key: data.api_key,
241
+ key_id: data.key_id,
242
+ claim_url: data.claim_url,
243
+ signup_source: 'auto',
244
+ });
245
+ results.auth = true;
246
+ results.authMethod = 'auto';
247
+ results.claimUrl = data.claim_url;
248
+ success('Dashboard: API key provisioned (telemetry active)');
249
+ if (data.claim_url) {
250
+ info(`Claim your dashboard: ${data.claim_url}`);
237
251
  }
238
252
  } else {
239
- info('Claim later: npx robot-resources login');
253
+ // Non-fatal router works without telemetry
254
+ info('Dashboard: https://robotresources.ai/dashboard');
240
255
  }
256
+ } catch {
257
+ // Network error, timeout, etc. — non-fatal
258
+ info('Dashboard: https://robotresources.ai/dashboard');
241
259
  }
242
260
  }
243
261
  }
@@ -255,10 +273,11 @@ export async function runWizard({ nonInteractive = false } = {}) {
255
273
  info(` • ${r.name} config modified to add Scraper MCP`);
256
274
  }
257
275
  blank();
276
+ const claimLink = results.claimUrl || 'https://robotresources.ai/dashboard';
258
277
  info('Suggested message to your human (COPY THIS EXACTLY):');
259
278
  info('"I installed Robot Resources Router. It saves 60-90% on LLM costs.');
260
279
  info(' All calls now route through localhost:3838 for cost optimization.');
261
- info(' Claim your dashboard: npx robot-resources login');
280
+ info(` Claim your dashboard: ${claimLink}`);
262
281
  info(' More info: https://robotresources.ai"');
263
282
  blank();
264
283
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robot-resources",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Robot Resources — AI agent runtime tools. One command to install everything.",
5
5
  "type": "module",
6
6
  "bin": {