From d7245d2484e5a5025cb6c7da3b86948e38a04b65 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 9 Mar 2026 13:48:30 +0800 Subject: [PATCH] fix(openclaw-installer): handle non-interactive tty and claude-mem allowlist cleanup --- openclaw/install.sh | 61 +++++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/openclaw/install.sh b/openclaw/install.sh index bd509fc4f..b4db86f88 100755 --- a/openclaw/install.sh +++ b/openclaw/install.sh @@ -80,17 +80,24 @@ setup_tty() { if [[ -t 0 ]]; then # stdin IS a terminal — use it directly TTY_FD=0 - elif [[ -e /dev/tty ]]; then - # stdin is piped (curl | bash) but /dev/tty is available - exec 3&2 + elif [[ "$NON_INTERACTIVE" == "true" ]]; then + # Non-interactive mode never needs prompt input. + # Avoid touching /dev/tty in headless environments. + TTY_FD=0 + elif [[ -r /dev/tty ]]; then + # stdin is piped (curl | bash) but /dev/tty may be available + if exec 3/dev/null; then + TTY_FD=3 + else + echo "Error: /dev/tty exists but is not readable." >&2 echo "Use --non-interactive or run directly: bash install.sh" >&2 exit 1 fi + else + # No terminal available at all + echo "Error: No terminal available for interactive prompts." >&2 + echo "Use --non-interactive or run directly: bash install.sh" >&2 + exit 1 fi } @@ -780,26 +787,33 @@ install_plugin() { # We temporarily remove the entry and save the config so `plugins install` can run, # then `plugins install` + `plugins enable` will re-create it properly. local oc_config="${HOME}/.openclaw/openclaw.json" - local saved_plugin_config="" + local saved_plugin_config="{}" + local had_allow_claude_mem="false" if [[ -f "$oc_config" ]]; then - saved_plugin_config=$(INSTALLER_CONFIG_FILE="$oc_config" node -e " + readarray -t __restore_state < <(INSTALLER_CONFIG_FILE="$oc_config" node -e " const fs = require('fs'); const configPath = process.env.INSTALLER_CONFIG_FILE; const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); const entry = config?.plugins?.entries?.['claude-mem']; - if (entry || config?.plugins?.slots?.memory === 'claude-mem') { - // Save the config block so we can restore it after install - process.stdout.write(JSON.stringify(entry?.config || {})); - // Remove the stale entry so OpenClaw CLI can run + const allow = config?.plugins?.allow; + const hadAllow = Array.isArray(allow) && allow.includes('claude-mem'); + const needsPatch = Boolean(entry) || config?.plugins?.slots?.memory === 'claude-mem' || hadAllow; + process.stdout.write(JSON.stringify(entry?.config || {})); + process.stdout.write('\n'); + process.stdout.write(hadAllow ? 'true' : 'false'); + if (needsPatch) { if (entry) delete config.plugins.entries['claude-mem']; - // Also remove the slot reference — if the slot points to a plugin - // that isn't in entries, OpenClaw's config validator rejects ALL commands if (config?.plugins?.slots?.memory === 'claude-mem') { delete config.plugins.slots.memory; } + if (Array.isArray(config?.plugins?.allow)) { + config.plugins.allow = config.plugins.allow.filter((id) => id !== 'claude-mem'); + } fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); } " 2>/dev/null) || true + saved_plugin_config="${__restore_state[0]:-{}}" + had_allow_claude_mem="${__restore_state[1]:-false}" fi # Install the plugin using OpenClaw's CLI @@ -818,6 +832,21 @@ install_plugin() { exit 1 fi + # Re-apply allowlist entry if it existed before cleanup. + if [[ "$had_allow_claude_mem" == "true" ]]; then + INSTALLER_CONFIG_FILE="$oc_config" node -e " + const fs = require('fs'); + const configPath = process.env.INSTALLER_CONFIG_FILE; + const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); + if (!config.plugins) config.plugins = {}; + if (!Array.isArray(config.plugins.allow)) config.plugins.allow = []; + if (!config.plugins.allow.includes('claude-mem')) { + config.plugins.allow.push('claude-mem'); + fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); + } + " 2>/dev/null || warn "Could not restore claude-mem allowlist entry" + fi + # Restore saved plugin config (workerPort, syncMemoryFile, observationFeed, etc.) # from any pre-existing installation that was temporarily removed above. if [[ -n "$saved_plugin_config" && "$saved_plugin_config" != "{}" ]]; then