#!/usr/bin/env bash set -euo pipefail # Tumpai Team VM bootstrapper. # It prepares the local SSH shortcut and one member workspace on the shared Ubuntu VM. VM_HOST="${TUMPAI_VM_HOST:-parallels@192.168.50.126}" VM_PORT="${TUMPAI_VM_PORT:-22}" SHORTCUT="${TUMPAI_VM_SHORTCUT:-tumpai-vm}" TEAM_IDS=(cj lj rxp lyx) GREEN=$'\033[32m' YELLOW=$'\033[33m' RED=$'\033[31m' BLUE=$'\033[36m' BOLD=$'\033[1m' RESET=$'\033[0m' info() { printf '%sℹ%s %s\n' "$BLUE" "$RESET" "$*"; } ok() { printf '%s✓%s %s\n' "$GREEN" "$RESET" "$*"; } warn() { printf '%s⚠%s %s\n' "$YELLOW" "$RESET" "$*"; } die() { printf '%s✗%s %s\n' "$RED" "$RESET" "$*" >&2; exit 1; } need_cmd() { command -v "$1" >/dev/null 2>&1 || die "缺少命令: $1。请先安装 OpenSSH 客户端。" } choose_member() { printf '\n%s请选择你的成员目录:%s\n' "$BOLD" "$RESET" printf ' 1) cj\n 2) lj\n 3) rxp\n 4) lyx\n' while true; do read -r -p "输入 1/2/3/4: " choice case "$choice" in 1) TEAM_ID="cj"; break ;; 2) TEAM_ID="lj"; break ;; 3) TEAM_ID="rxp"; break ;; 4) TEAM_ID="lyx"; break ;; cj|lj|rxp|lyx) TEAM_ID="$choice"; break ;; *) warn "只能选择 1、2、3、4,或直接输入 cj / lj / rxp / lyx。" ;; esac done } ensure_login_key() { LOGIN_KEY="${TUMPAI_VM_LOGIN_KEY:-$HOME/.ssh/id_ed25519}" if [ ! -f "$LOGIN_KEY.pub" ]; then info "本机还没有 SSH 登录公钥,正在生成: $LOGIN_KEY" mkdir -p "$HOME/.ssh" chmod 700 "$HOME/.ssh" ssh-keygen -t ed25519 -f "$LOGIN_KEY" -C "${USER:-member}@tumpai-vm-login" -N "" fi LOGIN_PUB="$(cat "$LOGIN_KEY.pub")" } check_route_hint() { local vm_ip="${VM_HOST#*@}" if command -v ping >/dev/null 2>&1; then if ! ping -c 1 -W 2 "$vm_ip" >/dev/null 2>&1; then warn "暂时 ping 不通 ${vm_ip}。若 SSH 也失败,请先确认 Tailscale 已登录,并能访问 R4S 暴露的 VM 路由。" fi fi } authorize_and_create_workspace() { info "现在会连接 ${VM_HOST}。首次执行会要求输入 VM 密码;只有密码正确才会创建 ~/${TEAM_ID}。" local remote_cmd remote_cmd='umask 077; mkdir -p ~/.ssh ~/'"$TEAM_ID"'; touch ~/.ssh/authorized_keys; IFS= read -r key; grep -qxF -- "$key" ~/.ssh/authorized_keys || printf "%s\n" "$key" >> ~/.ssh/authorized_keys; chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys; printf "REMOTE_READY='"$TEAM_ID"'\n"' if ! printf '%s\n' "$LOGIN_PUB" | ssh -p "$VM_PORT" "$VM_HOST" "$remote_cmd"; then die "SSH 登录 VM 失败。请先确认 Tailscale 可访问 192.168.50.126,并在 Ubuntu VM 内安装/启动 SSH:sudo apt update && sudo apt install -y openssh-server tmux git && sudo systemctl enable --now ssh" fi ok "VM 登录公钥已写入,成员目录 ~/${TEAM_ID} 已准备好。" } configure_remote_claude_runtime() { local remote_cmd remote_cmd=$(cat <<'REMOTE' set -e block_start="# >>> siyun claude update lock >>>" block_end="# <<< siyun claude update lock <<<" write_shell_env() { f="$1" touch "$f" tmp="$(mktemp)" awk -v start="$block_start" -v end="$block_end" '$0==start{skip=1; next} $0==end{skip=0; next} !skip{print}' "$f" > "$tmp" { cat "$tmp" printf '\n%s\nexport DISABLE_AUTOUPDATER=1\nexport DISABLE_UPDATES=1\n%s\n' "$block_start" "$block_end" } > "$f" rm -f "$tmp" } write_shell_env "$HOME/.bashrc" write_shell_env "$HOME/.profile" tmux_conf="$HOME/.tmux.conf" touch "$tmux_conf" tmp="$(mktemp)" awk -v start="$block_start" -v end="$block_end" '$0==start{skip=1; next} $0==end{skip=0; next} !skip{print}' "$tmux_conf" > "$tmp" { cat "$tmp" printf '\n%s\nset-environment -g DISABLE_AUTOUPDATER 1\nset-environment -g DISABLE_UPDATES 1\n%s\n' "$block_start" "$block_end" } > "$tmux_conf" rm -f "$tmp" REMOTE ) ssh -p "$VM_PORT" "$VM_HOST" "$remote_cmd" ok "已写入 VM Claude 运行环境:禁用自动更新提示并锁定当前安装。" } configure_remote_git_include() { local git_name="$1" local git_email="$2" local tmp_cfg tmp_cfg="$(mktemp)" { printf '[user]\n' printf '\tname = %s\n' "$git_name" if [ -n "$git_email" ]; then printf '\temail = %s\n' "$git_email" fi printf '[core]\n' printf '\tsshCommand = ssh -i ~/.ssh/github_siyun_dev_ed25519 -o IdentitiesOnly=yes\n' } > "$tmp_cfg" scp -P "$VM_PORT" "$tmp_cfg" "${VM_HOST}:.gitconfig-${TEAM_ID}" >/dev/null rm -f "$tmp_cfg" ssh -p "$VM_PORT" "$VM_HOST" "if command -v git >/dev/null 2>&1; then git config --global --replace-all 'includeIf.gitdir:~/${TEAM_ID}/.path' '~/.gitconfig-${TEAM_ID}'; else printf '%s\n' 'WARN_NO_GIT'; fi" ok "已写入 Git 目录级配置:~/${TEAM_ID} 下的仓库会使用 ~/.gitconfig-${TEAM_ID}。" } configure_git_ssh_aliases() { local remote_cmd remote_cmd='set -e umask 077 mkdir -p ~/.ssh touch ~/.ssh/config awk '\''/^[#] >>> siyun-dev github >>>$/ {skip=1; next} /^[#] <<< siyun-dev github <<<$/{skip=0; next} !skip {print}'\'' ~/.ssh/config > ~/.ssh/config.tmp mv ~/.ssh/config.tmp ~/.ssh/config cat >> ~/.ssh/config <<'\''EOF'\'' # >>> siyun-dev github >>> Host github-main HostName ssh.github.com Port 443 User git IdentityFile ~/.ssh/github_siyun_dev_ed25519 IdentitiesOnly yes # <<< siyun-dev github <<< EOF chmod 600 ~/.ssh/config ssh-keyscan -p 443 ssh.github.com >> ~/.ssh/known_hosts 2>/dev/null || true sort -u ~/.ssh/known_hosts -o ~/.ssh/known_hosts 2>/dev/null || true chmod 644 ~/.ssh/known_hosts 2>/dev/null || true' ssh -p "$VM_PORT" "$VM_HOST" "$remote_cmd" ok "已写入 SSH Host 别名:github-main。" } setup_git_key() { printf '\n%sGitHub 共享访问配置:%s\n' "$BOLD" "$RESET" info "正在 VM 内生成或复用 ~/.ssh/github_siyun_dev_ed25519" ssh -p "$VM_PORT" "$VM_HOST" "umask 077; mkdir -p ~/.ssh; if [ ! -f ~/.ssh/github_siyun_dev_ed25519 ]; then ssh-keygen -t ed25519 -N '' -C 'siyun-dev' -f ~/.ssh/github_siyun_dev_ed25519 >/dev/null; fi; chmod 600 ~/.ssh/github_siyun_dev_ed25519; chmod 644 ~/.ssh/github_siyun_dev_ed25519.pub; printf '\n请把下面这行公钥添加到你的 GitHub 账号 SSH Keys,Title 写 siyun-dev:\n'; cat ~/.ssh/github_siyun_dev_ed25519.pub" local git_name git_email read -r -p "Git 提交姓名 [$TEAM_ID]: " git_name git_name="${git_name:-$TEAM_ID}" read -r -p "Git 提交邮箱 [${TEAM_ID}@example.com]: " git_email git_email="${git_email:-${TEAM_ID}@example.com}" configure_git_ssh_aliases configure_remote_git_include "$git_name" "$git_email" } write_shortcut() { local bin_dir bin_path rc_file tmp login_shell bin_dir="$HOME/.local/bin" bin_path="$bin_dir/$SHORTCUT" mkdir -p "$bin_dir" cat > "$bin_path" <>> tumpai-vm shortcut >>>/ {skip=1; next} /# <<< tumpai-vm shortcut << "$tmp" mv "$tmp" "$rc_file" { printf '\n# >>> tumpai-vm shortcut >>>\n' printf 'export PATH="$HOME/.local/bin:$PATH"\n' printf 'alias vm="%s"\n' "$SHORTCUT" printf 'alias vm-%s="%s"\n' "$TEAM_ID" "$SHORTCUT" printf '# <<< tumpai-vm shortcut <<<\n' } >> "$rc_file" ok "已创建快捷命令: $bin_path" ok "已创建命令链接: $bin_dir/vm / $bin_dir/vm-$TEAM_ID" ok "已写入别名: vm / vm-${TEAM_ID} 到 $rc_file。重开终端后可直接使用。" } main() { printf '\n╔════════════════════════════════════════════╗\n' printf '║ Tumpai · 团队 Ubuntu VM 快捷入口 ║\n' printf '╚════════════════════════════════════════════╝\n' need_cmd ssh need_cmd scp need_cmd ssh-keygen choose_member ensure_login_key check_route_hint authorize_and_create_workspace configure_remote_claude_runtime setup_git_key write_shortcut printf '\n%s处理完毕。%s\n' "$GREEN" "$RESET" printf '以后打开终端执行:%s%s%s 或 %svm%s\n' "$BOLD" "$SHORTCUT" "$RESET" "$BOLD" "$RESET" printf '会自动进入 VM 的 ~/%s,并附着到 tmux 会话 %s-main。\n' "$TEAM_ID" "$TEAM_ID" } main "$@"