KeiSeiKit-1.0/install/lib-plan.sh
KeiSei84 9866d716d7
Some checks are pending
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / preflight (push) Waiting to run
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / vps-smoke (push) Waiting to run
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:frustration-matrix,kei-frustration-loop,kei-skill-importer,kei-projects-index,kei-projects-watcher,kei-gdrive-import,kei-leak-matrix,kei-skills,kei-gateway,kei-cron-scheduler,kei-export-trajectories,kei-backend-daytona,kei-d… (push) Blocked by required conditions
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-compute-baremetal,kei-compute-vultr,kei-compute-linode,kei-compute-digitalocean,kei-svc-systemd,kei-llm-bridge-mlx name:hosted-sleep-compute]) (push) Blocked by required conditions
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-diff,kei-scheduler,kei-watch,kei-prune,kei-discover,kei-brain-view,kei-hibernate,kei-ledger-sign,kei-fork name:wave13-15]) (push) Blocked by required conditions
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-git-gitea,kei-git-forgejo,kei-git-gitlab,kei-git-bitbucket,kei-memory-sled,kei-memory-redis,kei-memory-postgres,kei-memory-sqlite,kei-auth-google,kei-auth-apple,kei-auth-magiclink,kei-auth-webauthn,kei-notify-slack,kei-n… (push) Blocked by required conditions
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-ledger,kei-migrate,kei-changelog,kei-memory,kei-store,kei-conflict-scan,kei-refactor-engine,kei-graph-check,kei-shared,kei-dna-index,kei-pet name:core]) (push) Blocked by required conditions
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-machine-probe,kei-llm-ollama,kei-llm-llamacpp,kei-llm-mlx,kei-llm-router,kei-model name:llm-stack]) (push) Blocked by required conditions
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-router,kei-sage,kei-task,kei-chat-store,kei-crossdomain,kei-search-core,kei-content-store,kei-social-store,kei-curator,kei-auth,kei-artifact name:mcp-lbm]) (push) Blocked by required conditions
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:keisei,kei-forge,kei-runtime,kei-runtime-core,kei-atom-discovery,kei-agent-runtime,kei-capability,kei-provision,kei-entity-store,kei-pipe,kei-cache,kei-spawn,kei-replay name:atom-substrate]) (push) Blocked by required conditions
style(install): KeiSei brand colors + ASCII banner in installer output
- KEISEI ASCII logo (голубой) shown at install start via kei_banner().
- `[install]` prefix → тёмно-жёлтый (38;5;178); primitive names → голубой
  (38;5;39) in both the plan and the per-primitive install lines.
- Language menu: code голубой, native name тёмно-жёлтый.
- lib-log COLOR now enables under curl|bash too: detect terminal via
  `[ -t 1 ] || /dev/tty` (web-install tees stdout → -t 1 false → colors were
  silently off). This is color detection, not an interactivity gate (pairs
  with no -t 0 — does not violate tty-interactivity-gate rule).

Verified piped-under-pty: banner + gold [install] + blue/gold language menu
all render through the tee logfile.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 16:01:33 +08:00

152 lines
5.1 KiB
Bash

# shellcheck shell=bash
# lib-plan.sh — install-plan estimation, soft-dep status, confirm screen.
#
# Per-primitive time/disk estimates are hardcoded here (not in MANIFEST) to
# keep the manifest declarative + UX hints local. Shell primitives are
# ~1s / 5 KB; rust primitives vary by dep weight.
#
# Requires: primitive_field from lib-profile.sh.
# Requires: say / warn / err from lib-log.sh.
# Reads globals: ASSUME_YES, CONFIRM_TOTAL, CONFIRM_SECS, CONFIRM_MB (set by install.sh).
primitive_time_secs() {
local name="$1" kind
kind="$(primitive_field "$name" kind 2>/dev/null || true)"
case "$kind" in
shell) echo 1 ;;
rust)
case "$name" in
mock-render|kei-migrate|kei-ledger) echo 20 ;;
kei-changelog|firewall-diff) echo 15 ;;
visual-diff|tokens-sync|ssh-check) echo 5 ;;
*) echo 10 ;;
esac
;;
node) echo 2 ;;
*) echo 0 ;;
esac
}
primitive_disk_kb() {
local name="$1" kind
kind="$(primitive_field "$name" kind 2>/dev/null || true)"
case "$kind" in
shell) echo 5 ;;
rust)
case "$name" in
mock-render|kei-migrate|kei-ledger) echo 30000 ;;
kei-changelog|firewall-diff) echo 10000 ;;
visual-diff|tokens-sync|ssh-check) echo 5000 ;;
*) echo 8000 ;;
esac
;;
node) echo 12000 ;;
*) echo 0 ;;
esac
}
# estimate_install — reads newline-separated primitive names from stdin,
# prints "time_secs disk_kb" to stdout.
estimate_install() {
local total_secs=0 total_kb=0 name s d
while IFS= read -r name; do
[ -z "$name" ] && continue
s="$(primitive_time_secs "$name")"
d="$(primitive_disk_kb "$name")"
total_secs=$(( total_secs + s ))
total_kb=$(( total_kb + d ))
done
echo "$total_secs $total_kb"
}
# Consumers-of-tool — list primitives (from $2..$N) whose deps mention $1.
_consumers_of() {
local tool="$1"; shift
local n deps_raw out=""
for n in "$@"; do
deps_raw="$(primitive_field "$n" deps 2>/dev/null || true)"
echo "$deps_raw" | grep -qiE "(^|[^a-zA-Z])${tool}([^a-zA-Z]|$)" \
&& out="${out}${n},"
done
echo "${out%,}"
}
# check_soft_deps — reads newline-separated primitive names from stdin,
# prints one OK/MISS per unique soft-dep tool used by any listed primitive.
check_soft_deps() {
local names_nl
names_nl="$(cat)"
[ -z "$names_nl" ] && return 0
local -a tools=(jq pandoc playwright npx cargo hcloud vultr-cli yq sqlite3 curl)
local -a names_arr=()
local n tool consumers printed_header=0
while IFS= read -r n; do [ -n "$n" ] && names_arr+=("$n"); done <<< "$names_nl"
for tool in "${tools[@]}"; do
consumers="$(_consumers_of "$tool" "${names_arr[@]}")"
[ -z "$consumers" ] && continue
[ "$printed_header" = "0" ] && echo "Soft-dep status:" && printed_header=1
if command -v "$tool" >/dev/null 2>&1; then
echo " [OK] $tool installed"
else
echo " [MISS] $tool missing (needed for: $consumers)"
fi
done
}
# Per-primitive row (helper for print_plan_body). Stdin: newline names.
_print_primitive_rows() {
local name kind extra
while IFS= read -r name; do
[ -z "$name" ] && continue
kind="$(primitive_field "$name" kind 2>/dev/null || echo '?')"
extra="$(primitive_time_secs "$name")s, $(( $(primitive_disk_kb "$name") / 1024 )) MB"
printf ' + %s%-22s%s (%s, ~%s)\n' "${KEI_BLUE:-}" "$name" "${KEI_RST:-}" "$kind" "$extra"
done
}
# print_plan_body — prints "Install Plan" block for given label + names.
# Args: $1 = label, stdin = newline-separated primitive names.
# Sets globals: CONFIRM_TOTAL, CONFIRM_SECS, CONFIRM_MB.
print_plan_body() {
local profile_label="$1"
local names total est_secs est_kb est_mb
names="$(cat)"
total="$(printf '%s\n' "$names" | grep -c . || true)"
read -r est_secs est_kb <<< "$(printf '%s\n' "$names" | estimate_install)"
est_mb=$(( est_kb / 1024 ))
echo
echo "================================"
echo " Install Plan"
echo "================================"
echo
echo "Profile: $profile_label"
echo "Primitives: ${total:-0} to add"
[ "${total:-0}" -gt 0 ] && printf '%s\n' "$names" | _print_primitive_rows
echo
printf '%s\n' "$names" | check_soft_deps || true
echo
printf 'Estimated time: ~%ss\n' "$est_secs"
printf 'Estimated disk: ~%s MB\n' "$est_mb"
echo
CONFIRM_TOTAL="$total"; CONFIRM_SECS="$est_secs"; CONFIRM_MB="$est_mb"
}
# show_confirm_screen — prints plan body, then asks y/N (or whiptail --yesno).
# Stdin: newline-separated primitive names. Returns 0=confirmed, 1=declined.
show_confirm_screen() {
local profile_label="$1"
print_plan_body "$profile_label"
[ "$ASSUME_YES" = "1" ] && { echo "(--yes: auto-confirming)"; return 0; }
[ ! -t 0 ] && { echo "(non-TTY: auto-confirming)"; return 0; }
if command -v whiptail >/dev/null 2>&1; then
whiptail --yesno "Install ${CONFIRM_TOTAL:-0} primitive(s) for profile '$profile_label'?\n\nTime: ~${CONFIRM_SECS}s, disk: ~${CONFIRM_MB} MB" 14 70
return $?
fi
local reply
printf 'Proceed? [Y/n]: '
read -r reply || return 1
case "${reply:-Y}" in
y|Y|yes|YES|'') return 0 ;;
*) return 1 ;;
esac
}