Skip to content

Commit 5ca5496

Browse files
committed
fix(installer): auto-only gum flow and better npm diagnostics
1 parent b6d8851 commit 5ca5496

File tree

6 files changed

+68
-74
lines changed

6 files changed

+68
-74
lines changed

.github/workflows/install-matrix.yml

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@ on:
1414
options:
1515
- dry-run
1616
- full
17-
gum:
18-
description: Enable gum UI in matrix runs (may produce control codes in logs)
19-
required: true
20-
default: false
21-
type: boolean
2217

2318
jobs:
2419
linux-install-matrix:
@@ -38,14 +33,8 @@ jobs:
3833

3934
- name: Run matrix (push/pr)
4035
if: github.event_name != 'workflow_dispatch'
41-
run: bash scripts/test-install-matrix.sh --mode dry-run --image "${{ matrix.image }}" --no-gum
36+
run: bash scripts/test-install-matrix.sh --mode dry-run --image "${{ matrix.image }}"
4237

4338
- name: Run matrix (manual)
4439
if: github.event_name == 'workflow_dispatch'
45-
run: |
46-
if [[ "${{ inputs.gum }}" == "true" ]]; then
47-
GUM_FLAG="--gum"
48-
else
49-
GUM_FLAG="--no-gum"
50-
fi
51-
bash scripts/test-install-matrix.sh --mode "${{ inputs.mode }}" --image "${{ matrix.image }}" "$GUM_FLAG"
40+
run: bash scripts/test-install-matrix.sh --mode "${{ inputs.mode }}" --image "${{ matrix.image }}"

CHANGELOG.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## 2026-02-22
44

5-
- Installer: auto-disable gum UI/spinners in non-interactive shells (`OPENCLAW_USE_GUM=auto`) to reduce `ioctl` noise in piped/SSH installs.
6-
- Installer: after macOS `node@22` Homebrew install, force-check active `node` major and fail with explicit PATH remediation if shell still resolves an older Node.
7-
- Installer: add actionable npm failure diagnostics (exact install command, installer log path, npm debug log path, first npm error line) before retries.
5+
- Installer: make gum behavior fully automatic (interactive TTYs get gum, headless shells get plain status), and remove manual gum toggles.
6+
- Installer: after macOS `node@22` Homebrew install, force-check active `node` major, print active `node`/`npm` paths, and fail with explicit PATH remediation if shell still resolves an older Node.
7+
- Installer: strengthen npm failure diagnostics with parsed `code`/`syscall`/`errno`, exact install command, installer log path, npm debug log path, and first npm error line.
88
- CI/Tests: expand `install.sh` unit coverage for non-interactive gum disable, macOS Node PATH activation guard, and npm diagnostics parsing/output.
99
- Triage: close duplicate installer issue `openclaw/openclaw#23069` in favor of `openclaw/openclaw#23066` to keep ioctl troubleshooting centralized.
1010

@@ -22,7 +22,7 @@
2222

2323
## 2026-02-10
2424

25-
- Installer: modernize `install.sh` UX with staged progress, quieter command output, optional gum UI controls (`--gum`, `--no-gum`, `OPENCLAW_USE_GUM`, `CLAWDBOT_USE_GUM`), and verified-only temporary gum bootstrap (#50, thanks @sebslight).
25+
- Installer: modernize `install.sh` UX with staged progress, quieter command output, optional gum UI controls, and verified-only temporary gum bootstrap (#50, thanks @sebslight).
2626
- CI: add Linux installer matrix workflow and runner script for dry-run/full validation across distro images (#50, thanks @sebslight).
2727
## 2026-01-27
2828

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@ The landing page hosts installer scripts:
4343
- **Windows**: `iwr -useb https://openclaw.ai/install.ps1 | iex`
4444

4545
Installer UI controls (macOS/Linux `install.sh`):
46-
- Pass `--gum` to force gum UI when supported, or `--no-gum` to disable gum output.
47-
- Set `OPENCLAW_USE_GUM=auto|1|0` to control gum behavior in automation.
48-
- Compatibility alias: `CLAWDBOT_USE_GUM` (mapped to `OPENCLAW_USE_GUM`).
46+
- Gum UI is auto-detected; interactive terminals get richer status output, non-interactive shells fall back to plain output automatically.
4947

5048
These scripts:
5149
1. Install Homebrew (macOS) or detect package managers (Windows)

public/install.sh

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,6 @@ is_non_interactive_shell() {
8787
}
8888

8989
gum_is_tty() {
90-
if is_non_interactive_shell; then
91-
return 1
92-
fi
9390
if [[ -n "${NO_COLOR:-}" ]]; then
9491
return 1
9592
fi
@@ -142,20 +139,13 @@ bootstrap_gum_temp() {
142139
GUM_STATUS="skipped"
143140
GUM_REASON=""
144141

145-
if [[ "$OPENCLAW_USE_GUM" == "auto" ]] && is_non_interactive_shell; then
142+
if is_non_interactive_shell; then
146143
GUM_REASON="non-interactive shell (auto-disabled)"
147144
return 1
148145
fi
149146

150-
case "$OPENCLAW_USE_GUM" in
151-
0|false|False|FALSE|off|OFF|no|NO)
152-
GUM_REASON="disabled via OPENCLAW_USE_GUM"
153-
return 1
154-
;;
155-
esac
156-
157147
if ! gum_is_tty; then
158-
GUM_REASON="not a TTY"
148+
GUM_REASON="terminal does not support gum UI"
159149
return 1
160150
fi
161151

@@ -166,13 +156,6 @@ bootstrap_gum_temp() {
166156
return 0
167157
fi
168158

169-
if [[ "$OPENCLAW_USE_GUM" != "1" && "$OPENCLAW_USE_GUM" != "true" && "$OPENCLAW_USE_GUM" != "TRUE" ]]; then
170-
if [[ "$OPENCLAW_USE_GUM" != "auto" ]]; then
171-
GUM_REASON="invalid OPENCLAW_USE_GUM value: $OPENCLAW_USE_GUM"
172-
return 1
173-
fi
174-
fi
175-
176159
if ! command -v tar >/dev/null 2>&1; then
177160
GUM_REASON="tar not found"
178161
return 1
@@ -706,18 +689,51 @@ extract_first_npm_error_line() {
706689
grep -E 'npm (ERR!|error)|ERR!' "$log" | head -n1 || true
707690
}
708691

692+
extract_npm_error_code() {
693+
local log="$1"
694+
sed -n -E 's/^npm (ERR!|error) code[[:space:]]+([^[:space:]]+).*$/\2/p' "$log" | head -n1
695+
}
696+
697+
extract_npm_error_syscall() {
698+
local log="$1"
699+
sed -n -E 's/^npm (ERR!|error) syscall[[:space:]]+(.+)$/\2/p' "$log" | head -n1
700+
}
701+
702+
extract_npm_error_errno() {
703+
local log="$1"
704+
sed -n -E 's/^npm (ERR!|error) errno[[:space:]]+(.+)$/\2/p' "$log" | head -n1
705+
}
706+
709707
print_npm_failure_diagnostics() {
710708
local spec="$1"
711709
local log="$2"
712710
local debug_log=""
713711
local first_error=""
712+
local error_code=""
713+
local error_syscall=""
714+
local error_errno=""
714715

715716
ui_warn "npm install failed for ${spec}"
716717
if [[ -n "${LAST_NPM_INSTALL_CMD}" ]]; then
717718
echo " Command: ${LAST_NPM_INSTALL_CMD}"
718719
fi
719720
echo " Installer log: ${log}"
720721

722+
error_code="$(extract_npm_error_code "$log")"
723+
if [[ -n "$error_code" ]]; then
724+
echo " npm code: ${error_code}"
725+
fi
726+
727+
error_syscall="$(extract_npm_error_syscall "$log")"
728+
if [[ -n "$error_syscall" ]]; then
729+
echo " npm syscall: ${error_syscall}"
730+
fi
731+
732+
error_errno="$(extract_npm_error_errno "$log")"
733+
if [[ -n "$error_errno" ]]; then
734+
echo " npm errno: ${error_errno}"
735+
fi
736+
721737
debug_log="$(extract_npm_debug_log_path "$log" || true)"
722738
if [[ -n "$debug_log" ]]; then
723739
echo " npm debug log: ${debug_log}"
@@ -907,7 +923,6 @@ map_legacy_env "OPENCLAW_GIT_UPDATE" "CLAWDBOT_GIT_UPDATE"
907923
map_legacy_env "OPENCLAW_NPM_LOGLEVEL" "CLAWDBOT_NPM_LOGLEVEL"
908924
map_legacy_env "OPENCLAW_VERBOSE" "CLAWDBOT_VERBOSE"
909925
map_legacy_env "OPENCLAW_PROFILE" "CLAWDBOT_PROFILE"
910-
map_legacy_env "OPENCLAW_USE_GUM" "CLAWDBOT_USE_GUM"
911926
map_legacy_env "OPENCLAW_INSTALL_SH_NO_RUN" "CLAWDBOT_INSTALL_SH_NO_RUN"
912927

913928
pick_tagline() {
@@ -943,7 +958,6 @@ SHARP_IGNORE_GLOBAL_LIBVIPS="${SHARP_IGNORE_GLOBAL_LIBVIPS:-1}"
943958
NPM_LOGLEVEL="${OPENCLAW_NPM_LOGLEVEL:-error}"
944959
NPM_SILENT_FLAG="--silent"
945960
VERBOSE="${OPENCLAW_VERBOSE:-0}"
946-
OPENCLAW_USE_GUM="${OPENCLAW_USE_GUM:-auto}"
947961
OPENCLAW_BIN=""
948962
PNPM_CMD=()
949963
HELP=0
@@ -967,8 +981,6 @@ Options:
967981
--no-prompt Disable prompts (required in CI/automation)
968982
--dry-run Print what would happen (no changes)
969983
--verbose Print debug output (set -x, npm verbose)
970-
--gum Force gum UI if possible
971-
--no-gum Disable gum UI
972984
--help, -h Show this help
973985
974986
Environment variables:
@@ -981,7 +993,6 @@ Environment variables:
981993
OPENCLAW_DRY_RUN=1
982994
OPENCLAW_NO_ONBOARD=1
983995
OPENCLAW_VERBOSE=1
984-
OPENCLAW_USE_GUM=auto|1|0 Default: auto (try gum on interactive TTY)
985996
OPENCLAW_NPM_LOGLEVEL=error|warn|notice Default: error (hide npm deprecation noise)
986997
SHARP_IGNORE_GLOBAL_LIBVIPS=0|1 Default: 1 (avoid sharp building against global libvips)
987998
@@ -1011,14 +1022,6 @@ parse_args() {
10111022
VERBOSE=1
10121023
shift
10131024
;;
1014-
--gum)
1015-
OPENCLAW_USE_GUM=1
1016-
shift
1017-
;;
1018-
--no-gum)
1019-
OPENCLAW_USE_GUM=0
1020-
shift
1021-
;;
10221025
--no-prompt)
10231026
NO_PROMPT=1
10241027
shift
@@ -1226,6 +1229,23 @@ node_major_version() {
12261229
return 1
12271230
}
12281231

1232+
print_active_node_paths() {
1233+
if ! command -v node &> /dev/null; then
1234+
return 1
1235+
fi
1236+
local node_path node_version npm_path npm_version
1237+
node_path="$(command -v node 2>/dev/null || true)"
1238+
node_version="$(node -v 2>/dev/null || true)"
1239+
ui_info "Active Node.js: ${node_version:-unknown} (${node_path:-unknown})"
1240+
1241+
if command -v npm &> /dev/null; then
1242+
npm_path="$(command -v npm 2>/dev/null || true)"
1243+
npm_version="$(npm -v 2>/dev/null || true)"
1244+
ui_info "Active npm: ${npm_version:-unknown} (${npm_path:-unknown})"
1245+
fi
1246+
return 0
1247+
}
1248+
12291249
ensure_macos_node22_active() {
12301250
if [[ "$OS" != "macos" ]]; then
12311251
return 0
@@ -1265,6 +1285,7 @@ check_node() {
12651285
NODE_VERSION="$(node_major_version || true)"
12661286
if [[ -n "$NODE_VERSION" && "$NODE_VERSION" -ge 22 ]]; then
12671287
ui_success "Node.js v$(node -v | cut -d'v' -f2) found"
1288+
print_active_node_paths || true
12681289
return 0
12691290
else
12701291
if [[ -n "$NODE_VERSION" ]]; then
@@ -1290,6 +1311,7 @@ install_node() {
12901311
exit 1
12911312
fi
12921313
ui_success "Node.js installed"
1314+
print_active_node_paths || true
12931315
elif [[ "$OS" == "linux" ]]; then
12941316
ui_info "Installing Node.js via NodeSource"
12951317
require_sudo
@@ -1341,6 +1363,7 @@ install_node() {
13411363
fi
13421364

13431365
ui_success "Node.js v22 installed"
1366+
print_active_node_paths || true
13441367
fi
13451368
}
13461369

scripts/test-install-matrix.sh

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,21 @@
22
set -euo pipefail
33

44
MODE="dry-run"
5-
USE_GUM=0
65
IMAGES=()
76

87
usage() {
98
cat <<'EOF'
109
Run install.sh in clean Linux containers (matrix style).
1110
1211
Note: gum UI is disabled by default because CI/container logs often render
13-
raw ANSI/OSC control sequences. Use --gum only in a real interactive terminal.
12+
raw ANSI/OSC control sequences. The installer now auto-detects interactivity.
1413
1514
Usage:
1615
bash scripts/test-install-matrix.sh [options]
1716
1817
Options:
1918
--mode dry-run|full Test mode (default: dry-run)
2019
--image <docker-image> Image to test (repeatable)
21-
--gum Force gum UI
22-
--no-gum Disable gum UI (default)
2320
--help, -h Show this help
2421
2522
Examples:
@@ -39,14 +36,6 @@ while [[ $# -gt 0 ]]; do
3936
IMAGES+=("$2")
4037
shift 2
4138
;;
42-
--gum)
43-
USE_GUM=1
44-
shift
45-
;;
46-
--no-gum)
47-
USE_GUM=0
48-
shift
49-
;;
5039
--help|-h)
5140
usage
5241
exit 0
@@ -101,11 +90,6 @@ build_install_args() {
10190
if [[ "$MODE" == "dry-run" ]]; then
10291
INSTALL_ARGS+=(--dry-run)
10392
fi
104-
if [[ "$USE_GUM" == "1" ]]; then
105-
INSTALL_ARGS+=(--gum)
106-
else
107-
INSTALL_ARGS+=(--no-gum)
108-
fi
10993
}
11094

11195
run_case() {
@@ -125,7 +109,6 @@ run_case() {
125109
echo "============================================================"
126110
echo "Image: $image"
127111
echo "Mode: $MODE"
128-
echo "GUM: $([[ "$USE_GUM" == "1" ]] && echo on || echo off)"
129112
echo "============================================================"
130113

131114
docker run --rm -t \

scripts/test-install-sh-unit.sh

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -300,13 +300,9 @@ EOF
300300

301301
echo "==> case: bootstrap_gum_temp (auto disable in non-interactive shell)"
302302
(
303-
# shellcheck disable=SC2034
304-
OPENCLAW_USE_GUM=auto
305303
# shellcheck disable=SC2034
306304
GUM=""
307305
# shellcheck disable=SC2034
308-
GUM_STATUS="skipped"
309-
# shellcheck disable=SC2034
310306
GUM_REASON=""
311307

312308
is_non_interactive_shell() { return 0; }
@@ -382,6 +378,8 @@ echo "==> case: print_npm_failure_diagnostics"
382378

383379
cat >"${log}" <<'EOF'
384380
npm ERR! code EACCES
381+
npm ERR! syscall rename
382+
npm ERR! errno -13
385383
npm ERR! A complete log of this run can be found in: /tmp/npm-debug.log
386384
EOF
387385

@@ -392,6 +390,9 @@ EOF
392390

393391
assert_contains "$out" "Command: env SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm --loglevel error --no-fund --no-audit install -g openclaw@latest" "print_npm_failure_diagnostics command"
394392
assert_contains "$out" "Installer log: ${log}" "print_npm_failure_diagnostics installer log"
393+
assert_contains "$out" "npm code: EACCES" "print_npm_failure_diagnostics code"
394+
assert_contains "$out" "npm syscall: rename" "print_npm_failure_diagnostics syscall"
395+
assert_contains "$out" "npm errno: -13" "print_npm_failure_diagnostics errno"
395396
assert_contains "$out" "npm debug log: /tmp/npm-debug.log" "print_npm_failure_diagnostics debug log"
396397
assert_contains "$out" "First npm error: npm ERR! code EACCES" "print_npm_failure_diagnostics first error"
397398
)

0 commit comments

Comments
 (0)