@beeos-ai/cli 1.0.17 → 1.0.19

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.
@@ -1,58 +1,68 @@
1
1
  #!/usr/bin/env bash
2
2
  #
3
3
  # BeeOS CLI Installer (macOS / Linux)
4
+ #
4
5
  # Usage:
5
6
  # curl -fsSL https://beeos.ai/install | bash
6
7
  # curl -fsSL https://beeos.ai/install | bash -s -- [beeos init args]
7
- # curl -fsSL https://beeos.ai/install | bash -s -- --device # jump into device attach
8
+ # curl -fsSL https://beeos.ai/install | bash -s -- --device # beeos device attach
8
9
  #
9
- # Entry script responsibilities:
10
+ # Responsibilities (deliberately minimal — framework-agnostic):
10
11
  # 1. Detect OS + CPU architecture, refuse unsupported targets early.
11
- # 2. Make sure Node.js >= MIN_NODE_VERSION is available (install via nvm /
12
- # fnm / brew when possible). Heavier deps (Python, uv, adb, scrcpy/vnc
13
- # bridges) are handled lazily by the CLI itself.
14
- # 3. Detect an existing BeeOS install and let the user pick
15
- # upgrade / rebind / skip before re-running the bind flow.
16
- # 4. Dispatch into `beeos init` (default) or `beeos device attach` when
17
- # `--device` is passed.
12
+ # 2. Make sure Node.js >= MIN_NODE_VERSION is available (install via
13
+ # nvm / fnm / brew when possible). All heavier dependencies (adb,
14
+ # scrcpy-bridge, the device-agent suite) are installed lazily by
15
+ # the CLI itself when the user actually needs them.
16
+ # 3. `npm install -g @beeos-ai/cli`.
17
+ # 4. `exec beeos init` (or `beeos device attach` with `--device`).
18
+ #
19
+ # Anything else — "you already have BeeOS installed, what now?",
20
+ # framework selection, rebind variants — lives inside the CLI's own
21
+ # `beeos init` menu, not here. The bootstrap script stays small so it's
22
+ # easy to maintain and easy to diagnose on a customer machine.
23
+ #
24
+ # ── Exit codes ────────────────────────────────────────────────────
25
+ # 0 Success (or `exec` handed off — the CLI's own exit code wins)
26
+ # 1 Node bootstrap failure (Node missing / version too old / npm
27
+ # not on PATH after Node install)
28
+ # 2 Unsupported OS / CPU architecture (and user declined override)
29
+ # 3 `npm install -g @beeos-ai/cli` failed (CLI didn't reach PATH)
30
+ #
31
+ # Automation can branch on these — `1` is "fix your Node install",
32
+ # `2` is "wrong machine", `3` is "your npm prefix / proxy / disk".
33
+ #
34
+ # ── Optional env vars ─────────────────────────────────────────────
35
+ # BEEOS_API_URL Public API base (this script uses it for
36
+ # telemetry; the CLI uses it for runtime).
37
+ # Defaults to production.
38
+ # BEEOS_AGENT_GATEWAY_URL Agent Gateway base (forwarded as-is to the
39
+ # spawned CLI).
40
+ # BEEOS_DASHBOARD_URL Dashboard base (OAuth / bind redirect).
41
+ # BEEOS_INSTALL_LOG Path to a forensic log of Node-bootstrap
42
+ # stderr; defaults to /tmp/beeos-install-$$.log.
43
+ # BEEOS_INSTALL_DRY_RUN=1 CI smoke-test escape hatch — return 0
44
+ # from main() before any side effect.
45
+ # BEEOS_NO_TELEMETRY=1 Disable the script-level telemetry POSTs.
46
+ # BEEOS_USE_NPX=1 Power-user throwaway install (beeos won't
47
+ # persist on PATH).
18
48
  #
19
- # ── Staging / dev-loop env vars (CLI ≥ 1.0.10) ──────────────────────
20
- # All four are inherited by the spawned `beeos init` / `beeos device
21
- # attach` child via the normal `exec` env passthrough there is no
22
- # extra `export` needed. CLI 1.0.10 reads them via the `loadOrCreate
23
- # Config` env-overrides layer; older CLIs only honor BEEOS_API_URL
24
- # (telemetry) + BEEOS_AGENT_GATEWAY_URL (runtime).
49
+ # IMPORTANT (env inheritance):
50
+ # BEEOS_API_URL / BEEOS_AGENT_GATEWAY_URL / BEEOS_DASHBOARD_URL must
51
+ # be set in THE SHELL THAT RUNS THIS SCRIPT before the curl pipe.
52
+ # They reach `beeos init` only via the normal exec env passthrough
53
+ # there is NO auto-injection from the curl arguments.
25
54
  #
26
- # BEEOS_API_URL Public API base; both the script (telemetry)
27
- # and the CLI runtime use this.
28
- # BEEOS_AGENT_GATEWAY_URL Agent Gateway base (Ed25519-signed
29
- # bootstrap requests).
30
- # BEEOS_DASHBOARD_URL Dashboard base (OAuth + bind redirect).
31
- # BEEOS_DEVICE_AGENT_VERSION Pin @beeos-ai/device-agent semver.
32
- # NOT consumed by this script (CLI ≥ 1.0.16
33
- # installs the device suite lazily on the
34
- # first `beeos device attach`); export it
35
- # in the shell that runs `beeos device
36
- # attach` instead.
37
- # BEEOS_MCP_SERVER_VERSION Same as above, for @beeos-ai/device-mcp-server.
38
- # BEEOS_USE_NPX=1 (Power-user escape hatch) Use `npx` for a
39
- # throwaway install. `beeos` will NOT
40
- # persist on PATH after the script exits.
41
- # Default behaviour (since CLI 1.0.11) is
42
- # always `npm install -g` so the CLI is
43
- # globally available for follow-up commands.
44
- # The device-agent suite is no longer
45
- # eagerly installed (CLI ≥ 1.0.16); see
46
- # `web/packages/core/src/device-setup.ts`.
55
+ # Working: `BEEOS_API_URL=... bash -c 'curl ...| bash'`
56
+ # Working: Set the var in your shell profile, then run normally.
57
+ # Broken: `bash -c "BEEOS_API_URL=... curl ... | bash"`
58
+ # (the var is local to the inner bash, not exported).
47
59
  #
48
- # Example: bare-metal one-shot staging install (no device-agent pin —
49
- # add `BEEOS_DEVICE_AGENT_VERSION=...` to the shell when you later run
50
- # `beeos device attach` if you need to pin a specific build):
60
+ # Bare-metal staging one-liner:
51
61
  #
52
62
  # BEEOS_API_URL=https://public-api-staging.beeos.ai \
53
63
  # BEEOS_AGENT_GATEWAY_URL=https://agent-gw-staging.beeos.ai \
54
64
  # BEEOS_DASHBOARD_URL=https://beeos-staging-web.vercel.app \
55
- # curl -fsSL https://beeos.ai/install | bash -s -- --version 1.0.16
65
+ # curl -fsSL https://beeos.ai/install | bash -s -- --version 1.0.18
56
66
 
57
67
  set -euo pipefail
58
68
 
@@ -65,11 +75,6 @@ RED="\033[31m"
65
75
  CYAN="\033[36m"
66
76
 
67
77
  CLI_PACKAGE="@beeos-ai/cli@latest"
68
- # `@beeos-ai/device-agent` + `@beeos-ai/device-mcp-server` are NOT
69
- # installed here. CLI ≥ 1.0.16 installs them lazily on the first
70
- # `beeos device attach` via `ensureDeviceAgent` in
71
- # `web/packages/core/src/device-setup.ts`. OpenClaw-only users never
72
- # download the device suite at all.
73
78
  MIN_NODE_VERSION=18
74
79
  NVM_VERSION="v0.40.1"
75
80
  FNM_INSTALL_URL="https://fnm.vercel.app/install"
@@ -116,6 +121,25 @@ success() { printf "${BOLD}${GREEN}[beeos]${RESET} %s\n" "$*"; }
116
121
  # `BEEOS_NO_TELEMETRY=1` short-circuits everything. This matches the
117
122
  # Node CLI's opt-out env var verbatim so a user who disabled telemetry
118
123
  # for the CLI doesn't unexpectedly get events from the bootstrap.
124
+ # Minimal JSON string-value escaper. Maps the four characters that
125
+ # can break a `"..."` JSON literal to their backslash escapes:
126
+ #
127
+ # \ -> \\
128
+ # " -> \"
129
+ # <CR> -> \r
130
+ # <LF> -> \n
131
+ #
132
+ # We deliberately don't pull in jq (not always available) or full
133
+ # JSON encoding — telemetry payload values are short slugs and human
134
+ # strings, not arbitrary binary. Tab + control-char escaping is
135
+ # nice-to-have but the four cases above are the ones that actually
136
+ # show up (e.g. `error_code` strings carrying quoted reasons, or
137
+ # error messages with embedded newlines).
138
+ json_escape() {
139
+ printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' \
140
+ | tr '\r' ' ' | tr '\n' ' '
141
+ }
142
+
119
143
  send_telemetry() {
120
144
  local event="$1"
121
145
  local error_code="${2:-}"
@@ -137,13 +161,25 @@ send_telemetry() {
137
161
  local host_hint
138
162
  host_hint="$(hostname 2>/dev/null || echo unknown)-${os_arch}"
139
163
 
164
+ # 1.0.19: every value below goes through `json_escape` so a stray
165
+ # `"` or newline in any of these fields can't break the POST body.
166
+ # `success_flag` is a bare boolean literal — never user-controlled —
167
+ # so it stays unquoted/unescaped.
168
+ local ev_e os_e arch_e node_e ec_e host_e
169
+ ev_e=$(json_escape "$event")
170
+ os_e=$(json_escape "$os_kind")
171
+ arch_e=$(json_escape "$os_arch")
172
+ node_e=$(json_escape "$node_ver")
173
+ ec_e=$(json_escape "$error_code")
174
+ host_e=$(json_escape "$host_hint")
175
+
140
176
  # POST body kept deliberately small — matches Node CLI payload.
141
177
  # Note: `cli_version` is empty until after npx install; we fill it
142
178
  # only when the bootstrap telemetry is fired post-install, from the
143
179
  # Node side. For pre-install events it stays "" and that's fine.
144
180
  local body
145
181
  body=$(cat <<JSON
146
- {"event":"${event}","cli_version":"","dist_tag":"","os":"${os_kind}","arch":"${os_arch}","node_version":"${node_ver}","success":${success_flag},"error_code":"${error_code}","host_hint":"${host_hint}"}
182
+ {"event":"${ev_e}","cli_version":"","dist_tag":"","os":"${os_e}","arch":"${arch_e}","node_version":"${node_e}","success":${success_flag},"error_code":"${ec_e}","host_hint":"${host_e}"}
147
183
  JSON
148
184
  )
149
185
 
@@ -340,8 +376,12 @@ try_install_node() {
340
376
  fi
341
377
  fi
342
378
 
343
- # 3. fnm — works on locked-down Linux without git/curl quirks
344
- if [[ "$OS_KIND" == "linux" ]] && ! command -v fnm &>/dev/null; then
379
+ # 3. fnm — works on locked-down Linux without git/curl quirks AND
380
+ # on macOS where users have neither Homebrew nor an existing nvm
381
+ # (the historical 1.0.18 path required brew on darwin, which is not
382
+ # always available — corporate-managed Macs, fresh users).
383
+ if [[ "$OS_KIND" == "linux" || "$OS_KIND" == "darwin" ]] \
384
+ && ! command -v fnm &>/dev/null; then
345
385
  info "Trying fnm (single-user, no sudo)..."
346
386
  if curl -fsSL "$FNM_INSTALL_URL" 2>>"$BEEOS_INSTALL_LOG" \
347
387
  | bash -s -- --skip-shell >> "$BEEOS_INSTALL_LOG" 2>&1; then
@@ -355,7 +395,8 @@ try_install_node() {
355
395
  fi
356
396
  fi
357
397
 
358
- # 4. macOS Homebrew
398
+ # 4. macOS Homebrew (last resort — already-installed brew only,
399
+ # we don't try to install brew itself).
359
400
  if [[ "$OS_KIND" == "darwin" ]] && command -v brew &>/dev/null; then
360
401
  info "Trying Homebrew..."
361
402
  if brew install node >> "$BEEOS_INSTALL_LOG" 2>&1; then
@@ -410,76 +451,6 @@ print_install_hints() {
410
451
  echo ""
411
452
  }
412
453
 
413
- # ── Existing install detection ───────────────────────────────
414
-
415
- beeos_already_installed() {
416
- if command -v beeos &>/dev/null; then
417
- return 0
418
- fi
419
- return 1
420
- }
421
-
422
- beeos_current_version() {
423
- # `beeos --version` currently prints just the semver string. Tolerate
424
- # other formats by extracting the first dotted number we can find.
425
- local out
426
- out=$(beeos --version 2>/dev/null | head -n1 | tr -d '[:space:]' || true)
427
- if [[ "$out" =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
428
- echo "${BASH_REMATCH[0]}"
429
- else
430
- echo "$out"
431
- fi
432
- }
433
-
434
- prompt_existing_install_action() {
435
- # The labels here are anchored against the equivalents in
436
- # install.ps1 (Read-ExistingInstallAction) and `init.ts`'s
437
- # `decideAction` menu by
438
- # `web/packages/cli/scripts/_existing_install_actions.json` and the
439
- # vitest grep lint at
440
- # `web/packages/cli/src/__tests__/existing-install-actions.test.ts`
441
- # (P1-E of the install-link review). Keep at least one keyword from
442
- # the manifest's `keywords[action]` array per option so the lint
443
- # doesn't break.
444
- #
445
- # Only prompt on an interactive TTY. When the script is piped without a
446
- # TTY attached (e.g. one-liner with no tty allocated), default to
447
- # "reinstall + re-run init" which is the safest non-destructive choice.
448
- if [[ ! -t 0 ]] && [[ ! -t 1 ]]; then
449
- info "Non-interactive shell detected — defaulting to reinstall."
450
- echo "upgrade"
451
- return 0
452
- fi
453
-
454
- # Note on naming: the option below is labelled "Reinstall + upgrade
455
- # CLI" deliberately. `beeos init`'s own menu has an item called
456
- # "Upgrade CLI & agents" — it does (now) call `npm i -g` for the
457
- # three-piece suite and re-runs `beeos start openclaw`. The script
458
- # action here is broader: it also re-bootstraps Node / pnpm if
459
- # missing, re-applies env vars from this shell, and *exec*s the
460
- # newly-installed binary. Different verb avoids the user thinking
461
- # they're picking the same code path twice. (See `init.ts`'s own
462
- # upgrade branch for the in-CLI behavior.)
463
- local ver
464
- ver=$(beeos_current_version || true)
465
- ver="${ver:-unknown}"
466
- warn "BeeOS CLI is already installed (v${ver})."
467
- echo ""
468
- echo " [1] Reinstall + upgrade CLI to the latest version, then run ${BOLD}beeos init${RESET}"
469
- echo " [2] Re-run ${BOLD}beeos init${RESET} without reinstalling"
470
- echo " [3] Skip (do nothing)"
471
- echo ""
472
-
473
- local choice
474
- read -rp "Choose [1-3]: " choice </dev/tty || choice=""
475
- case "$choice" in
476
- ""|1) echo "upgrade" ;;
477
- 2) echo "rerun" ;;
478
- 3) echo "skip" ;;
479
- *) echo "upgrade" ;;
480
- esac
481
- }
482
-
483
454
  # ── Main ─────────────────────────────────────────────────────
484
455
 
485
456
  run_cli() {
@@ -519,20 +490,27 @@ run_cli() {
519
490
  fi
520
491
 
521
492
  info "Installing ${CLI_PACKAGE} globally..."
522
- if ! npm install -g "$CLI_PACKAGE"; then
493
+ # 1.0.19: tee npm output into BEEOS_INSTALL_LOG. Without this, when
494
+ # `npm install -g` fails the user (and support engineers) only see
495
+ # whatever scrolled past in the terminal — important details like
496
+ # the npm error code, registry URL, or proxy hint may be gone by
497
+ # the time they go to copy-paste. `set -o pipefail` (file header)
498
+ # ensures the pipe's exit status is `npm`'s, not `tee`'s.
499
+ if ! npm install -g "$CLI_PACKAGE" 2>&1 | tee -a "$BEEOS_INSTALL_LOG"; then
523
500
  # P0-A of the install-link review: separate "Node ready" from
524
501
  # "CLI is actually on PATH" so the dashboard never reports a
525
502
  # success that the user can't reproduce. `install.bootstrap.npm_fail`
526
503
  # is the canonical fail-after-bootstrap marker.
527
504
  send_telemetry "install.bootstrap.npm_fail" "npm_install_cli_failed" false
528
505
  error "npm install -g ${CLI_PACKAGE} failed."
506
+ error " Full log: ${BEEOS_INSTALL_LOG}"
529
507
  error ""
530
508
  error "Common fixes:"
531
509
  error " - EEXIST on /bin/beeos from another package:"
532
- error " npm uninstall -g beeos # then re-run installer"
510
+ error " npm uninstall -g @beeos-ai/cli # then re-run installer"
533
511
  error " - EACCES permission error:"
534
512
  error " use a node version manager (nvm / fnm) or sudo"
535
- exit 1
513
+ exit 3
536
514
  fi
537
515
  # NPM succeeded — CLI is now on PATH. The device-agent suite is
538
516
  # deliberately NOT installed here; `beeos device attach` will
@@ -581,41 +559,12 @@ main() {
581
559
 
582
560
  success "Node.js $(node -v) detected"
583
561
 
584
- # Existing install? Let the user pick upgrade / rerun / skip.
585
- if beeos_already_installed; then
586
- local action
587
- action=$(prompt_existing_install_action)
588
- case "$action" in
589
- skip)
590
- info "Skipping. Run \`beeos init\` or \`beeos device attach\` manually later."
591
- exit 0
592
- ;;
593
- upgrade)
594
- info "Reinstalling ${CLI_PACKAGE}..."
595
- if command -v npm &>/dev/null; then
596
- if ! npm install -g "$CLI_PACKAGE"; then
597
- send_telemetry "install.bootstrap.npm_fail" "npm_install_cli_failed_upgrade" false
598
- error "npm install -g ${CLI_PACKAGE} failed."
599
- error ""
600
- error "Common fixes:"
601
- error " - EEXIST on /bin/beeos from another package:"
602
- error " npm uninstall -g beeos # then re-run installer"
603
- error " - EACCES permission error:"
604
- error " use a node version manager (nvm / fnm) or sudo"
605
- exit 1
606
- fi
607
- # Device-agent suite is intentionally NOT upgraded here.
608
- # `beeos device upgrade` is the canonical refresh path (it
609
- # also restarts the running fleet); the install-script
610
- # upgrade prompt only refreshes the CLI itself.
611
- fi
612
- ;;
613
- rerun)
614
- info "Reusing existing install."
615
- ;;
616
- esac
617
- fi
618
-
562
+ # Bootstrap is finished. Hand off to `run_cli` which performs
563
+ # `npm install -g @beeos-ai/cli` (idempotent — npm short-circuits
564
+ # when the requested version is already on disk) and then `exec`s
565
+ # the freshly-installed binary. "What does the CLI do when it's
566
+ # already installed?" is now `beeos init`'s problem; we don't
567
+ # second-guess it from out here.
619
568
  info "Running BeeOS CLI..."
620
569
  echo ""
621
570