KeiSeiKit-1.0/install/lib-preflight.sh
Parfii-bot 7ce43cd80f feat(install): preflight модуль — проверка CLI по выбранному провайдеру
Добавлен шаг между выбором модели и сбором ключей: для провайдеров
требующих внешний CLI/daemon — проверка наличия, инструкция по
установке, опциональный авто-install (TTY only).

install/lib-preflight.sh — диспетчер:
  preflight_run <provider-id>
  - ищет install/preflight/<id>.sh, source'ит, вызывает
    preflight_check_<sanitized_id>
  - функция возвращает 0/1, печатает инструкцию в stderr
  - non-TTY: только печать, без вопросов

preflight_offer_install <cli> <install-cmd>:
  - TTY: спрашивает [y/N/skip], выполняет install-cmd
  - non-TTY: печатает и пропускает

install/preflight/ — 6 файлов (только для провайдеров с CLI):
  anthropic-bedrock.sh  — aws CLI + sts get-caller-identity
  google-vertex.sh      — gcloud CLI + project config
  codex.sh              — codex CLI (npm) + login status
  ollama-local.sh       — ollama binary + 127.0.0.1:11434 daemon
  mlx-local.sh          — mlx_lm.server (arm64 only) + 127.0.0.1:8080
  lmstudio-local.sh     — порт 127.0.0.1:1234 (desktop app)

Direct-api провайдеры (anthropic, openai, xai, deepseek, google) +
proxy (litellm, openrouter) + openai-azure — preflight-файла нет,
диспетчер тихо пропускает, ключ собирается обычно.

Тесты: bash -n чисто на всех 8 файлах, unit dispatcher показывает
silent-pass для anthropic, warn+exit-1 для bedrock без aws на PATH.
2026-05-17 15:57:54 +08:00

66 lines
2.3 KiB
Bash

# shellcheck shell=bash
# lib-preflight.sh — диспетчер preflight-проверок CLI.
#
# Контракт:
# preflight_run <provider-id>
# 1. Ищет файл install/preflight/<provider-id>.sh
# 2. Если есть — source'ит и вызывает `preflight_check_<sanitized-id>`
# 3. Функция возвращает 0 (ok) / 1 (missing, инструкция напечатана)
# 4. Если файла нет — провайдеру CLI не нужен, тихо exit 0
#
# Файл per-provider должен экспортировать ОДНУ функцию:
# preflight_check_<id>() — печатает инструкцию в stderr, exit 0/1
#
# Sanitize: dashes в id заменяются на underscores для имени функции
# (bash не любит dashes в идентификаторах).
PREFLIGHT_DIR="${LIB_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}/preflight"
# Печатает инструкцию по установке, спрашивает действие.
# Аргументы: $1 — имя CLI, $2 — команда установки.
preflight_offer_install() {
local cli="$1"
local install_cmd="$2"
echo "" >&2
echo "$cli не найден." >&2
echo " Установить: $install_cmd" >&2
echo "" >&2
if [ -t 0 ] && [ -t 1 ]; then
read -r -p " Поставить сейчас? [y/N/skip] " ans
case "$ans" in
y|Y|yes)
eval "$install_cmd"
return $?
;;
skip|s|S)
echo " пропускаю — поставите вручную позже." >&2
return 0
;;
*)
echo " пропуск (по умолчанию)." >&2
return 1
;;
esac
else
# non-TTY: только печатаем инструкцию.
return 1
fi
}
# Главный диспетчер. Вызывается из onboarding между pick_model и collect_auth.
preflight_run() {
local provider="$1"
[ -z "$provider" ] && return 0
local script="$PREFLIGHT_DIR/${provider}.sh"
if [ ! -f "$script" ]; then
return 0 # CLI не нужен — direct-api, ключ собирается ниже
fi
# shellcheck disable=SC1090
source "$script"
local fn="preflight_check_${provider//-/_}"
if command -v "$fn" >/dev/null 2>&1; then
"$fn"
return $?
fi
return 0
}