脚本
#!/data/data/com.termux/files/usr/bin/bash
set -euo pipefail
readonly SCRIPT_NAME="$(basename "$0")"
readonly MIMO_PACKAGE_NAME="@mimo-ai/cli"
readonly MIMO_PACKAGE_VERSION="${MIMO_CODE_VERSION:-${MIMOCODE_VERSION:-latest}}"
readonly PREFIX_DIR="${PREFIX:-/data/data/com.termux/files/usr}"
readonly HOST_MIMO_PATH="$PREFIX_DIR/bin/mimo"
readonly MIMO_CLI_PKG_DIR="$PREFIX_DIR/lib/node_modules/@mimo-ai/cli"
readonly MIMO_ARCH_PKG_NAME="@mimo-ai/mimocode-linux-arm64"
readonly MIMO_ARCH_PKG_DIR="$PREFIX_DIR/lib/node_modules/$MIMO_ARCH_PKG_NAME"
readonly TMP_ROOT="$HOME/tmp"
readonly BACKUP_DIR="$TMP_ROOT/mimocode-backups"
readonly WRAPPER_MARKER="# mimocode-termux-glibc-wrapper"
# Resolved by install_mimo_package() after locating the real glibc ELF.
MIMO_BINARY_PATH=""
MIMO_RESOLVED_VERSION=""
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 (glibc-runner mode, no proot):
1. Installs glibc-repo, refreshes apt metadata, installs glibc-runner.
2. Installs nodejs-lts + npm in Termux (if missing).
3. npm installs ${MIMO_PACKAGE_NAME} globally, then force-installs the
${MIMO_ARCH_PKG_NAME} native linux-arm64 package.
4. Skips MiMoCode's postinstall script because Termux Node reports
process.platform='android' and the upstream script looks for a
non-existent @mimo-ai/mimocode-android-arm64 package.
5. Replaces \$PREFIX/bin/mimo with a grun wrapper that runs the
glibc ELF directly on Termux.
Environment overrides:
MIMO_CODE_VERSION npm package version/tag, default: ${MIMO_PACKAGE_VERSION}
examples: latest, preview, 0.1.0, v0.1.0
MIMOCODE_VERSION alias for MIMO_CODE_VERSION
Notes:
- Official MiMoCode install docs: https://github.com/XiaomiMiMo/MiMo-Code
- glibc-runner injects glibc via LD_LIBRARY_PATH; kernel calls are native.
EOF
}
command_exists() { command -v "$1" >/dev/null 2>&1; }
# ELF magic = 7f 45 4c 46; e_machine at offset 18 = 0xb7 for EM_AARCH64.
is_valid_aarch64_elf() {
local f="$1"
[ -f "$f" ] || return 1
local magic machine
magic=$(od -An -tx1 -N4 "$f" 2>/dev/null | tr -d ' \n')
[ "$magic" = "7f454c46" ] || return 1
machine=$(od -An -tx1 -j18 -N1 "$f" 2>/dev/null | tr -d ' \n')
[ "$machine" = "b7" ]
}
find_arch_binary() {
local candidate
for candidate in \
"$MIMO_ARCH_PKG_DIR/bin/mimo" \
"$MIMO_CLI_PKG_DIR/bin/.mimocode"; do
if is_valid_aarch64_elf "$candidate"; then
MIMO_BINARY_PATH="$candidate"
return 0
fi
done
while IFS= read -r candidate; do
if is_valid_aarch64_elf "$candidate"; then
MIMO_BINARY_PATH="$candidate"
return 0
fi
done < <(find "$MIMO_ARCH_PKG_DIR" "$MIMO_CLI_PKG_DIR" -type f -size +10M 2>/dev/null)
return 1
}
ensure_tmp_root() {
mkdir -p "$TMP_ROOT"
[ -w "$TMP_ROOT" ] || die "Temp directory is not writable: $TMP_ROOT"
export TMPDIR="$TMP_ROOT"
}
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."
if [ -r /proc/1/status ] && grep -q 'TracerPid:.*[1-9]' /proc/1/status 2>/dev/null; then
warn "Detected non-zero TracerPid on PID 1 -- looks like a proot session."
warn "Run this script from a plain Termux shell, not from inside proot-distro."
fi
}
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() {
ensure_termux_package "glibc-repo"
if ! apt-cache show glibc-runner >/dev/null 2>&1; then
info "Refreshing apt metadata so glibc-repo becomes visible"
pkg update -y || apt-get update -y || true
fi
ensure_termux_package "glibc-runner"
command_exists grun || die "grun not found after installing glibc-runner."
}
ensure_nodejs() {
if command_exists node && command_exists npm; then
success "Termux node present: $(node --version), npm $(npm --version)"
return 0
fi
if dpkg -s nodejs >/dev/null 2>&1; then
success "nodejs already installed"
else
ensure_termux_package "nodejs-lts"
fi
command_exists node && command_exists npm || die "node/npm not found after installing nodejs."
}
resolve_mimo_version() {
local requested="$MIMO_PACKAGE_VERSION"
if [ "$requested" != "latest" ]; then
requested="${requested#v}"
fi
local pkg_spec="$MIMO_PACKAGE_NAME"
if [ "$requested" != "latest" ]; then
pkg_spec="${MIMO_PACKAGE_NAME}@${requested}"
fi
info "Resolving version for ${pkg_spec}"
local resolved
resolved=$(npm view "$pkg_spec" version 2>/dev/null | tail -n1) \
|| die "Failed to resolve version for ${pkg_spec} via npm view"
[[ "$resolved" =~ ^[0-9]+\.[0-9]+ ]] \
|| die "npm view returned a bogus version: '$resolved'"
MIMO_RESOLVED_VERSION="$resolved"
}
backup_existing_launcher() {
mkdir -p "$BACKUP_DIR"
[ -e "$HOST_MIMO_PATH" ] || return 0
if grep -Fq "$WRAPPER_MARKER" "$HOST_MIMO_PATH" 2>/dev/null; then
success "glibc-runner wrapper already in place"
return 0
fi
local backup_path="$BACKUP_DIR/mimo.host-backup.$(date +%Y%m%d_%H%M%S)"
cp -P "$HOST_MIMO_PATH" "$backup_path"
success "Backed up existing launcher to $backup_path"
}
install_mimo_package() {
resolve_mimo_version
local main_version="$MIMO_RESOLVED_VERSION"
local pinned_main="${MIMO_PACKAGE_NAME}@${main_version}"
local arch_spec="${MIMO_ARCH_PKG_NAME}@${main_version}"
info "Installing ${pinned_main} without upstream optional platform packages"
npm install -g --force --ignore-scripts --omit=optional "$pinned_main"
info "Installing ${arch_spec} for Termux via glibc-runner"
npm install -g --force --ignore-scripts --os=linux --cpu=arm64 "$arch_spec"
find_arch_binary || die "No valid aarch64 ELF found under $MIMO_ARCH_PKG_DIR. \
The arch package may not have unpacked correctly; inspect with: \
ls -la $MIMO_ARCH_PKG_DIR"
success "MiMoCode native binary: $MIMO_BINARY_PATH ($(stat -c %s "$MIMO_BINARY_PATH" 2>/dev/null || echo '?') bytes)"
}
install_host_wrapper() {
local tmp_wrapper
tmp_wrapper="$(mktemp "$TMP_ROOT/mimo-grun.XXXXXX")"
cat >"$tmp_wrapper" <<EOF
#!/data/data/com.termux/files/usr/bin/sh
$WRAPPER_MARKER
mkdir -p "\$HOME/tmp" 2>/dev/null || true
export TMPDIR="\${TMPDIR:-\$HOME/tmp}"
exec grun "$MIMO_BINARY_PATH" "\$@"
EOF
chmod 755 "$tmp_wrapper"
rm -f "$HOST_MIMO_PATH"
mv "$tmp_wrapper" "$HOST_MIMO_PATH"
chmod 755 "$HOST_MIMO_PATH"
success "Installed Termux launcher: $HOST_MIMO_PATH"
}
verify_install() {
info "Verifying binary via grun"
grun "$MIMO_BINARY_PATH" --version
info "Verifying Termux launcher"
"$HOST_MIMO_PATH" --version
local path_mimo=""
path_mimo="$(command -v mimo 2>/dev/null || true)"
if [ -n "$path_mimo" ] && [ "$path_mimo" != "$HOST_MIMO_PATH" ]; then
warn "Your PATH resolves 'mimo' to $path_mimo, not $HOST_MIMO_PATH."
warn "Move $PREFIX_DIR/bin earlier in PATH or remove the older launcher."
fi
success "MiMoCode setup completed (glibc-runner mode)"
}
main() {
if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then
usage
exit 0
fi
ensure_tmp_root
require_termux
ensure_glibc_runner
ensure_nodejs
backup_existing_launcher
install_mimo_package
install_host_wrapper
verify_install
cat <<EOF
Run MiMoCode with:
mimo
Configuration:
mode: glibc-runner (no proot)
binary: $MIMO_BINARY_PATH
launcher: $HOST_MIMO_PATH
temp: $TMP_ROOT
If the official installer previously added ~/.mimocode/bin before $PREFIX_DIR/bin,
that older launcher may shadow this Termux wrapper.
Troubleshooting:
- If npm cannot resolve a preview version, install with:
MIMO_CODE_VERSION=preview bash $SCRIPT_NAME
- If subprocess errors mention libc/ld.so, the binary is loading Termux
bionic libs via inherited LD_LIBRARY_PATH. Check glibc-runner docs.
EOF
}
main "$@"
1 个帖子 - 1 位参与者