mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:50:42 +00:00
fix(installer): handle macos gum node failures
This commit is contained in:
@@ -71,6 +71,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Installer/macOS: rerun Homebrew install steps without the gum spinner when raw-mode ioctl failures occur, and avoid claiming `node@24` was installed when the Homebrew keg binary is missing. Fixes #70411. Thanks @1fanwang and @dad-io.
|
||||
- Docker: copy patched dependency files into runtime images so downstream `pnpm install` layers keep working. Fixes #69224. Thanks @gucasbrg.
|
||||
- Agents/runtime: submit heartbeat, cron, and exec wakeups as transient runtime context instead of visible user prompts, keeping synthetic system work out of chat transcripts. Fixes #66496 and #66814. Thanks @jeades and @mandomaker.
|
||||
- Telegram: include native quote excerpts automatically for threaded replies and reply tags when the original Telegram text is available, without adding another config knob. Fixes #6975. Thanks @rex05ai.
|
||||
|
||||
@@ -404,7 +404,7 @@ is_shell_function() {
|
||||
is_gum_raw_mode_failure() {
|
||||
local err_log="$1"
|
||||
[[ -s "$err_log" ]] || return 1
|
||||
grep -Eiq 'setrawmode' "$err_log"
|
||||
grep -Eiq 'setrawmode|inappropriate ioctl' "$err_log"
|
||||
}
|
||||
|
||||
run_with_spinner() {
|
||||
@@ -412,13 +412,25 @@ run_with_spinner() {
|
||||
shift
|
||||
|
||||
if [[ -n "$GUM" ]] && gum_is_tty && ! is_shell_function "${1:-}"; then
|
||||
local gum_err
|
||||
local gum_err gum_out
|
||||
gum_err="$(mktempfile)"
|
||||
if "$GUM" spin --spinner dot --title "$title" -- "$@" 2>"$gum_err"; then
|
||||
gum_out="$(mktempfile)"
|
||||
if "$GUM" spin --spinner dot --title "$title" -- "$@" >"$gum_out" 2>"$gum_err"; then
|
||||
if is_gum_raw_mode_failure "$gum_out" || is_gum_raw_mode_failure "$gum_err"; then
|
||||
GUM=""
|
||||
GUM_STATUS="skipped"
|
||||
GUM_REASON="gum raw mode unavailable"
|
||||
ui_warn "Spinner unavailable in this terminal; continuing without spinner"
|
||||
"$@"
|
||||
return $?
|
||||
fi
|
||||
if [[ -s "$gum_out" ]]; then
|
||||
cat "$gum_out"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
local gum_status=$?
|
||||
if is_gum_raw_mode_failure "$gum_err"; then
|
||||
if is_gum_raw_mode_failure "$gum_err" || is_gum_raw_mode_failure "$gum_out"; then
|
||||
GUM=""
|
||||
GUM_STATUS="skipped"
|
||||
GUM_REASON="gum raw mode unavailable"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const SCRIPT_PATH = "scripts/install.sh";
|
||||
@@ -123,4 +125,52 @@ describe("install.sh macOS Homebrew Node behavior", () => {
|
||||
expect(result.stdout).not.toContain("Node.js v24 was installed");
|
||||
expect(result.stdout).not.toContain("Add this to your shell profile");
|
||||
});
|
||||
|
||||
it("falls back when gum reports raw-mode ioctl failures", () => {
|
||||
expect(script).toContain("setrawmode|inappropriate ioctl");
|
||||
expect(script).toContain(
|
||||
'if "$GUM" spin --spinner dot --title "$title" -- "$@" >"$gum_out" 2>"$gum_err"; then',
|
||||
);
|
||||
expect(script).toContain(
|
||||
'if is_gum_raw_mode_failure "$gum_out" || is_gum_raw_mode_failure "$gum_err"; then',
|
||||
);
|
||||
expect(script).toContain(
|
||||
'ui_warn "Spinner unavailable in this terminal; continuing without spinner"',
|
||||
);
|
||||
expect(script).toContain('"$@"\n return $?');
|
||||
});
|
||||
|
||||
it("reruns spinner-wrapped commands when gum reports ioctl failure", () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "openclaw-install-sh-gum-"));
|
||||
try {
|
||||
const gumPath = join(dir, "gum");
|
||||
const commandPath = join(dir, "command");
|
||||
const markerPath = join(dir, "marker");
|
||||
writeFileSync(
|
||||
gumPath,
|
||||
"#!/usr/bin/env bash\nprintf 'inappropriate ioctl for device\\n'\nexit 0\n",
|
||||
{ mode: 0o755 },
|
||||
);
|
||||
writeFileSync(commandPath, `#!/usr/bin/env bash\nprintf 'ran' >"${markerPath}"\n`, {
|
||||
mode: 0o755,
|
||||
});
|
||||
|
||||
const result = runInstallShell(`
|
||||
set -euo pipefail
|
||||
source "${SCRIPT_PATH}"
|
||||
gum_is_tty() { return 0; }
|
||||
GUM="${gumPath}"
|
||||
run_with_spinner "Installing node" "${commandPath}"
|
||||
cat "${markerPath}"
|
||||
`);
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.stdout).toContain(
|
||||
"Spinner unavailable in this terminal; continuing without spinner",
|
||||
);
|
||||
expect(result.stdout).toContain("ran");
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user