#!/bin/sh set -u say() { printf '%s\n' "$*" } warn() { printf '错误: %s\n' "$*" >&2 } usage() { cat <<'EOF' 用法: ./search_config.sh ./search_config.sh --tavily KEY --exa KEY --keenable KEY ./search_config.sh --migrate [search.env 路径] ./search_config.sh --list 选项: --tavily KEY 配置 tavily api_key 凭据 --exa KEY 配置 exa api_key 凭据 --keenable KEY 配置 keenable api_key 凭据 --migrate 从旧 search.env 导入缺失的 key --list 显示各 provider 配置状态(不输出 key) --auth FILE 覆盖 auth.json 路径 -h, --help 显示帮助 不传 key 参数时进入隐藏输入的交互模式;传入任意 key 参数时不交互, 未指定的 provider 保留已有值。凭据写入 Pi 的 auth.json ($PI_CODING_AGENT_DIR/auth.json 或 ~/.pi/agent/auth.json,权限 600)。 key 支持 auth.json 原生语义:字面量、$ENV_VAR / ${ENV_VAR} 插值、 以及 !command(执行命令取 stdout,如 "!op read op://Vault/Tavily/key")。 EOF } SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" && pwd) AUTH_MJS="$SCRIPT_DIR/scripts/search-auth.mjs" [ -f "$AUTH_MJS" ] || { warn "找不到 ${AUTH_MJS}"; exit 1; } AUTH_FILE= mode=interactive did_work=0 run_auth() { if [ -n "$AUTH_FILE" ]; then node "$AUTH_MJS" --auth "$AUTH_FILE" "$@" else node "$AUTH_MJS" "$@" fi } has_key() { run_auth --has "$1" >/dev/null 2>&1 } prompt_key() { prompt_label=$1 prompt_configured=$2 if [ ! -t 0 ]; then warn "交互模式需要终端;请改用 --tavily/--exa/--keenable 参数。" return 2 fi if [ "$prompt_configured" -eq 1 ]; then printf '%s API key(回车保留现有值): ' "$prompt_label" >&2 else printf '%s API key(回车跳过): ' "$prompt_label" >&2 fi stty -echo IFS= read -r prompt_value || prompt_status=$? stty echo printf '\n' >&2 [ "${prompt_status:-0}" -eq 0 ] || return "$prompt_status" printf '%s\n' "$prompt_value" } while [ "$#" -gt 0 ]; do case $1 in --tavily|--exa|--keenable) [ "$#" -ge 2 ] || { warn "$1 缺少 KEY"; exit 2; } mode=noninteractive; did_work=1 run_auth --set "${1#--}=$2" || exit $? shift 2 ;; --migrate) mode=noninteractive; did_work=1 if [ "$#" -ge 2 ] && [ "${2#--}" = "$2" ]; then run_auth --migrate "$2" || exit $? shift 2 else run_auth --migrate || exit $? shift fi say "如确认 auth.json 可用,可手动删除旧 search.env 文件。" ;; --list) mode=noninteractive; did_work=1; run_auth --list || exit $?; shift ;; --auth) [ "$#" -ge 2 ] || { warn "--auth 缺少 FILE"; exit 2; } AUTH_FILE=$2; shift 2 ;; -h|--help) usage; exit 0 ;; *) warn "未知参数:$1"; usage >&2; exit 2 ;; esac done if [ "$mode" = interactive ]; then for provider in tavily exa keenable; do case $provider in tavily) label=Tavily ;; exa) label=Exa ;; keenable) label=Keenable ;; esac if has_key "$provider"; then configured=1; else configured=0; fi value=$(prompt_key "$label" "$configured") || exit $? if [ -n "$value" ]; then run_auth --set "$provider=$value" || exit $? did_work=1 fi done [ "$did_work" -eq 1 ] || say "未提供任何 key,auth.json 保持不变。" fi