robot-resources 1.3.0 → 1.3.1

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,6 +1,6 @@
1
1
  import { readConfig, writeConfig } from '@robot-resources/cli-core/config.mjs';
2
2
  import { login } from '@robot-resources/cli-core/login.mjs';
3
- import { findPython, isPortAvailable } from './detect.js';
3
+ import { findPython, isPortAvailable, isHeadless } from './detect.js';
4
4
  import { setupRouter, isRouterInstalled, getVenvPythonPath } from './python-bridge.js';
5
5
  import { installService, isServiceRunning, isServiceInstalled } from './service.js';
6
6
  import { configureAgentMCP } from './mcp-config.js';
@@ -219,11 +219,12 @@ export async function runWizard({ nonInteractive = false } = {}) {
219
219
  }
220
220
 
221
221
  if (!results.auth) {
222
- if (nonInteractive) {
223
- // Agent flow: don't prompt, just tell the agent what to relay
222
+ if (nonInteractive || isHeadless()) {
223
+ // Agent flow or headless server: no prompt, no browser login.
224
+ // Just print the command for the human to run on their own machine.
224
225
  info('Dashboard (optional): run "npx robot-resources login" to claim your dashboard');
225
226
  } else {
226
- // Interactive flow: offer login but don't block on "no"
227
+ // Interactive + has browser: offer login
227
228
  const shouldLogin = await confirm('Claim your dashboard? (optional)', { defaultYes: false, nonInteractive });
228
229
  if (shouldLogin) {
229
230
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robot-resources",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Robot Resources — AI agent runtime tools. One command to install everything.",
5
5
  "type": "module",
6
6
  "bin": {