fix(linux): truthful install failures, post-install repair, reachable reinstall (#128614)

The Linux desktop companion could complete a CLI install and still claim
'Installation did not finish' with circular update advice, discarding the
real failure. Verified end-to-end in a clean Ubuntu VM across all three
release channels:

- cli.rs: failed CLI commands now surface their stderr tail (deduped, last
  12 lines) instead of being mislabeled as JSON parse failures.
- gateway.rs: missing dashboard --json support maps to an honest curated
  message pointing at Beta/Development channels, not a circular npm-update
  hint.
- main.rs: run 'doctor --fix --non-interactive' right after install so the
  CLI repairs config/state before Gateway readiness checks; wrap
  post-install failures as 'installed, but connecting failed: <reason>'.
- installer.rs: keep structured step events out of the prose failure tail.
- ui/main.js: humanize streamed install steps, render real errors on the
  failure screen, and always offer Reinstall from connection failures.
- scripts/install-cli.sh: service refresh uses 'gateway status --json' with
  the bundled node runtime, corepack failure falls back to npm, dev channel
  clones with --filter=blob:none.
This commit is contained in:
Peter Steinberger
2026-08-24 02:01:15 -07:00
committed by GitHub
parent 12d0fd2ef8
commit f6aa7c24f1
6 changed files with 184 additions and 27 deletions
+28 -7
View File
@@ -1152,10 +1152,16 @@ ensure_pnpm() {
emit_json "{\"event\":\"step\",\"name\":\"pnpm\",\"status\":\"start\",\"method\":\"corepack\"}"
log "Installing pnpm via Corepack..."
"$(node_dir)/bin/corepack" enable >/dev/null 2>&1 || true
"$(node_dir)/bin/corepack" prepare pnpm@11 --activate
if detect_pnpm_cmd && pnpm_cmd_is_ready && [[ "$("${PNPM_CMD[@]}" --version 2>/dev/null || true)" =~ ^11\. ]]; then
emit_json "{\"event\":\"step\",\"name\":\"pnpm\",\"status\":\"ok\"}"
return 0
# Corepack downloads fail hard on npm registry key rotation (its bundled
# signature set goes stale); the npm fallback below must stay reachable.
if "$(node_dir)/bin/corepack" prepare pnpm@11 --activate; then
if detect_pnpm_cmd && pnpm_cmd_is_ready && [[ "$("${PNPM_CMD[@]}" --version 2>/dev/null || true)" =~ ^11\. ]]; then
emit_json "{\"event\":\"step\",\"name\":\"pnpm\",\"status\":\"ok\"}"
return 0
fi
else
emit_json "{\"event\":\"step\",\"name\":\"pnpm\",\"status\":\"warn\",\"reason\":\"corepack-failed\"}"
log "Corepack could not provision pnpm; falling back to npm."
fi
fi
@@ -1450,7 +1456,9 @@ clone_git_checkout_transactionally() {
fi
TMPFILES+=("$staging_dir")
git clone "$repo_url" "$staging_dir" || clone_status=$?
# Blobless partial clone: the dev checkout only needs current files plus pullable
# history refs; full multi-gigabyte blob history would dominate install time.
git clone --filter=blob:none "$repo_url" "$staging_dir" || clone_status=$?
if [[ "$clone_status" -ne 0 ]]; then
return "$clone_status"
fi
@@ -1624,12 +1632,25 @@ is_gateway_daemon_loaded() {
fi
local status_json=""
status_json="$("$claw" daemon status --json 2>/dev/null || true)"
# Unlike daemon status, gateway status reports service.loaded during pending migrations.
status_json="$("$claw" gateway status --json 2>/dev/null || true)"
if [[ -z "$status_json" ]]; then
return 1
fi
printf '%s' "$status_json" | node -e '
# Managed installs must parse with their provisioned Node even when the system has none.
local node_bin="${PREFIX}/tools/node/bin/node"
if [[ ! -x "$node_bin" ]]; then
if command -v node >/dev/null 2>&1; then
node_bin="$(command -v node)"
else
# Approximate POSIX-safe fallback when neither managed nor system Node is available.
printf '%s\n' "$status_json" | grep -Eq '"loaded"[[:space:]]*:[[:space:]]*true'
return
fi
fi
printf '%s' "$status_json" | "$node_bin" -e '
const fs = require("fs");
const raw = fs.readFileSync(0, "utf8").trim();
if (!raw) process.exit(1);