@beeos-ai/cli 1.0.4 → 1.0.5
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/README.md +74 -3
- package/dist/index.js +3428 -593
- package/package.json +2 -1
- package/scripts/install.ps1 +246 -0
- package/scripts/install.sh +364 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beeos-ai/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "BeeOS CLI — run AI agents from your desktop",
|
|
6
6
|
"bin": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"bin/",
|
|
13
13
|
"dist/",
|
|
14
|
+
"scripts/",
|
|
14
15
|
"README.md"
|
|
15
16
|
],
|
|
16
17
|
"dependencies": {
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#Requires -Version 5.1
|
|
2
|
+
<#
|
|
3
|
+
.SYNOPSIS
|
|
4
|
+
BeeOS CLI Installer for Windows.
|
|
5
|
+
|
|
6
|
+
.DESCRIPTION
|
|
7
|
+
Detects or installs Node.js (via winget / Chocolatey fallback), then
|
|
8
|
+
dispatches into `beeos init` (default) or `beeos device attach` when
|
|
9
|
+
`-Device` is passed. Heavier deps (Python, uv, adb, scrcpy/vnc bridges)
|
|
10
|
+
are installed lazily by the CLI itself.
|
|
11
|
+
|
|
12
|
+
.EXAMPLE
|
|
13
|
+
# One-liner (PowerShell 5+):
|
|
14
|
+
irm https://beeos.ai/install.ps1 | iex
|
|
15
|
+
|
|
16
|
+
.EXAMPLE
|
|
17
|
+
# With specific CLI version:
|
|
18
|
+
.\install.ps1 -Version 1.0.4
|
|
19
|
+
|
|
20
|
+
.EXAMPLE
|
|
21
|
+
# Jump straight into device attach instead of init:
|
|
22
|
+
.\install.ps1 -Device
|
|
23
|
+
#>
|
|
24
|
+
param(
|
|
25
|
+
[string]$Version = "latest",
|
|
26
|
+
[switch]$Device,
|
|
27
|
+
[Parameter(ValueFromRemainingArguments=$true)]
|
|
28
|
+
[string[]]$Passthrough
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
$ErrorActionPreference = "Stop"
|
|
32
|
+
$MinNodeVersion = 18
|
|
33
|
+
|
|
34
|
+
$CliPackage = if ($Version -eq "latest") { "@beeos-ai/cli@latest" } else { "@beeos-ai/cli@$Version" }
|
|
35
|
+
|
|
36
|
+
# ── Helpers ──────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
function Write-BeeInfo { param([string]$Msg) Write-Host "[beeos] $Msg" -ForegroundColor Cyan }
|
|
39
|
+
function Write-BeeWarn { param([string]$Msg) Write-Host "[beeos] $Msg" -ForegroundColor Yellow }
|
|
40
|
+
function Write-BeeError { param([string]$Msg) Write-Host "[beeos] $Msg" -ForegroundColor Red }
|
|
41
|
+
function Write-BeeOk { param([string]$Msg) Write-Host "[beeos] $Msg" -ForegroundColor Green }
|
|
42
|
+
|
|
43
|
+
# ── Platform detection ───────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
function Test-Platform {
|
|
46
|
+
$arch = $env:PROCESSOR_ARCHITECTURE
|
|
47
|
+
$effectiveArch = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $arch }
|
|
48
|
+
Write-BeeInfo "detected: win32 $effectiveArch"
|
|
49
|
+
if ($effectiveArch -notin @("AMD64","ARM64","x86_64")) {
|
|
50
|
+
Write-BeeWarn "Unusual CPU architecture: $effectiveArch. Some sidecar binaries may be unavailable."
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# ── Node.js detection ────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
function Test-NodeVersion {
|
|
57
|
+
try {
|
|
58
|
+
$nodePath = (Get-Command node -ErrorAction SilentlyContinue).Source
|
|
59
|
+
if (-not $nodePath) { return $false }
|
|
60
|
+
|
|
61
|
+
$raw = & node -v 2>$null
|
|
62
|
+
if (-not $raw) { return $false }
|
|
63
|
+
|
|
64
|
+
$ver = $raw -replace '^v', ''
|
|
65
|
+
$major = [int]($ver.Split('.')[0])
|
|
66
|
+
|
|
67
|
+
if ($major -lt $MinNodeVersion) {
|
|
68
|
+
Write-BeeWarn "Node.js $ver found, but v${MinNodeVersion}+ is required."
|
|
69
|
+
return $false
|
|
70
|
+
}
|
|
71
|
+
return $true
|
|
72
|
+
} catch {
|
|
73
|
+
return $false
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# ── Auto-install Node.js ─────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
function Install-NodeAuto {
|
|
80
|
+
Write-BeeInfo "Node.js not found. Attempting automatic installation..."
|
|
81
|
+
Write-Host ""
|
|
82
|
+
|
|
83
|
+
$winget = Get-Command winget -ErrorAction SilentlyContinue
|
|
84
|
+
if ($winget) {
|
|
85
|
+
Write-BeeInfo "Installing Node.js LTS via winget..."
|
|
86
|
+
try {
|
|
87
|
+
winget install OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements --silent 2>$null
|
|
88
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" +
|
|
89
|
+
[System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
90
|
+
if (Test-NodeVersion) {
|
|
91
|
+
Write-BeeOk "Node.js installed via winget"
|
|
92
|
+
return $true
|
|
93
|
+
}
|
|
94
|
+
} catch {
|
|
95
|
+
Write-BeeWarn "winget install failed: $_"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
$choco = Get-Command choco -ErrorAction SilentlyContinue
|
|
100
|
+
if ($choco) {
|
|
101
|
+
Write-BeeInfo "Installing Node.js LTS via Chocolatey..."
|
|
102
|
+
try {
|
|
103
|
+
choco install nodejs-lts -y 2>$null
|
|
104
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" +
|
|
105
|
+
[System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
106
|
+
if (Test-NodeVersion) {
|
|
107
|
+
Write-BeeOk "Node.js installed via Chocolatey"
|
|
108
|
+
return $true
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
Write-BeeWarn "Chocolatey install failed: $_"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return $false
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# ── Manual install hints ─────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
function Show-InstallHints {
|
|
121
|
+
Write-BeeError "Could not install Node.js automatically."
|
|
122
|
+
Write-Host ""
|
|
123
|
+
Write-BeeInfo "Please install Node.js >= $MinNodeVersion manually:"
|
|
124
|
+
Write-Host ""
|
|
125
|
+
Write-Host " winget (recommended):" -ForegroundColor White
|
|
126
|
+
Write-Host " winget install OpenJS.NodeJS.LTS"
|
|
127
|
+
Write-Host ""
|
|
128
|
+
Write-Host " Official installer:" -ForegroundColor White
|
|
129
|
+
Write-Host " https://nodejs.org/en/download/"
|
|
130
|
+
Write-Host ""
|
|
131
|
+
Write-Host " Chocolatey:" -ForegroundColor White
|
|
132
|
+
Write-Host " choco install nodejs-lts"
|
|
133
|
+
Write-Host ""
|
|
134
|
+
Write-BeeInfo "Then run this script again:"
|
|
135
|
+
Write-Host " irm https://beeos.ai/install.ps1 | iex"
|
|
136
|
+
Write-Host ""
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# ── Existing install detection ───────────────────────────────
|
|
140
|
+
|
|
141
|
+
function Get-BeeosVersion {
|
|
142
|
+
try {
|
|
143
|
+
$out = & beeos --version 2>$null
|
|
144
|
+
if ($out) {
|
|
145
|
+
if ($out -match "\d+\.\d+\.\d+") { return $Matches[0] }
|
|
146
|
+
return ($out -replace '\s+','')
|
|
147
|
+
}
|
|
148
|
+
} catch {}
|
|
149
|
+
return $null
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function Read-ExistingInstallAction {
|
|
153
|
+
$ver = Get-BeeosVersion
|
|
154
|
+
if (-not $ver) { $ver = "unknown" }
|
|
155
|
+
Write-BeeWarn "BeeOS CLI is already installed (v$ver)."
|
|
156
|
+
Write-Host ""
|
|
157
|
+
Write-Host " [1] Upgrade to the latest version and run beeos init"
|
|
158
|
+
Write-Host " [2] Re-run beeos init without upgrading"
|
|
159
|
+
Write-Host " [3] Skip (do nothing)"
|
|
160
|
+
Write-Host ""
|
|
161
|
+
|
|
162
|
+
if (-not [Environment]::UserInteractive) {
|
|
163
|
+
Write-BeeInfo "Non-interactive shell — defaulting to upgrade."
|
|
164
|
+
return "upgrade"
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
$choice = Read-Host "Choose [1-3]"
|
|
168
|
+
switch ($choice) {
|
|
169
|
+
"" { return "upgrade" }
|
|
170
|
+
"1" { return "upgrade" }
|
|
171
|
+
"2" { return "rerun" }
|
|
172
|
+
"3" { return "skip" }
|
|
173
|
+
default { return "upgrade" }
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# ── Run CLI ──────────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
function Invoke-BeeosCli {
|
|
180
|
+
param(
|
|
181
|
+
[string]$Subcommand,
|
|
182
|
+
[string[]]$ExtraArgs
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
$npxPath = Get-Command npx -ErrorAction SilentlyContinue
|
|
186
|
+
$args = @($Subcommand)
|
|
187
|
+
if ($ExtraArgs) { $args += $ExtraArgs }
|
|
188
|
+
|
|
189
|
+
if ($npxPath) {
|
|
190
|
+
& npx --yes $CliPackage @args
|
|
191
|
+
} else {
|
|
192
|
+
Write-BeeWarn "npx not found, installing globally..."
|
|
193
|
+
& npm install -g $CliPackage
|
|
194
|
+
& beeos @args
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
# ── Main ─────────────────────────────────────────────────────
|
|
199
|
+
|
|
200
|
+
Write-Host ""
|
|
201
|
+
Write-Host " BeeOS CLI Installer" -ForegroundColor White
|
|
202
|
+
Write-Host " https://beeos.ai" -ForegroundColor DarkGray
|
|
203
|
+
Write-Host ""
|
|
204
|
+
|
|
205
|
+
Test-Platform
|
|
206
|
+
|
|
207
|
+
if (-not (Test-NodeVersion)) {
|
|
208
|
+
if (-not (Install-NodeAuto)) {
|
|
209
|
+
Show-InstallHints
|
|
210
|
+
exit 1
|
|
211
|
+
}
|
|
212
|
+
if (-not (Test-NodeVersion)) {
|
|
213
|
+
Show-InstallHints
|
|
214
|
+
exit 1
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
$nodeVer = & node -v
|
|
219
|
+
Write-BeeOk "Node.js $nodeVer detected"
|
|
220
|
+
|
|
221
|
+
$beeosCmd = Get-Command beeos -ErrorAction SilentlyContinue
|
|
222
|
+
if ($beeosCmd) {
|
|
223
|
+
$action = Read-ExistingInstallAction
|
|
224
|
+
switch ($action) {
|
|
225
|
+
"skip" {
|
|
226
|
+
Write-BeeInfo "Skipping. Run `beeos init` or `beeos device attach` manually later."
|
|
227
|
+
exit 0
|
|
228
|
+
}
|
|
229
|
+
"upgrade" {
|
|
230
|
+
Write-BeeInfo "Upgrading $CliPackage..."
|
|
231
|
+
try { & npm install -g $CliPackage 2>$null } catch {}
|
|
232
|
+
}
|
|
233
|
+
"rerun" {
|
|
234
|
+
Write-BeeInfo "Reusing existing install."
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
Write-BeeInfo "Running BeeOS CLI..."
|
|
240
|
+
Write-Host ""
|
|
241
|
+
|
|
242
|
+
if ($Device) {
|
|
243
|
+
Invoke-BeeosCli -Subcommand "device" -ExtraArgs (@("attach") + $Passthrough)
|
|
244
|
+
} else {
|
|
245
|
+
Invoke-BeeosCli -Subcommand "init" -ExtraArgs $Passthrough
|
|
246
|
+
}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# BeeOS CLI Installer (macOS / Linux)
|
|
4
|
+
# Usage:
|
|
5
|
+
# curl -fsSL https://beeos.ai/install | bash
|
|
6
|
+
# 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
|
+
#
|
|
9
|
+
# Entry script responsibilities:
|
|
10
|
+
# 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.
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
BOLD="\033[1m"
|
|
22
|
+
DIM="\033[2m"
|
|
23
|
+
RESET="\033[0m"
|
|
24
|
+
GREEN="\033[32m"
|
|
25
|
+
YELLOW="\033[33m"
|
|
26
|
+
RED="\033[31m"
|
|
27
|
+
CYAN="\033[36m"
|
|
28
|
+
|
|
29
|
+
CLI_PACKAGE="@beeos-ai/cli@latest"
|
|
30
|
+
MIN_NODE_VERSION=18
|
|
31
|
+
NVM_VERSION="v0.40.1"
|
|
32
|
+
FNM_INSTALL_URL="https://fnm.vercel.app/install"
|
|
33
|
+
|
|
34
|
+
BEEOS_HOME="${BEEOS_HOME:-$HOME/.beeos}"
|
|
35
|
+
|
|
36
|
+
info() { printf "${BOLD}${CYAN}[beeos]${RESET} %s\n" "$*"; }
|
|
37
|
+
warn() { printf "${BOLD}${YELLOW}[beeos]${RESET} %s\n" "$*"; }
|
|
38
|
+
error() { printf "${BOLD}${RED}[beeos]${RESET} %s\n" "$*" >&2; }
|
|
39
|
+
success() { printf "${BOLD}${GREEN}[beeos]${RESET} %s\n" "$*"; }
|
|
40
|
+
|
|
41
|
+
# ── Parse arguments ──────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
CLI_VERSION=""
|
|
44
|
+
MODE="init" # "init" | "device"
|
|
45
|
+
PASSTHROUGH_ARGS=()
|
|
46
|
+
|
|
47
|
+
while [[ $# -gt 0 ]]; do
|
|
48
|
+
case "$1" in
|
|
49
|
+
--version)
|
|
50
|
+
CLI_VERSION="$2"
|
|
51
|
+
shift 2
|
|
52
|
+
;;
|
|
53
|
+
--device)
|
|
54
|
+
MODE="device"
|
|
55
|
+
shift
|
|
56
|
+
;;
|
|
57
|
+
--init)
|
|
58
|
+
MODE="init"
|
|
59
|
+
shift
|
|
60
|
+
;;
|
|
61
|
+
*)
|
|
62
|
+
PASSTHROUGH_ARGS+=("$1")
|
|
63
|
+
shift
|
|
64
|
+
;;
|
|
65
|
+
esac
|
|
66
|
+
done
|
|
67
|
+
|
|
68
|
+
if [[ -n "$CLI_VERSION" ]]; then
|
|
69
|
+
CLI_PACKAGE="@beeos-ai/cli@${CLI_VERSION}"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# ── OS / architecture detection ──────────────────────────────
|
|
73
|
+
|
|
74
|
+
OS_KIND="" # darwin | linux | *
|
|
75
|
+
OS_ARCH="" # x86_64 | arm64
|
|
76
|
+
LIBC_KIND="" # gnu | musl (Linux only, empty otherwise)
|
|
77
|
+
|
|
78
|
+
detect_platform() {
|
|
79
|
+
local uname_s uname_m
|
|
80
|
+
uname_s=$(uname -s 2>/dev/null || echo "unknown")
|
|
81
|
+
uname_m=$(uname -m 2>/dev/null || echo "unknown")
|
|
82
|
+
|
|
83
|
+
case "$uname_s" in
|
|
84
|
+
Darwin) OS_KIND="darwin" ;;
|
|
85
|
+
Linux) OS_KIND="linux" ;;
|
|
86
|
+
*) OS_KIND="$uname_s" ;;
|
|
87
|
+
esac
|
|
88
|
+
|
|
89
|
+
case "$uname_m" in
|
|
90
|
+
x86_64|amd64) OS_ARCH="x86_64" ;;
|
|
91
|
+
aarch64|arm64) OS_ARCH="arm64" ;;
|
|
92
|
+
*) OS_ARCH="$uname_m" ;;
|
|
93
|
+
esac
|
|
94
|
+
|
|
95
|
+
if [[ "$OS_KIND" == "linux" ]]; then
|
|
96
|
+
if ldd --version 2>&1 | head -n1 | grep -qi "musl"; then
|
|
97
|
+
LIBC_KIND="musl"
|
|
98
|
+
else
|
|
99
|
+
LIBC_KIND="gnu"
|
|
100
|
+
fi
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
info "detected: ${OS_KIND} ${OS_ARCH}${LIBC_KIND:+ (${LIBC_KIND})}"
|
|
104
|
+
|
|
105
|
+
case "$OS_KIND" in
|
|
106
|
+
darwin)
|
|
107
|
+
if [[ "$OS_ARCH" != "arm64" && "$OS_ARCH" != "x86_64" ]]; then
|
|
108
|
+
error "Unsupported macOS architecture: $OS_ARCH (need arm64 or x86_64)"
|
|
109
|
+
exit 2
|
|
110
|
+
fi
|
|
111
|
+
;;
|
|
112
|
+
linux)
|
|
113
|
+
if [[ "$OS_ARCH" != "arm64" && "$OS_ARCH" != "x86_64" ]]; then
|
|
114
|
+
error "Unsupported Linux architecture: $OS_ARCH (need arm64 or x86_64)"
|
|
115
|
+
exit 2
|
|
116
|
+
fi
|
|
117
|
+
if [[ "$LIBC_KIND" == "musl" ]]; then
|
|
118
|
+
# No musl prebuilt for scrcpy-bridge / vnc-bridge yet. The CLI
|
|
119
|
+
# still works (agents run on top of Node) but some sidecars
|
|
120
|
+
# will need to be built from source.
|
|
121
|
+
warn "musl libc detected — some Rust sidecar binaries may be unavailable."
|
|
122
|
+
fi
|
|
123
|
+
;;
|
|
124
|
+
*)
|
|
125
|
+
error "Unsupported OS: $OS_KIND (use install.ps1 for Windows)"
|
|
126
|
+
exit 2
|
|
127
|
+
;;
|
|
128
|
+
esac
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# ── Node.js detection ────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
check_node() {
|
|
134
|
+
if ! command -v node &>/dev/null; then
|
|
135
|
+
return 1
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
local version major
|
|
139
|
+
version=$(node -v 2>/dev/null | sed 's/^v//')
|
|
140
|
+
major=$(echo "$version" | cut -d. -f1)
|
|
141
|
+
|
|
142
|
+
if [ "$major" -lt "$MIN_NODE_VERSION" ] 2>/dev/null; then
|
|
143
|
+
warn "Node.js $version found, but v${MIN_NODE_VERSION}+ is required."
|
|
144
|
+
return 1
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
return 0
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# ── Auto-install Node.js (nvm -> fnm -> brew) ────────────────
|
|
151
|
+
|
|
152
|
+
try_install_node() {
|
|
153
|
+
info "Node.js not found or too old. Attempting automatic installation..."
|
|
154
|
+
echo ""
|
|
155
|
+
|
|
156
|
+
# 1. Existing nvm
|
|
157
|
+
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
|
|
158
|
+
if [[ -s "$NVM_DIR/nvm.sh" ]]; then
|
|
159
|
+
info "Loading existing nvm..."
|
|
160
|
+
# shellcheck source=/dev/null
|
|
161
|
+
. "$NVM_DIR/nvm.sh"
|
|
162
|
+
if nvm install --lts 2>/dev/null; then
|
|
163
|
+
success "Node.js $(node -v) installed via existing nvm"
|
|
164
|
+
return 0
|
|
165
|
+
fi
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
# 2. Fresh nvm install
|
|
169
|
+
info "Installing nvm ${NVM_VERSION}..."
|
|
170
|
+
if curl -fsSL "https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh" | bash 2>/dev/null; then
|
|
171
|
+
# shellcheck source=/dev/null
|
|
172
|
+
. "$NVM_DIR/nvm.sh" 2>/dev/null || true
|
|
173
|
+
if nvm install --lts 2>/dev/null; then
|
|
174
|
+
success "Node.js $(node -v) installed via nvm"
|
|
175
|
+
return 0
|
|
176
|
+
fi
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# 3. fnm — works on locked-down Linux without git/curl quirks
|
|
180
|
+
if [[ "$OS_KIND" == "linux" ]] && ! command -v fnm &>/dev/null; then
|
|
181
|
+
info "Trying fnm (single-user, no sudo)..."
|
|
182
|
+
if curl -fsSL "$FNM_INSTALL_URL" | bash -s -- --skip-shell 2>/dev/null; then
|
|
183
|
+
export PATH="$HOME/.local/share/fnm:$PATH"
|
|
184
|
+
eval "$(fnm env --shell bash 2>/dev/null)" || true
|
|
185
|
+
if fnm install --lts 2>/dev/null && fnm use lts-latest 2>/dev/null; then
|
|
186
|
+
success "Node.js $(node -v) installed via fnm"
|
|
187
|
+
return 0
|
|
188
|
+
fi
|
|
189
|
+
fi
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
# 4. macOS Homebrew
|
|
193
|
+
if [[ "$OS_KIND" == "darwin" ]] && command -v brew &>/dev/null; then
|
|
194
|
+
info "Trying Homebrew..."
|
|
195
|
+
if brew install node 2>/dev/null; then
|
|
196
|
+
success "Node.js installed via Homebrew"
|
|
197
|
+
return 0
|
|
198
|
+
fi
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
return 1
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
# ── Manual install hints ─────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
print_install_hints() {
|
|
207
|
+
error "Could not install Node.js automatically."
|
|
208
|
+
echo ""
|
|
209
|
+
info "Please install Node.js >= ${MIN_NODE_VERSION} manually:"
|
|
210
|
+
echo ""
|
|
211
|
+
|
|
212
|
+
case "$OS_KIND" in
|
|
213
|
+
darwin)
|
|
214
|
+
echo " ${BOLD}Homebrew (recommended):${RESET}"
|
|
215
|
+
echo " brew install node"
|
|
216
|
+
echo ""
|
|
217
|
+
echo " ${BOLD}Official installer:${RESET}"
|
|
218
|
+
echo " https://nodejs.org/en/download/"
|
|
219
|
+
;;
|
|
220
|
+
linux)
|
|
221
|
+
echo " ${BOLD}nvm (recommended):${RESET}"
|
|
222
|
+
echo " curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash"
|
|
223
|
+
echo " source ~/.bashrc && nvm install --lts"
|
|
224
|
+
echo ""
|
|
225
|
+
echo " ${BOLD}fnm (single-user, no sudo):${RESET}"
|
|
226
|
+
echo " curl -fsSL ${FNM_INSTALL_URL} | bash"
|
|
227
|
+
echo " fnm install --lts"
|
|
228
|
+
echo ""
|
|
229
|
+
echo " ${BOLD}NodeSource:${RESET}"
|
|
230
|
+
echo " https://github.com/nodesource/distributions"
|
|
231
|
+
echo ""
|
|
232
|
+
echo " ${BOLD}Official binaries:${RESET}"
|
|
233
|
+
echo " https://nodejs.org/en/download/"
|
|
234
|
+
;;
|
|
235
|
+
*)
|
|
236
|
+
echo " Visit https://nodejs.org/en/download/"
|
|
237
|
+
;;
|
|
238
|
+
esac
|
|
239
|
+
|
|
240
|
+
echo ""
|
|
241
|
+
info "Then run this script again:"
|
|
242
|
+
echo " curl -fsSL https://beeos.ai/install | bash"
|
|
243
|
+
echo ""
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
# ── Existing install detection ───────────────────────────────
|
|
247
|
+
|
|
248
|
+
beeos_already_installed() {
|
|
249
|
+
if command -v beeos &>/dev/null; then
|
|
250
|
+
return 0
|
|
251
|
+
fi
|
|
252
|
+
return 1
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
beeos_current_version() {
|
|
256
|
+
# `beeos --version` currently prints just the semver string. Tolerate
|
|
257
|
+
# other formats by extracting the first dotted number we can find.
|
|
258
|
+
local out
|
|
259
|
+
out=$(beeos --version 2>/dev/null | head -n1 | tr -d '[:space:]' || true)
|
|
260
|
+
if [[ "$out" =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
|
261
|
+
echo "${BASH_REMATCH[0]}"
|
|
262
|
+
else
|
|
263
|
+
echo "$out"
|
|
264
|
+
fi
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
prompt_existing_install_action() {
|
|
268
|
+
# Only prompt on an interactive TTY. When the script is piped without a
|
|
269
|
+
# TTY attached (e.g. one-liner with no tty allocated), default to
|
|
270
|
+
# "upgrade + re-run init" which is the safest non-destructive choice.
|
|
271
|
+
if [[ ! -t 0 ]] && [[ ! -t 1 ]]; then
|
|
272
|
+
info "Non-interactive shell detected — defaulting to upgrade."
|
|
273
|
+
echo "upgrade"
|
|
274
|
+
return 0
|
|
275
|
+
fi
|
|
276
|
+
|
|
277
|
+
local ver
|
|
278
|
+
ver=$(beeos_current_version || true)
|
|
279
|
+
ver="${ver:-unknown}"
|
|
280
|
+
warn "BeeOS CLI is already installed (v${ver})."
|
|
281
|
+
echo ""
|
|
282
|
+
echo " [1] Upgrade to the latest version and run ${BOLD}beeos init${RESET}"
|
|
283
|
+
echo " [2] Re-run ${BOLD}beeos init${RESET} without upgrading"
|
|
284
|
+
echo " [3] Skip (do nothing)"
|
|
285
|
+
echo ""
|
|
286
|
+
|
|
287
|
+
local choice
|
|
288
|
+
read -rp "Choose [1-3]: " choice </dev/tty || choice=""
|
|
289
|
+
case "$choice" in
|
|
290
|
+
""|1) echo "upgrade" ;;
|
|
291
|
+
2) echo "rerun" ;;
|
|
292
|
+
3) echo "skip" ;;
|
|
293
|
+
*) echo "upgrade" ;;
|
|
294
|
+
esac
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
# ── Main ─────────────────────────────────────────────────────
|
|
298
|
+
|
|
299
|
+
run_cli() {
|
|
300
|
+
local subcmd="$1"
|
|
301
|
+
shift || true
|
|
302
|
+
|
|
303
|
+
if command -v npx &>/dev/null; then
|
|
304
|
+
exec npx --yes "$CLI_PACKAGE" "$subcmd" "$@"
|
|
305
|
+
else
|
|
306
|
+
warn "npx not found, installing globally..."
|
|
307
|
+
npm install -g "$CLI_PACKAGE"
|
|
308
|
+
exec beeos "$subcmd" "$@"
|
|
309
|
+
fi
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
main() {
|
|
313
|
+
echo ""
|
|
314
|
+
echo " ${BOLD}BeeOS CLI Installer${RESET}"
|
|
315
|
+
echo " ${DIM}https://beeos.ai${RESET}"
|
|
316
|
+
echo ""
|
|
317
|
+
|
|
318
|
+
detect_platform
|
|
319
|
+
|
|
320
|
+
if ! check_node; then
|
|
321
|
+
if ! try_install_node; then
|
|
322
|
+
print_install_hints
|
|
323
|
+
exit 1
|
|
324
|
+
fi
|
|
325
|
+
if ! check_node; then
|
|
326
|
+
print_install_hints
|
|
327
|
+
exit 1
|
|
328
|
+
fi
|
|
329
|
+
fi
|
|
330
|
+
|
|
331
|
+
success "Node.js $(node -v) detected"
|
|
332
|
+
|
|
333
|
+
# Existing install? Let the user pick upgrade / rerun / skip.
|
|
334
|
+
if beeos_already_installed; then
|
|
335
|
+
local action
|
|
336
|
+
action=$(prompt_existing_install_action)
|
|
337
|
+
case "$action" in
|
|
338
|
+
skip)
|
|
339
|
+
info "Skipping. Run \`beeos init\` or \`beeos device attach\` manually later."
|
|
340
|
+
exit 0
|
|
341
|
+
;;
|
|
342
|
+
upgrade)
|
|
343
|
+
info "Upgrading ${CLI_PACKAGE}..."
|
|
344
|
+
if command -v npm &>/dev/null; then
|
|
345
|
+
npm install -g "$CLI_PACKAGE" >/dev/null 2>&1 || true
|
|
346
|
+
fi
|
|
347
|
+
;;
|
|
348
|
+
rerun)
|
|
349
|
+
info "Reusing existing install."
|
|
350
|
+
;;
|
|
351
|
+
esac
|
|
352
|
+
fi
|
|
353
|
+
|
|
354
|
+
info "Running BeeOS CLI..."
|
|
355
|
+
echo ""
|
|
356
|
+
|
|
357
|
+
if [[ "$MODE" == "device" ]]; then
|
|
358
|
+
run_cli "device" "attach" "${PASSTHROUGH_ARGS[@]+"${PASSTHROUGH_ARGS[@]}"}"
|
|
359
|
+
else
|
|
360
|
+
run_cli "init" "${PASSTHROUGH_ARGS[@]+"${PASSTHROUGH_ARGS[@]}"}"
|
|
361
|
+
fi
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
main
|