#!/usr/bin/env bash
# @desc: 远程脚本执行器 —— wcl <名字> 直接跑站点上的脚本; 单独 wcl 看清单
# ==============================================================================
#  wcl — t.melulu.top 远程脚本一键执行器
#
#  安装:  bash <(curl -sL t.melulu.top/wcl)
#  用法:  wcl <脚本名> [参数...]
#           wcl A        ->  bash <(curl -sL t.melulu.top/A)
#           wcl A a b c  ->  bash <(curl -sL t.melulu.top/A) a b c
#  卸载:  bash <(curl -sL t.melulu.top/wcl) --uninstall
#
#  本文件必须以 LF 行尾 + UTF-8 保存，否则 bash <(curl ...) 会报 $'\r'
#
#  注意: bash <(curl ...) 跑在子 shell，装完只能打印 source 提示；
#        想装完立刻可用，请执行:  source <(curl -sL t.melulu.top/wcl)
#        (source <(...) 才对当前 shell 生效，bash <(...) 做不到)
# ==============================================================================

WCL_BEGIN='# >>> wcl >>>'
WCL_END='# <<< wcl <<<'

# --------------------------------------------------------------------------- #
# 卸载
# --------------------------------------------------------------------------- #
wcl_strip() {   # $1 = rc 文件
  awk -v b="$WCL_BEGIN" -v e="$WCL_END" '
    $0==b {s=1; next}
    $0==e {s=0; next}
    !s   {print}
  ' "$1" > "$1.wcl.$$" && mv -f "$1.wcl.$$" "$1"
}

if [ "${1:-}" = "--uninstall" ] || [ "${1:-}" = "uninstall" ]; then
  rc="${WCL_RC:-$HOME/.bashrc}"
  if [ -f "$rc" ] && grep -qF "$WCL_BEGIN" "$rc" 2>/dev/null; then
    wcl_strip "$rc"
    printf 'wcl: 已从 %s 移除\n' "$rc"
  else
    printf 'wcl: %s 里没有 wcl，无需卸载\n' "$rc"
  fi
  exit 0
fi

# --------------------------------------------------------------------------- #
# 探测 curl 版本，把「老版本不支持的选项」在安装时就定死，避免运行时才报错
# --------------------------------------------------------------------------- #
CV=""
command -v curl >/dev/null 2>&1 && CV="$(curl --version 2>/dev/null | head -n 1)"
CV="${CV#curl }"; CV="${CV%% *}"
CV_MAJ="${CV%%.*}"; CV_REST="${CV#*.}"; CV_MIN="${CV_REST%%.*}"
case "$CV_MAJ$CV_MIN" in ''|*[!0-9]*) CV_MAJ=0; CV_MIN=0 ;; esac

GE=0            # curl >= 7.52
if [ "$CV_MAJ" -gt 7 ] || { [ "$CV_MAJ" -eq 7 ] && [ "$CV_MIN" -ge 52 ]; }; then
  GE=1
fi

# --------------------------------------------------------------------------- #
# 写 shell 配置：bash -> .bashrc，zsh -> .zshrc
# --------------------------------------------------------------------------- #
rc=""
case "${SHELL:-}" in
  */zsh|?zsh) rc="${WCL_RC:-$HOME/.zshrc}" ;;
  *)          rc="${WCL_RC:-$HOME/.bashrc}" ;;
esac

mkdir -p "$(dirname "$rc")" 2>/dev/null
touch "$rc" 2>/dev/null
if [ ! -w "$rc" ]; then
  printf 'wcl: 无权写入 %s，请检查权限\n' "$rc" >&2
  exit 1
fi

# 重复安装/升级：先无条件摘掉旧块，保证不堆叠
grep -qF "$WCL_BEGIN" "$rc" 2>/dev/null && wcl_strip "$rc"

# --------------------------------------------------------------------------- #
# 组装函数体：先进选项一次性拼成一个字符串，避免逐行追加时出现空行/断词
# --------------------------------------------------------------------------- #
EXTRA=""
[ "$GE" = "1" ] && EXTRA="--retry 3 --retry-delay 1 --retry-connrefused --compressed"
H11=0
if [ "$CV_MAJ" -gt 7 ] || { [ "$CV_MAJ" -eq 7 ] && [ "$CV_MIN" -ge 33 ]; }; then H11=1; fi

# --------------------------------------------------------------------------- #
# 清单显示函数（生成时内联进 .bashrc，随 wcl 一起安装）
#
# 数据来自站点上的 wcl.index（文本，一行一条: 名称|简介|示例）。
# 这样你以后往站点加脚本，只需更新 wcl.index，wcl 命令本身不用改。
#
# 站点没上传 wcl.index 时，用内置的 FALLBACK_INDEX 兜底，
# 保证 `wcl` 永远有提示，不会只报"用法"。
# --------------------------------------------------------------------------- #
wcl_index_fallback='nv|GPU 实时监控(温度/显存/功耗/进程)|wcl nv
y|同上，别名|wcl y
shinit|Shell 环境增强: 历史高可靠+耗时提示+别名+多shell|bash <(curl -sL t.melulu.top/shinit)
px|代理开关: 只对当前终端生效,关掉即恢复|source <(curl -sL t.melulu.top/px)
wcl|远程脚本执行器(本命令)|wcl'

wcl_func_helper() {
  cat <<WCL_HELPER_HEAD
# ==============================================================
#  显示站点脚本清单 —— 完全自动，不维护任何清单文件
#
#  机制:
#    1) 读站点目录列表, 拿到全部文本文件
#    2) 每个文件只下载【头部 4KB】(Range 请求, 不整份拉)
#    3) 从头部提取说明, 按优先级:
#         @desc: xxx          —— 显式声明, 最优先(推荐写这个)
#         第一段连续 # 注释   —— 自动识别, 跳过 shebang/空行/分隔线
#         没有注释            —— 只显示文件名
#
#  所以你写新脚本时, 只要在第一段注释里写清说明, wcl 就自动显示。
#  不用改 wcl, 不用改任何清单文件。
# ==============================================================

# 从一段脚本头部里提取说明, 输出 "DESC:第一行|第二行"
# 从脚本头部提取元信息, 输出最多两行:
#   DESC:<一句话说明>
#   USAGE:<用法, 可含续行>
#
# 规则:
#   @desc: xxx   显式说明(推荐写这个); 没有则自动取第一段连续 # 注释
#   @usage: xxx  显式用法; 后续以 "#   " 开头(>=3空格)的行视为续行
#   @example/@note 等其它 @xxx: 一律忽略
wcl_meta_of() {
  awk '
    BEGIN { started=0; s=""; desc=""; usage=""; umode=0; stop=0; done=0; printed=0 }
    {
      line = \$0
      if (done) next

      # --- 处于 @usage 状态: 收集续行 ---
      if (umode) {
        if (line ~ /^#[[:space:]]{3,}[^[:space:]]/) {
          t = line
          sub(/^#[[:space:]]{3}/, "  ", t)
          usage = usage "\n" t
          next
        }
        umode = 0
      }

      if (!printed) {
        if (desc != "") { print "DESC:" desc; printed=1 }
        else if (stop)  { print "DESC:" s;    printed=1 }
      }

      if (line ~ /^#!/) next
      if (line ~ /^[[:space:]]*$/) { if (started) stop=1; next }

      if (line ~ /^[[:space:]]*#/) {
        t = line
        sub(/^[[:space:]]*#+[[:space:]]?/, "", t)

        if (t ~ /^@desc:/) {
          sub(/^@desc:[[:space:]]*/, "", t)
          if (t != "") { desc = t; next }
        }
        if (t ~ /^@usage:/) {
          sub(/^@usage:[[:space:]]*/, "", t)
          usage = t
          umode = 1
          next
        }
        if (t ~ /^@[a-zA-Z_]+:/) next

        u = t
        gsub(/[ \t=_*~-]/, "", u)
        if (u == "") next
        if (t ~ /^!/) next

        started = 1
        s = (s == "" ? t : s "\n" t)
        next
      }
      if (started) stop = 1
    }
    END {
      if (!printed) {
        if (desc != "") print "DESC:" desc
        else print "DESC:" s
      }
      if (usage != "") print "USAGE:" usage
    }
  ' "\$1" 2>/dev/null
}

# ==============================================================
#  wcls —— 用 source 语义执行站点脚本
#
#  为什么需要它:
#    px / shinit 这类脚本靠 export 改环境变量, 必须 source 才作用到当前 shell。
#    而 bash <(curl ...) 跑在子进程, export 随进程退出而失效。
#
#  但【不能】无脑 source —— 实测两个坑:
#    1) 脚本里的 exit 会直接关掉你的终端
#       (source <(printf 'exit 0\\n') 之后, 后面的命令不再执行)
#    2) 脚本里的 set -e / set -u / cd / alias 会污染当前 shell
#       (tcping、dnsping 开头就是 set -e)
#
#  所以 wcls 的做法:
#    在当前 shell 里执行, 但执行前后把 shell 的关键选项快照/还原,
#    避免 set -e / set -u / cd / IFS 污染你的终端。
#    脚本里若有顶层 exit, 一律拒绝并提示改用 wcl —— 因为 source 里的
#    exit 会【关掉整个终端】(实测: source <(printf 'exit 0\\n') 之后的
#    命令不再执行)。
# ==============================================================
wcls() {
  if ! command -v curl >/dev/null 2>&1; then
    printf 'wcls: 系统里没有 curl\n' >&2; return 127
  fi
  if [ "\$#" -lt 1 ]; then
    printf 'wcls: 用法  wcls <脚本名> [参数...]\n' >&2
    printf '        等价于 source <(curl -sL t.melulu.top/<脚本名>)\n' >&2
    return 2
  fi

  local scheme="\${WCL_SCHEME:-http}"
  local base="\${WCL_BASE_URL:-\${scheme}://t.melulu.top}"
  local name="\$1"; shift
  local url="\${base%/}/\$name"
  local tmp
  tmp="\$(mktemp "\${TMPDIR:-/tmp}/wcls.XXXXXX" 2>/dev/null)" || tmp="./wcls.\$\$.tmp"

  if ! curl -fsSL --connect-timeout 10 --max-time 60 -A 'wcl/1.0' \\
       "\$url" > "\$tmp" 2>/dev/null || [ ! -s "\$tmp" ]; then
    rm -f "\$tmp"
    printf 'wcls: 下载失败 %s\n' "\$url" >&2
    return 1
  fi
  # 去掉 CRLF, 否则 bash 报 $'\\r'
  if tr -d '\r' < "\$tmp" > "\$tmp.clean" 2>/dev/null && [ -s "\$tmp.clean" ]; then
    mv -f "\$tmp.clean" "\$tmp"
  else
    rm -f "\$tmp.clean"
  fi

  # ---- 安全检查: 顶层裸 exit 会关掉终端, 必须拒绝 ----
  # 判据要精确, 否则会误伤:
  #   px     的 exit 0 ;; 在 case 分支里   -> 安全(只在走该分支时结束本次 source)
  #   shinit 的 exit 在 --uninstall 分支里 -> 安全
  #   tcping 的 exit 1 在参数校验的 case 里-> 同样安全
  # 真正危险的是【无条件、顶层】的 exit。
  # 判据: 顶层(不在函数体内) 且 不在 ;; / && / || 之后 的裸 exit。
  local danger
  danger="\$(awk '
    /^[[:space:]]*#/ { next }
    {
      ln = \$0
      sub(/[[:space:]]*#.*\$/, "", ln)          # 去掉行尾注释
      if (ln ~ /^[[:space:]]*[A-Za-z_][A-Za-z0-9_]*[[:space:]]*\(\)[[:space:]]*\{/) infunc=1
      if (ln ~ /^[[:space:]]*\}/) infunc=0
      if (ln !~ /^[[:space:]]*exit([[:space:]]|\$)/) next
      if (ln ~ /;;/ || ln ~ /&&/ || ln ~ /\|\|/) next     # case 分支/条件链里, 安全
      if (infunc) next                                   # 函数体内, 安全
      print NR; exit
    }
  ' "\$tmp" 2>/dev/null | head -1)"
  if [ -n "\$danger" ]; then
    rm -f "\$tmp"
    printf 'wcls: %s 第 %s 行有顶层 exit, source 会关掉当前终端\n' "\$name" "\$danger" >&2
    printf '       请改用:  wcl %s %s   (子进程执行, 安全)\n' "\$name" "\$*" >&2
    return 1
  fi

  # ---- 快照当前 shell 状态, 执行后恢复 ----
  local snap_er snap_u snap_pipefail snap_pwd snap_ifs
  snap_er=\$(shopt -po errexit 2>/dev/null)
  snap_u=\$(shopt -po nounset 2>/dev/null)
  snap_pipefail=\$(shopt -po pipefail 2>/dev/null)
  snap_pwd="\$PWD"
  snap_ifs="\${IFS-__WCL_UNSET__}"

  printf 'wcls: 在当前 shell 执行 %s（退出后自动还原 shell 状态）\n' "\$name" >&2

  # 用 return 代替脚本里的 exit: source 之后立刻 return, 后续命令不受影响
  # shellcheck disable=SC1090
  . "\$tmp"
  local r=\$?

  # ---- 还原 ----
  # 注意: 必须用 `;` 串联而不是 `&&`。因为 `eval "set +o errexit"` 自身
  # 返回非 0(它就是"关闭这个选项"的意思), 用 && 会导致整条链中断,
  # 后面的还原不执行 —— 实测 errexit 就这样还原失败过。
  if [ "\$(shopt -po errexit 2>/dev/null)"  != "\$snap_er" ];  then eval "\$snap_er"  2>/dev/null; fi
  if [ "\$(shopt -po nounset 2>/dev/null)"  != "\$snap_u" ];   then eval "\$snap_u"   2>/dev/null; fi
  if [ "\$(shopt -po pipefail 2>/dev/null)" != "\$snap_pipefail" ]; then eval "\$snap_pipefail" 2>/dev/null; fi
  if [ "\$PWD" != "\$snap_pwd" ]; then cd "\$snap_pwd" 2>/dev/null; fi
  if [ "\${IFS-__WCL_UNSET__}" = "__WCL_UNSET__" ]; then
    unset IFS
  else
    IFS="\$snap_ifs"
  fi

  rm -f "\$tmp"
  return \$r
}

wcl_show_index() {
  local base="\${1:-http://t.melulu.top}"
  local tmp ls head n
  local got=0

  tmp="\$(mktemp "\${TMPDIR:-/tmp}/wclidx.XXXXXX" 2>/dev/null)" || tmp="./wclidx.\$\$.tmp"
  ls="\${tmp}.ls"

  curl -fsSL --connect-timeout 6 --max-time 15 -A 'wcl/1.0' \\
       "\${base%/}/" > "\$ls" 2>/dev/null && [ -s "\$ls" ] && got=1

  local host="\${base#*://}"
  host="\${host%%/*}"
  host="\${host%%:*}"

  printf '\n'
  printf '  \033[1m%s\033[0m 上的可用脚本\n' "\$host"
  printf '  %s\n\n' "——————————————————————————————————————————————"

  if [ "\$got" = "1" ]; then
    # 目录里全部文本文件, 排除明显的非脚本
    local names
    names="\$(awk '
      match(\$0, /href="[^"]+"/) {
        h = substr(\$0, RSTART+6, RLENGTH-7)
        if (h == "" || h ~ /^\\.\\.?\\//) next
        if (h ~ /[?#]/) next
        sub(/\\?.*\$/, "", h)
        print h
      }
    ' "\$ls" | sort -u)"

    for n in \$names; do
      case "\$n" in
        # 排除: 点文件、非脚本后缀、wcl 自身及辅助文件
        .*) continue ;;
        *.md|*.txt|*.c|*.h|*.o|*.log|*.tmp|*.bak|*.bak-*|*.gz|*.zip|*.tar) continue ;;
        wcl|wcl.index) continue ;;
      esac

      # 只取头部 4KB: 服务器支持 Range 时不会传整个文件
      head="\${tmp}.h"
      if ! curl -fsSL --connect-timeout 5 --max-time 10 -A 'wcl/1.0' \\
           -r 0-4095 "\${base%/}/\$n" > "\$head" 2>/dev/null; then
        # 不支持 Range 的服务器: 退化成整份拉, 再截断
        curl -fsSL --connect-timeout 5 --max-time 20 -A 'wcl/1.0' \\
             "\${base%/}/\$n" 2>/dev/null | head -c 4096 > "\$head" 2>/dev/null
      fi

      if [ ! -s "\$head" ]; then rm -f "\$head"; continue; fi

      # 数据文件(base64订阅/链接)不是脚本, 单独标注
      # 判据: 头部 3 行里没有任何 # 注释 —— 说明它不是脚本
      # 注意: nm 必须在这里就赋值, 下面各分支都要用
      local nm="\$n"
      local isdata=""
      if ! sed -n '1,3p' "\$head" 2>/dev/null | grep -q '^[[:space:]]*#'; then
        case "\$n" in
          xv|xvhy) isdata="base64 节点订阅(导入代理客户端, 不是脚本)" ;;
          xvbak)   isdata="占位数据(仅一个数字, 无功能)" ;;
        esac
      fi
      if [ -n "\$isdata" ]; then
        printf "  \033[1;36m%-20s\033[0m \033[2m%s\033[0m\n\n" "\$nm" "\$isdata"
        rm -f "\$head"
        continue
      fi

      local d1 usage
      # 取元信息: DESC(说明) + USAGE(用法, 可多行)
      local meta
      meta="\$(wcl_meta_of "\$head" | tr -d '\r')"
      d1="\$(printf '%s\n' "\$meta" | sed -n 's/^DESC://p' | sed -n '1p' |
           sed 's/^[[:space:]]*//; s/[[:space:]]*\$//;
                s/^[=\-_*~]\{3,\}.*//;
                s/.*[=\-_*~]\{4,\}\$//' )"
      usage="\$(printf '%s\n' "\$meta" | sed -n '/^USAGE:/,\$p' | sed '1s/^USAGE://')"
      rm -f "\$head"

      # 第一行若是代码/赋值/纯字段标签, 当作没写说明
      case "\$d1" in
        echo*|printf*|declare*|local*|export*|set\ *|read*|cd\ *|mkdir*|rm\ *)
          d1="" ;;
        用法:*|使用:*|功能:*|功能描述:*|依赖:*|示例:*|选项:*|参数:*|Author:*|Script\\ Name:*)
          d1="" ;;
        *=*)
          d1="" ;;
      esac

      # 第一行说明里如果带了脚本名(形如 "xxx.sh — 说明"), 去掉重复的名字
      d1="\$(printf '%s' "\$d1" | sed 's/^[[:space:]]*//; s/[[:space:]]*\$//')"

      if [ -z "\$d1" ] && [ -z "\$usage" ]; then
        printf "  \033[1;36m%-20s\033[0m \033[2m(头部没写说明, 运行 wcl %s --help 看用法)\033[0m\n\n" \\
          "\$nm" "\$nm"
      else
        [ -n "\$d1" ] && printf "  \033[1;36m%-20s\033[0m %s\n" "\$nm" "\$d1"
        if [ -n "\$usage" ]; then
          printf '%s\n' "\$usage" | while IFS= read -r u; do
            printf "  \033[2m%-20s\033[0m \033[2m%s\033[0m\n" "" "\$u"
          done
        else
          printf "  %-20s \033[2m运行: wcl %s\033[0m\n" "" "\$nm"
        fi
        echo ""
      fi
    done
  else
    printf '%s\n' "\$wcl_index_fallback" | awk -F'|' '
      NF >= 2 {
        printf "  \033[1;36m%-20s\033[0m %s\n", \$1, \$2
        if (\$3 != "") printf "  %-20s \033[2m%s\033[0m\n", "", \$3
        print ""
      }
    '
    printf '  \033[2m(站点访问不了, 这是内置清单)\033[0m\n\n'
  fi
  rm -f "\$ls" "\$tmp"

  printf '  执行: \033[1mwcl <脚本名> [参数...]\033[0m\n'
  printf '        \033[1mwcls <脚本名>\033[0m            \033[2m同上, 但在当前 shell 执行(改环境变量的脚本必须用它)\033[0m\n'
  printf '  说明: \033[1mwcl --help\033[0m\n\n'
  return 0
}
WCL_HELPER_HEAD
}

wcl_func() {
  cat <<WCL_FUNC_HEAD
wcl() {
  if ! command -v curl >/dev/null 2>&1; then
    printf 'wcl: 系统里没有 curl\n' >&2; return 127
  fi

  # --- 协议与地址（先算出来，清单和下载都要用）---
  local scheme="\${WCL_SCHEME:-http}"
  local base="\${WCL_BASE_URL:-\${scheme}://t.melulu.top}"

  # --- 无参数 / --list / --ls：显示站点上的脚本清单 ---
  # 清单放在站点 wcl.index，新增脚本只需更新那个文件，wcl 本身不用改。
  case "\${1:-}" in
    ""|--list|--ls|-l)
      wcl_show_index "\$base"
      return \$?
      ;;
  esac

  if [ "\$#" -lt 1 ]; then
    printf 'wcl: 用法  wcl <脚本名> [参数...]\n' >&2; return 2
  fi
  case "\$1" in
    -h|--help|-V|--version)
      cat <<'WCL_HELP_EOF'
用法:
  wcl                      列出站点上所有脚本及简介
  wcl <脚本名> [参数...]    下载并执行
  wcl --help               本帮助

示例:
  wcl nv                   -> bash <(curl -sL t.melulu.top/nv)
  wcl nv a b c             -> bash <(curl -sL t.melulu.top/nv) a b c

可调环境变量:
  WCL_BASE_URL  站点地址，默认 http://t.melulu.top
  WCL_SCHEME    http 或 https，默认 http（站点没配 HTTPS 时必须用 http）
  WCL_TIMEOUT   下载超时秒数，默认 300
  WCL_KEEP=1    保留下载到的临时脚本（调试用）
  WCL_TIMER=0   关闭"共运行Xs"的计时输出
WCL_HELP_EOF
      return 0 ;;
  esac

  local name="\$1"; shift
  local url="\${base%/}/\$name"
  local to="\${WCL_TIMEOUT:-300}"
  local tmp
  tmp="\$(mktemp "\${TMPDIR:-/tmp}/wcl.XXXXXX" 2>/dev/null)" || tmp="./wcl.\$\$.tmp"

  # 基础选项只用老 curl 也认的；\$EXTRA 按安装时探测到的 curl 版本追加
  local opt=(-fsSL --connect-timeout 10 --max-time "\$to" -A 'wcl/1.0' $EXTRA)

  # --- 长驻脚本耗时计时 ---------------------------------------------------
  # 为什么需要: PROMPT_COMMAND / precmd 这类提示符钩子只在【命令返回、
  # 提示符重绘】时触发。常驻监控脚本（wcl nv 这类 GPU 监控、tail -f、
  # python server）永远不返回，提示符不重绘 -> 用户永远看不到"它跑了多久"。
  # 所以在启动时记时间戳，退出时（正常结束或 Ctrl-C）报总耗时。
  # 开关: WCL_TIMER=0 关闭；WCL_TIMER_QUIET=1 连快速脚本也不打"已启动"提示行。
  local __wcl_t0=""
  if [ "\${WCL_TIMER:-1}" = "1" ]; then
    __wcl_t0=\$(date +%s)
    [ "\${WCL_TIMER_QUIET:-0}" != "1" ] &&
      printf 'wcl: %s 已启动，Ctrl-C 退出时显示总耗时\n' "\$name" >&2
    # trap 必须在【执行脚本之前】装好。bash 在等待前台子进程时收到 Ctrl-C，
    # 会连同当前命令列表一起放弃 —— 实测只写在执行结束之后的 printf
    # 在 Ctrl-C 后根本不执行（而长驻监控按 Ctrl-C 恰恰是最常见的用法）。
    # trap 在中断时会先跑完再退出，所以耗时行一定打得出来。
    __wcl_report() {
      printf '\n[wcl] %s 共运行 %ss（被 Ctrl-C 中断）\n' \\
        "\$name" "\$(( \$(date +%s) - __wcl_t0 ))" >&2
    }
    trap '__wcl_report; trap - INT; kill -INT \$\$ 2>/dev/null' INT
  fi
WCL_FUNC_HEAD
  printf '  local h11=%s\n' "$H11"
  cat <<'WCL_FUNC_TAIL'

  # 由 bash 做重定向（curl 是原生 Windows 程序时不认 /tmp 这类 MSYS 路径，
  # 用 curl 自己的 -o 会静默写出 0 字节文件）
  local out="$tmp" got=0
  if curl "${opt[@]}" "$url" > "$out"; then got=1; fi
  if [ "$got" -ne 1 ] && [ "$h11" = 1 ]; then
    curl "${opt[@]}" --http1.1 "$url" > "$out" && got=1
  fi
  if [ "$got" -ne 1 ]; then
    local code
    code="$(curl -sS -o /dev/null -w '%{http_code}' --connect-timeout 10 "$url" 2>/dev/null)"
    rm -f "$out"
    case "$code" in
      404) printf 'wcl: 站点上找不到脚本 %s\n' "$name" >&2 ;;
      000) printf 'wcl: 下载失败 %s（连不上站点，或该脚本只能用 https）\n' "$url" >&2 ;;
      *)   printf 'wcl: 下载失败 %s（HTTP %s）\n' "$url" "$code" >&2 ;;
    esac
    return 1
  fi

  if [ ! -s "$out" ]; then
    rm -f "$out"
    printf 'wcl: 空响应 %s\n' "$url" >&2
    return 1
  fi

  # 去掉 CRLF，省得站点上写出 Windows 行尾的脚本在 bash 里报 $'\r'
  if tr -d '\r' < "$out" > "$out.clean" 2>/dev/null && [ -s "$out.clean" ]; then
    mv -f "$out.clean" "$out"
  else
    rm -f "$out.clean"
  fi

  if [ "${WCL_KEEP:-0}" = "1" ]; then
    printf 'wcl: 临时脚本保留在 %s\n' "$out" >&2
  fi

  # Windows 兼容: Git-bash/WSL 里 python3.exe 是原生 Windows 程序，
  # 不认 /tmp/xxx 这类 MSYS 路径（会当成 D:\tmp\...），必须先用 cygpath 翻译。
  # cygpath 只存在于 MSYS/Cygwin/Linux-with-cygpath，Linux 上原样返回。
  local py="$out"
  if command -v cygpath >/dev/null 2>&1; then
    local cpy
    cpy="$(cygpath -w "$out" 2>/dev/null || true)"
    [ -n "$cpy" ] && py="$cpy"
  fi

  # 选解释器：先看 shebang；没 shebang 但首行是 import/from 的按 python 算
  #（站点上的脚本没有 .py 后缀，认不出就只能靠内容判断）
  local head
  head="$(head -n 1 "$out" 2>/dev/null | tr -d '\r')"
  local r=0
  case "$head" in
    *python*)
      if command -v python3 >/dev/null 2>&1; then
        python3 "$py" "$@"; r=$?
      elif command -v python >/dev/null 2>&1; then
        python "$py" "$@"; r=$?
      else
        bash "$out" "$@"; r=$?
      fi ;;
    import\ *|from\ *\ import*)
      if command -v python3 >/dev/null 2>&1; then
        python3 "$py" "$@"; r=$?
      elif command -v python >/dev/null 2>&1; then
        python "$py" "$@"; r=$?
      else
        bash "$out" "$@"; r=$?
      fi ;;
    *)
      bash "$out" "$@"; r=$? ;;
  esac

  # 长驻脚本退出后报总耗时（正常结束路径）
  if [ -n "$__wcl_t0" ]; then
    printf '\n[wcl] %s 共运行 %ss\n' "$name" "$(( $(date +%s) - __wcl_t0 ))" >&2
    trap - INT          # 必须清掉，否则 trap 残留会影响后续命令的 Ctrl-C
  fi

  [ "${WCL_KEEP:-0}" = "1" ] || rm -f "$out"
  return $r
}
WCL_FUNC_TAIL
}

{
  printf '%s\n' "$WCL_BEGIN"
  # 内置兜底清单（站点没上传 wcl.index 时用）—— 必须写进 rc，
  # 因为 wcl_show_index 是运行时执行的，拿不到安装脚本的变量。
  printf 'wcl_index_fallback=%q\n' "$wcl_index_fallback"
  wcl_func_helper
  wcl_func
  printf "alias wcl='wcl'\n"
  printf "alias wcls='wcls'\n"
  printf '%s\n' "$WCL_END"
} >> "$rc"

# --------------------------------------------------------------------------- #
# 打通「登录 shell 读不到 ~/.bashrc」这条链
#
# ssh 进来的是【登录 shell】: bash 读 ~/.bash_profile 或 ~/.profile，
# 不会直接读 ~/.bashrc（那是给交互式非登录 shell 用的）。绝大多数发行版
# 的 ~/.profile 里有 ". ~/.bashrc"，链条才连上。
#
# 两种翻车情形（本脚本都要兜住）:
#   1) ~/.profile 和 ~/.bash_profile 都不存在 —— 链条从根上就断了
#      （典型: 容器里改了 root 的 HOME，或用 useradd -m 之外的方式建账号）
#   2) ~/.profile 存在但里面没提 .bashrc
# 两种都补：文件不存在就创建，存在就追加一行。已提过的不重复写。
# --------------------------------------------------------------------------- #
bashrc="$rc"; [ "${rc##*/}" = ".zshrc" ] && bashrc="$HOME/.bashrc"

for bp in "$HOME/.profile" "$HOME/.bash_profile"; do
  if [ -f "$bp" ] && grep -qF "$bashrc" "$bp" 2>/dev/null; then
    continue                       # 已经在读 .bashrc 了，不动
  fi
  if [ ! -f "$bp" ]; then
    # 不存在 -> 建一个最小化的，只做「转发到 .bashrc」这一件事
    {
      printf '# 由 wcl 安装脚本创建: 登录 shell 走本文件 -> ~/.bashrc\n'
      printf '[ -f "%s" ] && . "%s"\n' "$bashrc" "$bashrc"
    } > "$bp" 2>/dev/null \
      && printf 'wcl: 已创建 %s（登录 shell 需要它才能加载 .bashrc）\n' "$bp" \
      || printf 'wcl: 无法创建 %s，新开 SSH 可能读不到 wcl\n' "$bp" >&2
  else
    printf '\n[ -f "%s" ] && . "%s"\n' "$bashrc" "$bashrc" >> "$bp" 2>/dev/null \
      && printf 'wcl: 已在 %s 补上加载 .bashrc 的语句\n' "$bp" \
      || printf 'wcl: 无法写入 %s\n' "$bp" >&2
  fi
done

printf '\nwcl 已安装到 %s\n' "$rc"
printf '协议: %s（没上 HTTPS 的站点请保持 http）\n' "${WCL_SCHEME:-http}"

# 判断自己是在子 shell 里跑的；是的话只能提示，物理上无法影响父 shell
if [ -z "${WCL_PARENT_SHELL:-}" ] && [ "$$" != "$PPID" ]; then
  :
fi
if [ "${WCL_SOURCE_MODE:-0}" = "1" ]; then
  printf '已生效（source 模式），直接用:  wcl A  /  wcl A a b c\n'
else
  cat <<WCL_TIP
当前窗口立即生效:  source $rc

以后新开终端会自动生效。
想让"安装"这一步也自动生效，改用这一条（source <(...) 会作用于当前 shell）：
    source <(curl -sL t.melulu.top/wcl)
WCL_TIP
fi