@beeos-ai/cli 1.0.23 → 1.0.24

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 +262 -39
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3314,20 +3314,24 @@ var init_desktop_detect = __esm({
3314
3314
  init_platform_adapter();
3315
3315
  MACOS_DESKTOP_HINT_LINES = [
3316
3316
  "Detected macOS Screen Sharing on :5900. Starting vnc-bridge...",
3317
- " If desktop view shows a black screen / connection error on the dashboard:",
3318
- " \u2022 System Settings \u2192 General \u2192 Sharing \u2192 Screen Sharing must be enabled",
3319
- " \u2022 System Settings \u2192 Privacy & Security \u2192 Screen Recording must grant",
3320
- " permission to the macOS Screen Sharing process",
3321
- " \u2022 If a VNC password was set, export BEEOS_VNC_PASSWORD=<password>",
3322
- " before re-running `beeos init`."
3317
+ " If the dashboard's desktop view shows a black screen, check:",
3318
+ " \u2022 System Settings \u2192 Privacy & Security \u2192 Screen Recording must",
3319
+ " grant permission to the Screen Sharing helper (look for an",
3320
+ " ARDAgent or screensharingd entry; check the box if missing)",
3321
+ " \u2022 The VNC viewer password BeeOS just installed lives at",
3322
+ " ~/.beeos/vnc.password \u2014 re-run `beeos init` to regenerate",
3323
+ " if you suspect it drifted out of sync with macOS."
3323
3324
  ];
3324
3325
  MACOS_DESKTOP_DOCTOR_HINT_LINES = [
3325
3326
  "vnc-bridge-openclaw is failing on macOS. Likely causes:",
3326
- " \u2022 System Settings \u2192 General \u2192 Sharing \u2192 Screen Sharing turned off",
3327
- " \u2022 System Settings \u2192 Privacy & Security \u2192 Screen Recording missing",
3328
- " permission for the macOS Screen Sharing process",
3329
- " \u2022 A VNC password is set; export BEEOS_VNC_PASSWORD=<password>",
3330
- " before `beeos start openclaw --force` to retry."
3327
+ " \u2022 System Settings \u2192 General \u2192 Sharing \u2192 Screen Sharing got",
3328
+ " turned off after BeeOS enabled it (re-run `beeos init` to",
3329
+ " redo cold-start)",
3330
+ " \u2022 System Settings \u2192 Privacy & Security \u2192 Screen Recording",
3331
+ " permission for the Screen Sharing helper was revoked",
3332
+ " \u2022 The macOS-side VNC viewer password drifted out of sync with",
3333
+ " ~/.beeos/vnc.password \u2014 re-run `beeos init` to regenerate",
3334
+ " both ends in one shot."
3331
3335
  ];
3332
3336
  LINUX_VNC_HINT_LINES = [
3333
3337
  "Tip: no VNC server detected on :5901. To enable BeeOS desktop streaming:",
@@ -3340,6 +3344,220 @@ var init_desktop_detect = __esm({
3340
3344
  }
3341
3345
  });
3342
3346
 
3347
+ // ../core/dist/openclaw/macos-desktop-cold-start.js
3348
+ async function detectColdStartState() {
3349
+ const p = getPlatformAdapter();
3350
+ const port5900Listening = await p.tcpProbe("127.0.0.1", 5900, PORT_5900_PROBE_TIMEOUT_MS).catch(() => false);
3351
+ const passwordFile = p.joinPath(beeoHome(), "vnc.password");
3352
+ let vncPasswordFileExists = false;
3353
+ try {
3354
+ const raw = await p.readFile(passwordFile);
3355
+ vncPasswordFileExists = raw.trim().length > 0;
3356
+ } catch {
3357
+ vncPasswordFileExists = false;
3358
+ }
3359
+ const ardAllLocalUsers = await probeArdAllLocalUsers();
3360
+ return {
3361
+ port5900Listening,
3362
+ vncPasswordFileExists,
3363
+ ardAllLocalUsers
3364
+ };
3365
+ }
3366
+ async function macosDesktopColdStart(opts = {}) {
3367
+ const log = opts.log ?? ((m) => console.log(m));
3368
+ const p = getPlatformAdapter();
3369
+ if (opts.noDesktop) {
3370
+ return { status: "skipped_opt_out" };
3371
+ }
3372
+ if (p.platform() !== "darwin") {
3373
+ return { status: "skipped_non_macos" };
3374
+ }
3375
+ const state = await detectColdStartState();
3376
+ const passwordFile = p.joinPath(beeoHome(), "vnc.password");
3377
+ const idempotent = state.port5900Listening && state.vncPasswordFileExists && state.ardAllLocalUsers === false;
3378
+ if (idempotent) {
3379
+ let existing;
3380
+ try {
3381
+ existing = (await p.readFile(passwordFile)).trim();
3382
+ } catch {
3383
+ existing = void 0;
3384
+ }
3385
+ return {
3386
+ status: "already_configured",
3387
+ vncPassword: existing
3388
+ };
3389
+ }
3390
+ if (!opts.prompt && !opts.yes) {
3391
+ return { status: "skipped_no_tty" };
3392
+ }
3393
+ if (!opts.yes) {
3394
+ log("");
3395
+ log("BeeOS desktop streaming needs macOS Screen Sharing enabled.");
3396
+ log("This will:");
3397
+ log(" - Turn on macOS Screen Sharing (RFB scheme 2 / legacy VNC)");
3398
+ log(" - Disable Apple ARD's all-local-users mode (avoids the");
3399
+ log(" noVNC scheme-30 trap that leaves the viewer black)");
3400
+ log(" - Generate a fresh 8-char VNC viewer password and store");
3401
+ log(" it both in /Library/Preferences/com.apple.VNCSettings.txt");
3402
+ log(" and in ~/.beeos/vnc.password");
3403
+ log("If you already use Screen Sharing for other tools the existing");
3404
+ log("VNC viewer password will be REPLACED. macOS will pop up a");
3405
+ log("password dialog (that's the OS asking for your login password,");
3406
+ log("not BeeOS \u2014 only this script runs as root).");
3407
+ log("");
3408
+ const answer = (await opts.prompt("Enable macOS Screen Sharing for desktop streaming? [Y/n]: ")).trim();
3409
+ if (answer !== "" && !/^y(es)?$/i.test(answer)) {
3410
+ return { status: "user_declined" };
3411
+ }
3412
+ }
3413
+ const newPassword = generateLegacyVncPassword();
3414
+ try {
3415
+ await ensureBeeoHome(p);
3416
+ await p.writeFile(passwordFile, newPassword);
3417
+ await p.chmod(passwordFile, 384);
3418
+ } catch (e) {
3419
+ return {
3420
+ status: "script_failed",
3421
+ warnings: [
3422
+ `cold-start: failed to write ${passwordFile}: ${e instanceof Error ? e.message : String(e)}. Desktop streaming will not work this run.`
3423
+ ]
3424
+ };
3425
+ }
3426
+ log("Requesting macOS administrator password (system dialog)...");
3427
+ const scriptResult = await runColdStartRootScript(newPassword);
3428
+ if (!scriptResult.ok) {
3429
+ const canceled = /user (canceled|cancelled)|cancellation|User did not enter/i.test(scriptResult.stderr);
3430
+ await p.rm(passwordFile).catch(() => void 0);
3431
+ return {
3432
+ status: canceled ? "user_canceled_dialog" : "script_failed",
3433
+ warnings: [
3434
+ canceled ? "macOS authorization dialog was canceled \u2014 desktop streaming not enabled." : `cold-start root script failed: ${scriptResult.stderr.trim()}. Desktop streaming will not work this run.`
3435
+ ]
3436
+ };
3437
+ }
3438
+ const up = await waitFor5900(VERIFY_5900_TIMEOUT_MS);
3439
+ if (!up) {
3440
+ return {
3441
+ status: "verify_timeout",
3442
+ warnings: [
3443
+ "cold-start ran but :5900 never came up within 5s. Re-run `beeos init` to retrigger, or check `beeos doctor`."
3444
+ ]
3445
+ };
3446
+ }
3447
+ log("macOS Screen Sharing enabled and listening on :5900.");
3448
+ return {
3449
+ status: "enabled_now",
3450
+ vncPassword: newPassword
3451
+ };
3452
+ }
3453
+ async function ensureBeeoHome(p) {
3454
+ const home = beeoHome();
3455
+ if (!await p.exists(home)) {
3456
+ await p.mkdir(home);
3457
+ }
3458
+ }
3459
+ function generateLegacyVncPassword() {
3460
+ const out = new Array(VNC_PASSWORD_LENGTH);
3461
+ const buf = new Uint8Array(VNC_PASSWORD_LENGTH);
3462
+ globalThis.crypto.getRandomValues(buf);
3463
+ for (let i = 0; i < VNC_PASSWORD_LENGTH; i++) {
3464
+ out[i] = VNC_PASSWORD_CHARSET[buf[i] % VNC_PASSWORD_CHARSET.length];
3465
+ }
3466
+ return out.join("");
3467
+ }
3468
+ function encodeMacosVncPassword(password) {
3469
+ const pwBytes = Buffer.alloc(APPLE_VNC_FIXED_KEY.length);
3470
+ Buffer.from(password, "utf8").copy(pwBytes);
3471
+ const out = Buffer.alloc(APPLE_VNC_FIXED_KEY.length);
3472
+ for (let i = 0; i < APPLE_VNC_FIXED_KEY.length; i++) {
3473
+ out[i] = pwBytes[i] ^ APPLE_VNC_FIXED_KEY[i];
3474
+ }
3475
+ return out.toString("hex");
3476
+ }
3477
+ async function runColdStartRootScript(vncPassword) {
3478
+ const p = getPlatformAdapter();
3479
+ if (!/^[a-zA-Z0-9]{8}$/.test(vncPassword)) {
3480
+ return {
3481
+ ok: false,
3482
+ stderr: "internal: generated VNC password contains shell-unsafe characters; refusing to run osascript"
3483
+ };
3484
+ }
3485
+ const encodedHex = encodeMacosVncPassword(vncPassword);
3486
+ const shellPayload = `set -e
3487
+ launchctl enable system/com.apple.screensharing 2>/dev/null || true
3488
+ defaults write ${ARD_PLIST_PATH} VNCLegacyConnectionsEnabled -bool YES
3489
+ defaults write ${ARD_PLIST_PATH} ARD_AllLocalUsers -bool NO
3490
+ defaults write ${ARD_PLIST_PATH} ARD_AllLocalUsersPrivs -int 0
3491
+ printf '%s' '${encodedHex}' > ${VNC_SETTINGS_PATH}
3492
+ chmod 0400 ${VNC_SETTINGS_PATH}
3493
+ launchctl kickstart -k system/com.apple.screensharing
3494
+ `;
3495
+ const aslEscaped = shellPayload.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
3496
+ const osascriptArg = `do shell script "${aslEscaped}" with administrator privileges`;
3497
+ let stderr = "";
3498
+ let code = 1;
3499
+ try {
3500
+ const result = await p.exec("osascript", ["-e", osascriptArg], {
3501
+ timeout: OSASCRIPT_TIMEOUT_MS
3502
+ });
3503
+ stderr = result.stderr;
3504
+ code = result.code;
3505
+ } catch (e) {
3506
+ return {
3507
+ ok: false,
3508
+ stderr: `osascript invocation failed: ${e instanceof Error ? e.message : String(e)}`
3509
+ };
3510
+ }
3511
+ return { ok: code === 0, stderr };
3512
+ }
3513
+ async function waitFor5900(timeoutMs) {
3514
+ const p = getPlatformAdapter();
3515
+ const deadline = Date.now() + timeoutMs;
3516
+ while (Date.now() < deadline) {
3517
+ if (await p.tcpProbe("127.0.0.1", 5900, PORT_5900_PROBE_TIMEOUT_MS).catch(() => false)) {
3518
+ return true;
3519
+ }
3520
+ await sleep3(VERIFY_5900_POLL_INTERVAL_MS);
3521
+ }
3522
+ return false;
3523
+ }
3524
+ async function probeArdAllLocalUsers() {
3525
+ const p = getPlatformAdapter();
3526
+ try {
3527
+ const result = await p.exec("plutil", ["-extract", "ARD_AllLocalUsers", "raw", ARD_PLIST_PATH], { timeout: 2e3 });
3528
+ if (result.code !== 0)
3529
+ return "unknown";
3530
+ const out = result.stdout.trim().toLowerCase();
3531
+ if (out === "true" || out === "1")
3532
+ return true;
3533
+ if (out === "false" || out === "0")
3534
+ return false;
3535
+ return "unknown";
3536
+ } catch {
3537
+ return "unknown";
3538
+ }
3539
+ }
3540
+ function sleep3(ms) {
3541
+ return new Promise((resolve) => setTimeout(resolve, ms));
3542
+ }
3543
+ var APPLE_VNC_FIXED_KEY, VNC_PASSWORD_LENGTH, VNC_PASSWORD_CHARSET, ARD_PLIST_PATH, VNC_SETTINGS_PATH, PORT_5900_PROBE_TIMEOUT_MS, VERIFY_5900_TIMEOUT_MS, VERIFY_5900_POLL_INTERVAL_MS, OSASCRIPT_TIMEOUT_MS;
3544
+ var init_macos_desktop_cold_start = __esm({
3545
+ "../core/dist/openclaw/macos-desktop-cold-start.js"() {
3546
+ "use strict";
3547
+ init_platform_adapter();
3548
+ init_paths();
3549
+ APPLE_VNC_FIXED_KEY = Buffer.from("1734516E8BA8C5E2FF1C39567390ADCA", "hex");
3550
+ VNC_PASSWORD_LENGTH = 8;
3551
+ VNC_PASSWORD_CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
3552
+ ARD_PLIST_PATH = "/Library/Preferences/com.apple.RemoteManagement.plist";
3553
+ VNC_SETTINGS_PATH = "/Library/Preferences/com.apple.VNCSettings.txt";
3554
+ PORT_5900_PROBE_TIMEOUT_MS = 200;
3555
+ VERIFY_5900_TIMEOUT_MS = 5e3;
3556
+ VERIFY_5900_POLL_INTERVAL_MS = 250;
3557
+ OSASCRIPT_TIMEOUT_MS = 6e4;
3558
+ }
3559
+ });
3560
+
3343
3561
  // ../core/dist/detect.js
3344
3562
  async function detectExistingInstall() {
3345
3563
  const p = getPlatformAdapter();
@@ -5195,6 +5413,7 @@ var init_dist = __esm({
5195
5413
  init_constants();
5196
5414
  init_agent_status();
5197
5415
  init_desktop_detect();
5416
+ init_macos_desktop_cold_start();
5198
5417
  init_detect();
5199
5418
  init_registry();
5200
5419
  init_target_spec();
@@ -5420,7 +5639,7 @@ var init_upgrade2 = __esm({
5420
5639
  });
5421
5640
 
5422
5641
  // src/lib/instance-picker.ts
5423
- import readline from "readline";
5642
+ import readline2 from "readline";
5424
5643
  function resolveIO(ctx) {
5425
5644
  return {
5426
5645
  input: ctx.input ?? process.stdin,
@@ -5432,7 +5651,7 @@ function isTTY(ctx, io) {
5432
5651
  return Boolean(io.input.isTTY);
5433
5652
  }
5434
5653
  function ask(io, question) {
5435
- const rl = readline.createInterface({ input: io.input, output: io.output });
5654
+ const rl = readline2.createInterface({ input: io.input, output: io.output });
5436
5655
  return new Promise((resolve) => {
5437
5656
  rl.question(question, (answer) => {
5438
5657
  rl.close();
@@ -5685,7 +5904,7 @@ var init_state2 = __esm({
5685
5904
 
5686
5905
  // src/commands/device/attach.ts
5687
5906
  import { spawn as spawn2 } from "child_process";
5688
- import readline2 from "readline";
5907
+ import readline3 from "readline";
5689
5908
  function resolvePerDeviceAgentGatewayUrl(cfg, override) {
5690
5909
  if (override === void 0) return resolveAgentGatewayUrl(cfg);
5691
5910
  const trimmed = override.trim();
@@ -6121,7 +6340,7 @@ async function maybeNotifyFleetWithHint(cfg) {
6121
6340
  console.log("it, the device is recorded in ~/.beeos/devices.json but");
6122
6341
  console.log("no process is supervising the per-device agent.");
6123
6342
  console.log("");
6124
- const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
6343
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
6125
6344
  const answer = await new Promise((resolve) => {
6126
6345
  rl.question("Enable fleet now (registers a launchd service)? [Y/n]: ", (a) => {
6127
6346
  rl.close();
@@ -6295,7 +6514,7 @@ Android SDK Platform-Tools (adb) is licensed under the Android SDK License Agree
6295
6514
  Set BEEOS_ACCEPT_ADB_LICENSE=1 in your environment to skip this prompt next time.
6296
6515
  `
6297
6516
  );
6298
- const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
6517
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
6299
6518
  const ans = await new Promise((resolve) => {
6300
6519
  rl.question("Agree to the Android SDK license and download platform-tools? [Y/n]: ", (a) => {
6301
6520
  rl.close();
@@ -6846,6 +7065,7 @@ init_progress2();
6846
7065
  init_fallback_banner();
6847
7066
  init_json_envelope();
6848
7067
  import os6 from "os";
7068
+ import readline from "readline";
6849
7069
  async function run(agentFramework, options) {
6850
7070
  const p = getPlatformAdapter();
6851
7071
  await ensureDirs();
@@ -6892,6 +7112,19 @@ async function run(agentFramework, options) {
6892
7112
  const launchWarnings = [...launchOutcome.warnings];
6893
7113
  reporter.stop();
6894
7114
  const ttyHints = !options.json && process.stdin.isTTY === true;
7115
+ let coldStart = null;
7116
+ if (agentFramework === OPENCLAW_ID) {
7117
+ const interactive = !options.json && process.stdin.isTTY === true && process.stdout.isTTY === true;
7118
+ coldStart = await macosDesktopColdStart({
7119
+ prompt: interactive ? promptYesNo : void 0,
7120
+ log: options.json ? () => void 0 : (m) => console.log(m),
7121
+ yes: options.force === true,
7122
+ noDesktop: process.env.BEEOS_NO_DESKTOP === "1"
7123
+ });
7124
+ if (coldStart.warnings && coldStart.warnings.length > 0) {
7125
+ launchWarnings.push(...coldStart.warnings);
7126
+ }
7127
+ }
6895
7128
  const vncEndpoint = agentFramework === OPENCLAW_ID ? await probeLocalVnc({ ttyHints }) : null;
6896
7129
  const hostname = buildHostname();
6897
7130
  const cachedBinding = await loadBindingInfo();
@@ -7013,10 +7246,6 @@ async function run(agentFramework, options) {
7013
7246
  if (vncEndpoint.kind === "macos" && ttyHints) {
7014
7247
  printMacosDesktopHint();
7015
7248
  }
7016
- if (vncEndpoint.kind === "macos") {
7017
- const ardWarning = await checkMacosARDConflict();
7018
- if (ardWarning) launchWarnings.push(ardWarning);
7019
- }
7020
7249
  const desktopWarning = await tryAttachOpenclawDesktopBridge({
7021
7250
  vncEndpoint,
7022
7251
  instanceId: boundInstanceId,
@@ -7082,23 +7311,17 @@ async function readVncPasswordOptional() {
7082
7311
  return void 0;
7083
7312
  }
7084
7313
  }
7085
- async function checkMacosARDConflict() {
7086
- if (process.platform !== "darwin") return null;
7087
- const p = getPlatformAdapter();
7088
- try {
7089
- const result = await p.exec("plutil", [
7090
- "-extract",
7091
- "ARD_AllLocalUsers",
7092
- "raw",
7093
- "/Library/Preferences/com.apple.RemoteManagement.plist"
7094
- ], { timeout: 2e3 });
7095
- const out = String(result.stdout || "").trim().toLowerCase();
7096
- if (out === "true" || out === "1") {
7097
- return "macOS ARD_AllLocalUsers is enabled \u2014 Screen Sharing also advertises RFB scheme 30 (Apple Auth) which noVNC will prefer over scheme 2 (legacy VNC password). The dashboard's device-viewer will then loop on `credentialsrequired` and never paint. Disable ARD to keep only legacy VNC:\n sudo defaults write /Library/Preferences/com.apple.RemoteManagement ARD_AllLocalUsers -bool NO\n sudo launchctl kickstart -k system/com.apple.screensharing";
7098
- }
7099
- } catch {
7100
- }
7101
- return null;
7314
+ async function promptYesNo(question) {
7315
+ return new Promise((resolve) => {
7316
+ const rl = readline.createInterface({
7317
+ input: process.stdin,
7318
+ output: process.stdout
7319
+ });
7320
+ rl.question(question, (answer) => {
7321
+ rl.close();
7322
+ resolve(answer);
7323
+ });
7324
+ });
7102
7325
  }
7103
7326
  function buildHostname() {
7104
7327
  const machine = os6.hostname();
@@ -7323,7 +7546,7 @@ init_device2();
7323
7546
 
7324
7547
  // src/commands/init.ts
7325
7548
  init_dist();
7326
- import readline3 from "readline";
7549
+ import readline4 from "readline";
7327
7550
  init_attach();
7328
7551
  init_progress2();
7329
7552
  init_fallback_banner();
@@ -7575,7 +7798,7 @@ function printNextSteps() {
7575
7798
  console.log("");
7576
7799
  }
7577
7800
  function prompt(question) {
7578
- const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
7801
+ const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
7579
7802
  return new Promise((resolve) => {
7580
7803
  rl.question(question, (answer) => {
7581
7804
  rl.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beeos-ai/cli",
3
- "version": "1.0.23",
3
+ "version": "1.0.24",
4
4
  "type": "module",
5
5
  "description": "BeeOS CLI — run AI agents from your desktop",
6
6
  "bin": {