我发现最新Claude code已无法直接在Android termux用npm安装来直接使用,会有报错,肯定是Termux环境的兼容问题,毕竟不是标准的Linux。如何解决: 1.非proot方案(推荐) #!/data/data/com.termux/files/usr/bin/bash set -euo pipefail readonly SCRIPT_NAME="$(basename "$0")" readonly PREFIX_DIR="${PREFIX:-/data/data/com.termux/files/usr}" readonly STATE_DIR="${CLAUDE_CODE_HOME:-$HOME/.claude-code-termux}" readonly NODE_DIR="$STATE_DIR/node" readonly WRAPPER_BIN_DIR="$STATE_DIR/bin" readonly PATCH_DIR="$STATE_DIR/patches" readonly GLOBAL_PREFIX_DIR="$STATE_DIR/npm-global" readonly GLOBAL_BIN_DIR="$GLOBAL_PREFIX_DIR/bin" readonly NPM_CACHE_DIR="$STATE_DIR/npm-cache" readonly TMP_ROOT_DIR="${TMPDIR:-$PREFIX_DIR/tmp}" readonly GLIBC_LDSO="$PREFIX_DIR/glibc/lib/ld-linux-aarch64.so.1" readonly GLIBC_RUNNER_BIN="$PREFIX_DIR/bin/grun" readonly GLIBC_MARKER="$STATE_DIR/.glibc-arch" readonly HOST_CLAUDE_PATH="$PREFIX_DIR/bin/claude" readonly BACKUP_DIR="$STATE_DIR/backups" readonly CLAUDE_PACKAGE_NAME="@anthropic-ai/claude-code" readonly CLAUDE_PACKAGE_VERSION="${CLAUDE_CODE_VERSION:-latest}" readonly NODE_VERSION="${CLAUDE_CODE_NODE_VERSION:-22.22.0}" readonly NODE_TARBALL="node-v${NODE_VERSION}-linux-arm64.tar.xz" readonly NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TARBALL}" readonly COMPAT_PATCH_PATH="$PATCH_DIR/claude-glibc-compat.js" readonly CLAUDE_EXE_PATH="$GLOBAL_PREFIX_DIR/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe" readonly HOST_WRAPPER_MARKER="# claude-code-termux-nonproot-wrapper" readonly C_BOLD_BLUE="\033[1;34m" readonly C_BOLD_GREEN="\033[1;32m" readonly C_BOLD_YELLOW="\033[1;33m" readonly C_BOLD_RED="\033[1;31m" readonly C_RESET="\033[0m" info() { printf '%b[INFO]%b %s\n' "$C_BOLD_BLUE" "$C_RESET" "$*" } success() { printf '%b[ OK ]%b %s\n' "$C_BOLD_GREEN" "$C_RESET" "$*" } warn() { printf '%b[WARN]%b %s\n' "$C_BOLD_YELLOW" "$C_RESET" "$*" >&2 } die() { printf '%b[ERR ]%b %s\n' "$C_BOLD_RED" "$C_RESET" "$*" >&2 exit 1 } usage() { cat <<EOF Usage: bash $SCRIPT_NAME What it does: 1. Installs Termux dependencies needed for a glibc-based Node runtime. 2. Installs glibc-runner through pacman (no proot distro). 3. Downloads official Node.js ${NODE_VERSION} linux-arm64. 4. Wraps node/npm with ld.so so they run on Termux. 5. Installs ${CLAUDE_PACKAGE_NAME} and exposes it as: $HOST_CLAUDE_PATH Environment overrides: CLAUDE_CODE_HOME install state dir, default: $STATE_DIR CLAUDE_CODE_VERSION npm package version/tag, default: $CLAUDE_PACKAGE_VERSION CLAUDE_CODE_NODE_VERSION Node.js linux-arm64 version, default: $NODE_VERSION Notes: - This follows the non-proot glibc-wrapper approach used by openclaw-android. - Only aarch64 Termux is supported. - Existing $HOST_CLAUDE_PATH will be backed up if it is not already managed. EOF } command_exists() { command -v "$1" >/dev/null 2>&1 } require_termux() { [ -d "$PREFIX_DIR" ] || die "This script must run in Termux." command_exists pkg || die "pkg not found. This script must run in Termux." } ensure_tmp_root() { mkdir -p "$TMP_ROOT_DIR" } ensure_state_dirs() { mkdir -p "$STATE_DIR" "$WRAPPER_BIN_DIR" "$PATCH_DIR" "$GLOBAL_PREFIX_DIR" \ "$GLOBAL_BIN_DIR" "$NPM_CACHE_DIR" "$BACKUP_DIR" } ensure_termux_package() { local package_name="$1" if dpkg -s "$package_name" >/dev/null 2>&1; then success "Termux package already installed: $package_name" return 0 fi info "Installing Termux package: $package_name" pkg install -y "$package_name" success "Installed Termux package: $package_name" } ensure_glibc_runner() { local arch local pacman_conf local siglevel_patched=0 arch="$(uname -m)" [ "$arch" = "aarch64" ] || die "glibc mode only supports aarch64, got: $arch" if [ -f "$GLIBC_MARKER" ] && [ -x "$GLIBC_LDSO" ]; then success "glibc-runner already available" return 0 fi ensure_termux_package "pacman" pacman_conf="$PREFIX_DIR/etc/pacman.conf" info "Initializing pacman for glibc-runner" if [ -f "$pacman_conf" ] && ! grep -q '^SigLevel = Never' "$pacman_conf"; then cp "$pacman_conf" "${pacman_conf}.bak" sed -i 's/^SigLevel\s*=.*/SigLevel = Never/' "$pacman_conf" siglevel_patched=1 warn "Applied temporary pacman SigLevel workaround" fi pacman-key --init 2>/dev/null || true pacman-key --populate 2>/dev/null || true info "Installing glibc-runner" if ! pacman -Sy glibc-runner --noconfirm --assume-installed bash,patchelf,resolv-conf; then if [ "$siglevel_patched" -eq 1 ] && [ -f "${pacman_conf}.bak" ]; then mv "${pacman_conf}.bak" "$pacman_conf" fi die "Failed to install glibc-runner" fi if [ "$siglevel_patched" -eq 1 ] && [ -f "${pacman_conf}.bak" ]; then mv "${pacman_conf}.bak" "$pacman_conf" success "Restored pacman SigLevel" fi [ -x "$GLIBC_LDSO" ] || die "glibc dynamic linker not found at $GLIBC_LDSO" touch "$GLIBC_MARKER" success "glibc-runner is ready" } write_compat_patch() { info "Writing Node compatibility patch" cat >"$COMPAT_PATCH_PATH" <<'EOF' 'use strict'; const childProcess = require('child_process'); const dns = require('dns'); const fs = require('fs'); const os = require('os'); const path = require('path'); const prefix = process.env.PREFIX || '/data/data/com.termux/files/usr'; const home = process.env.HOME || '/data/data/com.termux/files/home'; const wrapperPath = process.env._CLAUDE_WRAPPER_PATH || path.join(home, '.claude-code-termux', 'bin', 'node'); const termuxExec = path.join(prefix, 'lib', 'libtermux-exec-ld-preload.so'); const termuxShell = path.join(prefix, 'bin', 'sh'); try { if (fs.existsSync(wrapperPath)) { Object.defineProperty(process, 'execPath', { value: wrapperPath, writable: true, configurable: true, }); } } catch {} if (process.env._CLAUDE_ORIG_LD_PRELOAD) { process.env.LD_PRELOAD = process.env._CLAUDE_ORIG_LD_PRELOAD; delete process.env._CLAUDE_ORIG_LD_PRELOAD; } else if (!process.env.LD_PRELOAD) { try { if (fs.existsSync(termuxExec)) { process.env.LD_PRELOAD = termuxExec; } } catch {} } const originalCpus = os.cpus; os.cpus = function cpus() { try { const result = originalCpus.call(os); if (Array.isArray(result) && result.length > 0) { return result; } } catch {} return [{ model: 'unknown', speed: 0, times: { user: 0, nice: 0, sys: 0, idle: 0, irq: 0 }, }]; }; const originalNetworkInterfaces = os.networkInterfaces; os.networkInterfaces = function networkInterfaces() { try { return originalNetworkInterfaces.call(os); } catch { return { lo: [{ address: '127.0.0.1', netmask: '255.0.0.0', family: 'IPv4', mac: '00:00:00:00:00:00', internal: true, cidr: '127.0.0.1/8', }], }; } }; if (!fs.existsSync('/bin/sh') && fs.existsSync(termuxShell)) { const originalExec = childProcess.exec; const originalExecSync = childProcess.execSync; childProcess.exec = function exec(command, options, callback) { if (typeof options === 'function') { callback = options; options = {}; } options = options || {}; if (!options.shell) { options.shell = termuxShell; } return originalExec.call(childProcess, command, options, callback); }; childProcess.execSync = function execSync(command, options) { options = options || {}; if (!options.shell) { options.shell = termuxShell; } return originalExecSync.call(childProcess, command, options); }; } try { let dnsServers = ['8.8.8.8', '8.8.4.4']; try { const resolvConf = fs.readFileSync(path.join(prefix, 'etc', 'resolv.conf'), 'utf8'); const matches = resolvConf.match(/^nameserver\s+(.+)$/gm); if (matches && matches.length > 0) { dnsServers = matches.map((line) => line.replace(/^nameserver\s+/, '').trim()); } } catch {} try { dns.setServers(dnsServers); } catch {} const originalLookup = dns.lookup; const originalLookupPromise = dns.promises.lookup; dns.lookup = function lookup(hostname, options, callback) { if (typeof options === 'function') { callback = options; options = {}; } const originalOptions = options; const opts = typeof options === 'number' ? { family: options } : (options || {}); const wantAll = opts.all === true; const family = opts.family || 0; const resolveWith = (fam, done) => { const resolver = fam === 6 ? dns.resolve6 : dns.resolve4; resolver(hostname, done); }; const tryResolve = (fam) => { resolveWith(fam, (error, addresses) => { if (!error && Array.isArray(addresses) && addresses.length > 0) { const resolvedFamily = fam === 6 ? 6 : 4; if (wantAll) { callback(null, addresses.map((address) => ({ address, family: resolvedFamily, }))); return; } callback(null, addresses[0], resolvedFamily); return; } if (family === 0 && fam === 4) { tryResolve(6); return; } originalLookup.call(dns, hostname, originalOptions, callback); }); }; tryResolve(family === 6 ? 6 : 4); }; dns.promises.lookup = async function lookup(hostname, options) { const opts = typeof options === 'number' ? { family: options } : (options || {}); const wantAll = opts.all === true; const family = opts.family || 0; const resolveWith = family === 6 ? dns.promises.resolve6 : dns.promises.resolve4; try { const addresses = await resolveWith(hostname); if (addresses.length > 0) { const resolvedFamily = family === 6 ? 6 : 4; if (wantAll) { return addresses.map((address) => ({ address, family: resolvedFamily, })); } return { address: addresses[0], family: resolvedFamily, }; } } catch {} if (family === 0) { try { const addresses = await dns.promises.resolve6(hostname); if (addresses.length > 0) { if (wantAll) { return addresses.map((address) => ({ address, family: 6 })); } return { address: addresses[0], family: 6, }; } } catch {} } return originalLookupPromise.call(dns.promises, hostname, options); }; } catch {} EOF success "Compatibility patch written to $COMPAT_PATCH_PATH" } write_node_wrappers() { local node_bin_path local node_real_path node_bin_path="$NODE_DIR/bin/node" node_real_path="$NODE_DIR/bin/node.real" if [ -f "$node_real_path" ]; then : elif [ -f "$node_bin_path" ]; then mv "$node_bin_path" "$node_real_path" else die "Node binary missing at $node_bin_path" fi info "Writing node/npm wrappers" cat >"$WRAPPER_BIN_DIR/node" <<EOF #!$PREFIX_DIR/bin/bash [ -n "\${LD_PRELOAD:-}" ] && export _CLAUDE_ORIG_LD_PRELOAD="\$LD_PRELOAD" unset LD_PRELOAD export _CLAUDE_WRAPPER_PATH="$WRAPPER_BIN_DIR/node" export TMPDIR="\${TMPDIR:-$TMP_ROOT_DIR}" _CLAUDE_COMPAT="$COMPAT_PATCH_PATH" if [ -f "\$_CLAUDE_COMPAT" ]; then case "\${NODE_OPTIONS:-}" in *"\$_CLAUDE_COMPAT"*) ;; *) export NODE_OPTIONS="\${NODE_OPTIONS:+\$NODE_OPTIONS }-r \$_CLAUDE_COMPAT" ;; esac fi exec "$GLIBC_LDSO" --library-path "$PREFIX_DIR/glibc/lib" "$NODE_DIR/bin/node.real" "\$@" EOF cat >"$WRAPPER_BIN_DIR/npm" <<EOF #!$PREFIX_DIR/bin/bash export PATH="$WRAPPER_BIN_DIR:$NODE_DIR/bin:\$PATH" export TMPDIR="\${TMPDIR:-$TMP_ROOT_DIR}" export NPM_CONFIG_PREFIX="$GLOBAL_PREFIX_DIR" export npm_config_prefix="$GLOBAL_PREFIX_DIR" export NPM_CONFIG_CACHE="$NPM_CACHE_DIR" export npm_config_cache="$NPM_CACHE_DIR" export NPM_CONFIG_SCRIPT_SHELL="$PREFIX_DIR/bin/sh" export npm_config_script_shell="$PREFIX_DIR/bin/sh" exec "$WRAPPER_BIN_DIR/node" "$NODE_DIR/lib/node_modules/npm/bin/npm-cli.js" "\$@" EOF cat >"$WRAPPER_BIN_DIR/npx" <<EOF #!$PREFIX_DIR/bin/bash export PATH="$WRAPPER_BIN_DIR:$NODE_DIR/bin:\$PATH" export TMPDIR="\${TMPDIR:-$TMP_ROOT_DIR}" export NPM_CONFIG_PREFIX="$GLOBAL_PREFIX_DIR" export npm_config_prefix="$GLOBAL_PREFIX_DIR" export NPM_CONFIG_CACHE="$NPM_CACHE_DIR" export npm_config_cache="$NPM_CACHE_DIR" export NPM_CONFIG_SCRIPT_SHELL="$PREFIX_DIR/bin/sh" export npm_config_script_shell="$PREFIX_DIR/bin/sh" exec "$WRAPPER_BIN_DIR/node" "$NODE_DIR/lib/node_modules/npm/bin/npx-cli.js" "\$@" EOF chmod 755 "$WRAPPER_BIN_DIR/node" "$WRAPPER_BIN_DIR/npm" "$WRAPPER_BIN_DIR/npx" success "node/npm wrappers are ready" } install_node_runtime() { local installed_version local tmp_dir local extract_dir local fresh_dir ensure_termux_package "curl" ensure_termux_package "xz-utils" if [ -x "$WRAPPER_BIN_DIR/node" ]; then installed_version="$("$WRAPPER_BIN_DIR/node" --version 2>/dev/null | sed 's/^v//')" if [ "$installed_version" = "$NODE_VERSION" ]; then success "Node.js already installed: v$installed_version" write_compat_patch write_node_wrappers return 0 fi fi info "Downloading official Node.js ${NODE_VERSION} linux-arm64" tmp_dir="$(mktemp -d "$TMP_ROOT_DIR/claude-node.XXXXXX")" curl -fL --max-time 300 "$NODE_URL" -o "$tmp_dir/$NODE_TARBALL" success "Downloaded $NODE_TARBALL" extract_dir="$tmp_dir/extract" fresh_dir="$tmp_dir/node-fresh" mkdir -p "$extract_dir" "$fresh_dir" tar -xJf "$tmp_dir/$NODE_TARBALL" -C "$extract_dir" mv "$extract_dir"/node-v"${NODE_VERSION}"-linux-arm64/* "$fresh_dir"/ rm -rf "$NODE_DIR" mkdir -p "$(dirname "$NODE_DIR")" mv "$fresh_dir" "$NODE_DIR" write_compat_patch write_node_wrappers rm -rf "$tmp_dir" success "Node.js runtime installed in $NODE_DIR" } install_claude_package() { local package_spec package_spec="$CLAUDE_PACKAGE_NAME" if [ "$CLAUDE_PACKAGE_VERSION" != "latest" ]; then package_spec="${CLAUDE_PACKAGE_NAME}@${CLAUDE_PACKAGE_VERSION}" fi info "Installing $package_spec" PATH="$WRAPPER_BIN_DIR:$GLOBAL_BIN_DIR:$PATH" "$WRAPPER_BIN_DIR/npm" install -g "$package_spec" [ -e "$GLOBAL_BIN_DIR/claude" ] || die "npm install completed, but $GLOBAL_BIN_DIR/claude was not created" [ -x "$CLAUDE_EXE_PATH" ] || die "Claude native binary missing at $CLAUDE_EXE_PATH" success "Claude Code is installed under $GLOBAL_PREFIX_DIR" } backup_existing_launcher() { local backup_path if [ ! -e "$HOST_CLAUDE_PATH" ]; then return 0 fi if grep -Fq "$HOST_WRAPPER_MARKER" "$HOST_CLAUDE_PATH" 2>/dev/null; then success "Managed host launcher already present" return 0 fi backup_path="$BACKUP_DIR/claude.host-backup.$(date +%Y%m%d_%H%M%S)" cp "$HOST_CLAUDE_PATH" "$backup_path" success "Backed up existing launcher to $backup_path" } install_host_wrapper() { local tmp_wrapper tmp_wrapper="$(mktemp "$TMP_ROOT_DIR/claude-wrapper.XXXXXX")" cat >"$tmp_wrapper" <<EOF #!$PREFIX_DIR/bin/bash $HOST_WRAPPER_MARKER export PATH="$WRAPPER_BIN_DIR:$GLOBAL_BIN_DIR:\$PATH" export TMPDIR="\${TMPDIR:-$TMP_ROOT_DIR}" exec "$GLIBC_RUNNER_BIN" -t "$CLAUDE_EXE_PATH" "\$@" EOF chmod 755 "$tmp_wrapper" cp "$tmp_wrapper" "$HOST_CLAUDE_PATH" chmod 755 "$HOST_CLAUDE_PATH" rm -f "$tmp_wrapper" success "Installed host launcher: $HOST_CLAUDE_PATH" } verify_install() { info "Verifying Node wrapper" "$WRAPPER_BIN_DIR/node" --version info "Verifying npm wrapper" "$WRAPPER_BIN_DIR/npm" --version info "Verifying Claude Code launcher" "$HOST_CLAUDE_PATH" --version success "Non-proot Claude Code setup completed" } main() { if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then usage exit 0 fi require_termux ensure_tmp_root ensure_state_dirs ensure_glibc_runner install_node_runtime install_claude_package backup_existing_launcher install_host_wrapper verify_install cat <<EOF Run Claude Code with: claude Current configuration: state dir: $STATE_DIR node version: $NODE_VERSION package version: $CLAUDE_PACKAGE_VERSION launcher: $HOST_CLAUDE_PATH EOF } main "$@" 2.proot方案 (会卡顿 卡就对了 卡了就等待) #!/data/data/com.termux/files/usr/bin/bash set -euo pipefail readonly SCRIPT_NAME="$(basename "$0")" readonly DISTRO_NAME="${CLAUDE_CODE_DISTRO:-debian}" readonly CLAUDE_PACKAGE_NAME="@anthropic-ai/claude-code" readonly CLAUDE_PACKAGE_VERSION="${CLAUDE_CODE_VERSION:-latest}" readonly PREFIX_DIR="${PREFIX:-/data/data/com.termux/files/usr}" readonly HOST_CLAUDE_PATH="$PREFIX_DIR/bin/claude" readonly PROOT_ROOT_DIR="$PREFIX_DIR/var/lib/proot-distro/installed-rootfs" readonly BACKUP_DIR="$HOME/.codex/tmp" readonly WRAPPER_MARKER="# claude-code-termux-wrapper" readonly C_BOLD_BLUE="\033[1;34m" readonly C_BOLD_GREEN="\033[1;32m" readonly C_BOLD_YELLOW="\033[1;33m" readonly C_BOLD_RED="\033[1;31m" readonly C_RESET="\033[0m" info() { printf '%b[INFO]%b %s\n' "$C_BOLD_BLUE" "$C_RESET" "$*" } success() { printf '%b[ OK ]%b %s\n' "$C_BOLD_GREEN" "$C_RESET" "$*" } warn() { printf '%b[WARN]%b %s\n' "$C_BOLD_YELLOW" "$C_RESET" "$*" >&2 } die() { printf '%b[ERR ]%b %s\n' "$C_BOLD_RED" "$C_RESET" "$*" >&2 exit 1 } usage() { cat <<EOF Usage: bash $SCRIPT_NAME What it does: 1. Installs proot-distro in Termux if needed. 2. Installs Debian userspace if needed. 3. Installs nodejs + npm inside Debian. 4. Installs ${CLAUDE_PACKAGE_NAME} inside Debian. 5. Replaces Termux's claude launcher with a wrapper that forwards into Debian. Environment overrides: CLAUDE_CODE_DISTRO proot distro alias, default: ${DISTRO_NAME} CLAUDE_CODE_VERSION npm package version/tag, default: ${CLAUDE_PACKAGE_VERSION} Notes: - Official Claude Code npm binaries do not support Termux's android-arm64 host. - This script uses Debian in proot as the supported Linux runtime. EOF } command_exists() { command -v "$1" >/dev/null 2>&1 } require_termux() { [ -d "$PREFIX_DIR" ] || die "This script must run in Termux." command_exists pkg || die "pkg not found. This script must run in Termux." } ensure_termux_package() { local package_name="$1" if dpkg -s "$package_name" >/dev/null 2>&1; then success "Termux package already installed: $package_name" return 0 fi info "Installing Termux package: $package_name" pkg install -y "$package_name" success "Installed Termux package: $package_name" } ensure_distro() { if [ -d "$PROOT_ROOT_DIR/$DISTRO_NAME" ]; then success "proot distro already installed: $DISTRO_NAME" return 0 fi info "Installing proot distro: $DISTRO_NAME" proot-distro install "$DISTRO_NAME" success "Installed proot distro: $DISTRO_NAME" } run_in_distro() { local command_text="$1" proot-distro login "$DISTRO_NAME" -- bash -lc "$command_text" } ensure_distro_packages() { info "Updating apt metadata inside $DISTRO_NAME" run_in_distro "env DEBIAN_FRONTEND=noninteractive apt-get update" info "Installing nodejs and npm inside $DISTRO_NAME" run_in_distro "env DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs npm" success "nodejs and npm are ready inside $DISTRO_NAME" } install_claude_in_distro() { local package_spec="$CLAUDE_PACKAGE_NAME" if [ "$CLAUDE_PACKAGE_VERSION" != "latest" ]; then package_spec="${CLAUDE_PACKAGE_NAME}@${CLAUDE_PACKAGE_VERSION}" fi info "Installing ${package_spec} inside $DISTRO_NAME" run_in_distro "npm install -g ${package_spec@Q}" success "Claude Code is installed inside $DISTRO_NAME" } backup_existing_launcher() { local backup_path mkdir -p "$BACKUP_DIR" if [ ! -e "$HOST_CLAUDE_PATH" ]; then return 0 fi if grep -Fq "$WRAPPER_MARKER" "$HOST_CLAUDE_PATH" 2>/dev/null; then success "Managed Termux launcher already present" return 0 fi backup_path="$BACKUP_DIR/claude.host-backup.$(date +%Y%m%d_%H%M%S)" cp "$HOST_CLAUDE_PATH" "$backup_path" success "Backed up existing launcher to $backup_path" } install_host_wrapper() { local tmp_wrapper tmp_wrapper="$(mktemp "${TMPDIR:-/tmp}/claude-wrapper.XXXXXX")" cat >"$tmp_wrapper" <<EOF #!/data/data/com.termux/files/usr/bin/sh $WRAPPER_MARKER work_dir=\$PWD if [ ! -d "\$work_dir" ]; then work_dir=/root fi exec proot-distro login --shared-tmp --work-dir "\$work_dir" $DISTRO_NAME -- /usr/local/bin/claude "\$@" EOF chmod 755 "$tmp_wrapper" cp "$tmp_wrapper" "$HOST_CLAUDE_PATH" chmod 755 "$HOST_CLAUDE_PATH" rm -f "$tmp_wrapper" success "Installed Termux launcher: $HOST_CLAUDE_PATH" } verify_install() { info "Verifying Claude inside $DISTRO_NAME" run_in_distro "claude --version" info "Verifying Termux launcher" "$HOST_CLAUDE_PATH" --version success "Claude Code setup completed" } main() { if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then usage exit 0 fi require_termux ensure_termux_package "proot-distro" ensure_distro ensure_distro_packages install_claude_in_distro backup_existing_launcher install_host_wrapper verify_install cat <<EOF Run Claude Code with: claude Current configuration: distro: $DISTRO_NAME host launcher: $HOST_CLAUDE_PATH EOF } main "$@" 非proot方案参考 GitHub - AidanPark/openclaw-android: Run OpenClaw on Android with a single command — no proot, no Linux · GitHub 1 个帖子 - 1 位参与者 阅读完整话题