@beeos-ai/cli 1.0.19 → 1.0.21

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/dist/index.js +172 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -761,18 +761,22 @@ function buildBindUrl(dashboardBaseUrl, bindId) {
761
761
  const base = dashboardBaseUrl.replace(/\/+$/, "");
762
762
  return `${base}/bind/${bindId}`;
763
763
  }
764
- async function agentBind(apiUrl, publicKey, fingerprint2, agentFramework, hostname) {
764
+ async function agentBind(apiUrl, publicKey, fingerprint2, agentFramework, hostname, osType) {
765
765
  const p = getPlatformAdapter();
766
766
  const url = `${apiUrl}/api/v1/agent/bind`;
767
+ const body = {
768
+ public_key: publicKey,
769
+ fingerprint: fingerprint2,
770
+ agent_framework: agentFramework,
771
+ hostname
772
+ };
773
+ if (osType && osType.length > 0) {
774
+ body.os_type = osType;
775
+ }
767
776
  const resp = await p.fetch(url, {
768
777
  method: "POST",
769
778
  headers: { "Content-Type": "application/json" },
770
- body: JSON.stringify({
771
- public_key: publicKey,
772
- fingerprint: fingerprint2,
773
- agent_framework: agentFramework,
774
- hostname
775
- })
779
+ body: JSON.stringify(body)
776
780
  });
777
781
  if (!resp.ok) {
778
782
  throw await bindHttpError(resp, "bind");
@@ -925,7 +929,7 @@ async function bindAgent(opts) {
925
929
  const pollTimeoutMs = opts.pollTimeoutMs ?? 6e5;
926
930
  let resp;
927
931
  try {
928
- resp = await agentBind(opts.apiUrl, opts.publicKey, opts.fingerprint, opts.agentFramework, opts.hostname);
932
+ resp = await agentBind(opts.apiUrl, opts.publicKey, opts.fingerprint, opts.agentFramework, opts.hostname, opts.osType);
929
933
  } catch (e) {
930
934
  if (isNetworkError(e) && opts.cachedBinding && opts.cachedBinding.fingerprint === opts.fingerprint) {
931
935
  return {
@@ -2047,13 +2051,34 @@ var init_vnc_bridge = __esm({
2047
2051
  * Build the environment map used when launching vnc-bridge for a
2048
2052
  * device. Exposed separately so the service target-spec builder
2049
2053
  * can reuse the same logic without duplicating it.
2054
+ *
2055
+ * Env-var names are aligned with the **vnc-bridge 0.3.6** clap
2056
+ * definitions (`devices/vnc-bridge/src/main.rs`):
2057
+ *
2058
+ * --vnc env: VNC_ADDR=host:port (combined, NOT VNC_HOST/VNC_PORT)
2059
+ * --gateway env: AGENT_GATEWAY_URL
2060
+ * --key-file env: AGENT_KEY_FILE (single combined key, NOT BRIDGE_PRIVATE/PUBLIC)
2061
+ * --mqtt env: MQTT_BROKER_URL (static mode only)
2062
+ * --topic env: DEVICE_TOPIC (static mode only)
2063
+ *
2064
+ * Pre-1.0.21 we shipped the older naming (VNC_HOST + VNC_PORT,
2065
+ * BRIDGE_PRIVATE_KEY_FILE etc.) which the binary silently ignored,
2066
+ * causing it to bail out with `Error: Either --gateway + --key-file
2067
+ * (bootstrap mode) or --mqtt + --topic (static mode) is required`
2068
+ * at every restart. The legacy fields are retained alongside the
2069
+ * new ones so any older Rust build that did read them still works.
2050
2070
  */
2051
2071
  buildEnv(opts) {
2072
+ const vncPort = opts.vncPort ?? 5900;
2052
2073
  return {
2074
+ // ── vnc-bridge 0.3.6 canonical env vars ────────────────
2075
+ VNC_ADDR: `${opts.vncHost}:${vncPort}`,
2076
+ AGENT_GATEWAY_URL: opts.agentGatewayUrl,
2077
+ AGENT_KEY_FILE: opts.bridgePrivateKeyFile,
2078
+ // ── Legacy names (pre-0.3.6 / future-compat / forensic) ─
2053
2079
  DEVICE_ID: opts.deviceId,
2054
2080
  VNC_HOST: opts.vncHost,
2055
- VNC_PORT: String(opts.vncPort ?? 5900),
2056
- AGENT_GATEWAY_URL: opts.agentGatewayUrl,
2081
+ VNC_PORT: String(vncPort),
2057
2082
  BRIDGE_PRIVATE_KEY_FILE: opts.bridgePrivateKeyFile,
2058
2083
  BRIDGE_PUBLIC_KEY_FILE: opts.bridgePublicKeyFile,
2059
2084
  LOG_FORMAT: "json",
@@ -3244,6 +3269,74 @@ var init_agent_status = __esm({
3244
3269
  }
3245
3270
  });
3246
3271
 
3272
+ // ../core/dist/openclaw/desktop-detect.js
3273
+ function printMacosDesktopHint() {
3274
+ for (const line of MACOS_DESKTOP_HINT_LINES)
3275
+ console.log(line);
3276
+ }
3277
+ function readEnv(name) {
3278
+ return globalThis.process?.env?.[name];
3279
+ }
3280
+ async function probeLocalVnc(opts = {}) {
3281
+ if (readEnv("BEEOS_NO_DESKTOP") === "1")
3282
+ return null;
3283
+ const p = getPlatformAdapter();
3284
+ const platform = p.platform();
3285
+ if (platform !== "darwin" && platform !== "linux") {
3286
+ return null;
3287
+ }
3288
+ const host = "127.0.0.1";
3289
+ const timeoutMs = 200;
3290
+ if (platform === "darwin") {
3291
+ const ok2 = await p.tcpProbe(host, 5900, timeoutMs).catch(() => false);
3292
+ if (ok2) {
3293
+ return { kind: "macos", host, port: 5900, osType: "macos-desktop" };
3294
+ }
3295
+ return null;
3296
+ }
3297
+ const ok = await p.tcpProbe(host, 5901, timeoutMs).catch(() => false);
3298
+ if (ok) {
3299
+ return { kind: "linux", host, port: 5901, osType: "linux-desktop" };
3300
+ }
3301
+ if (opts.ttyHints) {
3302
+ for (const line of LINUX_VNC_HINT_LINES)
3303
+ console.log(line);
3304
+ }
3305
+ return null;
3306
+ }
3307
+ var MACOS_DESKTOP_HINT_LINES, MACOS_DESKTOP_DOCTOR_HINT_LINES, LINUX_VNC_HINT_LINES;
3308
+ var init_desktop_detect = __esm({
3309
+ "../core/dist/openclaw/desktop-detect.js"() {
3310
+ "use strict";
3311
+ init_platform_adapter();
3312
+ MACOS_DESKTOP_HINT_LINES = [
3313
+ "Detected macOS Screen Sharing on :5900. Starting vnc-bridge...",
3314
+ " If desktop view shows a black screen / connection error on the dashboard:",
3315
+ " \u2022 System Settings \u2192 General \u2192 Sharing \u2192 Screen Sharing must be enabled",
3316
+ " \u2022 System Settings \u2192 Privacy & Security \u2192 Screen Recording must grant",
3317
+ " permission to the macOS Screen Sharing process",
3318
+ " \u2022 If a VNC password was set, export BEEOS_VNC_PASSWORD=<password>",
3319
+ " before re-running `beeos init`."
3320
+ ];
3321
+ MACOS_DESKTOP_DOCTOR_HINT_LINES = [
3322
+ "vnc-bridge-openclaw is failing on macOS. Likely causes:",
3323
+ " \u2022 System Settings \u2192 General \u2192 Sharing \u2192 Screen Sharing turned off",
3324
+ " \u2022 System Settings \u2192 Privacy & Security \u2192 Screen Recording missing",
3325
+ " permission for the macOS Screen Sharing process",
3326
+ " \u2022 A VNC password is set; export BEEOS_VNC_PASSWORD=<password>",
3327
+ " before `beeos start openclaw --force` to retry."
3328
+ ];
3329
+ LINUX_VNC_HINT_LINES = [
3330
+ "Tip: no VNC server detected on :5901. To enable BeeOS desktop streaming:",
3331
+ " Debian/Ubuntu: sudo apt install tigervnc-standalone-server",
3332
+ " RHEL/Fedora: sudo dnf install tigervnc-server",
3333
+ " Arch: sudo pacman -S tigervnc",
3334
+ "Then run `vncserver :1` and re-run `beeos start openclaw`.",
3335
+ "Set BEEOS_NO_DESKTOP=1 to suppress this hint."
3336
+ ];
3337
+ }
3338
+ });
3339
+
3247
3340
  // ../core/dist/detect.js
3248
3341
  async function detectExistingInstall() {
3249
3342
  const p = getPlatformAdapter();
@@ -3486,12 +3579,20 @@ function buildVncBridgeTargetSpec(binary, opts) {
3486
3579
  label: `vnc-bridge (${opts.serial})`
3487
3580
  };
3488
3581
  }
3582
+ function buildOpenclawDesktopVncBridgeSpec(binary, opts) {
3583
+ return buildVncBridgeTargetSpec(binary, {
3584
+ ...opts,
3585
+ serial: OPENCLAW_VNC_BRIDGE_SERIAL
3586
+ });
3587
+ }
3588
+ var OPENCLAW_VNC_BRIDGE_SERIAL;
3489
3589
  var init_target_spec = __esm({
3490
3590
  "../core/dist/services/target-spec.js"() {
3491
3591
  "use strict";
3492
3592
  init_scrcpy_bridge();
3493
3593
  init_vnc_bridge();
3494
3594
  init_spawn_env2();
3595
+ OPENCLAW_VNC_BRIDGE_SERIAL = "openclaw";
3495
3596
  }
3496
3597
  });
3497
3598
 
@@ -4992,7 +5093,7 @@ function getCliVersion(moduleUrl, distTag) {
4992
5093
  return { version, distTag: safeTag, display };
4993
5094
  }
4994
5095
  function resolveActiveDistTag() {
4995
- const envTag = readEnv("BEEOS_CLI_TAG");
5096
+ const envTag = readEnv2("BEEOS_CLI_TAG");
4996
5097
  if (envTag && envTag.trim())
4997
5098
  return envTag.trim();
4998
5099
  const baked = readBakedDistTag();
@@ -5000,7 +5101,7 @@ function resolveActiveDistTag() {
5000
5101
  return baked.trim();
5001
5102
  return "latest";
5002
5103
  }
5003
- function readEnv(key) {
5104
+ function readEnv2(key) {
5004
5105
  const env = globalThis.process?.env;
5005
5106
  return env?.[key];
5006
5107
  }
@@ -5090,6 +5191,7 @@ var init_dist = __esm({
5090
5191
  init_driver2();
5091
5192
  init_constants();
5092
5193
  init_agent_status();
5194
+ init_desktop_detect();
5093
5195
  init_detect();
5094
5196
  init_registry();
5095
5197
  init_target_spec();
@@ -6783,8 +6885,10 @@ async function run(agentFramework, options) {
6783
6885
  };
6784
6886
  const launchOutcome = await driver.launch(ctx, reporter);
6785
6887
  const spec = launchOutcome.spec;
6786
- const launchWarnings = launchOutcome.warnings;
6888
+ const launchWarnings = [...launchOutcome.warnings];
6787
6889
  reporter.stop();
6890
+ const ttyHints = !options.json && process.stdin.isTTY === true;
6891
+ const vncEndpoint = agentFramework === OPENCLAW_ID ? await probeLocalVnc({ ttyHints }) : null;
6788
6892
  const hostname = buildHostname();
6789
6893
  const cachedBinding = await loadBindingInfo();
6790
6894
  const outcome = await bindAgent({
@@ -6794,6 +6898,7 @@ async function run(agentFramework, options) {
6794
6898
  fingerprint: fp,
6795
6899
  agentFramework,
6796
6900
  hostname,
6901
+ osType: vncEndpoint?.osType,
6797
6902
  headless: options.browser === false,
6798
6903
  cachedBinding: cachedBinding ? {
6799
6904
  fingerprint: cachedBinding.fingerprint,
@@ -6898,6 +7003,19 @@ async function run(agentFramework, options) {
6898
7003
  });
6899
7004
  }
6900
7005
  }
7006
+ if (vncEndpoint && !isOffline) {
7007
+ if (vncEndpoint.kind === "macos" && ttyHints) {
7008
+ printMacosDesktopHint();
7009
+ }
7010
+ const desktopWarning = await tryAttachOpenclawDesktopBridge({
7011
+ vncEndpoint,
7012
+ instanceId: boundInstanceId,
7013
+ keyFile,
7014
+ agentGatewayUrl,
7015
+ mgr
7016
+ });
7017
+ if (desktopWarning) launchWarnings.push(desktopWarning);
7018
+ }
6901
7019
  const gatewayPid = status2.pid ?? void 0;
6902
7020
  emit(options.json, {
6903
7021
  status: isOffline ? "bound_offline" : "bound",
@@ -6910,6 +7028,36 @@ async function run(agentFramework, options) {
6910
7028
  }, isOffline ? `Agent running (offline, cached instance: ${boundInstanceId})` : `Agent bound to instance: ${boundInstanceId}`);
6911
7029
  if (!options.json) printLaunchWarnings(launchWarnings);
6912
7030
  }
7031
+ async function tryAttachOpenclawDesktopBridge(params) {
7032
+ const reporter = new CliReporter();
7033
+ let binary = null;
7034
+ try {
7035
+ binary = await vncBridgeRuntime.ensureInstalled(reporter);
7036
+ } catch (e) {
7037
+ reporter.stop();
7038
+ const reason = e instanceof Error ? e.message : String(e);
7039
+ return `vnc-bridge install failed: ${reason}; OpenClaw is bound but desktop streaming is unavailable.`;
7040
+ }
7041
+ reporter.stop();
7042
+ if (!binary) {
7043
+ return `vnc-bridge binary unavailable (download or PATH lookup failed); OpenClaw is bound but desktop streaming is unavailable. Set BEEOS_VNC_BRIDGE_BIN to override.`;
7044
+ }
7045
+ const spec = buildOpenclawDesktopVncBridgeSpec(binary, {
7046
+ deviceId: params.instanceId,
7047
+ vncHost: params.vncEndpoint.host,
7048
+ vncPort: params.vncEndpoint.port,
7049
+ agentGatewayUrl: params.agentGatewayUrl,
7050
+ bridgePrivateKeyFile: params.keyFile,
7051
+ bridgePublicKeyFile: params.keyFile
7052
+ });
7053
+ try {
7054
+ await params.mgr.install(spec);
7055
+ } catch (e) {
7056
+ const reason = e instanceof Error ? e.message : String(e);
7057
+ return `vnc-bridge service install failed: ${reason}; OpenClaw is bound but desktop streaming is unavailable. Re-run \`beeos start openclaw --force\` to retry.`;
7058
+ }
7059
+ return null;
7060
+ }
6913
7061
  function buildHostname() {
6914
7062
  const machine = os6.hostname();
6915
7063
  const user = process.env.USER || process.env.USERNAME || "";
@@ -7538,6 +7686,17 @@ async function run8(options) {
7538
7686
  `service '${s.id}' looks like its Node binary moved (exit 127). Re-run \`beeos start ${s.id} --force\` to refresh the service definition with the current node path.`
7539
7687
  );
7540
7688
  }
7689
+ if (s.id === `vnc-bridge-${OPENCLAW_VNC_BRIDGE_SERIAL}`) {
7690
+ if (process.platform === "darwin") {
7691
+ for (const line of MACOS_DESKTOP_DOCTOR_HINT_LINES) {
7692
+ hints.push(line);
7693
+ }
7694
+ } else {
7695
+ hints.push(
7696
+ `vnc-bridge-${OPENCLAW_VNC_BRIDGE_SERIAL} is failing \u2014 see ${s.logFile} for the underlying error. Common causes: VNC server moved port, BEEOS_VNC_PASSWORD missing/incorrect, network blocking outbound MQTT.`
7697
+ );
7698
+ }
7699
+ }
7541
7700
  }
7542
7701
  }
7543
7702
  if (!tools.adb.path) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beeos-ai/cli",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "type": "module",
5
5
  "description": "BeeOS CLI — run AI agents from your desktop",
6
6
  "bin": {