Add CE OS Alpine installer v0.0.1 — Tier 0/1/2 dev scaffold

Staged installer set for Alpine Linux x86-64 (tinkerpad/ThinkPad T480).
Covers Base (Tier 0), Minimal (Tier 1), and Basic (Tier 2) tiers with
full phased structure, per-package error capture, and re-runnable test suites.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
John A. Hoeven 2026-06-10 02:25:38 +02:00
commit a194c14077
32 changed files with 1748 additions and 0 deletions

10
.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
# CE OS Alpine Installer — .gitignore
# macOS
.DS_Store
# Logs (generated at runtime on target machines)
*.log
# Temp files from 11_wiki.sh glow download
/tmp/ce-glow-*/

89
bootstrap.sh Normal file
View file

@ -0,0 +1,89 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# bootstrap.sh
# Served at: http://192.168.0.138/repo/scripts/alpine-ceos-installer/bootstrap.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Run this on tinkerpad to download the full CE OS installer from workbench.
# Usage: wget http://192.168.0.138/repo/scripts/alpine-ceos-installer/bootstrap.sh
# bash bootstrap.sh
#
# TODO — Forgejo: when git.jahnet.lan is deployed, replace the wget block
# below with these three lines and delete the rest of this file:
# doas apk add git
# git clone -b dev http://git.jahnet.lan/john/ceos-alpine-installer.git
# cd ceos-alpine-installer && bash ce-install.sh
# ---------------------------------------------------------------------------
BASE="http://192.168.0.138/repo/scripts/alpine-ceos-installer"
DEST="/tmp/ceos-installer-$(date +%Y%m%d%H%M%S)"
echo "CE OS Alpine Installer — Bootstrap"
echo "==================================="
echo "Source: ${BASE}"
echo "Dest: ${DEST}"
echo ""
mkdir -p \
"${DEST}/lib/base" \
"${DEST}/lib/minimal" \
"${DEST}/lib/basic" \
"${DEST}/tests"
fetch() {
local path="${1}"
if wget -q -O "${DEST}/${path}" "${BASE}/${path}"; then
echo " OK ${path}"
else
echo " ERR ${path}" >&2
echo "Bootstrap failed: could not fetch ${path}" >&2
exit 1
fi
}
echo "Fetching orchestrators..."
fetch "ce-install.sh"
fetch "ce-base.sh"
fetch "ce-minimal.sh"
fetch "ce-basic.sh"
echo "Fetching library..."
fetch "lib/ce-common.sh"
fetch "lib/base/01_core.sh"
fetch "lib/base/02_doas.sh"
echo "Fetching Tier 1 — Minimal..."
for n in 01_shell 02_terminal 03_files 04_vcs 05_systools \
06_comms 07_journal 08_web 09_network 10_record \
11_wiki 12_access; do
fetch "lib/minimal/${n}.sh"
done
echo "Fetching Tier 2 — Basic..."
for n in 01_comms 02_monitor 03_gui 04_media 05_fonts 06_utils; do
fetch "lib/basic/${n}.sh"
done
echo "Fetching tests..."
for t in test_base test_minimal test_basic; do
fetch "tests/${t}.sh"
done
find "${DEST}" -name "*.sh" -exec chmod +x {} \;
echo ""
echo "Bootstrap complete."
echo ""
echo "To install:"
echo " cd ${DEST}"
echo " bash ce-install.sh # full stack (Tier 0 + 1 + 2)"
echo " bash ce-base.sh # Tier 0 only"
echo " bash ce-minimal.sh # Tier 1 only (requires Tier 0)"
echo " bash ce-basic.sh # Tier 2 only (requires Tier 1)"
echo ""
echo "To run tests after install:"
echo " bash ${DEST}/tests/test_base.sh"
echo " bash ${DEST}/tests/test_minimal.sh"
echo " bash ${DEST}/tests/test_basic.sh"

76
ce-base.sh Normal file
View file

@ -0,0 +1,76 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# ce-base.sh
# ~/projects/ceos/alpine-installer/ce-base.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Tier 0 — Base. Prerequisites common to all hardware.
# Standalone-runnable. Sources lib/ce-common.sh and lib/base/*.sh.
# ---------------------------------------------------------------------------
SCRIPT_NAME="ce-base"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib/ce-common.sh" \
|| { echo "ERROR: lib/ce-common.sh not found"; exit 1; }
source "${SCRIPT_DIR}/lib/base/01_core.sh" \
|| { log_error "lib/base/01_core.sh not found"; exit 1; }
source "${SCRIPT_DIR}/lib/base/02_doas.sh" \
|| { log_error "lib/base/02_doas.sh not found"; exit 1; }
cleanup() {
local exit_code="${?}"
log_info "Running cleanup..."
doas apk cache clean >> "${LOG_FILE}" 2>&1 || true
doas rm -rf /var/cache/apk/* >> "${LOG_FILE}" 2>&1 || true
log_info "Cleanup complete (exit code: ${exit_code})"
}
trap cleanup EXIT INT TERM HUP
phase_preflight() {
log_info "=== TIER 0: PRE-FLIGHT ==="
check_not_root
run_test "bash >= 4" '[[ "${BASH_VERSINFO[0]}" -ge 4 ]]' fail
run_test "arch detected" '[[ -n "${ARCH}" ]]' fail
run_test "apk available" 'command -v apk >/dev/null 2>&1' fail
run_test "disk >= 500MB" '[[ $(df / --output=avail | tail -1) -ge 512000 ]]' warn
run_test "internet reachable" \
'curl --silent --max-time 10 --output /dev/null https://dl-cdn.alpinelinux.org' warn
log_info "Arch: ${ARCH}"
log_info "Pre-flight complete"
}
phase_install() {
log_info "=== TIER 0: INSTALL ==="
doas apk update >> "${LOG_FILE}" 2>&1 \
&& doas apk upgrade >> "${LOG_FILE}" 2>&1 \
|| { log_error "apk update/upgrade failed"; exit 1; }
run_test "apk functional post-update" \
'apk search bash 2>/dev/null | grep -q "^bash"' fail
install_base_core
install_base_doas
}
phase_verify() {
log_info "=== TIER 0: VERIFY ==="
run_test "bash present" 'command -v bash >/dev/null 2>&1' warn
run_test "curl present" 'command -v curl >/dev/null 2>&1' warn
run_test "ssh present" 'command -v ssh >/dev/null 2>&1' warn
run_test "doas present" 'command -v doas >/dev/null 2>&1' warn
run_test "doas wheel.conf" '[[ -f /etc/doas.d/wheel.conf ]]' warn
run_test "community repo live" 'grep -q "^[^#].*community" /etc/apk/repositories' warn
log_info "Tier 0 verify complete"
}
log_info "=== CE OS INSTALLER — TIER 0: BASE ==="
log_info "Arch: ${ARCH} | Log: ${LOG_FILE}"
phase_preflight
confirm_proceed
phase_install
phase_verify
print_summary
log_info "=== TIER 0 COMPLETE ==="

83
ce-basic.sh Normal file
View file

@ -0,0 +1,83 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# ce-basic.sh
# ~/projects/ceos/alpine-installer/ce-basic.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Tier 2 — Basic. Daily-use additions on top of Minimal.
# Standalone-runnable. Sources lib/ce-common.sh and lib/basic/*.sh.
# ---------------------------------------------------------------------------
SCRIPT_NAME="ce-basic"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib/ce-common.sh" \
|| { echo "ERROR: lib/ce-common.sh not found"; exit 1; }
for _sub in "${SCRIPT_DIR}"/lib/basic/*.sh; do
source "${_sub}" || { log_error "Failed to source: ${_sub}"; exit 1; }
done
unset _sub
cleanup() {
local exit_code="${?}"
log_info "Running cleanup..."
doas apk cache clean >> "${LOG_FILE}" 2>&1 || true
doas rm -rf /var/cache/apk/* >> "${LOG_FILE}" 2>&1 || true
log_info "Cleanup complete (exit code: ${exit_code})"
}
trap cleanup EXIT INT TERM HUP
phase_preflight() {
log_info "=== TIER 2: PRE-FLIGHT ==="
check_not_root
run_test "bash >= 4" '[[ "${BASH_VERSINFO[0]}" -ge 4 ]]' fail
run_test "arch detected" '[[ -n "${ARCH}" ]]' fail
run_test "doas present" 'command -v doas >/dev/null 2>&1' fail
run_test "Tier 1 complete" 'command -v tmux >/dev/null 2>&1' fail
run_test "community repo enabled" 'grep -q "^[^#].*community" /etc/apk/repositories' fail
run_test "internet reachable" \
'curl --silent --max-time 10 --output /dev/null https://dl-cdn.alpinelinux.org' warn
run_test "disk >= 2GB" '[[ $(df / --output=avail | tail -1) -ge 2097152 ]]' warn
log_info "Arch: ${ARCH}"
log_info "Pre-flight complete"
}
phase_install() {
log_info "=== TIER 2: INSTALL ==="
doas apk update >> "${LOG_FILE}" 2>&1 \
&& doas apk upgrade >> "${LOG_FILE}" 2>&1 \
|| { log_error "apk update/upgrade failed"; exit 1; }
run_test "apk functional" 'apk search jq 2>/dev/null | grep -q "^jq"' fail
install_basic_comms
install_basic_monitor
install_basic_gui
install_basic_media
install_basic_fonts
install_basic_utils
}
phase_verify() {
log_info "=== TIER 2: VERIFY ==="
local tools=(jq bc zip unzip ffmpeg mpv cmus figlet)
for tool in "${tools[@]}"; do
run_test "${tool} present" "command -v ${tool} >/dev/null 2>&1" warn
done
run_test "cagebreak present" 'command -v cagebreak >/dev/null 2>&1' warn
run_test "firefox present" 'command -v firefox >/dev/null 2>&1' warn
log_info "Tier 2 verify complete"
}
log_info "=== CE OS INSTALLER — TIER 2: BASIC ==="
log_info "Arch: ${ARCH} | Log: ${LOG_FILE}"
phase_preflight
confirm_proceed
phase_install
phase_verify
print_summary
log_info "=== TIER 2 COMPLETE ==="

63
ce-install.sh Normal file
View file

@ -0,0 +1,63 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# ce-install.sh
# ~/projects/ceos/alpine-installer/ce-install.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Top-level orchestrator. Runs Tier 0 → 1 → 2 in sequence.
# Stops if any tier exits non-zero. One confirmation prompt for all tiers.
# ---------------------------------------------------------------------------
SCRIPT_NAME="ce-install"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib/ce-common.sh" \
|| { echo "ERROR: lib/ce-common.sh not found"; exit 1; }
check_not_root
TIERS_COMPLETED=()
TIERS_FAILED=()
print_final_summary() {
log_info "=== FULL INSTALL SUMMARY ==="
log_info "Completed: ${TIERS_COMPLETED[*]:-none}"
if [[ ${#TIERS_FAILED[@]} -gt 0 ]]; then
log_warn "Failed: ${TIERS_FAILED[*]}"
fi
log_info "Full log: ${LOG_FILE}"
log_info "Per-tier logs: ${LOG_DIR}/ce-base-*.log, ce-minimal-*.log, ce-basic-*.log"
}
run_tier() {
local name="${1}" script="${2}"
log_info "--- Starting ${name} ---"
if CE_INSTALL_NO_CONFIRM=1 bash "${script}"; then
TIERS_COMPLETED+=("${name}")
log_info "--- ${name} complete ---"
else
TIERS_FAILED+=("${name}")
log_error "--- ${name} FAILED — stopping ---"
print_final_summary
exit 1
fi
}
log_info "=== CE OS INSTALLER — FULL STACK ==="
log_info "Arch: ${ARCH} | Log: ${LOG_FILE}"
log_info ""
log_info " Tier 0 — Base : prerequisites, SSH, doas"
log_info " Tier 1 — Minimal : full TUI workstation"
log_info " Tier 2 — Basic : daily-use additions + GUI"
log_info ""
confirm_proceed
run_tier "Tier 0 — Base" "${SCRIPT_DIR}/ce-base.sh"
run_tier "Tier 1 — Minimal" "${SCRIPT_DIR}/ce-minimal.sh"
run_tier "Tier 2 — Basic" "${SCRIPT_DIR}/ce-basic.sh"
print_final_summary
log_info "=== INSTALL COMPLETE ==="

89
ce-minimal.sh Normal file
View file

@ -0,0 +1,89 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# ce-minimal.sh
# ~/projects/ceos/alpine-installer/ce-minimal.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Tier 1 — Minimal. Full TUI workstation on top of Base.
# Standalone-runnable. Sources lib/ce-common.sh and lib/minimal/*.sh.
# ---------------------------------------------------------------------------
SCRIPT_NAME="ce-minimal"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib/ce-common.sh" \
|| { echo "ERROR: lib/ce-common.sh not found"; exit 1; }
for _sub in "${SCRIPT_DIR}"/lib/minimal/*.sh; do
source "${_sub}" || { log_error "Failed to source: ${_sub}"; exit 1; }
done
unset _sub
cleanup() {
local exit_code="${?}"
log_info "Running cleanup..."
doas apk cache clean >> "${LOG_FILE}" 2>&1 || true
doas rm -rf /var/cache/apk/* >> "${LOG_FILE}" 2>&1 || true
log_info "Cleanup complete (exit code: ${exit_code})"
}
trap cleanup EXIT INT TERM HUP
phase_preflight() {
log_info "=== TIER 1: PRE-FLIGHT ==="
check_not_root
run_test "bash >= 4" '[[ "${BASH_VERSINFO[0]}" -ge 4 ]]' fail
run_test "arch detected" '[[ -n "${ARCH}" ]]' fail
run_test "doas present" 'command -v doas >/dev/null 2>&1' fail
run_test "Tier 0 complete" 'command -v curl >/dev/null 2>&1' fail
run_test "community repo enabled" 'grep -q "^[^#].*community" /etc/apk/repositories' fail
run_test "internet reachable" \
'curl --silent --max-time 10 --output /dev/null https://dl-cdn.alpinelinux.org' warn
run_test "disk >= 1GB" '[[ $(df / --output=avail | tail -1) -ge 1048576 ]]' warn
log_info "Arch: ${ARCH}"
log_info "Pre-flight complete"
}
phase_install() {
log_info "=== TIER 1: INSTALL ==="
doas apk update >> "${LOG_FILE}" 2>&1 \
&& doas apk upgrade >> "${LOG_FILE}" 2>&1 \
|| { log_error "apk update/upgrade failed"; exit 1; }
run_test "apk functional" 'apk search vim 2>/dev/null | grep -q "^vim"' fail
install_minimal_shell
install_minimal_terminal
install_minimal_files
install_minimal_vcs
install_minimal_systools
install_minimal_comms
install_minimal_journal
install_minimal_web
install_minimal_network
install_minimal_record
install_minimal_wiki
install_minimal_access
}
phase_verify() {
log_info "=== TIER 1: VERIFY ==="
local tools=(tmux vim git gpg python3 lynx)
for tool in "${tools[@]}"; do
run_test "${tool} present" "command -v ${tool} >/dev/null 2>&1" warn
done
run_test "pipx present" 'command -v pipx >/dev/null 2>&1' warn
run_test "espeak-ng present" 'command -v espeak-ng >/dev/null 2>&1' warn
log_info "Tier 1 verify complete"
}
log_info "=== CE OS INSTALLER — TIER 1: MINIMAL ==="
log_info "Arch: ${ARCH} | Log: ${LOG_FILE}"
phase_preflight
confirm_proceed
phase_install
phase_verify
print_summary
log_info "=== TIER 1 COMPLETE ==="

45
deploy.sh Normal file
View file

@ -0,0 +1,45 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# deploy.sh
# ~/projects/ceos/alpine-installer/deploy.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: workbench (Pi 5, Alpine aarch64) — run on workbench, not tinkerpad
# ---------------------------------------------------------------------------
# Copies the script tree to /srv/repo/scripts/alpine-ceos-installer/ so
# tinkerpad can fetch files via bootstrap.sh.
#
# TODO — Forgejo: when git.jahnet.lan is deployed, replace this script with:
# git push origin dev
# ---------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEPLOY_TARGET="/srv/repo/scripts/alpine-ceos-installer"
echo "CE OS Alpine Installer — Deploy to serve tree"
echo "Source: ${SCRIPT_DIR}"
echo "Target: ${DEPLOY_TARGET}"
echo ""
read -r -p "Proceed with deploy? [y/N] " confirm
[[ "${confirm,,}" == "y" ]] || { echo "Aborted."; exit 0; }
doas mkdir -p \
"${DEPLOY_TARGET}/lib/base" \
"${DEPLOY_TARGET}/lib/minimal" \
"${DEPLOY_TARGET}/lib/basic" \
"${DEPLOY_TARGET}/tests" \
"${DEPLOY_TARGET}/spec"
doas cp -r "${SCRIPT_DIR}/." "${DEPLOY_TARGET}/"
doas chmod +x \
"${DEPLOY_TARGET}"/*.sh \
"${DEPLOY_TARGET}"/lib/base/*.sh \
"${DEPLOY_TARGET}"/lib/minimal/*.sh \
"${DEPLOY_TARGET}"/lib/basic/*.sh \
"${DEPLOY_TARGET}"/tests/*.sh
echo ""
echo "Deploy complete."
echo "Pull URL: http://192.168.0.138/repo/scripts/alpine-ceos-installer/"
echo "Bootstrap: wget http://192.168.0.138/repo/scripts/alpine-ceos-installer/bootstrap.sh"

57
lib/base/01_core.sh Normal file
View file

@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 01_core.sh
# ~/projects/ceos/alpine-installer/lib/base/01_core.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Base Tier subscript: enable community repo, install core packages,
# run setup-utmp. Defines install_base_core().
# ---------------------------------------------------------------------------
install_base_core() {
log_info "--- base/01_core: enabling community repo ---"
if grep -q "^[^#].*community" /etc/apk/repositories 2>/dev/null; then
log_info "Community repo already enabled — skipping"
else
doas sed -i '/^#.*community/s/^#//' /etc/apk/repositories \
>> "${LOG_FILE}" 2>&1 \
|| log_warn "Could not uncomment community repo — check /etc/apk/repositories"
run_test "community repo enabled" \
'grep -q "^[^#].*community" /etc/apk/repositories' warn
fi
log_info "--- base/01_core: verifying core packages available ---"
local missing=()
for pkg in bash bash-completion ca-certificates curl openssh tzdata utmps; do
apk search "${pkg}" 2>/dev/null | grep -q "^${pkg}" \
|| missing+=("${pkg}")
done
if [[ ${#missing[@]} -gt 0 ]]; then
log_warn "Not found in repo search: ${missing[*]} — install may fail"
fi
log_info "--- base/01_core: installing core packages ---"
local -a PKGS=(bash bash-completion ca-certificates curl openssh tzdata utmps)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
log_info "--- base/01_core: running setup-utmp ---"
if doas setup-utmp >> "${LOG_FILE}" 2>&1; then
log_info "setup-utmp complete"
else
log_warn "setup-utmp returned non-zero — may already be configured"
fi
}
# Standalone entry point
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="01_core"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_base_core
print_summary
fi

46
lib/base/02_doas.sh Normal file
View file

@ -0,0 +1,46 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 02_doas.sh
# ~/projects/ceos/alpine-installer/lib/base/02_doas.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Base Tier subscript: install doas and write /etc/doas.d/wheel.conf.
# Defines install_base_doas().
# ---------------------------------------------------------------------------
install_base_doas() {
log_info "--- base/02_doas: installing doas ---"
install_pkg "doas"
run_test "doas binary present" 'command -v doas >/dev/null 2>&1' warn
log_info "--- base/02_doas: configuring /etc/doas.d/wheel.conf ---"
if ! doas test -d /etc/doas.d 2>/dev/null; then
doas mkdir -p /etc/doas.d >> "${LOG_FILE}" 2>&1 \
|| { log_warn "Could not create /etc/doas.d — skipping wheel.conf"; return 1; }
fi
if doas test -f /etc/doas.d/wheel.conf 2>/dev/null; then
log_info "/etc/doas.d/wheel.conf already present — skipping write"
else
printf 'permit persist :wheel\n' \
| doas tee /etc/doas.d/wheel.conf > /dev/null 2>&1 \
|| log_warn "Failed to write wheel.conf — configure manually: permit persist :wheel"
run_test "wheel.conf written" '[[ -s /etc/doas.d/wheel.conf ]]' warn
fi
log_info "doas configuration complete"
}
# Standalone entry point
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="02_doas"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_base_doas
print_summary
fi

30
lib/basic/01_comms.sh Normal file
View file

@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 01_comms.sh
# ~/projects/ceos/alpine-installer/lib/basic/01_comms.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Basic Tier subscript: communication additions — abook, task (taskwarrior).
# Defines install_basic_comms().
# ---------------------------------------------------------------------------
install_basic_comms() {
log_info "--- basic/01_comms: communication additions ---"
local -a PKGS=(abook task)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "abook present" 'command -v abook >/dev/null 2>&1' warn
run_test "task present" 'command -v task >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="basic_01_comms"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_basic_comms
print_summary
fi

41
lib/basic/02_monitor.sh Normal file
View file

@ -0,0 +1,41 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 02_monitor.sh
# ~/projects/ceos/alpine-installer/lib/basic/02_monitor.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Basic Tier subscript: system monitoring — nethogs, iproute2, lnav (@edge).
# lnav is an edge package; failure is logged and marked for manual follow-up.
# Defines install_basic_monitor().
# ---------------------------------------------------------------------------
install_basic_monitor() {
log_info "--- basic/02_monitor: system monitoring ---"
local -a PKGS=(nethogs iproute2)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "ip present" 'command -v ip >/dev/null 2>&1' warn
# lnav — edge package, warn-on-fail
ensure_edge_repo
log_info "Installing lnav from @edge..."
if install_pkg_edge "lnav"; then
run_test "lnav present" 'command -v lnav >/dev/null 2>&1' warn
else
MANUAL_PKGS+=("lnav: edge install failed — requires manual verification")
fi
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="basic_02_monitor"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_basic_monitor
print_summary
fi

38
lib/basic/03_gui.sh Normal file
View file

@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 03_gui.sh
# ~/projects/ceos/alpine-installer/lib/basic/03_gui.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Basic Tier subscript: GUI layer — cagebreak, firefox, xwayland.
# Supported on x86-64. Boot config modification (/boot/cmdline.txt) is
# RPi-only and is explicitly skipped on x86-64 hardware.
# Defines install_basic_gui().
# ---------------------------------------------------------------------------
install_basic_gui() {
log_info "--- basic/03_gui: GUI layer (Wayland + Firefox) ---"
log_info "Arch: ${ARCH} — GUI supported on x86-64"
local -a PKGS=(cagebreak firefox xwayland)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "cagebreak present" 'command -v cagebreak >/dev/null 2>&1' warn
run_test "firefox present" 'command -v firefox >/dev/null 2>&1' warn
# /boot/cmdline.txt and /boot/extlinux.conf modifications are RPi-only
log_info "NOTICE: /boot/cmdline.txt modification skipped — not applicable on x86-64 (ThinkPad)"
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="basic_03_gui"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_basic_gui
print_summary
fi

34
lib/basic/04_media.sh Normal file
View file

@ -0,0 +1,34 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 04_media.sh
# ~/projects/ceos/alpine-installer/lib/basic/04_media.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Basic Tier subscript: media — cmus, mpv, ffmpeg, imagemagick, fbida-fbi.
# Note: package is 'fbida-fbi' (not 'fbida').
# Defines install_basic_media().
# ---------------------------------------------------------------------------
install_basic_media() {
log_info "--- basic/04_media: media tools ---"
local -a PKGS=(cmus mpv ffmpeg imagemagick fbida-fbi)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "cmus present" 'command -v cmus >/dev/null 2>&1' warn
run_test "mpv present" 'command -v mpv >/dev/null 2>&1' warn
run_test "ffmpeg present" 'command -v ffmpeg >/dev/null 2>&1' warn
run_test "convert present" 'command -v convert >/dev/null 2>&1' warn
run_test "fbi present" 'command -v fbi >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="basic_04_media"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_basic_media
print_summary
fi

40
lib/basic/05_fonts.sh Normal file
View file

@ -0,0 +1,40 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 05_fonts.sh
# ~/projects/ceos/alpine-installer/lib/basic/05_fonts.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Basic Tier subscript: fonts and display — figlet, nerd-fonts (@edge).
# nerd-fonts package name confirmed via pkgs.alpinelinux.org (edge/community).
# Installs with @edge tag; gracefully skips on failure.
# Defines install_basic_fonts().
# ---------------------------------------------------------------------------
install_basic_fonts() {
log_info "--- basic/05_fonts: fonts and display ---"
install_pkg "figlet"
run_test "figlet present" 'command -v figlet >/dev/null 2>&1' warn
# nerd-fonts — edge/community; package name verified as 'nerd-fonts'
ensure_edge_repo
log_info "Installing nerd-fonts from @edge/community..."
if install_pkg_edge "nerd-fonts"; then
log_info "nerd-fonts installed"
else
log_warn "nerd-fonts@edge not available — skipping gracefully"
MANUAL_PKGS+=("nerd-fonts: edge install failed — check pkgs.alpinelinux.org/packages?name=nerd-fonts&branch=edge")
fi
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="basic_05_fonts"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_basic_fonts
print_summary
fi

36
lib/basic/06_utils.sh Normal file
View file

@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 06_utils.sh
# ~/projects/ceos/alpine-installer/lib/basic/06_utils.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Basic Tier subscript: additional utilities —
# tealdeer, restic, jq, bc, zip, unzip, xz.
# Note: package name is 'tealdeer' (not 'tldr').
# Defines install_basic_utils().
# ---------------------------------------------------------------------------
install_basic_utils() {
log_info "--- basic/06_utils: additional utilities ---"
local -a PKGS=(tealdeer restic jq bc zip unzip xz)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "tldr present" 'command -v tldr >/dev/null 2>&1' warn
run_test "restic present" 'command -v restic >/dev/null 2>&1' warn
run_test "jq present" 'command -v jq >/dev/null 2>&1' warn
run_test "bc present" 'command -v bc >/dev/null 2>&1' warn
run_test "zip present" 'command -v zip >/dev/null 2>&1' warn
run_test "xz present" 'command -v xz >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="basic_06_utils"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_basic_utils
print_summary
fi

151
lib/ce-common.sh Normal file
View file

@ -0,0 +1,151 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# ce-common.sh
# ~/projects/ceos/alpine-installer/lib/ce-common.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Shared library: logging, run_test, package helpers, common guards.
# Source this file; do not execute directly.
# ---------------------------------------------------------------------------
# Guard against double-sourcing
[[ -n "${CE_COMMON_LOADED:-}" ]] && return 0
CE_COMMON_LOADED=1
# Architecture detection
ARCH="$(uname -m)"
# Logging setup — SCRIPT_NAME must be set before sourcing
LOG_DIR="${HOME}/.local/logs/ceos_installer"
SCRIPT_NAME="${SCRIPT_NAME:-ce-common}"
LOG_FILE="${LOG_DIR}/${SCRIPT_NAME}-$(date +%Y-%m-%d).log"
# Failed packages tracker — shared across all sourced subscripts
FAILED_PKGS=()
# Packages requiring manual follow-up (distinct from simple failures)
MANUAL_PKGS=()
mkdir -p "${LOG_DIR}"
# ---------------------------------------------------------------------------
# Logging
# ---------------------------------------------------------------------------
_log() {
local level="${1}" msg="${2}" ts
ts="$(date '+%Y-%m-%d %H:%M:%S')"
printf '[%s] [%s] %s\n' "${ts}" "${level}" "${msg}" | tee -a "${LOG_FILE}"
}
log_info() { _log "INFO " "${1}"; }
log_warn() { _log "WARN " "${1}" >&2; }
log_error() { _log "ERROR" "${1}" >&2; }
log_debug() { [[ "${CE_DEBUG:-0}" == "1" ]] && _log "DEBUG" "${1}"; }
# ---------------------------------------------------------------------------
# run_test <description> <test_expression> <fail|warn>
# ---------------------------------------------------------------------------
run_test() {
local desc="${1}" cmd="${2}" mode="${3:-fail}"
if eval "${cmd}" >/dev/null 2>&1; then
log_info " PASS: ${desc}"
return 0
fi
if [[ "${mode}" == "fail" ]]; then
log_error " FAIL: ${desc}"
exit 1
else
log_warn " WARN: ${desc}"
return 1
fi
}
# ---------------------------------------------------------------------------
# Package helpers
# ---------------------------------------------------------------------------
# install_pkg <package> — one package, logs result
install_pkg() {
local pkg="${1}"
if doas apk add "${pkg}" >> "${LOG_FILE}" 2>&1; then
log_info "Installed: ${pkg}"
return 0
else
log_warn "FAILED: ${pkg} — logged, continuing"
FAILED_PKGS+=("${pkg}")
return 1
fi
}
# install_pkg_edge <package> — install with @edge tag, warn on fail
install_pkg_edge() {
local pkg="${1}"
if doas apk add "${pkg}@edge" >> "${LOG_FILE}" 2>&1; then
log_info "Installed: ${pkg} (@edge)"
return 0
else
log_warn "FAILED: ${pkg}@edge — manual verification required"
FAILED_PKGS+=("${pkg} (edge, manual verification required)")
return 1
fi
}
# ensure_edge_repo — add @edge community tag if not present
ensure_edge_repo() {
if ! grep -q "^@edge" /etc/apk/repositories 2>/dev/null; then
log_info "Adding @edge community tag to /etc/apk/repositories"
printf '@edge https://dl-cdn.alpinelinux.org/alpine/edge/community\n' \
| doas tee -a /etc/apk/repositories > /dev/null 2>&1 \
|| log_warn "Could not add @edge tag — edge installs may fail"
fi
}
# ---------------------------------------------------------------------------
# Guards and prompts
# ---------------------------------------------------------------------------
# check_not_root — exit if accidentally run as root
check_not_root() {
if [[ "${EUID}" -eq 0 ]]; then
echo "ERROR: Do not run as root. Run as a standard user with doas configured." >&2
exit 1
fi
}
# confirm_proceed — single prompt; bypassed when CE_INSTALL_NO_CONFIRM=1
confirm_proceed() {
[[ "${CE_INSTALL_NO_CONFIRM:-0}" == "1" ]] && return 0
echo ""
read -r -p "Proceed with installation? [y/N] " confirm
[[ "${confirm,,}" == "y" ]] || { log_info "Aborted by user."; exit 0; }
}
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
print_summary() {
log_info "=== INSTALLATION SUMMARY ==="
if [[ ${#FAILED_PKGS[@]} -eq 0 && ${#MANUAL_PKGS[@]} -eq 0 ]]; then
log_info "All packages installed successfully."
return 0
fi
if [[ ${#FAILED_PKGS[@]} -gt 0 ]]; then
log_warn "Failed or skipped packages:"
for pkg in "${FAILED_PKGS[@]}"; do
log_warn " - ${pkg}"
done
fi
if [[ ${#MANUAL_PKGS[@]} -gt 0 ]]; then
log_warn "Requires manual follow-up:"
for item in "${MANUAL_PKGS[@]}"; do
log_warn " - ${item}"
done
fi
}

30
lib/minimal/01_shell.sh Normal file
View file

@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 01_shell.sh
# ~/projects/ceos/alpine-installer/lib/minimal/01_shell.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: shell environment — starship, less, mandoc, ncurses.
# Defines install_minimal_shell().
# ---------------------------------------------------------------------------
install_minimal_shell() {
log_info "--- minimal/01_shell: shell environment ---"
local -a PKGS=(starship less mandoc ncurses)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "less present" 'command -v less >/dev/null 2>&1' warn
run_test "starship present" 'command -v starship >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="01_shell"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_shell
print_summary
fi

View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 02_terminal.sh
# ~/projects/ceos/alpine-installer/lib/minimal/02_terminal.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: terminal environment — tmux, vim, nano.
# Defines install_minimal_terminal().
# ---------------------------------------------------------------------------
install_minimal_terminal() {
log_info "--- minimal/02_terminal: terminal environment ---"
local -a PKGS=(tmux vim nano)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "tmux present" 'command -v tmux >/dev/null 2>&1' warn
run_test "vim present" 'command -v vim >/dev/null 2>&1' warn
run_test "nano present" 'command -v nano >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="02_terminal"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_terminal
print_summary
fi

31
lib/minimal/03_files.sh Normal file
View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 03_files.sh
# ~/projects/ceos/alpine-installer/lib/minimal/03_files.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: file management — ranger, mc, ncdu, fzf, zoxide, stow.
# Defines install_minimal_files().
# ---------------------------------------------------------------------------
install_minimal_files() {
log_info "--- minimal/03_files: file management ---"
local -a PKGS=(ranger mc ncdu fzf zoxide stow)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "ranger present" 'command -v ranger >/dev/null 2>&1' warn
run_test "fzf present" 'command -v fzf >/dev/null 2>&1' warn
run_test "zoxide present" 'command -v zoxide >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="03_files"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_files
print_summary
fi

31
lib/minimal/04_vcs.sh Normal file
View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 04_vcs.sh
# ~/projects/ceos/alpine-installer/lib/minimal/04_vcs.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: version control and transfer — git, rsync, openssl, gnupg.
# Defines install_minimal_vcs().
# ---------------------------------------------------------------------------
install_minimal_vcs() {
log_info "--- minimal/04_vcs: version control and transfer ---"
local -a PKGS=(git rsync openssl gnupg)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "git present" 'command -v git >/dev/null 2>&1' warn
run_test "rsync present" 'command -v rsync >/dev/null 2>&1' warn
run_test "gpg present" 'command -v gpg >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="04_vcs"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_vcs
print_summary
fi

View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 05_systools.sh
# ~/projects/ceos/alpine-installer/lib/minimal/05_systools.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: system tools — btop, lsof, mosh, dialog.
# Defines install_minimal_systools().
# ---------------------------------------------------------------------------
install_minimal_systools() {
log_info "--- minimal/05_systools: system tools ---"
local -a PKGS=(btop lsof mosh dialog)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "btop present" 'command -v btop >/dev/null 2>&1' warn
run_test "lsof present" 'command -v lsof >/dev/null 2>&1' warn
run_test "dialog present" 'command -v dialog >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="05_systools"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_systools
print_summary
fi

34
lib/minimal/06_comms.sh Normal file
View file

@ -0,0 +1,34 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 06_comms.sh
# ~/projects/ceos/alpine-installer/lib/minimal/06_comms.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: communication and organisation —
# neomutt, msmtp, isync (mbsync), calcurse, pass.
# Defines install_minimal_comms().
# ---------------------------------------------------------------------------
install_minimal_comms() {
log_info "--- minimal/06_comms: communication and organisation ---"
local -a PKGS=(neomutt msmtp isync calcurse pass)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "neomutt present" 'command -v neomutt >/dev/null 2>&1' warn
run_test "msmtp present" 'command -v msmtp >/dev/null 2>&1' warn
run_test "mbsync present" 'command -v mbsync >/dev/null 2>&1' warn
run_test "calcurse present" 'command -v calcurse >/dev/null 2>&1' warn
run_test "pass present" 'command -v pass >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="06_comms"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_comms
print_summary
fi

46
lib/minimal/07_journal.sh Normal file
View file

@ -0,0 +1,46 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 07_journal.sh
# ~/projects/ceos/alpine-installer/lib/minimal/07_journal.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: journal — python3, pipx (apk), jrnl (pipx install).
# Defines install_minimal_journal().
# ---------------------------------------------------------------------------
install_minimal_journal() {
log_info "--- minimal/07_journal: python3, pipx, jrnl ---"
install_pkg "python3"
install_pkg "pipx"
run_test "python3 present" 'command -v python3 >/dev/null 2>&1' warn
run_test "pipx present" 'command -v pipx >/dev/null 2>&1' warn
if ! command -v pipx >/dev/null 2>&1; then
log_warn "pipx not available — skipping jrnl install"
FAILED_PKGS+=("jrnl (skipped: pipx not available)")
return 0
fi
log_info "Installing jrnl via pipx..."
if pipx install jrnl >> "${LOG_FILE}" 2>&1; then
log_info "Installed: jrnl (via pipx)"
else
log_warn "FAILED: jrnl (pipx install) — logged, continuing"
FAILED_PKGS+=("jrnl (pipx install failed)")
fi
run_test "jrnl present" 'command -v jrnl >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="07_journal"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_journal
print_summary
fi

30
lib/minimal/08_web.sh Normal file
View file

@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 08_web.sh
# ~/projects/ceos/alpine-installer/lib/minimal/08_web.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: web clients — lynx, w3m.
# Defines install_minimal_web().
# ---------------------------------------------------------------------------
install_minimal_web() {
log_info "--- minimal/08_web: web clients ---"
local -a PKGS=(lynx w3m)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "lynx present" 'command -v lynx >/dev/null 2>&1' warn
run_test "w3m present" 'command -v w3m >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="08_web"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_web
print_summary
fi

45
lib/minimal/09_network.sh Normal file
View file

@ -0,0 +1,45 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 09_network.sh
# ~/projects/ceos/alpine-installer/lib/minimal/09_network.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: network services — dbus, avahi.
# Enables both services in the default OpenRC runlevel.
# Defines install_minimal_network().
# ---------------------------------------------------------------------------
install_minimal_network() {
log_info "--- minimal/09_network: dbus and avahi ---"
install_pkg "dbus"
install_pkg "avahi"
run_test "dbus present" 'command -v dbus-daemon >/dev/null 2>&1' warn
run_test "avahi-daemon present" 'command -v avahi-daemon >/dev/null 2>&1' warn
log_info "Enabling dbus and avahi-daemon in OpenRC default runlevel..."
if command -v rc-update >/dev/null 2>&1; then
doas rc-update add dbus default >> "${LOG_FILE}" 2>&1 \
&& log_info "rc-update: dbus added to default" \
|| log_warn "rc-update add dbus failed — enable manually"
doas rc-update add avahi-daemon default >> "${LOG_FILE}" 2>&1 \
&& log_info "rc-update: avahi-daemon added to default" \
|| log_warn "rc-update add avahi-daemon failed — enable manually"
else
log_warn "rc-update not found — skipping service enablement"
MANUAL_PKGS+=("dbus + avahi-daemon: enable with rc-update add <svc> default")
fi
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="09_network"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_network
print_summary
fi

30
lib/minimal/10_record.sh Normal file
View file

@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 10_record.sh
# ~/projects/ceos/alpine-installer/lib/minimal/10_record.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: recording and screenshot — asciinema, fbgrab.
# Defines install_minimal_record().
# ---------------------------------------------------------------------------
install_minimal_record() {
log_info "--- minimal/10_record: recording and screenshot ---"
local -a PKGS=(asciinema fbgrab)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done
run_test "asciinema present" 'command -v asciinema >/dev/null 2>&1' warn
run_test "fbgrab present" 'command -v fbgrab >/dev/null 2>&1' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="10_record"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_record
print_summary
fi

87
lib/minimal/11_wiki.sh Normal file
View file

@ -0,0 +1,87 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 11_wiki.sh
# ~/projects/ceos/alpine-installer/lib/minimal/11_wiki.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: wiki viewer — glow from CE repo.
# Downloads binary, verifies sha256 and GPG signature, installs to ~/.local/bin/.
# Gracefully skips if CE repo is unreachable or verification fails.
# Defines install_minimal_wiki().
# ---------------------------------------------------------------------------
install_minimal_wiki() {
log_info "--- minimal/11_wiki: glow (CE repo) ---"
local CE_REPO="https://cervelloelettrico.it/bin/amd64/alpine"
local INSTALL_DIR="${HOME}/.local/bin"
local TEMP_DIR
TEMP_DIR="$(mktemp -d /tmp/ce-glow-XXXXXX)"
mkdir -p "${INSTALL_DIR}"
# Abort cleanly if CE repo unreachable
if ! curl --silent --max-time 10 --output /dev/null "${CE_REPO}/glow"; then
log_warn "CE repo unreachable (${CE_REPO}) — skipping glow"
FAILED_PKGS+=("glow (CE repo unreachable)")
rm -rf "${TEMP_DIR}"
return 0
fi
log_info "Downloading glow, sha256, and sig from CE repo..."
local ok=1
curl --silent --max-time 30 -o "${TEMP_DIR}/glow" "${CE_REPO}/glow" || ok=0
curl --silent --max-time 10 -o "${TEMP_DIR}/glow.sha256" "${CE_REPO}/glow.sha256" || ok=0
curl --silent --max-time 10 -o "${TEMP_DIR}/glow.sig" "${CE_REPO}/glow.sig" || ok=0
if [[ "${ok}" -eq 0 ]]; then
log_warn "glow download incomplete — skipping install"
FAILED_PKGS+=("glow (download failed)")
rm -rf "${TEMP_DIR}"
return 0
fi
# SHA256 verification
local expected actual
expected="$(awk '{print $1}' "${TEMP_DIR}/glow.sha256")"
actual="$(sha256sum "${TEMP_DIR}/glow" | awk '{print $1}')"
if [[ "${expected}" != "${actual}" ]]; then
log_warn "glow SHA256 mismatch — aborting (expected: ${expected}, got: ${actual})"
FAILED_PKGS+=("glow (sha256 mismatch)")
rm -rf "${TEMP_DIR}"
return 0
fi
log_info "glow SHA256 verified"
# GPG signature verification (gnupg available from 04_vcs)
if command -v gpg >/dev/null 2>&1; then
if gpg --verify "${TEMP_DIR}/glow.sig" "${TEMP_DIR}/glow" >> "${LOG_FILE}" 2>&1; then
log_info "glow GPG signature verified"
else
log_warn "glow GPG verification failed — aborting install"
FAILED_PKGS+=("glow (gpg verify failed)")
rm -rf "${TEMP_DIR}"
return 0
fi
else
log_warn "gpg not available — proceeding with sha256-only verification"
fi
chmod +x "${TEMP_DIR}/glow"
cp "${TEMP_DIR}/glow" "${INSTALL_DIR}/glow"
rm -rf "${TEMP_DIR}"
run_test "glow installed" 'command -v glow >/dev/null 2>&1' warn
log_info "glow installed to ${INSTALL_DIR}/glow"
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="11_wiki"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_wiki
print_summary
fi

56
lib/minimal/12_access.sh Normal file
View file

@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# 12_access.sh
# ~/projects/ceos/alpine-installer/lib/minimal/12_access.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Minimal Tier subscript: accessibility — espeak-ng, espeakup, speech-dispatcher.
# espeak conflict trap: removes espeak before installing espeak-ng.
# espeakup: repo-verified before install (package availability varies by release).
# speech-dispatcher: @edge, warn-on-fail.
# ly login manager: aarch64 CE repo only — SKIPPED on x86-64 with notice.
# Defines install_minimal_access().
# ---------------------------------------------------------------------------
install_minimal_access() {
log_info "--- minimal/12_access: accessibility ---"
# espeak conflict trap — must run before espeak-ng install
if doas apk info -e espeak >> "${LOG_FILE}" 2>&1; then
log_info "Removing conflicting 'espeak' package before installing espeak-ng..."
doas apk del espeak >> "${LOG_FILE}" 2>&1 \
|| log_warn "Could not remove espeak — espeak-ng may conflict"
fi
install_pkg "espeak-ng"
run_test "espeak-ng present" 'command -v espeak-ng >/dev/null 2>&1' warn
# espeakup — verify package exists in current repo before attempting install
if apk search espeakup 2>/dev/null | grep -q "^espeakup"; then
install_pkg "espeakup"
else
log_warn "espeakup not found in current Alpine repos — skipping"
MANUAL_PKGS+=("espeakup: not found in Alpine v3.23 — check https://github.com/dermotbradley/alpine-espeakup")
fi
# speech-dispatcher — edge package
ensure_edge_repo
install_pkg_edge "speech-dispatcher"
# ly login manager — CE repo, aarch64 only — skip on x86-64
if [[ "${ARCH}" == "x86_64" ]]; then
log_info "NOTICE: ly login manager — CE repo aarch64 only, not available for x86-64 — skipped"
MANUAL_PKGS+=("ly: aarch64 CE repo only — not available for x86-64 (${ARCH})")
fi
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT_NAME="12_access"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
check_not_root
install_minimal_access
print_summary
fi

132
spec/install_spec.md Normal file
View file

@ -0,0 +1,132 @@
# CE OS Alpine Installer — Subscript Specifications
<!-- ~/projects/ceos/alpine-installer/spec/install_spec.md -->
<!-- Version: v0.0.1 | Status: DEVELOPMENT -->
---
## lib/ce-common.sh
| Field | Value |
|---|---|
| Name | ce-common.sh — shared library |
| Inputs | SCRIPT_NAME env var (set by caller before sourcing) |
| Outputs | LOG_FILE written, FAILED_PKGS/MANUAL_PKGS arrays populated |
| Error behaviour | run_test exits on fail mode; all others log-and-continue |
| Privilege | standard user (doas called internally by install_pkg) |
| Distro target | Alpine |
---
## lib/base/01_core.sh
| Field | Value |
|---|---|
| Name | 01_core.sh — enable community repo, core packages, setup-utmp |
| Inputs | none (sources ce-common.sh) |
| Outputs | packages installed; /etc/apk/repositories modified |
| Error behaviour | per-package log-and-continue; setup-utmp warn-only |
| Privilege | requires doas for apk and sed on /etc/apk/repositories |
| Distro target | Alpine |
## lib/base/02_doas.sh
| Field | Value |
|---|---|
| Name | 02_doas.sh — doas install and wheel.conf |
| Inputs | none |
| Outputs | doas installed; /etc/doas.d/wheel.conf written |
| Error behaviour | warn if wheel.conf write fails — manual action noted |
| Privilege | requires doas for mkdir/tee on /etc/doas.d |
| Distro target | Alpine |
---
## lib/minimal/01_shell.sh — 06_comms.sh
Standard pattern: apk community packages, per-package install_pkg, run_test warn.
| Script | Packages |
|---|---|
| 01_shell.sh | starship, less, mandoc, ncurses |
| 02_terminal.sh | tmux, vim, nano |
| 03_files.sh | ranger, mc, ncdu, fzf, zoxide, stow |
| 04_vcs.sh | git, rsync, openssl, gnupg |
| 05_systools.sh | btop, lsof, mosh, dialog |
| 06_comms.sh | neomutt, msmtp, isync, calcurse, pass |
---
## lib/minimal/07_journal.sh
| Field | Value |
|---|---|
| Name | 07_journal.sh — python3, pipx, jrnl |
| Inputs | none |
| Outputs | python3 + pipx via apk; jrnl via pipx install |
| Error behaviour | skips jrnl if pipx unavailable; logs failure |
| Privilege | standard user (pipx runs as user) |
| Distro target | Alpine |
## lib/minimal/08_web.sh
Standard pattern: lynx, w3m.
## lib/minimal/09_network.sh
| Field | Value |
|---|---|
| Name | 09_network.sh — dbus, avahi + rc-update |
| Inputs | none |
| Outputs | dbus + avahi installed; both added to default runlevel |
| Error behaviour | rc-update failures warn-only; logged to MANUAL_PKGS |
| Privilege | doas for apk + rc-update |
| Distro target | Alpine + OpenRC |
## lib/minimal/10_record.sh
Standard pattern: asciinema, fbgrab.
## lib/minimal/11_wiki.sh
| Field | Value |
|---|---|
| Name | 11_wiki.sh — glow binary from CE repo |
| Inputs | CE_REPO URL (hardcoded to cervelloelettrico.it/bin/amd64/alpine) |
| Outputs | glow installed to ~/.local/bin/glow |
| Error behaviour | graceful skip on unreachable repo, download fail, sha256 mismatch, gpg fail |
| Privilege | standard user (installs to ~/.local/bin) |
| Distro target | Alpine x86-64; CE_REPO path must change for other arches |
| Doc references | cervelloelettrico.it CE repo |
## lib/minimal/12_access.sh
| Field | Value |
|---|---|
| Name | 12_access.sh — espeak-ng, espeakup, speech-dispatcher, ly notice |
| Inputs | ARCH (from ce-common.sh) |
| Outputs | espeak removed if present; espeak-ng installed; espeakup if available; speech-dispatcher@edge; ly notice on x86-64 |
| Error behaviour | espeak removal warn-only; espeakup skipped if not in repo; speech-dispatcher warn-on-fail; ly skipped with MANUAL notice |
| Privilege | doas for apk del + apk add |
| Distro target | Alpine; espeakup availability varies by release |
| Doc references | wiki.alpinelinux.org/wiki/Using_espeak_on_Alpine_Linux; github.com/dermotbradley/alpine-espeakup |
---
## lib/basic/01_comms.sh — 06_utils.sh
| Script | Packages | Notes |
|---|---|---|
| 01_comms.sh | abook, task | task = taskwarrior (package name is 'task') |
| 02_monitor.sh | nethogs, iproute2, lnav@edge | lnav is edge; warn-on-fail + MANUAL note |
| 03_gui.sh | cagebreak, firefox, xwayland | /boot/cmdline.txt skip noted; x86-64 only meaningful |
| 04_media.sh | cmus, mpv, ffmpeg, imagemagick, fbida-fbi | package is 'fbida-fbi' not 'fbida' |
| 05_fonts.sh | figlet, nerd-fonts@edge | nerd-fonts confirmed package name (edge/community) |
| 06_utils.sh | tealdeer, restic, jq, bc, zip, unzip, xz | tealdeer (not 'tldr') |
---
Source: ce-authored
Source-type: ce-authored
Licence: Public Domain — CE FFM Policy
Verified-on: 2026-06-10
Session: ceos-alpine-installer-v0.0.1-dev

50
tests/test_base.sh Normal file
View file

@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# test_base.sh
# ~/projects/ceos/alpine-installer/tests/test_base.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Re-runnable test suite for Tier 0 (Base). Run after ce-base.sh.
# Exits with count of failures (0 = all passed).
# ---------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SCRIPT_NAME="test_base"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
PASS=0
FAIL=0
check() {
local desc="${1}" cmd="${2}"
if eval "${cmd}" >/dev/null 2>&1; then
log_info "PASS: ${desc}"
((PASS++))
else
log_warn "FAIL: ${desc}"
((FAIL++))
fi
}
log_info "=== TEST SUITE: TIER 0 BASE ==="
check "bash present" 'command -v bash'
check "bash-completion installed" 'apk info -e bash-completion'
check "ca-certificates installed" 'apk info -e ca-certificates'
check "curl present" 'command -v curl'
check "openssh installed" 'apk info -e openssh'
check "sshd_config present" '[[ -f /etc/ssh/sshd_config ]]'
check "tzdata installed" 'apk info -e tzdata'
check "utmps installed" 'apk info -e utmps'
check "doas present" 'command -v doas'
check "doas wheel.conf present" '[[ -f /etc/doas.d/wheel.conf ]]'
check "wheel.conf non-empty" '[[ -s /etc/doas.d/wheel.conf ]]'
check "community repo enabled" 'grep -q "^[^#].*community" /etc/apk/repositories'
log_info "=== RESULTS: ${PASS} passed, ${FAIL} failed ==="
[[ "${FAIL}" -eq 0 ]] \
&& log_info "All Tier 0 tests passed." \
|| log_warn "${FAIL} test(s) failed — review ${LOG_FILE}"
exit "${FAIL}"

69
tests/test_basic.sh Normal file
View file

@ -0,0 +1,69 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# test_basic.sh
# ~/projects/ceos/alpine-installer/tests/test_basic.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Re-runnable test suite for Tier 2 (Basic). Run after ce-basic.sh.
# Exits with count of failures (0 = all passed).
# ---------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SCRIPT_NAME="test_basic"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
PASS=0
FAIL=0
check() {
local desc="${1}" cmd="${2}"
if eval "${cmd}" >/dev/null 2>&1; then
log_info "PASS: ${desc}"
((PASS++))
else
log_warn "FAIL: ${desc}"
((FAIL++))
fi
}
log_info "=== TEST SUITE: TIER 2 BASIC ==="
# Comms additions
check "abook present" 'command -v abook'
check "task present" 'command -v task'
# Monitoring
check "nethogs present" 'command -v nethogs'
check "ip present" 'command -v ip'
# GUI
check "cagebreak present" 'command -v cagebreak'
check "firefox present" 'command -v firefox'
check "xwayland present" 'command -v Xwayland'
# Media
check "cmus present" 'command -v cmus'
check "mpv present" 'command -v mpv'
check "ffmpeg present" 'command -v ffmpeg'
check "convert present" 'command -v convert'
check "fbi present" 'command -v fbi'
# Fonts
check "figlet present" 'command -v figlet'
# Utilities
check "tldr present" 'command -v tldr'
check "restic present" 'command -v restic'
check "jq present" 'command -v jq'
check "bc present" 'command -v bc'
check "zip present" 'command -v zip'
check "unzip present" 'command -v unzip'
check "xz present" 'command -v xz'
log_info "=== RESULTS: ${PASS} passed, ${FAIL} failed ==="
[[ "${FAIL}" -eq 0 ]] \
&& log_info "All Tier 2 tests passed." \
|| log_warn "${FAIL} test(s) failed — review ${LOG_FILE}"
exit "${FAIL}"

87
tests/test_minimal.sh Normal file
View file

@ -0,0 +1,87 @@
#!/usr/bin/env bash
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# test_minimal.sh
# ~/projects/ceos/alpine-installer/tests/test_minimal.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Re-runnable test suite for Tier 1 (Minimal). Run after ce-minimal.sh.
# Exits with count of failures (0 = all passed).
# ---------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SCRIPT_NAME="test_minimal"
source "${SCRIPT_DIR}/lib/ce-common.sh" || { echo "ERROR: ce-common.sh not found"; exit 1; }
PASS=0
FAIL=0
check() {
local desc="${1}" cmd="${2}"
if eval "${cmd}" >/dev/null 2>&1; then
log_info "PASS: ${desc}"
((PASS++))
else
log_warn "FAIL: ${desc}"
((FAIL++))
fi
}
log_info "=== TEST SUITE: TIER 1 MINIMAL ==="
# Shell environment
check "starship present" 'command -v starship'
check "less present" 'command -v less'
check "mandoc installed" 'apk info -e mandoc'
# Terminal
check "tmux present" 'command -v tmux'
check "vim present" 'command -v vim'
check "nano present" 'command -v nano'
# Files
check "ranger present" 'command -v ranger'
check "fzf present" 'command -v fzf'
check "zoxide present" 'command -v zoxide'
check "stow present" 'command -v stow'
# VCS and transfer
check "git present" 'command -v git'
check "rsync present" 'command -v rsync'
check "gpg present" 'command -v gpg'
# System tools
check "btop present" 'command -v btop'
check "lsof present" 'command -v lsof'
check "dialog present" 'command -v dialog'
# Comms
check "neomutt present" 'command -v neomutt'
check "msmtp present" 'command -v msmtp'
check "mbsync present" 'command -v mbsync'
check "pass present" 'command -v pass'
# Journal
check "python3 present" 'command -v python3'
check "pipx present" 'command -v pipx'
# Web
check "lynx present" 'command -v lynx'
check "w3m present" 'command -v w3m'
# Network services
check "avahi-daemon present" 'command -v avahi-daemon'
check "dbus-daemon present" 'command -v dbus-daemon'
# Recording
check "asciinema present" 'command -v asciinema'
# Accessibility
check "espeak-ng present" 'command -v espeak-ng'
log_info "=== RESULTS: ${PASS} passed, ${FAIL} failed ==="
[[ "${FAIL}" -eq 0 ]] \
&& log_info "All Tier 1 tests passed." \
|| log_warn "${FAIL} test(s) failed — review ${LOG_FILE}"
exit "${FAIL}"