robot-resources 1.9.1 → 1.9.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.
Files changed (2) hide show
  1. package/lib/wizard.js +49 -7
  2. package/package.json +1 -1
package/lib/wizard.js CHANGED
@@ -9,6 +9,40 @@ import { installService, isServiceRunning, isServiceInstalled } from './service.
9
9
  import { configureToolRouting, registerScraperMcp, restartOpenClawGateway } from './tool-config.js';
10
10
  import { checkHealth } from './health-report.js';
11
11
  import { header, step, success, warn, error, info, blank, summary } from './ui.js';
12
+ /**
13
+ * Classify an install error into a short reason code + bounded detail string.
14
+ *
15
+ * Before this existed, install_complete telemetry reported router:false with
16
+ * no context — 100% of rr-router installs failed and we couldn't diagnose.
17
+ * The reason code slots into a small enum so we can aggregate in the admin
18
+ * dashboard; detail is the tail of stderr/error message for deep-dives.
19
+ */
20
+ function classifyRouterError(err) {
21
+ const msg = (err?.message || String(err)).toLowerCase();
22
+ let reason = 'unknown';
23
+
24
+ if (msg.includes('python 3.10+') || msg.includes('python is required')) {
25
+ reason = 'python_not_found';
26
+ } else if (err?.code === 'ENOENT' || msg.includes('enoent')) {
27
+ reason = 'spawn_enoent';
28
+ } else if (msg.includes('timeout') || msg.includes('timed out') || err?.code === 'ETIMEDOUT') {
29
+ reason = 'timeout';
30
+ } else if (msg.includes('exited with code') || msg.includes('pip install')) {
31
+ reason = 'pip_install_failed';
32
+ } else if (msg.includes('permission denied') || err?.code === 'EACCES') {
33
+ reason = 'permission_denied';
34
+ } else if (msg.includes('disk') || msg.includes('space') || err?.code === 'ENOSPC') {
35
+ reason = 'disk_full';
36
+ } else if (msg.includes('network') || msg.includes('getaddrinfo') || msg.includes('enetunreach')) {
37
+ reason = 'network';
38
+ }
39
+
40
+ const rawDetail = err?.stderr?.trim?.() || err?.message || String(err);
41
+ const detail = rawDetail.slice(-500);
42
+
43
+ return { reason, detail, exitCode: err?.exitCode ?? null };
44
+ }
45
+
12
46
  /**
13
47
  * Main setup wizard. Handles the full onboarding flow:
14
48
  * 1. Router installation (Python venv + pip)
@@ -128,6 +162,8 @@ export async function runWizard({ nonInteractive = false } = {}) {
128
162
  warn('Python 3.10+ not found — skipping Router installation');
129
163
  info('Install Python from https://python.org and re-run this wizard');
130
164
  info('Scraper works without Python');
165
+ // Record the reason so install_complete tells us why router=false.
166
+ results.routerError = { reason: 'python_not_found', detail: 'Python 3.10+ not detected on PATH' };
131
167
  } else {
132
168
  info(`Found Python ${python.version} (${python.bin})`);
133
169
  step('Installing Router (this may take a moment)...');
@@ -138,7 +174,7 @@ export async function runWizard({ nonInteractive = false } = {}) {
138
174
  results.router = true;
139
175
  } catch (err) {
140
176
  error(`Router installation failed: ${err.message}`);
141
- results.routerError = 'install-failed';
177
+ results.routerError = classifyRouterError(err);
142
178
  }
143
179
  }
144
180
  }
@@ -298,15 +334,21 @@ export async function runWizard({ nonInteractive = false } = {}) {
298
334
  try {
299
335
  const config = readConfig();
300
336
  const platformUrl = process.env.RR_PLATFORM_URL || 'https://api.robotresources.ai';
337
+ const installPayload = {
338
+ router: results.router || false,
339
+ service: results.service || false,
340
+ scraper: results.scraper || false,
341
+ source: 'wizard',
342
+ };
343
+ if (results.routerError && typeof results.routerError === 'object') {
344
+ installPayload.routerError = results.routerError.reason;
345
+ installPayload.routerErrorDetail = results.routerError.detail;
346
+ installPayload.platform = process.platform;
347
+ }
301
348
  const body = JSON.stringify({
302
349
  product: 'cli',
303
350
  event_type: 'install_complete',
304
- payload: {
305
- router: results.router || false,
306
- service: results.service || false,
307
- scraper: results.scraper || false,
308
- source: 'wizard',
309
- },
351
+ payload: installPayload,
310
352
  });
311
353
 
312
354
  for (let attempt = 0; attempt < 2; attempt++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robot-resources",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "description": "Robot Resources — AI agent tools. One command to install everything.",
5
5
  "type": "module",
6
6
  "bin": {