From 6164746811147ce4d47485514184996863e0cb0c Mon Sep 17 00:00:00 2001 From: Andrejus Date: Thu, 12 Feb 2026 16:44:11 +0000 Subject: [PATCH] feat: logging, remote widget, ci fix --- files/home/.aliases | 29 +++++++++++++++++++++------- files/home/.zshrc | 21 ++++++++++++++++---- script/install | 3 ++- script/install.d/00-os.sh | 2 ++ script/install.d/10-brew.sh | 3 ++- script/install.d/11-apt.sh | 3 ++- script/install.d/12-pacman.sh | 3 ++- script/install.d/20-ssh.sh | 5 +++-- script/install.d/21-git.sh | 3 ++- script/install.d/22-zsh.sh | 13 ++----------- script/install.d/23-stow.sh | 2 ++ script/install.d/24-tmux.sh | 1 + script/install.d/30-mise.sh | 3 ++- script/install.d/41-docker.sh | 9 +++++---- script/install.d/42-azure.sh | 3 ++- script/install.d/50-redis.sh | 3 ++- script/install.d/60-iterm2.sh | 4 ++-- script/install.d/61-nerdfont.sh | 3 ++- script/install.d/70-cca.sh | 3 ++- script/install.d/71-rectangle.sh | 3 ++- script/install.d/72-meetingbar.sh | 3 ++- script/install.d/73-betterdisplay.sh | 3 ++- script/install.d/74-dockutil.sh | 3 ++- script/install.d/81-cmatrix.sh | 4 ++-- script/install.d/90-macos.sh | 5 +++-- script/install.d/99-fastfetch.sh | 3 ++- tests/test_binaries.py | 1 - 27 files changed, 91 insertions(+), 50 deletions(-) diff --git a/files/home/.aliases b/files/home/.aliases index 2270974..3561c0d 100644 --- a/files/home/.aliases +++ b/files/home/.aliases @@ -9,7 +9,24 @@ alias zen='curl -s https://api.github.com/zen && echo' alias la='ls -la' alias vi='vim' alias copilot='gh copilot' -alias cs='gh cs ssh' +cs() { + local codespace="${1:-}" + if [[ -z "$codespace" ]]; then + codespace="$(gh cs list --json name -q '.[].name' | fzf)" || return + fi + [[ -n "$TMUX" ]] && tmux rename-window "cs:$codespace" + trap '[[ -n "$TMUX" ]] && tmux set automatic-rename on' EXIT INT TERM + gh cs ssh -c "$codespace" + local rc=$? + trap - EXIT INT TERM + [[ -n "$TMUX" ]] && tmux set automatic-rename on + if (( rc == 0 )); then + local log="${XDG_DATA_HOME:-$HOME/.local/share}/ssh/log" + mkdir -p "$(dirname "$log")" + printf '%s cs:%s\n' "$(date +%s)" "$codespace" >> "$log" + fi + return $rc +} alias colby='copilot --allow-all-tools --allow-all-paths' alias gs='git s' alias gd='git d' @@ -26,12 +43,12 @@ f() { local f; f="$(fzf --preview 'head -100 {}')" && ${EDITOR:-vim} "$f"; } ssh() { local ssh_target="${@: -1}" - if [[ -n "$TMUX" ]]; then - tmux rename-window "ssh:$ssh_target" - fi - + [[ -n "$TMUX" ]] && tmux rename-window "ssh:$ssh_target" + trap '[[ -n "$TMUX" ]] && tmux set automatic-rename on' EXIT INT TERM command ssh "$@" local rc=$? + trap - EXIT INT TERM + [[ -n "$TMUX" ]] && tmux set automatic-rename on if (( rc == 0 )); then local host="$ssh_target" @@ -50,8 +67,6 @@ ssh() { printf '%s %s\n' "$(date +%s)" "$host" >> "$ssh_log" fi - - [[ -n "$TMUX" ]] && tmux set automatic-rename on return $rc } s() { local h; h="$(_dots_ssh_hosts | fzf)" && ssh "$h"; } diff --git a/files/home/.zshrc b/files/home/.zshrc index 93cf81f..add50f2 100644 --- a/files/home/.zshrc +++ b/files/home/.zshrc @@ -106,21 +106,34 @@ _dots_load_keybindings() { zle -N _dots_edit_widget bindkey '^E' _dots_edit_widget - # Ctrl+G: SSH host picker + # Ctrl+G: remote connect _dots_ssh_hosts() { local ssh_log="${XDG_DATA_HOME:-$HOME/.local/share}/ssh/log" + local cs_cache="$_dots_cache_dir/codespaces" + + # Refresh codespace cache in background if stale (>5 min) + if [[ ! -f "$cs_cache" ]] || [[ -n "$(find "$cs_cache" -mmin +5 2>/dev/null)" ]]; then + { gh cs list --json name -q '.[].name' 2>/dev/null | sed 's/^/cs:/' > "$cs_cache.tmp" && mv "$cs_cache.tmp" "$cs_cache"; } &! + fi + { if [[ -f "$ssh_log" ]]; then awk '{c[$2]++; t[$2]=$1} END {for(h in c) print c[h]*1000+t[h], h}' "$ssh_log" | sort -rn | awk '{print $2}' fi awk '/^Host / && !/\*/ {print $2}' ~/.ssh/config ~/.ssh/config.d/* 2>/dev/null awk '{print $1}' ~/.ssh/known_hosts 2>/dev/null | tr ',' '\n' | sed 's/\[//;s/\]:.*//' + [[ -f "$cs_cache" ]] && cat "$cs_cache" } | awk '!seen[$0]++' } _dots_ssh_widget() { - local host - host="$(_dots_ssh_hosts | fzf)" || { zle reset-prompt; return; } - BUFFER="ssh $host" + local target + target="$(_dots_ssh_hosts | fzf)" || { zle reset-prompt; return; } + if [[ "$target" == cs:* ]]; then + BUFFER="cs ${target#cs:}" + else + BUFFER="ssh $target" + fi + zle reset-prompt zle accept-line } zle -N _dots_ssh_widget diff --git a/script/install b/script/install index 5e32830..eb7c0e5 100755 --- a/script/install +++ b/script/install @@ -28,12 +28,13 @@ fi # Log functions log_info() { echo -e "${BLUE}[INFO]${NC} $*"; } log_pass() { echo -e "${GREEN}[PASS]${NC} $*"; } +log_skip() { echo -e "${GREY}[SKIP]${NC} $*"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } log_error() { echo -e "${RED}[FAIL]${NC} $*"; } log_debug() { echo -e "${CYAN}$*${NC}"; } # Export log functions -export -f log_info log_pass log_warn log_error log_debug +export -f log_info log_pass log_skip log_warn log_error log_debug printf "\n\t${CYAN} <<< ${CYAN_BOLD}dots${CYAN} >>> ${NC}\n" printf "\t${GREY}==============${NC}\n\n" diff --git a/script/install.d/00-os.sh b/script/install.d/00-os.sh index b628650..d11a47f 100755 --- a/script/install.d/00-os.sh +++ b/script/install.d/00-os.sh @@ -24,3 +24,5 @@ fi if [[ "$DOTS_ENV" == "codespaces" ]]; then log_info "Running in GitHub Codespaces" fi + +log_pass "OS detection complete" diff --git a/script/install.d/10-brew.sh b/script/install.d/10-brew.sh index 453e172..ff3a9f0 100755 --- a/script/install.d/10-brew.sh +++ b/script/install.d/10-brew.sh @@ -6,7 +6,7 @@ # # macOS only -[[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } +[[ "$DOTS_OS" != "macos" ]] && { log_skip "Not macOS"; return 0; } if ! command -v brew &> /dev/null; then echo "Installing Homebrew..." @@ -16,3 +16,4 @@ else echo "Homebrew is already installed." fi brew --version +log_pass "Homebrew installed" diff --git a/script/install.d/11-apt.sh b/script/install.d/11-apt.sh index 5c4db32..d523d5e 100755 --- a/script/install.d/11-apt.sh +++ b/script/install.d/11-apt.sh @@ -6,7 +6,7 @@ # # apt only -[[ "$DOTS_PKG" != "apt" ]] && { log_warn "Skipping: Not using apt"; return 0; } +[[ "$DOTS_PKG" != "apt" ]] && { log_skip "Not using apt"; return 0; } apt_packages=( build-essential @@ -23,3 +23,4 @@ sudo apt-get install -qq "${apt_packages[@]}" unset apt_packages apt --version +log_pass "apt packages installed" diff --git a/script/install.d/12-pacman.sh b/script/install.d/12-pacman.sh index eb0bd4b..a4148d9 100755 --- a/script/install.d/12-pacman.sh +++ b/script/install.d/12-pacman.sh @@ -6,7 +6,7 @@ # # pacman only -[[ "$DOTS_PKG" != "pacman" ]] && { log_warn "Skipping: Not using pacman"; return 0; } +[[ "$DOTS_PKG" != "pacman" ]] && { log_skip "Not using pacman"; return 0; } pacman_packages=( ca-certificates @@ -32,3 +32,4 @@ fi pacman --version yay --version +log_pass "pacman packages installed" diff --git a/script/install.d/20-ssh.sh b/script/install.d/20-ssh.sh index b8292e2..3d8d0c6 100755 --- a/script/install.d/20-ssh.sh +++ b/script/install.d/20-ssh.sh @@ -6,10 +6,10 @@ # # Skip in Codespaces (managed by GitHub) -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } +[[ "$DOTS_ENV" == "codespaces" ]] && { log_skip "Codespaces"; return 0; } # Skip if explicitly disabled -[[ -n "$SKIP_SSH_CONFIG" ]] && { log_warn "Skipping SSH configuration"; return 0; } +[[ -n "$SKIP_SSH_CONFIG" ]] && { log_skip "SKIP_SSH_CONFIG is set"; return 0; } ssh_method="ed25519" @@ -26,3 +26,4 @@ fi cat "$ssh_pub" unset ssh_method ssh_target ssh_key ssh_pub +log_pass "SSH key configured" diff --git a/script/install.d/21-git.sh b/script/install.d/21-git.sh index 79993d0..cbf9f04 100755 --- a/script/install.d/21-git.sh +++ b/script/install.d/21-git.sh @@ -6,7 +6,7 @@ # # Skip in Codespaces (pre-installed in universal image) -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; git --version; return 0; } +[[ "$DOTS_ENV" == "codespaces" ]] && { log_skip "Codespaces"; git --version; return 0; } if ! command -v git &> /dev/null; then case "$DOTS_PKG" in @@ -27,3 +27,4 @@ if ! command -v git &> /dev/null; then fi git --version +log_pass "git configured" diff --git a/script/install.d/22-zsh.sh b/script/install.d/22-zsh.sh index f34c3ca..ab81a3d 100755 --- a/script/install.d/22-zsh.sh +++ b/script/install.d/22-zsh.sh @@ -44,19 +44,10 @@ if [ ! -d "$PLUGIN_DIR/zsh-syntax-highlighting" ]; then "$PLUGIN_DIR/zsh-syntax-highlighting" fi -# warn about legacy oh-my-zsh directory -if [ -d "$HOME/.oh-my-zsh" ]; then - log_warn "Legacy ~/.oh-my-zsh directory found. Remove with: rm -rf ~/.oh-my-zsh" -fi - -# migrate zoxide database from z if available -if command -v zoxide &>/dev/null && [ -f "$HOME/.z" ]; then - log_info "Importing z database into zoxide..." - zoxide import --from z "$HOME/.z" 2>/dev/null || true -fi - # change default shell to zsh if [[ "$SHELL" != *zsh ]]; then sudo chsh -s "$(command -v zsh)" "$(whoami)" sudo usermod -s "$(command -v zsh)" "$(whoami)" fi + +log_pass "zsh configured" diff --git a/script/install.d/23-stow.sh b/script/install.d/23-stow.sh index 7268614..9867f23 100755 --- a/script/install.d/23-stow.sh +++ b/script/install.d/23-stow.sh @@ -44,3 +44,5 @@ stow --dir="$root_dir/files" --target="$HOME/.ssh" dot-ssh # Bust PATH cache to force regeneration with new profile rm -f "${XDG_CACHE_HOME:-$HOME/.cache}/dots/path" + +log_pass "stow linked" diff --git a/script/install.d/24-tmux.sh b/script/install.d/24-tmux.sh index dc1e1d8..746026a 100644 --- a/script/install.d/24-tmux.sh +++ b/script/install.d/24-tmux.sh @@ -24,3 +24,4 @@ if ! command -v tmux &> /dev/null; then fi tmux -V +log_pass "tmux installed" diff --git a/script/install.d/30-mise.sh b/script/install.d/30-mise.sh index cb1e28a..6eb2643 100755 --- a/script/install.d/30-mise.sh +++ b/script/install.d/30-mise.sh @@ -7,7 +7,7 @@ # # Skip in Codespaces (use pre-installed versions) -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } +[[ "$DOTS_ENV" == "codespaces" ]] && { log_skip "Codespaces"; return 0; } # Install mise if ! command -v mise &>/dev/null; then @@ -89,3 +89,4 @@ mise exec -- gh --version mise exec -- terraform --version | head -1 echo "firebase: $(mise exec -- firebase --version)" echo "fastfetch: $(mise exec -- fastfetch --version 2>&1 | head -1)" +log_pass "mise tools installed" diff --git a/script/install.d/41-docker.sh b/script/install.d/41-docker.sh index d5ad70f..d143551 100755 --- a/script/install.d/41-docker.sh +++ b/script/install.d/41-docker.sh @@ -7,19 +7,19 @@ # # skip if SKIP_DOCKER_CONFIG is set -[[ -n "$SKIP_DOCKER_CONFIG" ]] && { log_warn "Skipping: SKIP_DOCKER_CONFIG is set"; return 0; } +[[ -n "$SKIP_DOCKER_CONFIG" ]] && { log_skip "SKIP_DOCKER_CONFIG is set"; return 0; } # skip if in WSL if [[ -n "$WSL_DISTRO_NAME" ]]; then - log_warn "Skipping: Running in WSL" + log_skip "Running in WSL" return 0 fi # skip if in Codespaces -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } +[[ "$DOTS_ENV" == "codespaces" ]] && { log_skip "Codespaces"; return 0; } # skip on macOS -[[ "$DOTS_OS" == "macos" ]] && { log_warn "Skipping: macOS"; return 0; } +[[ "$DOTS_OS" == "macos" ]] && { log_skip "macOS"; return 0; } if ! command -v docker &> /dev/null; then case "$DOTS_PKG" in @@ -57,3 +57,4 @@ if ! groups "$USER" | grep -q "\b$docker_group\b"; then fi docker --version +log_pass "Docker configured" diff --git a/script/install.d/42-azure.sh b/script/install.d/42-azure.sh index ab51531..8be7d92 100755 --- a/script/install.d/42-azure.sh +++ b/script/install.d/42-azure.sh @@ -6,7 +6,7 @@ # # Skip in Codespaces (project-specific tool) -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } +[[ "$DOTS_ENV" == "codespaces" ]] && { log_skip "Codespaces"; return 0; } if ! command -v az &>/dev/null; then case "$DOTS_PKG" in @@ -27,3 +27,4 @@ if ! command -v az &>/dev/null; then fi az --version +log_pass "Azure CLI installed" diff --git a/script/install.d/50-redis.sh b/script/install.d/50-redis.sh index 8d2fdc6..98d9a8c 100755 --- a/script/install.d/50-redis.sh +++ b/script/install.d/50-redis.sh @@ -6,7 +6,7 @@ # # Skip in Codespaces (project-specific tool) -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } +[[ "$DOTS_ENV" == "codespaces" ]] && { log_skip "Codespaces"; return 0; } if ! command -v redis-cli &>/dev/null; then case "$DOTS_PKG" in @@ -32,3 +32,4 @@ if ! command -v redis-cli &>/dev/null; then fi redis-cli --version +log_pass "Redis installed" diff --git a/script/install.d/60-iterm2.sh b/script/install.d/60-iterm2.sh index 43eae73..452f560 100755 --- a/script/install.d/60-iterm2.sh +++ b/script/install.d/60-iterm2.sh @@ -6,9 +6,9 @@ # # macOS only -[[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } +[[ "$DOTS_OS" != "macos" ]] && { log_skip "Not macOS"; return 0; } if ! echo "$BREW_CASKS" | grep -q "^iterm2$"; then brew install --cask iterm2 fi -log_pass "iTerm2 installed successfully!" +log_pass "iTerm2 installed" diff --git a/script/install.d/61-nerdfont.sh b/script/install.d/61-nerdfont.sh index 9567caf..5935f86 100755 --- a/script/install.d/61-nerdfont.sh +++ b/script/install.d/61-nerdfont.sh @@ -6,7 +6,7 @@ # # macOS only -[[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } +[[ "$DOTS_OS" != "macos" ]] && { log_skip "Not macOS"; return 0; } fonts_list=( font-fira-mono-nerd-font @@ -32,3 +32,4 @@ if [[ "$fonts_missing" == "true" ]]; then fi unset fonts_list fonts_missing +log_pass "Nerd Fonts installed" diff --git a/script/install.d/70-cca.sh b/script/install.d/70-cca.sh index 53723f9..f69dd9b 100755 --- a/script/install.d/70-cca.sh +++ b/script/install.d/70-cca.sh @@ -6,10 +6,11 @@ # # macOS only -[[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } +[[ "$DOTS_OS" != "macos" ]] && { log_skip "Not macOS"; return 0; } if ! echo "$BREW_CASKS" | grep -q "^colour-contrast-analyser$"; then brew install --cask colour-contrast-analyser else echo "Colour Contrast Analyser (CCA) is already installed." fi +log_pass "CCA installed" diff --git a/script/install.d/71-rectangle.sh b/script/install.d/71-rectangle.sh index ec259a1..6280c5b 100755 --- a/script/install.d/71-rectangle.sh +++ b/script/install.d/71-rectangle.sh @@ -6,10 +6,11 @@ # # macOS only -[[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } +[[ "$DOTS_OS" != "macos" ]] && { log_skip "Not macOS"; return 0; } if ! echo "$BREW_CASKS" | grep -q "^rectangle$"; then brew install --cask rectangle else echo "Rectangle is already installed." fi +log_pass "Rectangle installed" diff --git a/script/install.d/72-meetingbar.sh b/script/install.d/72-meetingbar.sh index ad76488..5091e79 100755 --- a/script/install.d/72-meetingbar.sh +++ b/script/install.d/72-meetingbar.sh @@ -6,10 +6,11 @@ # # macOS only -[[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } +[[ "$DOTS_OS" != "macos" ]] && { log_skip "Not macOS"; return 0; } if ! echo "$BREW_CASKS" | grep -q "^meetingbar$"; then brew install --cask meetingbar else echo "MeetingBar is already installed." fi +log_pass "MeetingBar installed" diff --git a/script/install.d/73-betterdisplay.sh b/script/install.d/73-betterdisplay.sh index 579c9f8..bb6f6fe 100755 --- a/script/install.d/73-betterdisplay.sh +++ b/script/install.d/73-betterdisplay.sh @@ -6,10 +6,11 @@ # # macOS only -[[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } +[[ "$DOTS_OS" != "macos" ]] && { log_skip "Not macOS"; return 0; } if ! echo "$BREW_CASKS" | grep -q "^betterdisplay$"; then brew install --cask betterdisplay else echo "BetterDisplay is already installed." fi +log_pass "BetterDisplay installed" diff --git a/script/install.d/74-dockutil.sh b/script/install.d/74-dockutil.sh index 8bedbf3..f6d32ea 100755 --- a/script/install.d/74-dockutil.sh +++ b/script/install.d/74-dockutil.sh @@ -6,10 +6,11 @@ # # macOS only -[[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } +[[ "$DOTS_OS" != "macos" ]] && { log_skip "Not macOS"; return 0; } if ! echo "$BREW_FORMULAE" | grep -q "^dockutil$"; then brew install dockutil else echo "dockutil is already installed." fi +log_pass "dockutil installed" diff --git a/script/install.d/81-cmatrix.sh b/script/install.d/81-cmatrix.sh index fd79bd1..b44ae35 100755 --- a/script/install.d/81-cmatrix.sh +++ b/script/install.d/81-cmatrix.sh @@ -6,7 +6,7 @@ # # skip if in Codespaces -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } +[[ "$DOTS_ENV" == "codespaces" ]] && { log_skip "Codespaces"; return 0; } if ! command -v cmatrix &> /dev/null; then case "$DOTS_PKG" in @@ -24,4 +24,4 @@ if ! command -v cmatrix &> /dev/null; then ;; esac fi -log_pass "cmatrix installed successfully!" +log_pass "cmatrix installed" diff --git a/script/install.d/90-macos.sh b/script/install.d/90-macos.sh index a38f13c..a679aaf 100755 --- a/script/install.d/90-macos.sh +++ b/script/install.d/90-macos.sh @@ -6,7 +6,7 @@ # # macOS only -[[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; } +[[ "$DOTS_OS" != "macos" ]] && { log_skip "Not macOS"; return 0; } # Keyboard # -------- @@ -177,4 +177,5 @@ if [[ ! $dock_state == *"spacer"* ]]; then dockutil --add '' --type spacer --section apps --position "${#dock_order[@]}" --no-restart 2>/dev/null || true fi -log_info "macOS settings configured. Restart Finder/Dock to apply: osascript -e 'quit app \"Finder\"'" +log_info "Restart Finder/Dock to apply: osascript -e 'quit app \"Finder\"'" +log_pass "macOS defaults configured" diff --git a/script/install.d/99-fastfetch.sh b/script/install.d/99-fastfetch.sh index bb9a12a..8519d93 100755 --- a/script/install.d/99-fastfetch.sh +++ b/script/install.d/99-fastfetch.sh @@ -6,6 +6,7 @@ # # Skip in Codespaces (cosmetic only) -[[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; } +[[ "$DOTS_ENV" == "codespaces" ]] && { log_skip "Codespaces"; return 0; } fastfetch --pipe false + diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 10fb60a..018e557 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -46,7 +46,6 @@ binaries: List[Text] = [ # tools "git", "gh", - "copilot", "terraform", "docker" if not os.environ.get("SKIP_DOCKER_CONFIG") else None, "mise",