KeiSeiKit-1.0/install/lib-prereqs.sh
Parfii-bot 03d1dc7362 refactor(v0.16): split install.sh monolith (1238 LOC) into 17 cubes
Constructor Pattern (RULE ZERO). Zero behaviour change, zero flag
drift — all original CLI flags preserved verbatim.

Before: install.sh — 1238 LOC monolith
After:  install.sh — 138 LOC dispatcher (sources libs in order)
        install/lib-*.sh — 16 cubes, max 183 LOC (lib-menu)

Cubes:
  lib-log       21 LOC — logging primitives
  lib-backup    63 LOC — rollback trap + BACKUP_PAIRS
  lib-profile  115 LOC — MANIFEST.toml profile resolution
  lib-args      92 LOC — CLI parsing + --help heredoc
  lib-menu     183 LOC — whiptail/dialog/plain-text interactive picker
  lib-plan     150 LOC — dry-run --no-execute output
  lib-prereqs   91 LOC — hard + soft dependency checks
  lib-primitives 131 LOC — primitive copy + MANIFEST drive
  lib-rust     114 LOC — cargo workspace build + pre-built support
  lib-scaffold 144 LOC — agent/skill/block scaffolding
  lib-bridges   31 LOC — project-bridge install
  lib-hooks    104 LOC — settings.json jq merge
  lib-agents    77 LOC — assembled agent output
  lib-skills    23 LOC — skill copy
  lib-wizard    20 LOC — sleep-setup wizard invocation
  lib-summary   59 LOC — post-install summary

Invariants preserved:
  - macOS bash 3.2 compat (no associative arrays, no [[ ]], no ${,,})
  - rollback trap wired via setup_backup_trap early in dispatcher
  - jq-merge behaviour verbatim in lib-hooks
  - scoped Cargo.toml regeneration in lib-rust

Function LOC limits: largest non-heredoc fn 22 LOC (check_soft_prereqs).
Three functions kept >30 LOC because heredoc-dominated (print_help,
print_summary, profile_members); splitting would fragment logical unit.

62 unique function names across cubes, zero duplicates (grep-verified).

bash -n passes on all 17 files. Runtime smoke test deferred to user's
shell (bash-readonly sandbox constraint).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 15:09:35 +08:00

91 lines
3.9 KiB
Bash

# shellcheck shell=bash
# lib-prereqs.sh — hard + soft prerequisite checks.
#
# HARD: cargo, jq. SOFT: deps based on the primitives that will be installed.
# A profile-aware soft-warn: only check deps for primitives actually in scope.
#
# Requires: err / warn / say from lib-log.sh.
# Requires: profile_members from lib-profile.sh.
# Reads globals: $PROFILE, $CUSTOM_PRIMS, $MANIFEST.
# Sets global: $PROFILE_PRIMS (space-separated primitive names).
# Hard checks: cargo + jq. Exit 1 on missing — without them the install
# (or the installed hooks afterwards) cannot function.
check_hard_prereqs() {
say "checking prerequisites"
if ! command -v cargo >/dev/null 2>&1; then
err "cargo not found. Install Rust: https://rustup.rs/"
exit 1
fi
if ! cargo --version >/dev/null 2>&1; then
err "cargo is installed but not functional. Run: rustup default stable"
exit 1
fi
if ! command -v jq >/dev/null 2>&1; then
err "jq not found. jq is REQUIRED on any machine that will activate the"
err "KeiSeiKit hooks — without it the hooks become dead weight and would"
err "otherwise abort Claude Code's Edit/Write/Bash tool calls. Install it:"
err " brew install jq (macOS)"
err " apt install jq (Debian/Ubuntu)"
exit 1
fi
}
# Resolve primitive list for the current profile (or CUSTOM_PRIMS if custom)
# into PROFILE_PRIMS. Does not exit.
resolve_profile_prims() {
if [ "$PROFILE" = "custom" ]; then
PROFILE_PRIMS="$(echo "$CUSTOM_PRIMS" | tr ',' ' ')"
else
PROFILE_PRIMS="$(profile_members "$PROFILE" 2>/dev/null || true)"
fi
}
# Scan PROFILE_PRIMS and echo a space-separated list of tool-need flags:
# pandoc playwright sqlite hcloud vultr yq — one per line, each "1" or "0".
_soft_dep_flags() {
local needs_pandoc=0 needs_playwright=0 needs_sqlite=0
local needs_hcloud=0 needs_vultr=0 needs_yq=0 p
for p in $PROFILE_PRIMS; do
case "$p" in
tomd) needs_pandoc=1 ;;
design-scrape|live-preview|mock-render) needs_playwright=1 ;;
kei-ledger|kei-migrate) needs_sqlite=1 ;;
provision-hetzner) needs_hcloud=1 ;;
provision-vultr) needs_vultr=1 ;;
kei-ci-lint) needs_yq=1 ;;
esac
done
echo "$needs_pandoc $needs_playwright $needs_sqlite $needs_hcloud $needs_vultr $needs_yq"
}
# Soft checks: only warn for tools needed by primitives actually being installed.
check_soft_prereqs() {
local n_pandoc n_playwright n_sqlite n_hcloud n_vultr n_yq
read -r n_pandoc n_playwright n_sqlite n_hcloud n_vultr n_yq <<< "$(_soft_dep_flags)"
if [ "$n_pandoc" = "1" ] && ! command -v pandoc >/dev/null 2>&1; then
warn "pandoc not found — tomd primitive will fail on .docx/.pptx. Install: brew install pandoc"
fi
if [ "$n_playwright" = "1" ] && ! command -v playwright >/dev/null 2>&1 && ! command -v npx >/dev/null 2>&1; then
warn "playwright/npx not found — frontend primitives need them. Install: npm i -g playwright && playwright install chromium"
fi
if [ "$n_sqlite" = "1" ] && ! command -v sqlite3 >/dev/null 2>&1; then
warn "sqlite3 CLI not found — kei-ledger/kei-migrate work without it (rusqlite embedded). Install for manual DB inspection: brew install sqlite"
fi
if [ "$n_hcloud" = "1" ] && ! command -v hcloud >/dev/null 2>&1; then
warn "hcloud CLI not found — provision-hetzner requires it. Install: brew install hcloud"
fi
if [ "$n_vultr" = "1" ] && ! command -v vultr-cli >/dev/null 2>&1; then
warn "vultr-cli not found — provision-vultr requires it. Install: brew install vultr/vultr-cli/vultr-cli"
fi
if [ "$n_yq" = "1" ] && ! command -v yq >/dev/null 2>&1; then
warn "yq not found — kei-ci-lint requires yq v4+ (mikefarah/yq). Install: brew install yq"
fi
}
# Top-level orchestrator: hard first (exit on miss), then resolve + soft.
check_prereqs() {
check_hard_prereqs
resolve_profile_prims
check_soft_prereqs
}