Demo images / Build & push demo images (push) Failing after 2m16s
Keeps the dev and test tooling an outside contributor would want, and takes our node addresses out of it. Scripts that silently defaulted to one of our nodes now require an explicit host and exit 2 without one: smoke-test.sh, trust-archipelago-cert.sh, dev-container-test.sh (which also derives its RPC and health URLs from the SSH target instead of a second hardcoded copy), and image-recipe/dev-branding.sh. A default that points at a machine the user does not own is worse than no default: it fails confusingly, or reaches a stranger's device. Usage examples, mock data and test fixtures move to the RFC 5737 documentation range (192.0.2.0/24). CGNAT test values stay inside 100.64.0.0/10 so the range-check semantics they exercise still hold, and 192.168.1.0/.1/.254 are left alone — those are gateway logic and UI placeholders, not our addresses. Playwright and the perf spec defaulted their baseURL to one of our nodes; they now default to localhost:8100, the local dev server. Removed neode-ui APP_URLS entirely. It is dead code — exported, never imported — and it pinned fedimint's *prod* launch URL to 192.168.1.228:8175. Had anything consumed it, every user's node would have tried to reach an address that on their LAN is either nothing or someone else's machine. Deleting beats sanitizing dead config. Verified: frontend 868/868 vitest across 108 files; archipelago-container 75/75; mesh tests 9/9; audit-secrets 5/5. Zero node addresses and zero node names remain in tracked files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
634 lines
19 KiB
Bash
Executable File
634 lines
19 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ─────────────────────────────────────────────────────────────────
|
|
# Archipelago Install TUI Demo — 80s Hacker Edition
|
|
# Run: bash scripts/install-tui-demo.sh
|
|
# Ctrl+C to exit at any time.
|
|
# ─────────────────────────────────────────────────────────────────
|
|
set -euo pipefail
|
|
|
|
# ── Colors — everything orange unless noted ─────────────────────
|
|
ORANGE=$'\033[38;5;208m'
|
|
ORANGE_DIM=$'\033[38;5;130m'
|
|
ORANGE_BRIGHT=$'\033[38;5;214m'
|
|
ORANGE_GLOW=$'\033[38;5;220m'
|
|
GREEN=$'\033[32m'
|
|
GREEN_DIM=$'\033[38;5;22m'
|
|
GREEN_BRIGHT=$'\033[38;5;46m'
|
|
WHITE=$'\033[1;37m'
|
|
DIM=$'\033[38;5;242m'
|
|
DIMMER=$'\033[38;5;238m'
|
|
DARK=$'\033[38;5;235m'
|
|
NC=$'\033[0m'
|
|
BOLD=$'\033[1m'
|
|
|
|
# ── Terminal setup ──────────────────────────────────────────────
|
|
TW=$(tput cols 2>/dev/null || echo 80)
|
|
TH=$(tput lines 2>/dev/null || echo 24)
|
|
[[ $TW -gt 100 ]] && TW=100
|
|
|
|
BW=56
|
|
[[ $BW -gt $((TW - 4)) ]] && BW=$((TW - 4))
|
|
INNER=$((BW - 2))
|
|
|
|
PAD=$(( (TW - BW) / 2 ))
|
|
[[ $PAD -lt 0 ]] && PAD=0
|
|
PADS=$(printf "%*s" "$PAD" "")
|
|
|
|
LOGO_W=43
|
|
LOGO_PAD=$(( (TW - LOGO_W) / 2 ))
|
|
[[ $LOGO_PAD -lt 0 ]] && LOGO_PAD=0
|
|
LOGO_PADS=$(printf "%*s" "$LOGO_PAD" "")
|
|
|
|
cleanup() {
|
|
tput cnorm 2>/dev/null
|
|
tput sgr0 2>/dev/null
|
|
echo ""
|
|
}
|
|
trap cleanup EXIT INT TERM
|
|
|
|
# ── Primitives ──────────────────────────────────────────────────
|
|
hide_cursor() { tput civis 2>/dev/null || true; }
|
|
show_cursor() { tput cnorm 2>/dev/null || true; }
|
|
goto() { printf "\033[%d;%dH" "$1" "$2"; }
|
|
clear_line() { printf "\033[K"; }
|
|
p() { printf "%s%b\n" "$PADS" "$1"; }
|
|
pn() { printf "%s%b" "$PADS" "$1"; }
|
|
|
|
hrule() {
|
|
local len=$((INNER < 50 ? INNER : 50))
|
|
local hr=""
|
|
for _ in $(seq 1 "$len"); do hr="${hr}*"; done
|
|
p "${ORANGE_DIM}${hr}${NC}"
|
|
}
|
|
|
|
# ── Hacker glyphs ──────────────────────────────────────────────
|
|
HEXCHARS='0123456789abcdef'
|
|
SPIN_FRAMES='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
|
|
|
|
rand_hex() {
|
|
local len="${1:-8}" out=""
|
|
for _ in $(seq 1 "$len"); do
|
|
out="${out}${HEXCHARS:RANDOM % 16:1}"
|
|
done
|
|
echo -n "$out"
|
|
}
|
|
|
|
# ── Boot scan effect ───────────────────────────────────────────
|
|
boot_scan() {
|
|
clear
|
|
hide_cursor
|
|
|
|
local messages=(
|
|
"POST: memory check ............ 16384MB OK"
|
|
"BIOS: AES-NI .................. detected"
|
|
"UEFI: secure boot ............. disabled"
|
|
"SATA: TOSHIBA MQ01ACF0 ........ 465.8G"
|
|
"USB: boot media .............. verified"
|
|
"NET: interface enp0s31f6 ...... link up"
|
|
"INIT: loading archipelago ....."
|
|
)
|
|
|
|
for i in $(seq 1 8); do
|
|
local addr data
|
|
addr=$(rand_hex 8)
|
|
data=$(rand_hex 32)
|
|
goto $i 1
|
|
printf "%s%b0x%s %s%b" "$PADS" "$DARK" "$addr" "$data" "$NC"
|
|
sleep 0.02
|
|
done
|
|
|
|
local row=3
|
|
for msg in "${messages[@]}"; do
|
|
goto $row 1; clear_line
|
|
pn "${ORANGE_DIM}"
|
|
local i=0
|
|
while [[ $i -lt ${#msg} ]]; do
|
|
printf "%s" "${msg:$i:1}"
|
|
i=$((i + 1))
|
|
if [[ "${msg:$i:1}" == "." ]]; then sleep 0.005; else sleep 0.012; fi
|
|
done
|
|
printf "%b\n" "$NC"
|
|
row=$((row + 1))
|
|
sleep 0.05
|
|
done
|
|
|
|
sleep 0.3
|
|
for r in $(seq 1 $((row + 2))); do goto $r 1; clear_line; done
|
|
sleep 0.2
|
|
}
|
|
|
|
# ── ASCII Logo: A R C H I P E L A G O ─────────────────────────
|
|
# 43 chars wide, 3 lines tall. Correct spelling!
|
|
|
|
LOGO_FRONT=(
|
|
'▄▀█ █▀▄ █▀▀ █ █ █ █▀█ █▀▀ █ ▄▀█ █▀▀ █▀█'
|
|
'█▀█ █▀▄ █ █▀█ █ █▀▀ ██▀ █ █▀█ █ █ █ █'
|
|
'▀ ▀ ▀ ▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀'
|
|
)
|
|
|
|
# 3D shadow: draw shadow (dark, offset +1,+2) then front on top
|
|
draw_logo_3d_at() {
|
|
local row="$1" color="${2:-$ORANGE}"
|
|
local front_col=$((LOGO_PAD + 1))
|
|
local shadow_col=$((LOGO_PAD + 3))
|
|
|
|
for li in 0 1 2; do
|
|
goto $((row + li + 1)) "$shadow_col"
|
|
printf "%b%s%b" "$DARK" "${LOGO_FRONT[$li]}" "$NC"
|
|
done
|
|
for li in 0 1 2; do
|
|
goto $((row + li)) "$front_col"
|
|
printf "%b%s%b" "$color" "${LOGO_FRONT[$li]}" "$NC"
|
|
done
|
|
}
|
|
|
|
draw_logo_flat() {
|
|
for line in "${LOGO_FRONT[@]}"; do
|
|
printf "%s%b%s%b\n" "$LOGO_PADS" "${1:-$ORANGE}" "$line" "$NC"
|
|
done
|
|
}
|
|
|
|
# Decrypt reveal with 3D shadow
|
|
logo_decrypt_reveal() {
|
|
local row="$1"
|
|
local iterations=7
|
|
local scramble_chars='█▓▒░╳◆▀▄▌▐┃━╋╬╪'
|
|
local front_col=$((LOGO_PAD + 1))
|
|
local shadow_col=$((LOGO_PAD + 3))
|
|
|
|
# Draw shadow layer first (static, dark)
|
|
for li in 0 1 2; do
|
|
goto $((row + li + 1)) "$shadow_col"
|
|
printf "%b%s%b" "$DARK" "${LOGO_FRONT[$li]}" "$NC"
|
|
done
|
|
|
|
# Decrypt front layer
|
|
for iter in $(seq 1 "$iterations"); do
|
|
for li in 0 1 2; do
|
|
local real="${LOGO_FRONT[$li]}"
|
|
local out=""
|
|
local len=${#real}
|
|
local resolve=$(( iter * len / iterations ))
|
|
local ci=0
|
|
while [[ $ci -lt $len ]]; do
|
|
local ch="${real:$ci:1}"
|
|
if [[ $ci -lt $resolve ]]; then
|
|
out="${out}${ch}"
|
|
elif [[ "$ch" == " " ]]; then
|
|
out="${out} "
|
|
else
|
|
out="${out}${scramble_chars:RANDOM % ${#scramble_chars}:1}"
|
|
fi
|
|
ci=$((ci + 1))
|
|
done
|
|
|
|
local color="$DARK"
|
|
case $iter in
|
|
1) color="$DARK" ;; 2) color="$DIMMER" ;; 3) color="$DIM" ;;
|
|
4) color="$ORANGE_DIM" ;; 5) color="$ORANGE_DIM" ;;
|
|
6) color="$ORANGE" ;; 7) color="$ORANGE" ;;
|
|
esac
|
|
|
|
goto $((row + li)) "$front_col"
|
|
printf "%b%s%b" "$color" "$out" "$NC"
|
|
done
|
|
sleep 0.07
|
|
done
|
|
|
|
# Glow pulse
|
|
for color in "$ORANGE_BRIGHT" "$ORANGE_GLOW" "$ORANGE_BRIGHT" "$ORANGE"; do
|
|
for li in 0 1 2; do
|
|
goto $((row + li)) "$front_col"
|
|
printf "\033[K%b%s%b" "$color" "${LOGO_FRONT[$li]}" "$NC"
|
|
done
|
|
sleep 0.05
|
|
done
|
|
}
|
|
|
|
# Quick glow pulse on existing logo
|
|
logo_glow_pulse() {
|
|
local row="$1" cycles="${2:-2}"
|
|
local col=$((LOGO_PAD + 1))
|
|
for _ in $(seq 1 "$cycles"); do
|
|
for color in "$ORANGE" "$ORANGE_BRIGHT" "$ORANGE_GLOW" "$ORANGE_BRIGHT" "$ORANGE"; do
|
|
for li in 0 1 2; do
|
|
goto $((row + li)) "$col"
|
|
printf "\033[K%b%s%b" "$color" "${LOGO_FRONT[$li]}" "$NC"
|
|
done
|
|
sleep 0.04
|
|
done
|
|
done
|
|
}
|
|
|
|
# Celebration: logo strobes with color party
|
|
logo_celebrate() {
|
|
local row="$1"
|
|
local col=$((LOGO_PAD + 1))
|
|
local party_colors=("$ORANGE" "$ORANGE_GLOW" "$WHITE" "$ORANGE_BRIGHT" "$GREEN_BRIGHT" "$ORANGE_GLOW" "$ORANGE")
|
|
for color in "${party_colors[@]}"; do
|
|
for li in 0 1 2; do
|
|
goto $((row + li)) "$col"
|
|
printf "\033[K%b%s%b" "$color" "${LOGO_FRONT[$li]}" "$NC"
|
|
done
|
|
sleep 0.06
|
|
done
|
|
}
|
|
|
|
# Screen wipe transition
|
|
screen_transition() {
|
|
for r in $(seq 1 "$TH"); do
|
|
goto "$r" 1
|
|
printf "%b%*s%b" "$ORANGE_DIM" "$TW" "" "$NC"
|
|
sleep 0.005
|
|
done
|
|
sleep 0.05
|
|
clear
|
|
}
|
|
|
|
# CRT power-on scan line
|
|
crt_on() {
|
|
hide_cursor; clear
|
|
for r in $(seq 1 "$TH"); do
|
|
goto "$r" 1
|
|
printf "%b%*s%b" "$ORANGE_DIM" "$TW" "" "$NC"
|
|
if [[ $r -gt 1 ]]; then goto $((r - 1)) 1; clear_line; fi
|
|
sleep 0.008
|
|
done
|
|
goto "$TH" 1; clear_line
|
|
sleep 0.1; clear
|
|
}
|
|
|
|
# ── Phase data ─────────────────────────────────────────────────
|
|
PHASE_NAMES=(
|
|
"Checking tools"
|
|
"Detecting disks"
|
|
"Creating partitions"
|
|
"Formatting partitions"
|
|
"Installing base system"
|
|
"Encrypting data partition"
|
|
"Installing bootloader"
|
|
)
|
|
PHASE_DETAILS=(
|
|
"parted, mkfs, cryptsetup"
|
|
"/dev/sda (465.8G) — TOSHIBA MQ01ACF0"
|
|
"BIOS boot + EFI + root + data"
|
|
"FAT32, ext4, LUKS2"
|
|
"debootstrap → Debian 13 minimal"
|
|
"AES-256-XTS (AES-NI detected)"
|
|
"GRUB: BIOS + UEFI hybrid"
|
|
)
|
|
PHASE_DURATIONS=(8 6 12 10 40 15 10)
|
|
|
|
# ── Header (logo + right-aligned subtitle) ────────────────────
|
|
# "bitcoin node os" right-aligned to match logo's right edge
|
|
SUBTITLE_PAD=$(printf "%*s" $((LOGO_PAD + LOGO_W - 15)) "")
|
|
HEADER_LINES=6 # 3 logo + shadow row + subtitle + blank
|
|
|
|
draw_header() {
|
|
draw_logo_flat
|
|
printf "%s%b%s%b\n" "$SUBTITLE_PAD" "$ORANGE_DIM" "bitcoin node os" "$NC"
|
|
p ""
|
|
}
|
|
|
|
draw_header_3d() {
|
|
local start_row="$1"
|
|
local logo_row=$((start_row))
|
|
# Blank for logo + shadow + subtitle
|
|
goto "$start_row" 1
|
|
for _ in $(seq 1 5); do p ""; done
|
|
printf "%s%b%s%b\n" "$SUBTITLE_PAD" "$ORANGE_DIM" "bitcoin node os" "$NC"
|
|
|
|
sleep 0.15
|
|
logo_decrypt_reveal "$logo_row"
|
|
}
|
|
|
|
# ── Phase drawing (all orange) ─────────────────────────────────
|
|
draw_phase_pending() {
|
|
p " ${DIMMER}[${1}/7] ${PHASE_NAMES[$(($1-1))]}${NC}"
|
|
}
|
|
|
|
draw_phase_running() {
|
|
p " ${ORANGE}[${1}/7] ${PHASE_NAMES[$(($1-1))]}${NC} ${ORANGE_BRIGHT}◐${NC}"
|
|
}
|
|
|
|
draw_phase_done() {
|
|
local name="${PHASE_NAMES[$(($1-1))]}"
|
|
local dot_count=$((34 - ${#name}))
|
|
[[ $dot_count -lt 2 ]] && dot_count=2
|
|
local dots=""
|
|
for _ in $(seq 1 "$dot_count"); do dots="${dots}."; done
|
|
p " ${ORANGE_DIM}[${1}/7] ${name} ${DARK}${dots}${NC} ${ORANGE_BRIGHT}✓${NC}"
|
|
}
|
|
|
|
draw_phase_done_compact() {
|
|
p " ${ORANGE_DIM}[${1}/7] ${PHASE_NAMES[$(($1-1))]}${NC} ${ORANGE_BRIGHT}✓${NC}"
|
|
}
|
|
|
|
simulate_work() {
|
|
local ticks=$1 row=$2 phase=$3 fi=0
|
|
local col=$((PAD + 2 + 10 + ${#PHASE_NAMES[$((phase-1))]} + 2))
|
|
for _ in $(seq 1 "$ticks"); do
|
|
goto "$row" "$col"
|
|
printf "%b%s%b" "$ORANGE" "${SPIN_FRAMES:fi%10:1}" "$NC"
|
|
fi=$((fi + 1))
|
|
sleep 0.1
|
|
done
|
|
}
|
|
|
|
simulate_work_with_bar() {
|
|
local ticks=$1 row=$2 phase=$3 bar_row=$4 fi=0
|
|
local col=$((PAD + 2 + 10 + ${#PHASE_NAMES[$((phase-1))]} + 2))
|
|
local bar_width=36
|
|
|
|
# Bouncing ₿ — DVD screensaver style
|
|
local b_row=$((bar_row + 3)) b_col=$((PAD + 4))
|
|
local b_dr=1 b_dc=1
|
|
local b_min_row=$((bar_row + 3))
|
|
local b_max_row=$((TH - 2))
|
|
[[ $b_max_row -lt $((b_min_row + 3)) ]] && b_max_row=$((b_min_row + 3))
|
|
local b_min_col=$((PAD + 2))
|
|
local b_max_col=$((PAD + BW - 2))
|
|
local b_colors=("$ORANGE" "$ORANGE_BRIGHT" "$ORANGE_GLOW" "$ORANGE_DIM" "$WHITE")
|
|
local b_ci=0
|
|
local b_prev_row=$b_row b_prev_col=$b_col
|
|
|
|
for t in $(seq 1 "$ticks"); do
|
|
goto "$row" "$col"
|
|
printf "%b%s%b" "$ORANGE" "${SPIN_FRAMES:fi%10:1}" "$NC"
|
|
fi=$((fi + 1))
|
|
|
|
local pct=$(( t * 100 / ticks ))
|
|
local filled=$(( pct * bar_width / 100 ))
|
|
local empty=$(( bar_width - filled ))
|
|
local bar_f="" bar_e=""
|
|
for _ in $(seq 1 "$filled" 2>/dev/null); do bar_f="${bar_f}█"; done
|
|
for _ in $(seq 1 "$empty" 2>/dev/null); do bar_e="${bar_e}░"; done
|
|
|
|
goto "$bar_row" 1; clear_line
|
|
p " ${ORANGE}${bar_f}${DARK}${bar_e}${NC} ${ORANGE_DIM}${pct}%%${NC}"
|
|
|
|
goto "$b_prev_row" "$b_prev_col"; printf " "
|
|
|
|
b_row=$((b_row + b_dr)); b_col=$((b_col + b_dc))
|
|
|
|
if [[ $b_row -ge $b_max_row ]] || [[ $b_row -le $b_min_row ]]; then
|
|
b_dr=$(( -b_dr )); b_row=$((b_row + b_dr))
|
|
b_ci=$(( (b_ci + 1) % ${#b_colors[@]} ))
|
|
fi
|
|
if [[ $b_col -ge $b_max_col ]] || [[ $b_col -le $b_min_col ]]; then
|
|
b_dc=$(( -b_dc )); b_col=$((b_col + b_dc))
|
|
b_ci=$(( (b_ci + 1) % ${#b_colors[@]} ))
|
|
fi
|
|
|
|
goto "$b_row" "$b_col"
|
|
printf "%b₿%b" "${b_colors[$b_ci]}" "$NC"
|
|
b_prev_row=$b_row; b_prev_col=$b_col
|
|
|
|
sleep 0.1
|
|
done
|
|
|
|
goto "$b_prev_row" "$b_prev_col"; printf " "
|
|
goto "$bar_row" 1; clear_line
|
|
for r in $(seq "$b_min_row" "$b_max_row"); do goto "$r" 1; clear_line; done
|
|
}
|
|
|
|
typewrite() {
|
|
local text="$1" delay="${2:-0.025}"
|
|
pn "${ORANGE}"
|
|
local i=0
|
|
while [[ $i -lt ${#text} ]]; do
|
|
printf "%s" "${text:$i:1}"
|
|
i=$((i + 1))
|
|
sleep "$delay"
|
|
done
|
|
printf "%b\n" "$NC"
|
|
}
|
|
|
|
# ── SCREEN 1: Welcome ─────────────────────────────────────────
|
|
screen_welcome() {
|
|
crt_on
|
|
boot_scan
|
|
|
|
clear
|
|
hide_cursor
|
|
|
|
local start_row=$(( (TH - 16) / 2 ))
|
|
[[ $start_row -lt 2 ]] && start_row=2
|
|
|
|
draw_header_3d "$start_row"
|
|
|
|
local prompt_row=$((start_row + HEADER_LINES + 2))
|
|
goto "$prompt_row" 1
|
|
local prompt_text=" Press Enter to install │ Ctrl+C for shell"
|
|
pn "${ORANGE_DIM}"
|
|
local i=0
|
|
while [[ $i -lt ${#prompt_text} ]]; do
|
|
printf "%s" "${prompt_text:$i:1}"
|
|
i=$((i + 1))
|
|
sleep 0.018
|
|
done
|
|
printf "%b" "$NC"
|
|
|
|
# Logo breathing while cursor blinks
|
|
local logo_at=$((start_row + 1))
|
|
local front_col=$((LOGO_PAD + 1))
|
|
for _ in $(seq 1 3); do
|
|
goto "$prompt_row" $((PAD + ${#prompt_text} + 2))
|
|
printf "%b▌%b" "$ORANGE" "$NC"
|
|
for li in 0 1 2; do
|
|
goto $((logo_at + li)) "$front_col"
|
|
printf "\033[K%b%s%b" "$ORANGE_BRIGHT" "${LOGO_FRONT[$li]}" "$NC"
|
|
done
|
|
sleep 0.4
|
|
goto "$prompt_row" $((PAD + ${#prompt_text} + 2))
|
|
printf " "
|
|
for li in 0 1 2; do
|
|
goto $((logo_at + li)) "$front_col"
|
|
printf "\033[K%b%s%b" "$ORANGE" "${LOGO_FRONT[$li]}" "$NC"
|
|
done
|
|
sleep 0.4
|
|
done
|
|
}
|
|
|
|
# ── SCREEN 2: Disk Detection ──────────────────────────────────
|
|
screen_disk_detect() {
|
|
screen_transition
|
|
hide_cursor
|
|
|
|
local row=2
|
|
goto $row 1
|
|
draw_header
|
|
row=$((row + HEADER_LINES))
|
|
|
|
goto $row 1
|
|
draw_phase_running 1
|
|
simulate_work 8 $row 1
|
|
goto $row 1; draw_phase_done 1
|
|
row=$((row + 2))
|
|
|
|
goto $row 1
|
|
draw_phase_running 2
|
|
simulate_work 6 $row 2
|
|
goto $row 1; draw_phase_done 2
|
|
row=$((row + 2))
|
|
|
|
goto $row 1
|
|
typewrite " Found: /dev/sda (465.8G) — TOSHIBA MQ01ACF0" 0.02
|
|
row=$((row + 2))
|
|
|
|
goto $row 1; hrule; row=$((row + 2))
|
|
|
|
goto $row 1
|
|
p "${ORANGE} ⚠ All data on /dev/sda will be erased.${NC}"
|
|
row=$((row + 2))
|
|
|
|
goto $row 1
|
|
p "${ORANGE_DIM} Press Enter to install │ Ctrl+C to cancel${NC}"
|
|
|
|
for _ in $(seq 1 4); do
|
|
goto $row $((PAD + 49))
|
|
printf "%b▌%b" "$ORANGE" "$NC"
|
|
sleep 0.4
|
|
goto $row $((PAD + 49))
|
|
printf " "
|
|
sleep 0.4
|
|
done
|
|
}
|
|
|
|
# ── SCREEN 3: Installation ────────────────────────────────────
|
|
screen_install() {
|
|
screen_transition
|
|
hide_cursor
|
|
|
|
local row=2
|
|
goto $row 1
|
|
draw_header
|
|
local phase_start=$((row + HEADER_LINES))
|
|
|
|
for i in $(seq 0 6); do
|
|
goto $((phase_start + i * 2)) 1
|
|
draw_phase_pending $((i + 1))
|
|
done
|
|
|
|
local bar_row=$((phase_start + 14 + 1))
|
|
goto $bar_row 1; hrule
|
|
local status_row=$((bar_row + 2))
|
|
|
|
for i in $(seq 0 6); do
|
|
local pr=$((phase_start + i * 2))
|
|
local pnum=$((i + 1))
|
|
local dur=${PHASE_DURATIONS[$i]}
|
|
|
|
goto $pr 1; clear_line
|
|
draw_phase_running $pnum
|
|
|
|
goto $status_row 1; clear_line
|
|
p " ${ORANGE_DIM}${PHASE_DETAILS[$i]}${NC}"
|
|
|
|
if [[ $dur -gt 15 ]]; then
|
|
simulate_work_with_bar "$dur" "$pr" "$pnum" "$((status_row - 1))"
|
|
else
|
|
simulate_work "$dur" "$pr" "$pnum"
|
|
fi
|
|
|
|
goto $pr 1; clear_line
|
|
draw_phase_done $pnum
|
|
done
|
|
|
|
goto $((bar_row + 1)) 1; clear_line
|
|
goto $status_row 1; clear_line
|
|
|
|
logo_glow_pulse 3 2
|
|
sleep 0.3
|
|
}
|
|
|
|
# ── SCREEN 4: Complete ─────────────────────────────────────────
|
|
screen_complete() {
|
|
screen_transition
|
|
hide_cursor
|
|
|
|
local row=2
|
|
goto $row 1
|
|
draw_header
|
|
logo_celebrate 3
|
|
row=$((row + HEADER_LINES))
|
|
|
|
for i in $(seq 1 7); do
|
|
goto $row 1
|
|
draw_phase_done_compact $i
|
|
row=$((row + 1))
|
|
done
|
|
|
|
row=$((row + 1))
|
|
goto $row 1; hrule; row=$((row + 2))
|
|
|
|
# Success flash
|
|
for color in "$ORANGE_DIM" "$ORANGE" "$ORANGE_BRIGHT" "$ORANGE"; do
|
|
goto $row 1; clear_line
|
|
p " ${color}✓ Installation Complete${NC}"
|
|
sleep 0.06
|
|
done
|
|
row=$((row + 2))
|
|
|
|
goto $row 1
|
|
typewrite " After reboot, access from any device:" 0.02
|
|
row=$((row + 2))
|
|
|
|
# URL in orange
|
|
goto $row 1
|
|
p " ${ORANGE}http://192.0.2.11${NC}"
|
|
row=$((row + 2))
|
|
|
|
# Credentials — white, NOT orange (user request)
|
|
goto $row 1
|
|
p " ${WHITE}SSH ssh archipelago@192.0.2.11${NC}"
|
|
row=$((row + 1))
|
|
goto $row 1
|
|
p " ${WHITE}Password archipelago${NC}"
|
|
row=$((row + 1))
|
|
goto $row 1
|
|
p " ${WHITE}Web Login password123${NC}"
|
|
row=$((row + 2))
|
|
|
|
goto $row 1; hrule; row=$((row + 2))
|
|
|
|
for _ in $(seq 1 5); do
|
|
goto $row 1; clear_line
|
|
p "${ORANGE}${BOLD} >>> REMOVE THE USB DRIVE NOW <<<${NC}"
|
|
sleep 0.5
|
|
goto $row 1; clear_line
|
|
p "${ORANGE_DIM} >>> REMOVE THE USB DRIVE NOW <<<${NC}"
|
|
sleep 0.5
|
|
done
|
|
goto $row 1; clear_line
|
|
p "${ORANGE}${BOLD} >>> REMOVE THE USB DRIVE NOW <<<${NC}"
|
|
|
|
goto $((row + 2)) 1
|
|
p "${ORANGE_DIM} Press Enter to reboot${NC}"
|
|
sleep 3
|
|
}
|
|
|
|
# ── Main ───────────────────────────────────────────────────────
|
|
main() {
|
|
echo ""
|
|
echo " ${ORANGE}▌${NC} ${ORANGE}Archipelago Install TUI Demo${NC}"
|
|
echo " ${ORANGE_DIM} Each screen auto-advances. Ctrl+C to exit.${NC}"
|
|
echo ""
|
|
sleep 2
|
|
|
|
screen_welcome
|
|
sleep 0.3
|
|
screen_disk_detect
|
|
sleep 0.3
|
|
screen_install
|
|
sleep 0.3
|
|
screen_complete
|
|
|
|
show_cursor
|
|
echo ""
|
|
p "${ORANGE_DIM}** Demo complete **${NC}"
|
|
echo ""
|
|
}
|
|
|
|
main "$@"
|