From b1145c169ce93029455649fc5a968a332059b3a8 Mon Sep 17 00:00:00 2001 From: Ethan Lane <1124774683@qq.com> Date: Thu, 19 Feb 2026 11:18:45 +0800 Subject: [PATCH] feat: enhance installation scripts with improved logging and user feedback - Added step tracking and enhanced logging functions to both install.ps1 and install.sh for better user experience during installation. - Implemented version checking and update notifications, ensuring users are informed about the installation status. - Improved platform detection and error handling for unsupported architectures. - Enhanced the onboarding process with clearer instructions and feedback for users. Co-Authored-By: Claude Opus 4.6 --- install.ps1 | 216 +++++++++++++++++++++++++++++++++------ install.sh | 287 ++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 409 insertions(+), 94 deletions(-) diff --git a/install.ps1 b/install.ps1 index b0976f2..cef0670 100644 --- a/install.ps1 +++ b/install.ps1 @@ -6,80 +6,232 @@ $ErrorActionPreference = "Stop" $InstallDir = if ($env:CODEBLOG_INSTALL_DIR) { $env:CODEBLOG_INSTALL_DIR } else { "$env:USERPROFILE\.local\bin" } $BinName = "codeblog" $NpmRegistry = "https://registry.npmjs.org" +$CurrentStep = 0 +$TotalSteps = 4 +$WasInstalled = $false -function Write-Info($msg) { Write-Host "[codeblog] $msg" -ForegroundColor Cyan } -function Write-Ok($msg) { Write-Host "[codeblog] $msg" -ForegroundColor Green } -function Write-Err($msg) { Write-Host "[codeblog] $msg" -ForegroundColor Red; exit 1 } +# ── Logging ───────────────────────────────────────────────────────────────── +function Write-Step($msg) { + $script:CurrentStep++ + Write-Host "" + Write-Host " " -NoNewline + Write-Host ([char]0x25C6) -NoNewline -ForegroundColor Cyan + Write-Host " Step $script:CurrentStep/$TotalSteps" -NoNewline -ForegroundColor White + Write-Host " - " -NoNewline -ForegroundColor DarkGray + Write-Host $msg +} + +function Write-Info($msg) { + Write-Host " " -NoNewline + Write-Host ([char]0x2502) -NoNewline -ForegroundColor Cyan + Write-Host " $msg" +} + +function Write-Ok($msg) { + Write-Host " " -NoNewline + Write-Host ([char]0x2502) -NoNewline -ForegroundColor Green + Write-Host " " -NoNewline + Write-Host ([char]0x2714) -NoNewline -ForegroundColor Green + Write-Host " $msg" +} + +function Write-Warn($msg) { + Write-Host " " -NoNewline + Write-Host ([char]0x2502) -NoNewline -ForegroundColor Yellow + Write-Host " $msg" -ForegroundColor Yellow +} +function Write-Fail($msg) { + Write-Host "" + Write-Host " " -NoNewline + Write-Host ([char]0x2716) -NoNewline -ForegroundColor Red + Write-Host " $msg" -ForegroundColor Red + Write-Host "" + exit 1 +} + +# ── Header ────────────────────────────────────────────────────────────────── +function Write-Header { + Write-Host "" + Write-Host " " -NoNewline + $logo = @( + " ██████╗ ██████╗ ██████╗ ███████╗██████╗ ██╗ ██████╗ ██████╗ " + " ██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗██║ ██╔═══██╗██╔════╝ " + " ██║ ██║ ██║██║ ██║█████╗ ██████╔╝██║ ██║ ██║██║ ███╗" + " ██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗██║ ██║ ██║██║ ██║" + " ╚██████╗╚██████╔╝██████╔╝███████╗██████╔╝███████╗╚██████╔╝╚██████╔╝" + " ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ " + ) + foreach ($line in $logo) { + Write-Host " $line" -ForegroundColor Cyan + } + Write-Host "" + Write-Host " AI-powered coding forum - codeblog.ai" -ForegroundColor DarkGray + Write-Host " ────────────────────────────────────────────────────────────────" -ForegroundColor DarkGray +} + +# ── Platform detection ────────────────────────────────────────────────────── +function Get-Platform { + $arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLower() + if ($arch -eq "x64") { return "x64" } + elseif ($arch -eq "arm64") { return "arm64" } + else { Write-Fail "Unsupported architecture: $arch" } +} + +function Format-Platform($arch) { + switch ($arch) { + "x64" { return "Windows (x86_64)" } + "arm64" { return "Windows (ARM64)" } + default { return "Windows ($arch)" } + } +} + +# ── Version fetching ──────────────────────────────────────────────────────── function Get-LatestVersion { $resp = Invoke-RestMethod -Uri "$NpmRegistry/codeblog-app/latest" -ErrorAction Stop return $resp.version } -function Install-Binary { - $arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLower() - if ($arch -eq "x64") { $arch = "x64" } - elseif ($arch -eq "arm64") { $arch = "arm64" } - else { Write-Err "Unsupported architecture: $arch" } - +# ── Binary install ────────────────────────────────────────────────────────── +function Install-Binary($arch) { $pkg = "codeblog-app-windows-$arch" + $binPath = Join-Path $InstallDir "$BinName.exe" + + if (Test-Path $binPath) { + $script:WasInstalled = $true + } - Write-Info "Checking latest version..." $version = Get-LatestVersion - if (-not $version) { Write-Err "Failed to fetch latest version" } - Write-Info "Latest version: $version" + if (-not $version) { Write-Fail "Failed to fetch latest version from npm registry" } + Write-Ok "Latest version: v$version" + + # Check if already up to date + if ($script:WasInstalled) { + try { + $currentVersion = & $binPath --version 2>$null + if ($currentVersion -eq $version) { + Write-Ok "Already up to date (v$version)" + return + } + Write-Info "Updating: $currentVersion -> v$version" + } catch {} + } - Write-Info "Downloading $pkg@$version..." $url = "$NpmRegistry/$pkg/-/$pkg-$version.tgz" - $tmpDir = Join-Path $env:TEMP "codeblog-install-$(Get-Random)" New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null try { $tgz = Join-Path $tmpDir "pkg.tgz" + Write-Info "Downloading ${pkg}@${version}..." Invoke-WebRequest -Uri $url -OutFile $tgz -ErrorAction Stop + Write-Ok "Downloaded" - Write-Info "Installing..." + Write-Info "Extracting..." tar -xzf $tgz -C $tmpDir New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null - Copy-Item -Force (Join-Path $tmpDir "package\bin\codeblog.exe") (Join-Path $InstallDir "$BinName.exe") - - Write-Ok "Installed codeblog v$version to $InstallDir\$BinName.exe" + Copy-Item -Force (Join-Path $tmpDir "package\bin\codeblog.exe") $binPath + Write-Ok "Installed to $binPath" } finally { Remove-Item -Recurse -Force $tmpDir -ErrorAction SilentlyContinue } } +# ── PATH setup ────────────────────────────────────────────────────────────── function Setup-Path { $currentPath = [Environment]::GetEnvironmentVariable("Path", "User") - if ($currentPath -split ";" | Where-Object { $_ -eq $InstallDir }) { return } + if ($currentPath -split ";" | Where-Object { $_ -eq $InstallDir }) { + Write-Ok "Already in PATH" + return + } [Environment]::SetEnvironmentVariable("Path", "$InstallDir;$currentPath", "User") $env:PATH = "$InstallDir;$env:PATH" - Write-Info "Added $InstallDir to user PATH" + Write-Ok "Added to user PATH" } -function Main { +# ── Outro ─────────────────────────────────────────────────────────────────── +function Write-OutroFresh { Write-Host "" - Write-Host " CodeBlog CLI Installer" -ForegroundColor Cyan + Write-Host " " -NoNewline + Write-Host ([char]0x25C7) -NoNewline -ForegroundColor Green + Write-Host " Installation complete!" -ForegroundColor Green Write-Host "" + Write-Host " ───────────────────────────────────────────────────────────" -ForegroundColor DarkGray + Write-Host "" + Write-Host " Welcome to " -NoNewline + Write-Host "CodeBlog" -NoNewline -ForegroundColor Cyan + Write-Host " -- the AI-powered coding forum." + Write-Host "" + Write-Host " Your AI agent analyzes your coding sessions and shares" + Write-Host " insights with the community. Other developers read," + Write-Host " vote, and discuss -- all powered by real coding context." + Write-Host "" + Write-Host " Let's get you set up. The setup wizard will walk you" + Write-Host " through connecting your account and creating your agent." + Write-Host "" + Write-Host " ───────────────────────────────────────────────────────────" -ForegroundColor DarkGray + Write-Host "" +} - Write-Info "Platform: windows-$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLower())" - - Install-Binary - Setup-Path - +function Write-OutroUpdate { Write-Host "" - Write-Ok "codeblog installed successfully!" + Write-Host " " -NoNewline + Write-Host ([char]0x25C7) -NoNewline -ForegroundColor Green + Write-Host " Installation complete!" -ForegroundColor Green Write-Host "" - Write-Host " Get started:" -ForegroundColor White + Write-Host " " -NoNewline; Write-Host "codeblog" -NoNewline -ForegroundColor Cyan; Write-Host " Launch interactive TUI" + Write-Host " " -NoNewline; Write-Host "codeblog setup" -NoNewline -ForegroundColor Cyan; Write-Host " First-time setup" + Write-Host " " -NoNewline; Write-Host "codeblog --help" -NoNewline -ForegroundColor Cyan; Write-Host " See all commands" Write-Host "" - Write-Host " codeblog " -NoNewline -ForegroundColor Cyan; Write-Host "Launch interactive TUI" - Write-Host " codeblog --help " -NoNewline -ForegroundColor Cyan; Write-Host "See all commands" + Write-Host " " -NoNewline + Write-Host ([char]0x25B2) -NoNewline -ForegroundColor Yellow + Write-Host " Restart your terminal for PATH changes to take effect." -ForegroundColor Yellow Write-Host "" - Write-Host " Note: Restart your terminal for PATH changes to take effect." -ForegroundColor Yellow +} + +# ── Launch prompt ─────────────────────────────────────────────────────────── +function Prompt-Launch { + Write-Host " " -NoNewline + Write-Host ([char]0x25C6) -NoNewline -ForegroundColor Cyan + Write-Host " Press Enter to launch codeblog" -NoNewline -ForegroundColor White + Write-Host " (or Ctrl+C to exit)" -ForegroundColor DarkGray Write-Host "" + Read-Host | Out-Null + + $binPath = Join-Path $InstallDir "$BinName.exe" + & $binPath +} + +# ── Main ──────────────────────────────────────────────────────────────────── +function Main { + Write-Header + + # Step 1: Detect platform + Write-Step "Detecting platform" + $arch = Get-Platform + $platformDisplay = Format-Platform $arch + Write-Ok "$platformDisplay (windows-$arch)" + + # Step 2: Download and install + Write-Step "Installing codeblog" + Install-Binary $arch + + # Step 3: Configure PATH + Write-Step "Configuring PATH" + Setup-Path + + # Step 4: Post-install + Write-Step "Post-install" + if ($script:WasInstalled) { + Write-Ok "Update complete" + Write-OutroUpdate + } else { + Write-Ok "Ready to go" + Write-OutroFresh + Prompt-Launch + } } Main diff --git a/install.sh b/install.sh index 191f926..99371bc 100755 --- a/install.sh +++ b/install.sh @@ -9,19 +9,73 @@ BIN_NAME="codeblog" NPM_REGISTRY="https://registry.npmjs.org" RUN_ONBOARD="auto" WAS_INSTALLED=0 +CURRENT_STEP=0 +TOTAL_STEPS=4 +# ── Colors ────────────────────────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' CYAN='\033[0;36m' +BLUE='\033[0;34m' +DIM='\033[2m' BOLD='\033[1m' NC='\033[0m' -info() { echo -e "${CYAN}[codeblog]${NC} $1"; } -success() { echo -e "${GREEN}[codeblog]${NC} $1"; } -warn() { echo -e "${YELLOW}[codeblog]${NC} $1"; } -error() { echo -e "${RED}[codeblog]${NC} $1" >&2; exit 1; } +# ── Logging ───────────────────────────────────────────────────────────────── +info() { echo -e " ${CYAN}│${NC} $1"; } +success() { echo -e " ${GREEN}│${NC} ${GREEN}✔${NC} $1"; } +warn() { echo -e " ${YELLOW}│${NC} ${YELLOW}▲${NC} $1"; } +fail() { echo -e "\n ${RED}✖${NC} $1\n" >&2; exit 1; } +step() { + CURRENT_STEP=$((CURRENT_STEP + 1)) + echo "" + echo -e " ${CYAN}◆${NC} ${BOLD}Step ${CURRENT_STEP}/${TOTAL_STEPS}${NC} ${DIM}─${NC} $1" +} + +# ── Spinner ───────────────────────────────────────────────────────────────── +SPINNER_PID="" + +spinner_start() { + local msg="$1" + if [ ! -t 1 ]; then + info "$msg" + return + fi + ( + local frames=("⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏") + local i=0 + while true; do + printf "\r ${CYAN}│${NC} ${BLUE}${frames[$i]}${NC} %s" "$msg" + i=$(( (i + 1) % ${#frames[@]} )) + sleep 0.08 + done + ) & + SPINNER_PID=$! +} + +spinner_stop() { + local msg="$1" + if [ -n "$SPINNER_PID" ]; then + kill "$SPINNER_PID" 2>/dev/null || true + wait "$SPINNER_PID" 2>/dev/null || true + SPINNER_PID="" + printf "\r\033[K" + fi + echo -e " ${GREEN}│${NC} ${GREEN}✔${NC} $msg" +} + +# ── Cleanup ───────────────────────────────────────────────────────────────── +cleanup() { + if [ -n "$SPINNER_PID" ]; then + kill "$SPINNER_PID" 2>/dev/null || true + wait "$SPINNER_PID" 2>/dev/null || true + fi +} +trap cleanup EXIT + +# ── Usage ─────────────────────────────────────────────────────────────────── usage() { cat </dev/null | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4 + local response + response="$(curl -fsSL "$NPM_REGISTRY/codeblog-app/latest" 2>/dev/null)" || return 1 + echo "$response" | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4 } +# ── Binary install ────────────────────────────────────────────────────────── install_binary() { local platform="$1" local pkg="codeblog-app-${platform}" + if [ -x "$INSTALL_DIR/$BIN_NAME" ]; then WAS_INSTALLED=1 fi - info "Checking latest version..." + spinner_start "Fetching latest version..." local version - version="$(get_latest_version)" + version="$(get_latest_version)" || true if [ -z "$version" ]; then - error "Failed to fetch latest version from npm" + spinner_stop "Version check" + fail "Failed to fetch latest version from npm registry" + fi + spinner_stop "Latest version: ${BOLD}v${version}${NC}" + + # Check if already up to date + if [ "$WAS_INSTALLED" -eq 1 ]; then + local current_version + current_version="$("$INSTALL_DIR/$BIN_NAME" --version 2>/dev/null || echo "")" + if [ "$current_version" = "$version" ]; then + success "Already up to date ${DIM}(v${version})${NC}" + return 0 + fi + info "Updating: ${DIM}${current_version:-unknown}${NC} → ${BOLD}v${version}${NC}" fi - info "Latest version: $version" - info "Downloading $pkg@$version..." local tarball_url="$NPM_REGISTRY/$pkg/-/$pkg-$version.tgz" - local tmpdir tmpdir="$(mktemp -d)" - trap "rm -rf $tmpdir" EXIT - curl -fsSL "$tarball_url" -o "$tmpdir/pkg.tgz" || error "Failed to download binary for $platform" + spinner_start "Downloading ${pkg}@${version}..." + curl -fsSL "$tarball_url" -o "$tmpdir/pkg.tgz" || fail "Failed to download binary for $platform" + spinner_stop "Downloaded ${DIM}(${pkg}@${version})${NC}" - info "Installing..." + spinner_start "Extracting and installing..." mkdir -p "$INSTALL_DIR" tar -xzf "$tmpdir/pkg.tgz" -C "$tmpdir" - cp "$tmpdir/package/bin/$BIN_NAME" "$INSTALL_DIR/$BIN_NAME" chmod +x "$INSTALL_DIR/$BIN_NAME" + # macOS code signing if [ "$(uname -s)" = "Darwin" ] && command -v codesign >/dev/null 2>&1; then codesign --sign - --force "$INSTALL_DIR/$BIN_NAME" 2>/dev/null || true fi + spinner_stop "Installed to ${DIM}${INSTALL_DIR}/${BIN_NAME}${NC}" - success "Installed codeblog v$version to $INSTALL_DIR/$BIN_NAME" + rm -rf "$tmpdir" } +# ── Onboarding ────────────────────────────────────────────────────────────── should_run_onboard() { - if [ "$RUN_ONBOARD" = "no" ]; then - return 1 - fi - if [ "$RUN_ONBOARD" = "yes" ]; then - return 0 - fi - if [ "$WAS_INSTALLED" -eq 0 ]; then - return 0 - fi + if [ "$RUN_ONBOARD" = "no" ]; then return 1; fi + if [ "$RUN_ONBOARD" = "yes" ]; then return 0; fi + # Auto: only on fresh install + if [ "$WAS_INSTALLED" -eq 0 ]; then return 0; fi return 1 } run_onboard() { - if ! should_run_onboard; then - return - fi + if ! should_run_onboard; then return; fi if [ ! -t 1 ] || [ ! -r /dev/tty ]; then - warn "Skipping first-time setup (no interactive TTY). Run: codeblog setup" + warn "Skipping first-time setup (no interactive TTY)" + info "Run later: ${CYAN}codeblog setup${NC}" return fi echo "" info "Starting first-time setup wizard..." + echo "" if ! "$INSTALL_DIR/$BIN_NAME" setup < /dev/tty > /dev/tty 2>&1; then - warn "Setup was not completed. You can rerun anytime: codeblog setup" + warn "Setup was not completed. Run anytime: ${CYAN}codeblog setup${NC}" fi } +# ── PATH setup ────────────────────────────────────────────────────────────── setup_path() { - if [[ ":$PATH:" == *":$INSTALL_DIR:"* ]]; then - return - fi + if [[ ":$PATH:" == *":$INSTALL_DIR:"* ]]; then return; fi local shell_rc case "${SHELL:-/bin/bash}" in - */zsh) shell_rc="$HOME/.zshrc" ;; + */zsh) shell_rc="$HOME/.zshrc" ;; */bash) shell_rc="$HOME/.bashrc" ;; - *) shell_rc="$HOME/.profile" ;; + *) shell_rc="$HOME/.profile" ;; esac if ! grep -q "codeblog" "$shell_rc" 2>/dev/null; then echo "" >> "$shell_rc" echo "# codeblog" >> "$shell_rc" echo "export PATH=\"$INSTALL_DIR:\$PATH\"" >> "$shell_rc" - info "Added $INSTALL_DIR to PATH in $shell_rc" + success "Added to PATH in ${DIM}${shell_rc}${NC}" fi } -main() { - parse_args "$@" +# ── Header ────────────────────────────────────────────────────────────────── +print_header() { + echo "" + echo -e " ${CYAN}${BOLD}" + echo -e " ██████╗ ██████╗ ██████╗ ███████╗██████╗ ██╗ ██████╗ ██████╗ " + echo -e " ██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗██║ ██╔═══██╗██╔════╝ " + echo -e " ██║ ██║ ██║██║ ██║█████╗ ██████╔╝██║ ██║ ██║██║ ███╗" + echo -e " ██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗██║ ██║ ██║██║ ██║" + echo -e " ╚██████╗╚██████╔╝██████╔╝███████╗██████╔╝███████╗╚██████╔╝╚██████╔╝" + echo -e " ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ " + echo -e " ${NC}" + echo -e " ${DIM}AI-powered coding forum — codeblog.ai${NC}" + echo -e " ${DIM}────────────────────────────────────────────────────────────────${NC}" +} + +# ── Outro ─────────────────────────────────────────────────────────────────── +print_outro() { + local is_fresh=$1 # "fresh" or "update" echo "" - echo -e "${CYAN} ██████╗ ██████╗ ██████╗ ███████╗${BOLD}██████╗ ██╗ ██████╗ ██████╗ ${NC}" - echo -e "${CYAN} ██╔════╝██╔═══██╗██╔══██╗██╔════╝${BOLD}██╔══██╗██║ ██╔═══██╗██╔════╝ ${NC}" - echo -e "${CYAN} ██║ ██║ ██║██║ ██║█████╗ ${BOLD}██████╔╝██║ ██║ ██║██║ ███╗${NC}" - echo -e "${CYAN} ██║ ██║ ██║██║ ██║██╔══╝ ${BOLD}██╔══██╗██║ ██║ ██║██║ ██║${NC}" - echo -e "${CYAN} ╚██████╗╚██████╔╝██████╔╝███████╗${BOLD}██████╔╝███████╗╚██████╔╝╚██████╔╝${NC}" - echo -e "${CYAN} ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝${BOLD}╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ ${NC}" + echo -e " ${GREEN}◇${NC} ${GREEN}${BOLD}Installation complete!${NC}" echo "" + if [ "$is_fresh" = "fresh" ]; then + echo -e " ${DIM}───────────────────────────────────────────────────────────${NC}" + echo "" + echo -e " Welcome to ${CYAN}${BOLD}CodeBlog${NC} -- the AI-powered coding forum." + echo "" + echo -e " Your AI agent analyzes your coding sessions and shares" + echo -e " insights with the community. Other developers read," + echo -e " vote, and discuss -- all powered by real coding context." + echo "" + echo -e " Let's get you set up. The setup wizard will walk you" + echo -e " through connecting your account and creating your agent." + echo "" + echo -e " ${DIM}───────────────────────────────────────────────────────────${NC}" + else + echo "" + echo -e " ${CYAN}codeblog${NC} Launch interactive TUI" + echo -e " ${CYAN}codeblog setup${NC} First-time setup" + echo -e " ${CYAN}codeblog --help${NC} See all commands" + fi + + if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then + echo "" + echo -e " ${YELLOW}▲${NC} Restart your terminal or run:" + local shell_name + case "${SHELL:-/bin/bash}" in + */zsh) shell_name=".zshrc" ;; + */bash) shell_name=".bashrc" ;; + *) shell_name=".profile" ;; + esac + echo -e " ${DIM}source ~/${shell_name}${NC}" + fi + echo "" +} + +# ── Launch prompt ─────────────────────────────────────────────────────────── +prompt_launch() { + # Only prompt on fresh install with TTY + if [ "$WAS_INSTALLED" -eq 1 ]; then return; fi + if [ "$RUN_ONBOARD" = "no" ]; then return; fi + if [ ! -t 1 ] || [ ! -r /dev/tty ]; then + info "Run ${CYAN}codeblog${NC} to get started." + return + fi + + echo -e " ${CYAN}◆${NC} ${BOLD}Press Enter to launch codeblog${NC} ${DIM}(or Ctrl+C to exit)${NC}" + echo "" + read -r < /dev/tty + + # Source PATH if needed so the binary is found + export PATH="$INSTALL_DIR:$PATH" + exec "$INSTALL_DIR/$BIN_NAME" < /dev/tty > /dev/tty 2>&1 +} + +# ── Main ──────────────────────────────────────────────────────────────────── +main() { + parse_args "$@" + print_header + + # Step 1: Detect platform + step "Detecting platform" local platform platform="$(detect_platform)" - info "Platform: $platform" + local platform_display + platform_display="$(format_platform "$platform")" + success "${platform_display} ${DIM}(${platform})${NC}" + # Step 2: Download and install + step "Installing codeblog" install_binary "$platform" - setup_path - run_onboard - echo "" - success "codeblog installed successfully!" - echo "" - echo -e " ${BOLD}Get started:${NC}" - echo "" - echo -e " ${CYAN}codeblog${NC} Launch interactive TUI" - echo -e " ${CYAN}codeblog setup${NC} Run first-time setup wizard" - echo -e " ${CYAN}codeblog --help${NC} See all commands" - echo "" - echo -e " ${YELLOW}Note:${NC} Restart your terminal or run: source ~/.zshrc" - echo "" + # Step 3: Configure PATH + step "Configuring PATH" + if [[ ":$PATH:" == *":$INSTALL_DIR:"* ]]; then + success "Already in PATH" + else + setup_path + fi + + # Step 4: Post-install + step "Post-install" + if [ "$WAS_INSTALLED" -eq 1 ]; then + success "Update complete" + else + success "Ready to go" + fi + + # Show outro — different for fresh vs update + if [ "$WAS_INSTALLED" -eq 0 ]; then + print_outro "fresh" + prompt_launch + else + print_outro "update" + fi } main "$@"