31 Commits

Author SHA1 Message Date
David Tomaschik
e2ec4e1f9c Update Brewfile 2026-07-23 12:41:19 -07:00
David Tomaschik
ba97442895 Fix iterm integration for zsh prompt 2026-07-13 15:55:34 -07:00
David Tomaschik
a9b68bfe1f New script to deploy a checkout 2026-07-09 20:31:01 -07:00
David Tomaschik
2814312d60 Optimize startup 2026-07-07 14:53:56 -07:00
David Tomaschik
a390d0a4d4 Improve SSH_AUTH_SOCK handling. 2026-07-07 14:28:37 -07:00
David Tomaschik
6caee04853 Update install_tool for ssh-agent-mux. 2026-07-07 10:10:59 -07:00
David Tomaschik
da1ee162c2 Script cleanup 2026-07-06 15:59:12 -07:00
David Tomaschik
22b3f2e049 Update install_tool 2026-07-01 12:15:39 -07:00
David Tomaschik
b81ca9703b Fix broken shenv merge 2026-06-30 12:24:00 -07:00
David Tomaschik
be903aeb2c Merge branch 'main' of https://github.com/Matir/skel 2026-06-30 12:22:44 -07:00
David Tomaschik
37816c7f72 Merge branch 'main' of https://github.com/Matir/skel 2026-06-30 12:20:24 -07:00
David Tomaschik
63f8bb9364 Update SSH socket handling 2026-06-30 12:20:00 -07:00
David Tomaschik
691b2a7c6f shenv update 2026-06-30 10:57:52 -07:00
David Tomaschik
8e42781710 Merge branch 'main' of https://github.com/Matir/skel 2026-06-30 10:47:42 -07:00
David Tomaschik
de601c4a83 Update dotfiles 2026-06-30 10:47:40 -07:00
David Tomaschik
684f6c6e95 Update update-authorized-keys 2026-06-29 23:01:21 -07:00
David Tomaschik
91972eed59 Update ssh keys 2026-06-29 22:49:37 -07:00
David Tomaschik
eca9a6bcb2 Merge branch 'main' of github.com:Matir/skel 2026-06-29 22:42:10 -07:00
David Tomaschik
3214af0617 Add authorized_keys.d 2026-06-29 22:35:18 -07:00
David Tomaschik
be3fdefd23 Bump brewfile 2026-06-24 13:22:53 -07:00
David Tomaschik
00eb8832c2 Move codex 2026-06-24 13:21:27 -07:00
David Tomaschik
5852b8564f Brewfile update for veracrypt 2026-06-24 13:06:28 -07:00
David Tomaschik
f56bcf4cdf bump brewfile 2026-06-19 14:20:59 -07:00
David Tomaschik
ad135fac37 Updates 2026-06-19 14:17:48 -07:00
David Tomaschik
e4b9a7c16b Merge branch 'main' of https://github.com/Matir/skel 2026-06-18 12:11:22 -07:00
David Tomaschik
75348c4413 Fixup zcompile 2026-06-18 12:11:17 -07:00
David Tomaschik
2e0c11c044 Support LC paths 2026-06-09 08:59:05 -07:00
David Tomaschik
68daa27893 Remove starship custom for gemini-cli 2026-06-04 14:41:59 -07:00
David Tomaschik
398d55b8e4 Add newnote 2026-06-02 15:40:34 -07:00
David Tomaschik
c9918cf213 Update install.sh 2026-05-27 16:53:38 -07:00
David Tomaschik
d1e3c8e43e Update gitignore 2026-05-27 15:58:25 -07:00
33 changed files with 925 additions and 291 deletions

View File

@@ -1,6 +1,7 @@
tap "dart-lang/dart" tap "dart-lang/dart", trusted: true
tap "holtwick/tap" tap "espressif/eim"
tap "sass/sass" tap "holtwick/tap", trusted: true
tap "sass/sass", trusted: true
brew "ack" brew "ack"
brew "acme.sh" brew "acme.sh"
@@ -20,9 +21,10 @@ brew "devcontainer"
brew "dfu-util" brew "dfu-util"
brew "difftastic" brew "difftastic"
brew "direnv" brew "direnv"
brew "dua-cli"
brew "duck" brew "duck"
brew "dust" brew "dust"
brew "earthly" brew "espressif/eim/eim", trusted: true
brew "esptool" brew "esptool"
brew "fish" brew "fish"
brew "fq" brew "fq"
@@ -31,11 +33,14 @@ brew "ghidra", link: false
brew "git" brew "git"
brew "git-delta" brew "git-delta"
brew "git-lfs" brew "git-lfs"
brew "git-xet"
brew "glib"
brew "gnupg" brew "gnupg"
brew "go" brew "go"
brew "gradle" brew "gradle"
brew "hashcat"
brew "hf" brew "hf"
brew "holtwick/tap/bx" brew "holtwick/tap/bx", trusted: true
brew "htop" brew "htop"
brew "httpie" brew "httpie"
brew "hugo" brew "hugo"
@@ -44,7 +49,9 @@ brew "john-jumbo"
brew "jq" brew "jq"
brew "kubeconform" brew "kubeconform"
brew "kubectx" brew "kubectx"
brew "libgcrypt"
brew "librsvg" brew "librsvg"
brew "libslirp"
brew "lima" brew "lima"
brew "minikube" brew "minikube"
brew "mise" brew "mise"
@@ -56,23 +63,27 @@ brew "ollama"
brew "p7zip" brew "p7zip"
brew "pipenv" brew "pipenv"
brew "pipx" brew "pipx"
brew "pixman"
brew "pkgconf" brew "pkgconf"
brew "protobuf" brew "protobuf"
brew "pwgen" brew "pwgen"
brew "pwntools" brew "pwntools"
brew "python@3.13" brew "python@3.13"
brew "python@3.14"
brew "qemu" brew "qemu"
brew "restic" brew "restic"
brew "ripgrep" brew "ripgrep"
brew "ruby" brew "ruby", link: false
brew "ruby@3.3" brew "ruby@3.3"
brew "rustup" brew "rustup"
brew "sass/sass/migrator" brew "sass/sass/migrator"
brew "sass/sass/sass" brew "sass/sass/sass"
brew "sdl2-compat"
brew "shellcheck" brew "shellcheck"
brew "smartmontools" brew "smartmontools"
brew "starship" brew "starship"
brew "tmux" brew "tmux"
brew "todoist-cli"
brew "uv" brew "uv"
brew "virtualenvwrapper" brew "virtualenvwrapper"
brew "wget" brew "wget"
@@ -101,7 +112,6 @@ cask "raycast"
cask "rectangle" cask "rectangle"
cask "scroll-reverser" cask "scroll-reverser"
cask "temurin" cask "temurin"
cask "veracrypt"
cask "wezterm" cask "wezterm"
cask "zulu@17" cask "zulu@17"
@@ -121,11 +131,12 @@ if !is_corp?
brew "virt-manager" brew "virt-manager"
cask "claude-code" cask "claude-code"
cask "codex"
cask "cryptomator" cask "cryptomator"
cask "keepassxc" cask "keepassxc"
cask "gcloud-cli" cask "gcloud-cli"
cask "google-cloud-sdk"
cask "keybase" cask "keybase"
cask "orbstack" cask "orbstack"
cask "jordanbaird-ice" cask "jordanbaird-ice@beta"
cask "veracrypt"
end end

1
CLAUDE.md Symbolic link
View File

@@ -0,0 +1 @@
AGENTS.md

View File

@@ -4,7 +4,12 @@ set -ueo pipefail
shopt -s extglob shopt -s extglob
# get libraries # get libraries
. ${HOME}/.local/lib/bash/tui.sh if [[ -f "${HOME}/.local/lib/bash/tui.sh" ]]; then
. "${HOME}/.local/lib/bash/tui.sh"
else
echo "Error: ${HOME}/.local/lib/bash/tui.sh not found!" >&2
exit 1
fi
COMMANDS=( COMMANDS=(
gctx gctx
@@ -43,7 +48,7 @@ _gctx_choose() {
--format='value(is_active, name, format("{} (as {})", properties.core.project, properties.core.account))') --format='value(is_active, name, format("{} (as {})", properties.core.project, properties.core.account))')
local choice local choice
if choice=$(printf "%-${maxnamelen}s %s\n" "${lines[@]}" | select_entry "gcloud config" "$default") ; then if choice=$(printf "%-${maxnamelen}s %s\n" "${lines[@]}" | select_entry "gcloud config" "$default") ; then
_gctx_set "${choice}" _gctx_set "$(echo "${choice}" | awk '{print $1}')"
else else
echo "No option selected, leaving unchanged." echo "No option selected, leaving unchanged."
fi fi
@@ -68,7 +73,7 @@ _gctx_clone() {
local oldconfig=() local oldconfig=()
local line local line
while IFS= read -r line ; do while IFS= read -r line ; do
old_config+=("$line") oldconfig+=("$line")
done < <(gcloud config configurations describe "$(_gctx_name)" --format='multi(properties:format="flattened[separator=\" \"]")') done < <(gcloud config configurations describe "$(_gctx_name)" --format='multi(properties:format="flattened[separator=\" \"]")')
# create new # create new

View File

@@ -1,8 +1,22 @@
#!/bin/sh #!/bin/sh
env > ${TMPDIR}/env-pre set -o nounset
. ${HOME}/.shenv
env > ${TMPDIR}/env-post TMP_DIR="${TMPDIR:-/tmp}"
for VAR in $(env | cut -d'=' -f1) ; do TMP_DIR="${TMP_DIR%/}"
/bin/launchctl setenv "${VAR}" "$(eval echo \$${VAR})"
done env > "${TMP_DIR}/env-pre" 2>/dev/null || true
if [ -f "${HOME}/.shenv" ]; then
. "${HOME}/.shenv"
fi
env > "${TMP_DIR}/env-post" 2>/dev/null || true
if [ -x "/bin/launchctl" ]; then
for VAR in $(env | awk -F= '/^[a-zA-Z_][a-zA-Z0-9_]*=/ {print $1}') ; do
case "${VAR}" in
_|""|*[!a-zA-Z0-9_]*|[0-9]*) continue ;;
esac
eval "val=\${${VAR}:-}"
/bin/launchctl setenv "${VAR}" "${val}"
done
fi

View File

@@ -47,7 +47,7 @@ shift $((OPTIND - 1)) # Remove the parsed options
# --- Set target directory --- # --- Set target directory ---
# Use the first remaining argument as the target directory. # Use the first remaining argument as the target directory.
if [ -n "$1" ]; then if [ "$#" -gt 0 ]; then
TARGET_DIR="$1" TARGET_DIR="$1"
fi fi
@@ -75,7 +75,7 @@ find "${TARGET_DIR}" -type l ! -exec test -e {} \; -print0 | while IFS= read -r
continue continue
fi fi
# Ask the user for confirmation. # Ask the user for confirmation.
read -p "Remove broken symlink '${link}'? [y/N] " -n 1 -r read -p "Remove broken symlink '${link}'? [y/N] " -n 1 -r < /dev/tty
echo # Move to a new line after input. echo # Move to a new line after input.
if [[ $REPLY =~ ^[Yy]$ ]]; then if [[ $REPLY =~ ^[Yy]$ ]]; then

View File

@@ -3,7 +3,7 @@
# Installs Ansible, trying user-space methods first before falling back to sudo. # Installs Ansible, trying user-space methods first before falling back to sudo.
# This script is designed to be idempotent and safe to run multiple times. # This script is designed to be idempotent and safe to run multiple times.
set -e # Exit immediately if a command exits with a non-zero status. set -euo pipefail # Exit immediately if a command exits with a non-zero status, undefined variable, or pipe failure.
# --- Helper Functions --- # --- Helper Functions ---
info() { echo "[INFO] $1"; } info() { echo "[INFO] $1"; }
@@ -44,8 +44,8 @@ fi
# Try Python's venv module if pipx failed or wasn't present # Try Python's venv module if pipx failed or wasn't present
VENV_PATH="${HOME}/.local/share/ansible_venv" VENV_PATH="${HOME}/.local/share/ansible_venv"
# Create a temp path to avoid clobbering a failed install # Create a temp path securely to avoid clobbering a failed install
VENV_TEST_PATH="/tmp/ansible_venv_test_$$" VENV_TEST_PATH="$(mktemp -d "${TMPDIR:-/tmp}/ansible_venv_test.XXXXXX")"
if python3 -m venv "${VENV_TEST_PATH}" >/dev/null 2>&1; then if python3 -m venv "${VENV_TEST_PATH}" >/dev/null 2>&1; then
rm -rf "${VENV_TEST_PATH}" # Clean up test rm -rf "${VENV_TEST_PATH}" # Clean up test
info "Python's venv module is available. Creating a virtual environment at ${VENV_PATH}..." info "Python's venv module is available. Creating a virtual environment at ${VENV_PATH}..."
@@ -55,7 +55,7 @@ if python3 -m venv "${VENV_TEST_PATH}" >/dev/null 2>&1; then
info "Ansible installed successfully into a virtual environment." info "Ansible installed successfully into a virtual environment."
info "To use it, run: '${VENV_PATH}/bin/ansible'" info "To use it, run: '${VENV_PATH}/bin/ansible'"
info "To make it available everywhere, add its bin directory to your PATH:" info "To make it available everywhere, add its bin directory to your PATH:"
info " echo 'export PATH="${VENV_PATH}/bin:$PATH"' >> ~/.profile" info " echo 'export PATH=\"${VENV_PATH}/bin:\$PATH\"' >> ~/.profile"
info "(You may need to source ~/.profile or restart your shell)." info "(You may need to source ~/.profile or restart your shell)."
exit 0 exit 0
else else
@@ -63,6 +63,7 @@ if python3 -m venv "${VENV_TEST_PATH}" >/dev/null 2>&1; then
rm -rf "${VENV_PATH}" # Clean up failed attempt rm -rf "${VENV_PATH}" # Clean up failed attempt
fi fi
else else
rm -rf "${VENV_TEST_PATH}" # Clean up test after failure
info "Python's venv module not available or failed to create a test environment." info "Python's venv module not available or failed to create a test environment."
fi fi

View File

@@ -1,9 +1,11 @@
#!/bin/bash #!/bin/bash
set -ue set -ueo pipefail
TMPDIR=$(mktemp -d) SYS_TMPDIR="${TMPDIR:-/tmp}"
TMPDIR="$(mktemp -d "${SYS_TMPDIR%/}/install_tool.XXXXXX")"
trap 'rm -rf -- "${TMPDIR}"' EXIT trap 'rm -rf -- "${TMPDIR}"' EXIT
export -n TMPDIR 2>/dev/null || true
REINSTALL=0 REINSTALL=0
PACKAGES=1 PACKAGES=1
@@ -38,7 +40,7 @@ shift $((OPTIND-1))
function list_tools { function list_tools {
echo "Options:" >/dev/stderr echo "Options:" >/dev/stderr
awk 'BEGIN {s=0;FS=")"};/main tool selection/{s=1};/^\s+\w+)$/{if(s==1){print $1}}' "$0" | sort | while read -r opt; do awk 'BEGIN {s=0;FS=")"};/main tool selection/{s=1};/^\s+[a-zA-Z0-9_.-]+)$/{if(s==1){print $1}}' "$0" | sort | while read -r opt; do
echo -e "\\t${opt}" >/dev/stderr echo -e "\\t${opt}" >/dev/stderr
done done
} }
@@ -124,11 +126,13 @@ function get_latest_github_release_url {
local repo="$1" local repo="$1"
local glob="$2" local glob="$2"
curl -s "https://api.github.com/repos/${repo}/releases/latest" | \ curl -s "https://api.github.com/repos/${repo}/releases/latest" | \
jq -r ".assets[] | select(.name|test(\"${glob}\")) | .browser_download_url" jq -r --arg rx "${glob}" '.assets[] | select(.name | test($rx)) | .browser_download_url'
} }
function require_pipx { function require {
command -v pipx >/dev/null 2>&1 || die "Requires pipx" local cmd="${1}"
local msg="${2:-Requires ${cmd}}"
command -v "${cmd}" >/dev/null 2>&1 || die "${msg}"
} }
# Begin main tool selection # Begin main tool selection
@@ -288,10 +292,7 @@ case ${TOOL} in
git clone "${src}" "${DESTDIR}" git clone "${src}" "${DESTDIR}"
;; ;;
pwndbg) pwndbg)
if ! command -v gdb > /dev/null 2>&1 ; then require gdb "No gdb available!"
echo 'No gdb available!' >/dev/stderr
exit 1
fi
git clone --depth 1 -b stable https://github.com/pwndbg/pwndbg.git "${DESTDIR}" git clone --depth 1 -b stable https://github.com/pwndbg/pwndbg.git "${DESTDIR}"
PY_PACKAGES=${DESTDIR}/vendor PY_PACKAGES=${DESTDIR}/vendor
mkdir -p "${PY_PACKAGES}" mkdir -p "${PY_PACKAGES}"
@@ -311,10 +312,7 @@ case ${TOOL} in
;; ;;
gef) gef)
makedest_or_die makedest_or_die
if ! command -v gdb > /dev/null 2>&1 ; then require gdb "No gdb available!"
echo 'No gdb available!' >/dev/stderr
exit 1
fi
download \ download \
https://github.com/hugsy/gef/raw/master/gef.py \ https://github.com/hugsy/gef/raw/master/gef.py \
"${DESTDIR}/gef.py" "${DESTDIR}/gef.py"
@@ -441,25 +439,19 @@ EOF
add_bin_symlink docker-compose add_bin_symlink docker-compose
;; ;;
tldr) tldr)
require_pipx require pipx
pipx install tldr pipx install tldr
;; ;;
blint) blint)
require_pipx require pipx
pipx install blint pipx install blint
;; ;;
dust) dust)
if ! command -v cargo >/dev/null 2>&1 ; then require cargo "This needs cargo (for rust)!"
echo "This needs cargo (for rust)!" >/dev/stderr
exit 1
fi
cargo install du-dust cargo install du-dust
;; ;;
bottom) bottom)
if ! command -v cargo >/dev/null 2>&1 ; then require cargo "This needs cargo (for rust)!"
echo "This needs cargo (for rust)!" >/dev/stderr
exit 1
fi
cargo install bottom cargo install bottom
;; ;;
delta) delta)
@@ -476,7 +468,8 @@ EOF
ropper) ropper)
deb_only deb_only
install_pkgs python3-z3 install_pkgs python3-z3
pip3 install --user pyvex ropper require pipx
pipx install ropper
;; ;;
kubeconform) kubeconform)
go install github.com/yannh/kubeconform/cmd/kubeconform@latest go install github.com/yannh/kubeconform/cmd/kubeconform@latest
@@ -527,14 +520,11 @@ EOF
sh "${rustup_init}" --no-modify-path -y sh "${rustup_init}" --no-modify-path -y
;; ;;
igrep) igrep)
if ! command -v cargo >/dev/null 2>&1 ; then require cargo "This needs cargo (for rust)!"
echo "This needs cargo (for rust)!" >/dev/stderr
exit 1
fi
cargo install igrep cargo install igrep
;; ;;
unblob) unblob)
require_pipx require pipx
pipx install unblob pipx install unblob
;; ;;
fq) fq)
@@ -555,6 +545,37 @@ EOF
fi fi
fi fi
;; ;;
speckit)
require uv
latest_version=$(curl -s "https://api.github.com/repos/github/spec-kit/releases/latest" | jq -r '.tag_name')
if [ -z "${latest_version}" ] || [ "${latest_version}" = "null" ]; then
die "Failed to determine latest release version for speckit."
fi
uv tool install specify-cli --from "git+https://github.com/github/spec-kit.git@${latest_version}"
;;
ssh-agent-mux)
makedest_or_die
os=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$(uname -m)" in
x86_64|amd64)
arch="amd64"
;;
aarch64|arm64)
arch="arm64"
;;
*)
die "Unsupported architecture: $(uname -m)"
;;
esac
tar_url=$(get_latest_github_release_url "overhacked/ssh-agent-mux" ".*${os}-${arch}\\.tar\\.gz$")
if [ -z "${tar_url}" ]; then
die "Could not find ssh-agent-mux release for ${os}-${arch}"
fi
download "${tar_url}" "${TMPDIR}/ssh-agent-mux.tar.gz"
tar zxf "${TMPDIR}/ssh-agent-mux.tar.gz" --strip-components=1 -C "${DESTDIR}"
chmod +x "${DESTDIR}/ssh-agent-mux"
add_bin_symlink ssh-agent-mux
;;
*) *)
echo "Unknown tool: ${TOOL}" >/dev/stderr echo "Unknown tool: ${TOOL}" >/dev/stderr
list_tools list_tools

View File

@@ -2,12 +2,20 @@
set -ue set -ue
if [ "$(id -u)" -ne 0 ]; then
echo "Error: This script must be run as root." >&2
exit 1
fi
cat >/usr/local/bin/x-resize <<"EOF" cat >/usr/local/bin/x-resize <<"EOF"
#!/bin/sh #!/bin/sh
PATH=/usr/bin:/bin:/usr/local/bin PATH=/usr/bin:/bin:/usr/local/bin
desktopuser=$(/bin/ps -ef | /bin/grep -oP '^\w+ (?=.*vdagent( |$))') || exit 0 desktopuser=$(/bin/ps -eo user,comm 2>/dev/null | awk '$2 ~ /vdagent/ {print $1; exit}')
[ -z "$desktopuser" ] && exit 0
desktophome=$(getent passwd "$desktopuser" | cut -d: -f6)
[ -z "$desktophome" ] && exit 0
export DISPLAY=:0 export DISPLAY=:0
export XAUTHORITY=$(eval echo "~$desktopuser")/.Xauthority export XAUTHORITY="${desktophome}/.Xauthority"
/usr/bin/xrandr --output $(/usr/bin/xrandr | awk '/ connected/{print $1; exit; }') --auto /usr/bin/xrandr --output $(/usr/bin/xrandr | awk '/ connected/{print $1; exit; }') --auto
EOF EOF
chmod 755 /usr/local/bin/x-resize chmod 755 /usr/local/bin/x-resize

213
bin/newnote Executable file
View File

@@ -0,0 +1,213 @@
#!/usr/bin/env bash
# Exit on error, undefined variables, and pipe failures
set -euo pipefail
show_help() {
cat << EOF
Usage: $(basename "$0") [options] <note_name_or_path>
Create a new note in your Obsidian vault.
Options:
-v, --vault <dir> Specify the Obsidian vault directory.
--overwrite Overwrite the file if it already exists.
-h, --help Show this help message.
EOF
}
VAULT_DIR=""
OVERWRITE="false"
NOTE_PATH=""
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-v|--vault)
if [[ -z "${2:-}" ]]; then
echo "Error: --vault requires a directory path." >&2
exit 1
fi
VAULT_DIR="$2"
shift 2
;;
--overwrite)
OVERWRITE="true"
shift
;;
-h|--help)
show_help
exit 0
;;
-*)
echo "Error: Unknown option: $1" >&2
show_help
exit 1
;;
*)
if [[ -n "$NOTE_PATH" ]]; then
echo "Error: Multiple note paths provided: $NOTE_PATH and $1" >&2
exit 1
fi
NOTE_PATH="$1"
shift
;;
esac
done
if [[ -z "$NOTE_PATH" ]]; then
echo "Error: Missing note path/name." >&2
show_help
exit 1
fi
# 1. Find the Obsidian vault.
if [[ -n "$VAULT_DIR" ]]; then
# -v/--vault was passed. Check that the directory exists and contains a .obsidian directory.
if [[ ! -d "$VAULT_DIR" ]]; then
echo "Error: Specified vault directory does not exist: $VAULT_DIR" >&2
exit 1
fi
if [[ ! -d "$VAULT_DIR/.obsidian" ]]; then
echo "Error: Specified directory is not an Obsidian vault (missing .obsidian): $VAULT_DIR" >&2
exit 1
fi
VAULT_DIR="$(cd "$VAULT_DIR" && pwd)"
else
# Search directories upward for a parent (or current) directory containing a .obsidian subdirectory.
# Stop at the user's home directory or a filesystem boundary.
CURRENT_DIR="$PWD"
FOUND_VAULT=""
get_device_id() {
local dir="$1"
if [[ "$(uname)" == "Darwin" ]]; then
stat -f '%d' "$dir" 2>/dev/null || echo ""
else
stat -c '%d' "$dir" 2>/dev/null || echo ""
fi
}
CURRENT_DEV="$(get_device_id "$CURRENT_DIR")"
while [[ "$CURRENT_DIR" != "/" && "$CURRENT_DIR" != "$HOME" ]]; do
if [[ -d "$CURRENT_DIR/.obsidian" ]]; then
FOUND_VAULT="$CURRENT_DIR"
break
fi
PARENT_DIR="$(dirname "$CURRENT_DIR")"
if [[ "$PARENT_DIR" == "$CURRENT_DIR" ]]; then
break
fi
# Check filesystem boundary
PARENT_DEV="$(get_device_id "$PARENT_DIR")"
if [[ -n "$CURRENT_DEV" && -n "$PARENT_DEV" && "$CURRENT_DEV" != "$PARENT_DEV" ]]; then
break
fi
CURRENT_DIR="$PARENT_DIR"
CURRENT_DEV="$PARENT_DEV"
done
# Check the last checked directory (could be HOME or /)
if [[ -z "$FOUND_VAULT" && -d "$CURRENT_DIR/.obsidian" ]]; then
FOUND_VAULT="$CURRENT_DIR"
fi
if [[ -n "$FOUND_VAULT" ]]; then
VAULT_DIR="$FOUND_VAULT"
else
# Fallback paths in order: ~/Notes, ~/Obsidian/Notes, ~/Personal/Notes, ~/Projects/Notes.
FALLBACKS=(
"$HOME/Notes"
"$HOME/notes"
"$HOME/Obsidian/Notes"
"$HOME/Obsidian/notes"
"$HOME/Personal/Notes"
"$HOME/Personal/notes"
"$HOME/Projects/Notes"
"$HOME/Projects/notes"
)
for path in "${FALLBACKS[@]}"; do
if [[ -d "$path" && -d "$path/.obsidian" ]]; then
VAULT_DIR="$(cd "$path" && pwd)"
break
fi
done
fi
fi
if [[ -z "$VAULT_DIR" ]]; then
echo "Error: Could not find an Obsidian vault. Please specify one with -v/--vault." >&2
exit 1
fi
# Strip leading slash from NOTE_PATH to handle relative paths properly
NOTE_PATH="${NOTE_PATH#/}"
# 2. Determine if current working directory is within the vault.
# Resolve physical paths to handle symlinks cleanly.
RESOLVED_PWD="$(pwd -P)"
RESOLVED_VAULT="$(cd "$VAULT_DIR" && pwd -P)"
if [[ "$RESOLVED_PWD" == "$RESOLVED_VAULT" || "$RESOLVED_PWD" == "$RESOLVED_VAULT"/* ]]; then
# Within the vault, treat relative to CWD
TARGET_FILE="$PWD/$NOTE_PATH"
else
# Not within the vault, treat relative to vault root
TARGET_FILE="$VAULT_DIR/$NOTE_PATH"
fi
TARGET_DIR="$(dirname "$TARGET_FILE")"
TARGET_BASE="$(basename "$TARGET_FILE")"
# If there's no file extension on the argument, add .md.
if [[ "$TARGET_BASE" != *.* ]]; then
TARGET_BASE="$TARGET_BASE.md"
fi
TARGET_FILE="$TARGET_DIR/$TARGET_BASE"
# If the necessary directory components don't exist, create them.
if [[ ! -d "$TARGET_DIR" ]]; then
mkdir -p "$TARGET_DIR"
fi
# 3. If the file exists and there's no --overwrite argument, throw an error.
if [[ -f "$TARGET_FILE" && "$OVERWRITE" != "true" ]]; then
echo "Error: File already exists: $TARGET_FILE (use --overwrite to replace it)" >&2
exit 1
fi
# 4. If the path ends in .md (case-insensitive), generate appropriate YAML front matter and write it to the new file.
if [[ "$TARGET_BASE" =~ \.[mM][dD]$ ]]; then
NOTE_TITLE="${TARGET_BASE%.*}"
NOTE_TITLE_ESCAPED="${NOTE_TITLE//\"/\\\"}"
CURRENT_DATE="$(date +"%Y-%m-%d %H:%M")"
cat << EOF > "$TARGET_FILE"
---
title: "$NOTE_TITLE_ESCAPED"
date: $CURRENT_DATE
tags: []
---
EOF
else
# Just touch the file to ensure it exists
touch "$TARGET_FILE"
fi
# 5. Open the user's $EDITOR (falling back to vim/vi if unset) pointing to the new file.
EDITOR="${EDITOR:-}"
if [[ -z "$EDITOR" ]]; then
if command -v vim >/dev/null 2>&1; then
EDITOR="vim"
else
EDITOR="vi"
fi
fi
exec "$EDITOR" "$TARGET_FILE"

View File

@@ -18,7 +18,7 @@ HOST_SPECIFIC_SCRIPT="${RESTIC_SCRIPTS_DIR}/${HOSTNAME}"
# Check if the script exists and is executable # Check if the script exists and is executable
if [[ -f "${HOST_SPECIFIC_SCRIPT}" && -x "${HOST_SPECIFIC_SCRIPT}" ]]; then if [[ -f "${HOST_SPECIFIC_SCRIPT}" && -x "${HOST_SPECIFIC_SCRIPT}" ]]; then
echo "Executing restic script for hostname: ${HOSTNAME}" echo "Executing restic script for hostname: ${HOSTNAME}"
"${HOST_SPECIFIC_SCRIPT}" "${HOST_SPECIFIC_SCRIPT}" "$@"
else else
echo "Error: No executable restic script found for hostname '${HOSTNAME}' at '${HOST_SPECIFIC_SCRIPT}'." >&2 echo "Error: No executable restic script found for hostname '${HOSTNAME}' at '${HOST_SPECIFIC_SCRIPT}'." >&2
echo "Please create an executable script at that path if you want to use this functionality." >&2 echo "Please create an executable script at that path if you want to use this functionality." >&2

View File

@@ -12,8 +12,8 @@ set -o pipefail
# For this script, we assume the user's home directory. # For this script, we assume the user's home directory.
SOURCE_DIR="${HOME}" SOURCE_DIR="${HOME}"
# Exclude file location. We'll create a default one next to the script. # Exclude file location.
EXCLUDE_FILE="$HOME/.restic_exclude.darwin" EXCLUDE_FILE="${HOME}/.restic_exclude.darwin"
# --- Functions --- # --- Functions ---
usage() { usage() {
@@ -34,7 +34,7 @@ EOF
# --- Main Script --- # --- Main Script ---
# Check if restic is installed # Check if restic is installed
if ! command -v restic &> /dev/null; then if ! command -v restic >/dev/null 2>&1; then
echo "Error: restic command not found." >&2 echo "Error: restic command not found." >&2
echo "Please install restic first: https://restic.net/" >&2 echo "Please install restic first: https://restic.net/" >&2
exit 1 exit 1
@@ -57,7 +57,7 @@ while getopts ":l:bu:h" opt; do
;; ;;
b) b)
BACKUP_MODE="b2" BACKUP_MODE="b2"
if [[ ${OPTIND} -le $# && "${!OPTIND}" != -* ]]; then if [[ ${OPTIND} -le $# && "${!OPTIND:-}" != -* ]]; then
REPO="b2:${!OPTIND}:" REPO="b2:${!OPTIND}:"
OPTIND=$((OPTIND + 1)) OPTIND=$((OPTIND + 1))
fi fi
@@ -84,70 +84,86 @@ done
# --- Pre-run checks --- # --- Pre-run checks ---
if [[ -z "${BACKUP_MODE}" ]]; then if [[ -z "${BACKUP_MODE}" ]]; then
echo "Error: You must specify a backup mode (-l or -b)." >&2 echo "Error: You must specify a backup mode (-l or -b)." >&2
usage usage
exit 1 exit 1
fi fi
if [[ "${BACKUP_MODE}" == "b2" ]]; then if [[ "${BACKUP_MODE}" == "b2" ]]; then
if [[ -f "${HOME}/.resticb2" ]] ; then if [[ -f "${HOME}/.resticb2" ]] ; then
. "${HOME}/.resticb2" # shellcheck disable=SC1090
fi . "${HOME}/.resticb2"
export B2_ACCOUNT_ID fi
export B2_ACCOUNT_KEY export B2_ACCOUNT_ID="${B2_ACCOUNT_ID:-}"
export B2_BUCKET_NAME export B2_ACCOUNT_KEY="${B2_ACCOUNT_KEY:-}"
if [[ -z "${B2_ACCOUNT_ID:-}" || -z "${B2_ACCOUNT_KEY:-}" ]]; then export B2_BUCKET_NAME="${B2_BUCKET_NAME:-}"
echo "Error: For Backblaze B2 backups, you must set the B2_ACCOUNT_ID and B2_ACCOUNT_KEY environment variables." >&2 if [[ -z "${B2_ACCOUNT_ID}" || -z "${B2_ACCOUNT_KEY}" ]]; then
exit 1 echo "Error: For Backblaze B2 backups, you must set the B2_ACCOUNT_ID and B2_ACCOUNT_KEY environment variables." >&2
fi exit 1
fi
if [[ -z "${REPO:-}" ]]; then if [[ -z "${REPO}" ]]; then
if [[ -n "${B2_BUCKET_NAME:-}" ]]; then if [[ -n "${B2_BUCKET_NAME}" ]]; then
REPO="b2:${B2_BUCKET_NAME}:" REPO="b2:${B2_BUCKET_NAME}:"
else else
echo "Error: Backup mode is B2 but no bucket name was provided and the B2_BUCKET_NAME environment variable is not set." >&2 echo "Error: Backup mode is B2 but no bucket name was provided and the B2_BUCKET_NAME environment variable is not set." >&2
usage usage
exit 1 exit 1
fi
fi fi
fi
fi fi
KEYCHAIN_ENTRY_NAME="restic_repo_password" KEYCHAIN_ENTRY_NAME="restic_repo_password"
if security find-generic-password -a "$(whoami)" -s "${KEYCHAIN_ENTRY_NAME}" >/dev/null 2>&1 ; then local_user="$(id -un 2>/dev/null || whoami)"
export RESTIC_PASSWORD_COMMAND="security find-generic-password -a \"$(whoami)\" -s \"${KEYCHAIN_ENTRY_NAME}\" -w" if security find-generic-password -a "${local_user}" -s "${KEYCHAIN_ENTRY_NAME}" >/dev/null 2>&1 ; then
printf -v RESTIC_PASSWORD_COMMAND 'security find-generic-password -a %q -s %q -w' "${local_user}" "${KEYCHAIN_ENTRY_NAME}"
export RESTIC_PASSWORD_COMMAND
# Source file? # Source file?
elif [[ -f "${HOME}/.resticpass" ]] ; then elif [[ -f "${HOME}/.resticpass" ]] ; then
export RESTIC_PASSWORD_FILE="${HOME}/.resticpass" export RESTIC_PASSWORD_FILE="${HOME}/.resticpass"
fi fi
# Ensure exclude file exists so restic does not fail when checking exclusions.
if [[ ! -f "${EXCLUDE_FILE}" ]]; then
echo "Exclude file '${EXCLUDE_FILE}' not found. Creating a default macOS exclude file..."
cat << 'EOF' > "${EXCLUDE_FILE}"
# Default restic exclusions for macOS
.Trash
Library/Caches
Library/Logs
.CFUserTextEncoding
EOF
fi
# If the repository does not exist, initialize it. # If the repository does not exist, initialize it.
# The user will be prompted for a password, which will be required for all # The user will be prompted for a password, which will be required for all
# future interactions with the repository. # future interactions with the repository.
if ! restic -r "${REPO}" snapshots &> /dev/null; then if ! restic -r "${REPO}" snapshots >/dev/null 2>&1; then
echo "Restic repository not found or not accessible. Initializing..." echo "Restic repository not found or not accessible. Initializing..."
restic init -r "${REPO}" restic init -r "${REPO}"
fi fi
# --- Run Backup --- # --- Run Backup ---
echo "Starting restic backup..." echo "Starting restic backup..."
echo "Source: ${SOURCE_DIR}" echo "Source: ${SOURCE_DIR}"
echo "Repository: ${REPO}" echo "Repository: ${REPO}"
BACKUP_CMD="restic backup \ BACKUP_ARGS=(
--verbose \ "restic" "backup"
--repo \"${REPO}\" \ "--verbose"
--exclude-file \"${EXCLUDE_FILE}\" \ "--repo" "${REPO}"
--one-file-system \ "--exclude-file" "${EXCLUDE_FILE}"
--tag \"macbook-backup\"" "--one-file-system"
"--tag" "macbook-backup"
)
if [[ -n "${UPLOAD_LIMIT}" ]]; then if [[ -n "${UPLOAD_LIMIT}" ]]; then
BACKUP_CMD="${BACKUP_CMD} --limit-upload ${UPLOAD_LIMIT}" BACKUP_ARGS+=("--limit-upload" "${UPLOAD_LIMIT}")
fi fi
BACKUP_CMD="${BACKUP_CMD} \"${SOURCE_DIR}\"" BACKUP_ARGS+=("${SOURCE_DIR}")
eval "${BACKUP_CMD}" "${BACKUP_ARGS[@]}"
echo "Backup complete." echo "Backup complete."
@@ -155,11 +171,11 @@ echo "Backup complete."
# Keeps the last 7 daily, 4 weekly, and 6 monthly snapshots. # Keeps the last 7 daily, 4 weekly, and 6 monthly snapshots.
echo "Pruning old snapshots..." echo "Pruning old snapshots..."
restic forget \ restic forget \
--repo "${REPO}" \ --repo "${REPO}" \
--keep-daily 7 \ --keep-daily 7 \
--keep-weekly 4 \ --keep-weekly 4 \
--keep-monthly 6 \ --keep-monthly 6 \
--prune --prune
echo "Pruning complete." echo "Pruning complete."
echo "Restic backup script finished." echo "Restic backup script finished."

View File

@@ -72,15 +72,51 @@ shift # Consume the subcommand
# Separate arguments from the file to be signed # Separate arguments from the file to be signed
declare -a remaining_args declare -a remaining_args
file_to_sign="" file_to_sign=""
f_provided=false
n_provided=false
I_provided=false
s_provided=false
while [[ "$#" -gt 0 ]]; do while [[ "$#" -gt 0 ]]; do
# If we see a non-flag argument, assume it's the file to sign. case "$1" in
# This works because the file to sign is the only positional argument. -f)
if [[ "$1" != -* ]] && [[ -z "$file_to_sign" ]]; then [[ -z "${2:-}" ]] && error "Option -f requires an argument."
file_to_sign="$1" remaining_args+=("-f" "$2")
else f_provided=true
remaining_args+=("$1") shift 2
fi ;;
shift -n)
[[ -z "${2:-}" ]] && error "Option -n requires an argument."
remaining_args+=("-n" "$2")
n_provided=true
shift 2
;;
-I)
[[ -z "${2:-}" ]] && error "Option -I requires an argument."
remaining_args+=("-I" "$2")
I_provided=true
shift 2
;;
-s)
[[ -z "${2:-}" ]] && error "Option -s requires an argument."
remaining_args+=("-s" "$2")
s_provided=true
shift 2
;;
-h|--help)
usage
;;
-*)
error "Unknown option: $1"
;;
*)
if [[ -n "$file_to_sign" ]]; then
error "Unexpected positional argument '$1' (already specified '$file_to_sign')."
fi
file_to_sign="$1"
shift
;;
esac
done done
# --- Build command based on subcommand --- # --- Build command based on subcommand ---
@@ -90,18 +126,6 @@ CMD_ARGS=("ssh-keygen" "-Y" "$SUBCOMMAND")
# Append all the flag-based arguments (-f, -n, -I, -s) # Append all the flag-based arguments (-f, -n, -I, -s)
CMD_ARGS+=("${remaining_args[@]}") CMD_ARGS+=("${remaining_args[@]}")
# Scan for provided flags to handle defaults correctly
f_provided=false
n_provided=false
I_provided=false
s_provided=false
for arg in "${remaining_args[@]}"; do
[[ "$arg" == "-f" ]] && f_provided=true
[[ "$arg" == "-n" ]] && n_provided=true
[[ "$arg" == "-I" ]] && I_provided=true
[[ "$arg" == "-s" ]] && s_provided=true
done
if [[ "$SUBCOMMAND" == "sign" ]]; then if [[ "$SUBCOMMAND" == "sign" ]]; then
if [[ -z "$file_to_sign" ]]; then if [[ -z "$file_to_sign" ]]; then
error "Path to file to be signed is required for 'sign' command." error "Path to file to be signed is required for 'sign' command."

View File

@@ -76,7 +76,8 @@ run_self_test() {
cat <<EOF > "${target}" cat <<EOF > "${target}"
${key_man} ${key_man}
${key1} # This should be removed as it's now managed # This is a manual annotation for key1
${key1}
EOF EOF
echo "Executing script in test mode..." echo "Executing script in test mode..."
@@ -107,6 +108,9 @@ EOF
echo -n "Check masking... " echo -n "Check masking... "
if ! grep -q "masked" "${target}"; then echo "OK"; else echo "FAIL"; exit 1; fi if ! grep -q "masked" "${target}"; then echo "OK"; else echo "FAIL"; exit 1; fi
echo -n "Check user comment preservation... "
if grep -q "This is a manual annotation for key1" "${target}"; then echo "OK"; else echo "FAIL"; exit 1; fi
echo "Self-test passed successfully!" echo "Self-test passed successfully!"
exit 0 exit 0
} }
@@ -138,6 +142,40 @@ mkdir -p "$(dirname "${TARGET_FILE}")"
TMP_FILE=$(mktemp) TMP_FILE=$(mktemp)
CLEANUP_FILES+=("${TMP_FILE}") CLEANUP_FILES+=("${TMP_FILE}")
# Build a map of key-signature -> user comments from the existing target file.
# Comments above keys are preserved into the managed block (# Source: lines are excluded).
# Multiple comment lines are joined with SUBSEP (\034) for safe transport through AWK.
USER_COMMENTS_FILE=$(mktemp)
CLEANUP_FILES+=("${USER_COMMENTS_FILE}")
if [[ -f "${TARGET_FILE}" ]]; then
awk -v begin="${BEGIN_MARKER}" -v end="${END_MARKER}" '
BEGIN { pending="" }
$0 == begin { pending=""; next }
$0 == end { pending=""; next }
/^# Source:/ { next }
/^[[:space:]]*#/ {
pending = (pending == "" ? $0 : pending SUBSEP $0)
next
}
/^[[:space:]]*$/ { pending=""; next }
{
n = split($0, parts, " ")
sig = ""
for (i=1; i<=n; i++) {
sig = (sig == "" ? parts[i] : sig " " parts[i])
if (parts[i] ~ /^(ssh-|ecdsa-|sk-)/ && i < n) {
sig = sig " " parts[i+1]
break
}
}
if (sig != "" && pending != "") {
print sig "\t" pending
}
pending = ""
}
' "${TARGET_FILE}" > "${USER_COMMENTS_FILE}"
fi
collect_keys() { collect_keys() {
local dirs=("${@}") local dirs=("${@}")
for dir in "${dirs[@]}"; do for dir in "${dirs[@]}"; do
@@ -158,13 +196,23 @@ collect_keys() {
} }
# Use a HEREDOC for the complex AWK script to avoid shell interpolation issues # Use a HEREDOC for the complex AWK script to avoid shell interpolation issues
MANAGED_BLOCK=$(collect_keys "${SOURCE_DIRS[@]}" | awk -F'\t' ' MANAGED_BLOCK=$(collect_keys "${SOURCE_DIRS[@]}" | awk -F'\t' -v user_comments_file="${USER_COMMENTS_FILE}" '
BEGIN {
while ((getline line < user_comments_file) > 0) {
tab = index(line, "\t")
if (tab > 0) {
sig = substr(line, 1, tab - 1)
user_comments[sig] = substr(line, tab + 1)
}
}
close(user_comments_file)
}
{ {
# Splitting on the first tab manually to be robust # Splitting on the first tab manually to be robust
tab_idx = index($0, "\t") tab_idx = index($0, "\t")
source = substr($0, 1, tab_idx - 1) source = substr($0, 1, tab_idx - 1)
full_line = substr($0, tab_idx + 1) full_line = substr($0, tab_idx + 1)
# Signature detection: all options + key type + key data # Signature detection: all options + key type + key data
# (Excludes the comment at the end) # (Excludes the comment at the end)
n = split(full_line, parts, " ") n = split(full_line, parts, " ")
@@ -191,6 +239,12 @@ END {
for (i=1; i<=count; i++) { for (i=1; i<=count; i++) {
sig = order[i] sig = order[i]
print "# Source: " sources[sig] print "# Source: " sources[sig]
if (sig in user_comments) {
n = split(user_comments[sig], comment_lines, SUBSEP)
for (j=1; j<=n; j++) {
print comment_lines[j]
}
}
print keys[sig] print keys[sig]
} }
}') }')
@@ -206,6 +260,7 @@ if [[ -f "${TARGET_FILE}" ]]; then
fi fi
MANAGED_SIGS_TMP=$(mktemp) MANAGED_SIGS_TMP=$(mktemp)
CLEANUP_FILES+=("${MANAGED_SIGS_TMP}")
echo "${MANAGED_BLOCK}" | awk '/^[^#]/ { echo "${MANAGED_BLOCK}" | awk '/^[^#]/ {
n = split($0, parts, " ") n = split($0, parts, " ")
sig = "" sig = ""

View File

@@ -1,7 +1,49 @@
#!/bin/sh #!/bin/sh
set -e set -eu
SKEL_DIR=$(dirname -- "$(readlink -f -- "$HOME/.profile")")
cd -- "$SKEL_DIR" resolve_symlink() {
cd -- "$(git rev-parse --show-toplevel)" _target="$1"
if command -v readlink >/dev/null 2>&1 && readlink -f -- "$_target" >/dev/null 2>&1; then
readlink -f -- "$_target"
elif command -v python3 >/dev/null 2>&1; then
python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$_target"
else
while [ -L "$_target" ]; do
_dir=$(cd -P "$(dirname -- "$_target")" >/dev/null 2>&1 && pwd)
_target=$(readlink "$_target")
case "$_target" in
/*) ;;
*) _target="$_dir/$_target" ;;
esac
done
echo "$_target"
fi
}
if [ -e "$HOME/.profile" ]; then
TARGET=$(resolve_symlink "$HOME/.profile")
SKEL_DIR=$(dirname -- "$TARGET")
else
SKEL_DIR=""
fi
REPO_ROOT=""
if [ -n "$SKEL_DIR" ] && cd -- "$SKEL_DIR" 2>/dev/null; then
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
fi
if [ -z "$REPO_ROOT" ] || [ ! -f "$REPO_ROOT/install.sh" ]; then
SCRIPT_DIR=$(dirname -- "$(resolve_symlink "$0")")
if cd -- "$SCRIPT_DIR" 2>/dev/null; then
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
fi
if [ -z "$REPO_ROOT" ] || [ ! -f "$REPO_ROOT/install.sh" ]; then
echo "Error: Could not determine skel repository root." >&2
exit 1
fi
fi
cd -- "$REPO_ROOT"
git pull git pull
./install.sh ./install.sh "$@"

65
deploy_checkout.sh Executable file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: $(basename "$0") [--dry-run] user@host" >&2
exit 1
}
DRY_RUN=0
REMOTE=
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run)
DRY_RUN=1
shift
;;
-h|--help)
usage
;;
--)
shift
break
;;
-*)
usage
;;
*)
if [[ -n "${REMOTE}" ]]; then
usage
fi
REMOTE="$1"
shift
;;
esac
done
if [[ $# -gt 0 || -z "${REMOTE}" ]]; then
usage
fi
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
if ! git -C "$SCRIPT_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "Error: $SCRIPT_DIR is not inside a git repository." >&2
exit 1
fi
if [[ "$DRY_RUN" -eq 1 ]]; then
archive_list="$(git -C "$SCRIPT_DIR" archive --format=tar HEAD | tar -tf - | sed 's#^\./##' | sed '/^$/d;/^\.$/d' | sort)"
remote_list="$(ssh "$REMOTE" 'if [ -d "$HOME/.skel" ]; then cd "$HOME/.skel" && find . | sed "s#^\./##" | sed "/^$/d;/^\.$/d" | sort; fi' || true)"
printf 'Would deploy HEAD from %s to %s:%s\n' "$SCRIPT_DIR" "$REMOTE" '$HOME/.skel'
printf 'Would replace remote ~/.skel with %s tracked paths\n' "$(printf '%s' "$archive_list" | awk 'NF { n++ } END { print n + 0 }')"
if [[ -n "$remote_list" ]]; then
printf 'Would remove %s existing remote paths not present in HEAD\n' "$(comm -13 <(printf '%s\n' "$archive_list") <(printf '%s\n' "$remote_list") | awk 'NF { n++ } END { print n + 0 }')"
else
printf 'Remote ~/.skel does not exist or is empty\n'
fi
exit 0
fi
git -C "$SCRIPT_DIR" archive --format=tar HEAD | \
ssh "$REMOTE" 'rm -rf "$HOME/.skel" && mkdir -p "$HOME/.skel" && tar -xf - -C "$HOME/.skel"'

View File

@@ -28,6 +28,9 @@ alias clear-gpg-agent="echo RELOADAGENT | gpg-connect-agent"
# Earthly ssh # Earthly ssh
alias earthly='earthly --ssh-auth-sock ""' alias earthly='earthly --ssh-auth-sock ""'
# ESP-IDF
alias activate_idf="source ~/.espressif/tools/activate_idf_v*.sh"
if [ "$(uname)" = "Linux" ]; then if [ "$(uname)" = "Linux" ]; then
# Cryptsetup alias # Cryptsetup alias
alias luksFormat='cryptsetup luksFormat --type=luks2 --pbkdf-memory=2560000 --pbkdf=argon2id -i 15000 -s 512 -h sha256 -c aes-xts-plain64' alias luksFormat='cryptsetup luksFormat --type=luks2 --pbkdf-memory=2560000 --pbkdf=argon2id -i 15000 -s 512 -h sha256 -c aes-xts-plain64'

View File

@@ -39,16 +39,3 @@ disabled = true
[kubernetes] [kubernetes]
disabled = false disabled = false
detect_folders = ["k8s"] detect_folders = ["k8s"]
[custom.gemini_context]
description = "Displays the current Gemini CLI context"
when = "test -n \"$GEMINI_CLI_HOME\""
command = """
context_dir=\"${XDG_CONFIG_HOME:-$HOME/.config}/gemini\"
if [[ \"$GEMINI_CLI_HOME\" == $context_dir/* ]]; then
basename \"$GEMINI_CLI_HOME\"
fi
"""
style = "bold blue"
format = "♊[$output](blue) "
shell = ["/bin/sh", "-c"]

View File

@@ -104,3 +104,9 @@
[rerere] [rerere]
enabled = true enabled = true
[lfs]
concurrenttransfers = 3
[lfs "customtransfer.xet"]
path = git-xet
args = transfer
concurrent = true

View File

@@ -38,3 +38,4 @@ mise.local.toml
.copilot/ .copilot/
.cursor/ .cursor/
.gemini/ .gemini/
.jetskicli/

View File

@@ -4,16 +4,17 @@
# Should only use POSIX constructs. # Should only use POSIX constructs.
# Always load ENV # Always load ENV
test -f "$HOME/.shenv" && . "$HOME/.shenv" test -f "${HOME}/.shenv" && . "${HOME}/.shenv"
# Setup GREP_COLORS # Setup GREP_COLORS
export GREP_COLOR='01;31' export GREP_COLOR='01;31'
export GREP_COLORS='mt=01;31:mc=01;31:ms=01;31' export GREP_COLORS='mt=01;31:mc=01;31:ms=01;31'
# Setup LS_COLORS # Setup LS_COLORS
if whence dircolors >/dev/null 2>&1 ; then if command -v dircolors >/dev/null 2>&1 && test -f "${HOME}/.dircolors" ; then
test -f "${HOME}/.dircolors" && \ eval "$(dircolors -b "${HOME}/.dircolors" 2>/dev/null)"
eval "$(dircolors "${HOME}/.dircolors")" elif command -v gdircolors >/dev/null 2>&1 && test -f "${HOME}/.dircolors" ; then
eval "$(gdircolors -b "${HOME}/.dircolors" 2>/dev/null)"
else else
# Static solarized LS_COLORS # Static solarized LS_COLORS
LS_COLORS='no=00:fi=00:di=34:ow=34;40:ln=35:pi=30;44:so=35;44:do=35;44:bd=33;44:cd=37;44:or=05;37;41:mi=05;37;41:ex=01;31:*.cmd=01;31:*.exe=01;31:*.com=01;31:*.bat=01;31:*.reg=01;31:*.app=01;31:*.txt=32:*.org=32:*.md=32:*.mkd=32:*.h=32:*.hpp=32:*.c=32:*.C=32:*.cc=32:*.cpp=32:*.cxx=32:*.objc=32:*.cl=32:*.sh=32:*.bash=32:*.csh=32:*.zsh=32:*.el=32:*.vim=32:*.java=32:*.pl=32:*.pm=32:*.py=32:*.rb=32:*.hs=32:*.php=32:*.htm=32:*.html=32:*.shtml=32:*.erb=32:*.haml=32:*.xml=32:*.rdf=32:*.css=32:*.sass=32:*.scss=32:*.less=32:*.js=32:*.coffee=32:*.man=32:*.0=32:*.1=32:*.2=32:*.3=32:*.4=32:*.5=32:*.6=32:*.7=32:*.8=32:*.9=32:*.l=32:*.n=32:*.p=32:*.pod=32:*.tex=32:*.go=32:*.sql=32:*.csv=32:*.sv=32:*.svh=32:*.v=32:*.vh=32:*.vhd=32:*.bmp=33:*.cgm=33:*.dl=33:*.dvi=33:*.emf=33:*.eps=33:*.gif=33:*.jpeg=33:*.jpg=33:*.JPG=33:*.mng=33:*.pbm=33:*.pcx=33:*.pdf=33:*.pgm=33:*.png=33:*.PNG=33:*.ppm=33:*.pps=33:*.ppsx=33:*.ps=33:*.svg=33:*.svgz=33:*.tga=33:*.tif=33:*.tiff=33:*.xbm=33:*.xcf=33:*.xpm=33:*.xwd=33:*.xwd=33:*.yuv=33:*.aac=33:*.au=33:*.flac=33:*.m4a=33:*.mid=33:*.midi=33:*.mka=33:*.mp3=33:*.mpa=33:*.mpeg=33:*.mpg=33:*.ogg=33:*.opus=33:*.ra=33:*.wav=33:*.anx=33:*.asf=33:*.avi=33:*.axv=33:*.flc=33:*.fli=33:*.flv=33:*.gl=33:*.m2v=33:*.m4v=33:*.mkv=33:*.mov=33:*.MOV=33:*.mp4=33:*.mp4v=33:*.mpeg=33:*.mpg=33:*.nuv=33:*.ogm=33:*.ogv=33:*.ogx=33:*.qt=33:*.rm=33:*.rmvb=33:*.swf=33:*.vob=33:*.webm=33:*.wmv=33:*.doc=31:*.docx=31:*.rtf=31:*.odt=31:*.dot=31:*.dotx=31:*.ott=31:*.xls=31:*.xlsx=31:*.ods=31:*.ots=31:*.ppt=31:*.pptx=31:*.odp=31:*.otp=31:*.fla=31:*.psd=31:*.7z=1;35:*.apk=1;35:*.arj=1;35:*.bin=1;35:*.bz=1;35:*.bz2=1;35:*.cab=1;35:*.deb=1;35:*.dmg=1;35:*.gem=1;35:*.gz=1;35:*.iso=1;35:*.jar=1;35:*.msi=1;35:*.rar=1;35:*.rpm=1;35:*.tar=1;35:*.tbz=1;35:*.tbz2=1;35:*.tgz=1;35:*.tx=1;35:*.war=1;35:*.xpi=1;35:*.xz=1;35:*.z=1;35:*.Z=1;35:*.zip=1;35:*.ANSI-30-black=30:*.ANSI-01;30-brblack=01;30:*.ANSI-31-red=31:*.ANSI-01;31-brred=01;31:*.ANSI-32-green=32:*.ANSI-01;32-brgreen=01;32:*.ANSI-33-yellow=33:*.ANSI-01;33-bryellow=01;33:*.ANSI-34-blue=34:*.ANSI-01;34-brblue=01;34:*.ANSI-35-magenta=35:*.ANSI-01;35-brmagenta=01;35:*.ANSI-36-cyan=36:*.ANSI-01;36-brcyan=01;36:*.ANSI-37-white=37:*.ANSI-01;37-brwhite=01;37:*.log=01;32:*~=01;32:*#=01;32:*.bak=01;33:*.BAK=01;33:*.old=01;33:*.OLD=01;33:*.org_archive=01;33:*.off=01;33:*.OFF=01;33:*.dist=01;33:*.DIST=01;33:*.orig=01;33:*.ORIG=01;33:*.swp=01;33:*.swo=01;33:*,v=01;33:*.gpg=34:*.gpg=34:*.pgp=34:*.asc=34:*.3des=34:*.aes=34:*.enc=34:*.sqlite=34:'; LS_COLORS='no=00:fi=00:di=34:ow=34;40:ln=35:pi=30;44:so=35;44:do=35;44:bd=33;44:cd=37;44:or=05;37;41:mi=05;37;41:ex=01;31:*.cmd=01;31:*.exe=01;31:*.com=01;31:*.bat=01;31:*.reg=01;31:*.app=01;31:*.txt=32:*.org=32:*.md=32:*.mkd=32:*.h=32:*.hpp=32:*.c=32:*.C=32:*.cc=32:*.cpp=32:*.cxx=32:*.objc=32:*.cl=32:*.sh=32:*.bash=32:*.csh=32:*.zsh=32:*.el=32:*.vim=32:*.java=32:*.pl=32:*.pm=32:*.py=32:*.rb=32:*.hs=32:*.php=32:*.htm=32:*.html=32:*.shtml=32:*.erb=32:*.haml=32:*.xml=32:*.rdf=32:*.css=32:*.sass=32:*.scss=32:*.less=32:*.js=32:*.coffee=32:*.man=32:*.0=32:*.1=32:*.2=32:*.3=32:*.4=32:*.5=32:*.6=32:*.7=32:*.8=32:*.9=32:*.l=32:*.n=32:*.p=32:*.pod=32:*.tex=32:*.go=32:*.sql=32:*.csv=32:*.sv=32:*.svh=32:*.v=32:*.vh=32:*.vhd=32:*.bmp=33:*.cgm=33:*.dl=33:*.dvi=33:*.emf=33:*.eps=33:*.gif=33:*.jpeg=33:*.jpg=33:*.JPG=33:*.mng=33:*.pbm=33:*.pcx=33:*.pdf=33:*.pgm=33:*.png=33:*.PNG=33:*.ppm=33:*.pps=33:*.ppsx=33:*.ps=33:*.svg=33:*.svgz=33:*.tga=33:*.tif=33:*.tiff=33:*.xbm=33:*.xcf=33:*.xpm=33:*.xwd=33:*.xwd=33:*.yuv=33:*.aac=33:*.au=33:*.flac=33:*.m4a=33:*.mid=33:*.midi=33:*.mka=33:*.mp3=33:*.mpa=33:*.mpeg=33:*.mpg=33:*.ogg=33:*.opus=33:*.ra=33:*.wav=33:*.anx=33:*.asf=33:*.avi=33:*.axv=33:*.flc=33:*.fli=33:*.flv=33:*.gl=33:*.m2v=33:*.m4v=33:*.mkv=33:*.mov=33:*.MOV=33:*.mp4=33:*.mp4v=33:*.mpeg=33:*.mpg=33:*.nuv=33:*.ogm=33:*.ogv=33:*.ogx=33:*.qt=33:*.rm=33:*.rmvb=33:*.swf=33:*.vob=33:*.webm=33:*.wmv=33:*.doc=31:*.docx=31:*.rtf=31:*.odt=31:*.dot=31:*.dotx=31:*.ott=31:*.xls=31:*.xlsx=31:*.ods=31:*.ots=31:*.ppt=31:*.pptx=31:*.odp=31:*.otp=31:*.fla=31:*.psd=31:*.7z=1;35:*.apk=1;35:*.arj=1;35:*.bin=1;35:*.bz=1;35:*.bz2=1;35:*.cab=1;35:*.deb=1;35:*.dmg=1;35:*.gem=1;35:*.gz=1;35:*.iso=1;35:*.jar=1;35:*.msi=1;35:*.rar=1;35:*.rpm=1;35:*.tar=1;35:*.tbz=1;35:*.tbz2=1;35:*.tgz=1;35:*.tx=1;35:*.war=1;35:*.xpi=1;35:*.xz=1;35:*.z=1;35:*.Z=1;35:*.zip=1;35:*.ANSI-30-black=30:*.ANSI-01;30-brblack=01;30:*.ANSI-31-red=31:*.ANSI-01;31-brred=01;31:*.ANSI-32-green=32:*.ANSI-01;32-brgreen=01;32:*.ANSI-33-yellow=33:*.ANSI-01;33-bryellow=01;33:*.ANSI-34-blue=34:*.ANSI-01;34-brblue=01;34:*.ANSI-35-magenta=35:*.ANSI-01;35-brmagenta=01;35:*.ANSI-36-cyan=36:*.ANSI-01;36-brcyan=01;36:*.ANSI-37-white=37:*.ANSI-01;37-brwhite=01;37:*.log=01;32:*~=01;32:*#=01;32:*.bak=01;33:*.BAK=01;33:*.old=01;33:*.OLD=01;33:*.org_archive=01;33:*.off=01;33:*.OFF=01;33:*.dist=01;33:*.DIST=01;33:*.orig=01;33:*.ORIG=01;33:*.swp=01;33:*.swo=01;33:*,v=01;33:*.gpg=34:*.gpg=34:*.pgp=34:*.asc=34:*.3des=34:*.aes=34:*.enc=34:*.sqlite=34:';
@@ -27,16 +28,16 @@ if [ "$(uname)" = "Darwin" ] ; then
fi fi
# Setup for libvirt # Setup for libvirt
if [ -z "${LIBVIRT_DEFAULT_URI}" ] ; then if [ -z "${LIBVIRT_DEFAULT_URI:-}" ] ; then
if [ "$(id -u)" = "0" ] || (id -g -n | grep -q "\blibvirt\b") ; then export LIBVIRT_DEFAULT_URI="qemu:///system"
LIBVIRT_DEFAULT_URI="qemu:///system"
export LIBVIRT_DEFAULT_URI
fi
fi fi
# Got rust? (gvim, etc.) # Got rust? (gvim, etc.)
if test -d "${HOME}/.cargo/bin" ; then if test -d "${HOME}/.cargo/bin" ; then
PATH="${PATH}:${HOME}/.cargo/bin" case ":${PATH}:" in
*:"${HOME}/.cargo/bin":*) ;;
*) PATH="${PATH}:${HOME}/.cargo/bin" ;;
esac
fi fi
test -f "${HOME}/.profile.local" && . "${HOME}/.profile.local" test -f "${HOME}/.profile.local" && . "${HOME}/.profile.local"

View File

@@ -45,3 +45,6 @@
hibernationfile hibernationfile
sleepimage sleepimage
swapfile swapfile
# Android and other big tools
/Users/*/.android

View File

@@ -29,6 +29,9 @@ export WORKON_HOME="$HOME/.virtualenvs"
# GPG full key id # GPG full key id
export GPG_ID=7FD58D9A196DCEEEAD671F94F4D7A7915DEA789B export GPG_ID=7FD58D9A196DCEEEAD671F94F4D7A7915DEA789B
# Capture uname early
_UNAME="$(uname)"
# things we need in all interactive shells # things we need in all interactive shells
case "$-" in case "$-" in
*i*) *i*)
@@ -86,7 +89,6 @@ case "$-" in
;; ;;
esac esac
# Opt out of .net telemetry # Opt out of .net telemetry
export DOTNET_CLI_TELEMETRY_OPTOUT=1 export DOTNET_CLI_TELEMETRY_OPTOUT=1
@@ -97,96 +99,164 @@ export LVM_SUPPRESS_FD_WARNINGS=1
export EARTHLY_SSH_AUTH_SOCK="" export EARTHLY_SSH_AUTH_SOCK=""
# Handle SSH_AUTH_SOCK for tmux consistency # Handle SSH_AUTH_SOCK for tmux consistency
_SSH_AUTH_LINK="${HOME}/.ssh/ssh_auth_sock" case "$-" in
*i*)
_SSH_AUTH_LINK="${HOME}/.ssh/ssh_auth_sock"
# Helper to check if a path is our link or points to it # Helper to check if a path is our link or points to it
_is_link_path() { _is_link_path() {
[ -z "$1" ] && return 1 [ -z "$1" ] && return 1
[ "$1" = "${_SSH_AUTH_LINK}" ] && return 0 _target="${_SSH_AUTH_LINK:-${HOME}/.ssh/ssh_auth_sock}"
if [ -L "$1" ] && command -v readlink >/dev/null 2>&1; then [ "$1" = "${_target}" ] && { unset -v _target; return 0; }
_T=$(readlink "$1") if [ -L "$1" ] && command -v readlink >/dev/null 2>&1; then
# Handle relative symlinks _T=$(readlink "$1")
case "${_T}" in /*) ;; *) _T="$(dirname "$1")/${_T}" ;; esac # Handle relative symlinks
[ "${_T}" = "${_SSH_AUTH_LINK}" ] && return 0 case "${_T}" in /*) ;; *) _T="$(dirname "$1")/${_T}" ;; esac
fi [ "${_T}" = "${_target}" ] && { unset -v _target _T; return 0; }
return 1 unset -v _T
}
_CANDIDATE=""
# 1. If current environment has a valid socket that is NOT our link, it's a prime candidate
# (e.g. fresh SSH login: sshd sets SSH_AUTH_SOCK to the raw forwarded socket before ssh/rc
# rewrites it to the stable symlink; the shell inherits the original raw path).
if [ -S "${SSH_AUTH_SOCK:-}" ] && ! _is_link_path "${SSH_AUTH_SOCK}"; then
_CANDIDATE="${SSH_AUTH_SOCK}"
fi
# 2. Only look for a system agent if the stable link is already broken. If the link is
# valid (e.g. a tmux pane where SSH_AUTH_SOCK points to our symlink which ssh/rc just
# updated to the forwarded socket), leave it alone — don't clobber it with a local agent.
if [ -z "${_CANDIDATE}" ] && [ ! -S "${_SSH_AUTH_LINK}" ]; then
_FOUND=""
if [ "$(uname)" = "Darwin" ]; then
_FOUND=$(launchctl getenv SSH_AUTH_SOCK 2>/dev/null)
elif command -v systemctl >/dev/null 2>&1; then
# Query systemd socket units directly to avoid environment overrides.
for _u in ssh-agent.socket openssh-agent.socket gcr-ssh-agent.socket gpg-agent-ssh.socket; do
_P=$(systemctl --user show "${_u}" -p Listen 2>/dev/null | cut -d= -f2- | cut -d' ' -f1)
if [ -S "${_P}" ]; then
_FOUND="${_P}"
break
fi fi
done unset -v _target
# Fallback to systemd environment return 1
if [ -z "${_FOUND}" ] || _is_link_path "${_FOUND}"; then }
_FOUND=$(systemctl --user show-environment 2>/dev/null | grep "^SSH_AUTH_SOCK=" | cut -d= -f2-)
# Helper to check if an SSH socket is valid and useful
_is_valid_ssh_sock() {
[ -z "$1" ] && return 1
[ -S "$1" ] || return 1
if command -v nc >/dev/null 2>&1; then
# Use nc to quickly check if the socket is listening.
# We use -N to shutdown the socket after EOF on stdin (for OpenBSD netcat compatibility).
if echo '' | nc -w 1 -N -U "$1" >/dev/null 2>&1; then
return 0
fi
fi
if command -v ssh-add >/dev/null 2>&1; then
SSH_AUTH_SOCK="$1" ssh-add -l >/dev/null 2>&1
case "$?" in
0|1) return 0 ;;
*) return 1 ;;
esac
fi
if command -v nc >/dev/null 2>&1; then
return 1
fi
return 0
}
# Function to get the path to the socket for the local ssh-agent
get_local_ssh_agent_sock() {
_found=""
if [ "$(uname)" = "Darwin" ]; then
_found=$(launchctl getenv SSH_AUTH_SOCK 2>/dev/null)
elif command -v systemctl >/dev/null 2>&1; then
# Query systemd socket units directly to avoid environment overrides.
for _u in ssh-agent.socket openssh-agent.socket gcr-ssh-agent.socket gpg-agent-ssh.socket; do
_p=$(systemctl --user show "${_u}" -p Listen 2>/dev/null | cut -d= -f2- | cut -d' ' -f1)
if ! _is_link_path "${_p}" && _is_valid_ssh_sock "${_p}"; then
_found="${_p}"
break
fi
done
# Fallback to systemd environment
if [ -z "${_found}" ] || _is_link_path "${_found}" || ! _is_valid_ssh_sock "${_found}"; then
_found=$(systemctl --user show-environment 2>/dev/null | grep "^SSH_AUTH_SOCK=" | cut -d= -f2-)
fi
fi
if [ -n "${_found}" ] && ! _is_link_path "${_found}" && _is_valid_ssh_sock "${_found}"; then
echo "${_found}"
unset -v _found _u _p
return 0
fi
# Search common fallback paths
_u=$(id -u)
for _p in "/run/user/${_u}/keyring/ssh" "/run/user/${_u}/ssh-agent.socket" "/run/user/${_u}/openssh_agent" "/run/user/${_u}/gnupg/S.gpg-agent.ssh"; do
if ! _is_link_path "${_p}" && _is_valid_ssh_sock "${_p}"; then
echo "${_p}"
unset -v _found _u _p
return 0
fi
done
# Search /run/user/UID and /tmp for agent.* sockets
_search=""
for _d in "/run/user/${_u}" /tmp; do [ -d "${_d}" ] && _search="${_search} ${_d}"; done
if [ -n "${_search}" ]; then
for _p in $(find ${_search} -maxdepth 2 -type s -name 'agent.*' 2>/dev/null); do
if ! _is_link_path "${_p}" && _is_valid_ssh_sock "${_p}"; then
echo "${_p}"
unset -v _found _u _p _search _d
return 0
fi
done
fi
unset -v _found _u _p _search _d
return 1
}
# Function to reset SSH_AUTH_SOCK to the local ssh-agent
reset_ssh_socket() {
_rss_sock=$(get_local_ssh_agent_sock)
if [ -n "${_rss_sock}" ]; then
_rss_link="${HOME}/.ssh/ssh_auth_sock"
mkdir -p "$(dirname "${_rss_link}")"
ln -sf "${_rss_sock}" "${_rss_link}"
export SSH_AUTH_SOCK="${_rss_link}"
if command -v systemctl >/dev/null 2>&1; then
systemctl --user set-environment SSH_AUTH_SOCK="${_rss_link}" 2>/dev/null
fi
echo "Reset SSH_AUTH_SOCK to ${_rss_link} -> ${_rss_sock}"
unset -v _rss_sock _rss_link
return 0
else
echo "reset_ssh_socket: no valid local ssh-agent socket found." >&2
unset -v _rss_sock
return 1
fi
}
_CANDIDATE=""
# 1. If current environment has a valid socket that is NOT our link, it's a prime candidate
# (e.g. fresh SSH login: sshd sets SSH_AUTH_SOCK to the raw forwarded socket before ssh/rc
# rewrites it to the stable symlink; the shell inherits the original raw path).
if ! _is_link_path "${SSH_AUTH_SOCK:-}" && _is_valid_ssh_sock "${SSH_AUTH_SOCK:-}"; then
_CANDIDATE="${SSH_AUTH_SOCK}"
fi fi
fi
if [ -S "${_FOUND}" ] && ! _is_link_path "${_FOUND}"; then # 2. Only look for a system agent if the stable link is already broken. If the link is
_CANDIDATE="${_FOUND}" # valid (e.g. a tmux pane where SSH_AUTH_SOCK points to our symlink which ssh/rc just
fi # updated to the forwarded socket), leave it alone — don't clobber it with a local agent.
fi if [ -z "${_CANDIDATE}" ] && ! _is_valid_ssh_sock "${_SSH_AUTH_LINK}"; then
_CANDIDATE=$(get_local_ssh_agent_sock)
# 3. Last resort: search common paths if we still don't have a candidate and the link is broken.
if [ ! -S "${_CANDIDATE}" ] && [ ! -S "${_SSH_AUTH_LINK}" ]; then
_U=$(id -u)
for _p in "/run/user/${_U}/keyring/ssh" "/run/user/${_U}/ssh-agent.socket" "/run/user/${_U}/openssh_agent" "/run/user/${_U}/gnupg/S.gpg-agent.ssh"; do
if [ -S "${_p}" ] && ! _is_link_path "${_p}"; then
_CANDIDATE="${_p}"
break
fi fi
done
if [ -z "${_CANDIDATE}" ]; then # 3. Sync the stable link if we found a valid "real" socket.
# Build search path list based on what actually exists if [ -n "${_CANDIDATE}" ] && ! _is_link_path "${_CANDIDATE}" && _is_valid_ssh_sock "${_CANDIDATE}"; then
_SEARCH="" mkdir -p "$(dirname "${_SSH_AUTH_LINK}")"
for _d in "/run/user/${_U}" /tmp; do [ -d "${_d}" ] && _SEARCH="${_SEARCH} ${_d}"; done ln -sf "${_CANDIDATE}" "${_SSH_AUTH_LINK}"
if [ -n "${_SEARCH}" ]; then export SSH_AUTH_SOCK="${_SSH_AUTH_LINK}"
_CANDIDATE=$(find ${_SEARCH} -maxdepth 2 -type s -name 'agent.*' 2>/dev/null | grep -F -v "${_SSH_AUTH_LINK}" | head -n 1) # Update systemd if present to keep everything in sync
if command -v systemctl >/dev/null 2>&1; then
systemctl --user set-environment SSH_AUTH_SOCK="${_SSH_AUTH_LINK}" 2>/dev/null
fi
elif _is_valid_ssh_sock "${_SSH_AUTH_LINK}"; then
# If we found nothing better but the link is valid, use it.
export SSH_AUTH_SOCK="${_SSH_AUTH_LINK}"
fi fi
fi
fi
# 4. Sync the stable link if we found a valid "real" socket. unset _SSH_AUTH_LINK _CANDIDATE
if [ -S "${_CANDIDATE}" ] && ! _is_link_path "${_CANDIDATE}"; then ;;
mkdir -p "$(dirname "${_SSH_AUTH_LINK}")" esac
ln -sf "${_CANDIDATE}" "${_SSH_AUTH_LINK}"
export SSH_AUTH_SOCK="${_SSH_AUTH_LINK}"
# Update systemd if present to keep everything in sync
if command -v systemctl >/dev/null 2>&1; then
systemctl --user set-environment SSH_AUTH_SOCK="${_SSH_AUTH_LINK}" 2>/dev/null
fi
elif [ -S "${_SSH_AUTH_LINK}" ]; then
# If we found nothing better but the link is valid, use it.
export SSH_AUTH_SOCK="${_SSH_AUTH_LINK}"
fi
unset _SSH_AUTH_LINK _CANDIDATE _FOUND _T _P _U _u _SEARCH _d
unset -f _is_link_path
# Setup XDG-like dirs on MacOS # Setup XDG-like dirs on MacOS
# Based on https://leebyron.com/til/mac-xdg/ # Based on https://leebyron.com/til/mac-xdg/
if [ "$(uname)" = "Darwin" ] ; then if [ "${_UNAME}" = "Darwin" ] ; then
export XDG_BIN_HOME="${XDG_BIN_HOME:-$HOME/.local/bin}" export XDG_BIN_HOME="${XDG_BIN_HOME:-$HOME/.local/bin}"
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/Library/Caches}" export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/Library/Caches}"
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
@@ -195,10 +265,12 @@ if [ "$(uname)" = "Darwin" ] ; then
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-$TMPDIR/runtime-$(id -u)}" export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-$TMPDIR/runtime-$(id -u)}"
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}" export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
export PATH="${HOME}/bin/macos:${PATH}" export PATH="${HOME}/bin/macos:${PATH}"
elif [ "$(uname)" = "Linux" ] ; then elif [ "${_UNAME}" = "Linux" ] ; then
export PATH="${HOME}/bin/linux:${PATH}" export PATH="${HOME}/bin/linux:${PATH}"
fi fi
unset _UNAME
if test -e "$HOME/.localenv"; then if test -e "$HOME/.localenv"; then
# shellcheck source=/dev/null # shellcheck source=/dev/null
. "$HOME/.localenv" . "$HOME/.localenv"

View File

@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDYQOAB5bJ9DjMXyY67GEI99kK1LG8XF+cWJ4md52rPnOeJd0da7l26bn9NtXCma6DP5gZQArfxHsPh7I4SbYJRYxTCCCE/Jsd8mLB22DcoeY+MqPA2g71j3KrYsvuJC++9GHK2Xc7ZRmhAugEmC/NAdtORBVhtBSAUgyCmUczKHoCAqHmq8j54En8kRYjbvlHPpDsNoRuhcH5uDGBIVkbV7UtBl2oUlRNVw7grs6XS7cPU2zCQSxcrRRuAfV4hmGG2eKaPpieNg0MAAbR0G5ssWW3IuYwd1ys5wA0YQuWUhxadUuYc46/cqyyoVIFlfjxCVTX+2w3900SDPOF/YrOwctAb23+78WN6GPnAmmS3zcmXTGsJiw/mmyBlqYI/JdSgrgI+COlcP0rlF/uklzEywfD91m1lno1u2IApdAumZWHR8aFnpHQXfI6rWc1o/V+RBpz5Xe6D2h9CPT3AE303BV09HGmidb0t6bCKoabTDwvE+KojIcbKBji6g8V6KTM=

View File

@@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOP0EQthckpi83EoFXtbPnn4Ytd7FYW6Nb3W9ZahqOKhNAqv1owot957ihKHtGKFnYr0Jwgp0TNOdpz6nV9wwCo= david@zazu

View File

@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINFlZdKMzY8S/znw16R3X9jO+BaJ30NloH9XWtftjYh6 david@baymax.local

View File

@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBeDzE5KLJh2a9p0u702H9+rvaB1HoLLBU1I2Lx6NUbC david@scar

View File

@@ -0,0 +1 @@
sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBF8YzO0pEZ9DKHyqgPZpwlv6s4FBYDunIV23R4VUfiC3dw3P1vX9+tDO2+K65v+0vL2rAuBr5ZAHmDxiY8PzDwoAAAAEc3NoOg== david@zazu-sk

View File

@@ -1,8 +1,11 @@
# For interactive shells # For interactive shells
[[ -n "$ZSH_PROFILE" ]] && { [[ -n "$ZSH_PROFILE" ]] && {
zmodload zsh/datetime zmodload zsh/datetime
zshrc_start_time=$EPOCHREALTIME
zmodload zsh/zprof zmodload zsh/zprof
export PS4='+[%D{%f} / %D{%s.%N}] %N:%i> '
exec 3>&2 2>/tmp/zsh_startup.log
set -x
zshrc_start_time=$EPOCHREALTIME
} }
HISTFILE=~/.zhistory HISTFILE=~/.zhistory
HISTSIZE=10000 HISTSIZE=10000
@@ -129,7 +132,12 @@ case $TERM in
else else
# this will also work in tmux but is not what we want # this will also work in tmux but is not what we want
# Set the terminal title to include the command being run # Set the terminal title to include the command being run
print -Pn "\e]0;%n@%m: %~ ($cmd)\a" # Skip adding (cmd) in iTerm2 — shell integration already injects the job name
if [[ -z "$ITERM_SESSION_ID" ]]; then
print -Pn "\e]0;%n@%m: %~ ($cmd)\a"
else
print -Pn "\e]0;%n@%m: %~\a"
fi
fi fi
} }
# Add the hooks to zsh # Add the hooks to zsh
@@ -214,7 +222,7 @@ if [[ $- == *i* ]] ; then
if [[ ! -f "$DUMPFILE" || ( -n "$newest_comp" && "$newest_comp" -nt "$DUMPFILE" ) ]]; then if [[ ! -f "$DUMPFILE" || ( -n "$newest_comp" && "$newest_comp" -nt "$DUMPFILE" ) ]]; then
compinit -i -d "$DUMPFILE" compinit -i -d "$DUMPFILE"
# Asynchronously compile the dump file with an atomic rename # Asynchronously compile the dump file with an atomic rename
{ zcompile "$DUMPFILE.zwc.tmp" "$DUMPFILE" && mv -f "$DUMPFILE.zwc.tmp" "$DUMPFILE.zwc" } &! { zcompile "$DUMPFILE.zwc.$$.tmp" "$DUMPFILE" && mv -f "$DUMPFILE.zwc.$$.tmp" "$DUMPFILE.zwc" } &!
else else
compinit -C -i -d "$DUMPFILE" compinit -C -i -d "$DUMPFILE"
fi fi
@@ -298,6 +306,8 @@ typeset -U PATH
if [[ -n "$ZSH_PROFILE" ]]; then if [[ -n "$ZSH_PROFILE" ]]; then
zshrc_end_time=$EPOCHREALTIME zshrc_end_time=$EPOCHREALTIME
set +x
exec 2>&3 3>&-
# Calculation in ms using zsh floating point math # Calculation in ms using zsh floating point math
elapsed_ms=$(( (zshrc_end_time - zshrc_start_time) * 1000 )) elapsed_ms=$(( (zshrc_end_time - zshrc_start_time) * 1000 ))
printf "zshrc done: %.0fms\n" "$elapsed_ms" printf "zshrc done: %.0fms\n" "$elapsed_ms"

View File

@@ -14,4 +14,8 @@
have_command docker && \ have_command docker && \
missing_comp _docker && \ missing_comp _docker && \
docker completion zsh > $COMPDIR/_docker || true docker completion zsh > $COMPDIR/_docker || true
have_command resticprofile && \
missing_comp _resticprofile && \
resticprofile generate --zsh-completion > $COMPDIR/_resticprofile || true
} &>/dev/null &! } &>/dev/null &!

View File

@@ -72,3 +72,27 @@ function generate_secure_key {
local BYTES=$((BITS/8)) local BYTES=$((BITS/8))
head -c "${BYTES}" /dev/urandom | ${(s: :)ENCODE} head -c "${BYTES}" /dev/urandom | ${(s: :)ENCODE}
} }
function reset-ssh-socket {
reset_ssh_socket "$@"
}
function with-local-ssh-agent {
local sock
sock=$(get_local_ssh_agent_sock)
if [[ -z "${sock}" ]] ; then
echo "with-local-ssh-agent: no valid local ssh-agent socket found." >&2
return 1
fi
if [ "$#" -eq 0 ] ; then
(
export SSH_AUTH_SOCK="${sock}"
"${SHELL:-zsh}"
)
else
(
export SSH_AUTH_SOCK="${sock}"
eval "$@"
)
fi
}

View File

@@ -28,6 +28,27 @@ have_command() {
command -v "${1}" >/dev/null 2>&1 command -v "${1}" >/dev/null 2>&1
} }
raw_sha256sum() {
local file="${1}"
if [[ -z "${file}" ]]; then
echo "Error: No file specified" >&2
return 1
fi
if [[ ! -f "${file}" ]]; then
echo "Error: File not found: ${file}" >&2
return 1
fi
if have_command sha256sum ; then
sha256sum "${file}" | awk '{print $1}'
elif have_command shasum ; then
shasum -a 256 "${file}" | awk '{print $1}'
else
echo "Error: Neither sha256sum nor shasum is available" >&2
return 1
fi
}
sudo_group() { sudo_group() {
if [[ "$(id -u)" -eq 0 ]] ; then if [[ "$(id -u)" -eq 0 ]] ; then
return 0 return 0
@@ -65,48 +86,6 @@ link_directory_contents() {
done done
} }
ssh_key_already_installed() {
# Return 1 if the key isn't already installed, 0 if it is
local AK="${HOME}/.ssh/authorized_keys"
if [[ ! -f "$AK" ]] ; then
return 1
fi
# Extract the key data (field 2) from the key file, ignoring comments
local key_data
key_data=$(awk '/^ssh-/ {print $2}' "$1")
if [[ -z "${key_data}" ]]; then
# Not a valid key file
return 1
fi
# Use grep with fixed-string matching to see if the key is present.
# The exit code of grep is 0 on match, 1 on no match, which is perfect.
grep -F -q -- "${key_data}" "${AK}"
}
install_ssh_keys() {
# Install SSH keys
verbose 'Installing SSH keys...'
local AK="${HOME}/.ssh/authorized_keys"
local key
local keydir
if [[ "${TRUST_ALL_KEYS}" = 1 ]] ; then
keydir="${BASEDIR}/keys/ssh"
else
keydir="${BASEDIR}/keys/ssh/trusted"
fi
for key in "${keydir}"/* ; do
if [[ ! -f "${key}" ]] ; then
continue
fi
if ssh_key_already_installed "${key}" ; then
verbose "Key $(basename "${key}") already installed..."
continue
fi
echo "# $(basename "${key}") added from skel on $(date +%Y-%m-%d)" >> "${AK}"
cat "${key}" >> "${AK}"
done
}
install_gpg_keys() { install_gpg_keys() {
have_command gpg || \ have_command gpg || \
return 0 return 0
@@ -120,7 +99,7 @@ install_known_hosts() {
verbose 'Installing known hosts...' >&2 verbose 'Installing known hosts...' >&2
local skel_hosts="${BASEDIR}/keys/known_hosts" local skel_hosts="${BASEDIR}/keys/known_hosts"
local user_hosts="${HOME}/.ssh/known_hosts" local user_hosts="${HOME}/.ssh/known_hosts"
local merge_script="${BASEDIR}/skeltools/merge_authorized_keys" local merge_script="${BASEDIR}/skeltools/merge_known_hosts"
if [[ ! -f "${skel_hosts}" ]]; then if [[ ! -f "${skel_hosts}" ]]; then
return 0 return 0
@@ -151,7 +130,10 @@ install_known_hosts() {
} }
install_keys() { install_keys() {
install_ssh_keys if [[ -x "${BASEDIR}/bin/update-authorized-keys" ]]; then
verbose 'Installing SSH keys via update-authorized-keys...'
printf 'y\n' | "${BASEDIR}/bin/update-authorized-keys"
fi
install_gpg_keys install_gpg_keys
install_known_hosts install_known_hosts
} }
@@ -169,13 +151,12 @@ read_saved_prefs() {
save_prefs() { save_prefs() {
[[ "$SAVE" = 1 ]] || return 0 [[ "$SAVE" = 1 ]] || return 0
local pref_file=${BASEDIR}/.installed-prefs local pref_file="${BASEDIR}/.installed-prefs"
{ {
echo "BASEDIR=\"${BASEDIR}\"" printf 'BASEDIR=%q\n' "${BASEDIR}"
echo "MINIMAL=\"${MINIMAL}\"" printf 'MINIMAL=%q\n' "${MINIMAL}"
echo "INSTALL_KEYS=\"${INSTALL_KEYS}\"" printf 'INSTALL_KEYS=%q\n' "${INSTALL_KEYS}"
echo "TRUST_ALL_KEYS=\"${TRUST_ALL_KEYS}\"" printf 'VERBOSE=%q\n' "${VERBOSE}"
echo "VERBOSE=\"${VERBOSE}\""
} >| "$pref_file" } >| "$pref_file"
} }
@@ -208,6 +189,15 @@ install_dotfiles() {
install_starship() { install_starship() {
if have_command starship ; then return 0 ; fi if have_command starship ; then return 0 ; fi
if have_command brew ; then
verbose "Attempting to install Starship via Homebrew..."
if brew install starship ; then
return 0
fi
echo "brew install starship failed, trying other methods..." >&2
fi
if have_command apt-get && sudo_group ; then if have_command apt-get && sudo_group ; then
if maybe_sudo apt-get install -qy starship ; then if maybe_sudo apt-get install -qy starship ; then
return 0 return 0
@@ -215,7 +205,8 @@ install_starship() {
echo "apt-get install starship failed, installing locally" >&2 echo "apt-get install starship failed, installing locally" >&2
fi fi
local tmpd local tmpd
tmpd="$(mktemp -d tmp.starship.XXXXXX)" tmpd="$(mktemp -d "${TMPDIR:-/tmp}/starship.XXXXXX")" || return 1
local install_path="${tmpd}/install.sh" local install_path="${tmpd}/install.sh"
if have_command curl ; then if have_command curl ; then
curl -sSL --show-error -o "${install_path}" https://starship.rs/install.sh curl -sSL --show-error -o "${install_path}" https://starship.rs/install.sh
@@ -223,22 +214,26 @@ install_starship() {
wget -q -O "${install_path}" --https-only https://starship.rs/install.sh wget -q -O "${install_path}" --https-only https://starship.rs/install.sh
else else
echo "No curl or wget available!!" >&2 echo "No curl or wget available!!" >&2
rm -rf "${tmpd}"
return 1 return 1
fi fi
local dl_hash local dl_hash
dl_hash="$(sha256sum "${install_path}" | awk '{print $1}')" dl_hash="$(raw_sha256sum "${install_path}")"
if [[ "$dl_hash" != "${STARSHIP_INSTALL_HASH}" ]] ; then if [[ "$dl_hash" != "${STARSHIP_INSTALL_HASH}" ]] ; then
echo "Hash check failed!!" >&2 echo "Hash check failed!!" >&2
echo "Expected: ${STARSHIP_INSTALL_HASH}, got ${dl_hash} on ${install_path}" >&2 echo "Expected: ${STARSHIP_INSTALL_HASH}, got ${dl_hash} on ${install_path}" >&2
rm -rf "${tmpd}"
return 1 return 1
fi fi
if sudo_group ; then if sudo_group ; then
if maybe_sudo sh "${install_path}" ; then if maybe_sudo sh "${install_path}" ; then
rm -rf "${tmpd}"
return 0 return 0
fi fi
echo "root installation failed, falling back to user-local" >&2 echo "root installation failed, falling back to user-local" >&2
fi fi
sh "${install_path}" -b "${LOCAL_BIN}" sh "${install_path}" -b "${LOCAL_BIN}"
rm -rf "${tmpd}"
} }
install_main() { install_main() {
@@ -313,7 +308,6 @@ read_saved_prefs
: ${BASEDIR:=${SCRIPT_DIR}} : ${BASEDIR:=${SCRIPT_DIR}}
: ${MINIMAL:=0} : ${MINIMAL:=0}
: ${INSTALL_KEYS:=1} : ${INSTALL_KEYS:=1}
: ${TRUST_ALL_KEYS:=0}
: ${VERBOSE:=0} : ${VERBOSE:=0}
: ${SAVE:=1} : ${SAVE:=1}

View File

@@ -1,3 +1,51 @@
|1|ZWm0E5aueYzKuoY8OrGAI2ZUdWI=|L8KgVjGyomaw47OGrhpPnipXDKU= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKX08QrgyP7du28Re9NlKxLm6aJFUD4F2vWBCuiqo7KNrIPbgjVP9yOwy2gXueC6fbuVQj/C4BdnkgHw9hFXbC0= |1|ZWm0E5aueYzKuoY8OrGAI2ZUdWI=|L8KgVjGyomaw47OGrhpPnipXDKU= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKX08QrgyP7du28Re9NlKxLm6aJFUD4F2vWBCuiqo7KNrIPbgjVP9yOwy2gXueC6fbuVQj/C4BdnkgHw9hFXbC0=
|1|MjwrIkZqV0wbZ7pWue9nsFREyhk=|lGN2O8BcMHleUkD4yBtYRXSm1Yw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwbTUJWJ3mytxrYPKrzRDIuBRd+/X/3T/QT2gudQfDN/mxkAMTg+uLoObXnUOtfhXD+lXP/s/GKXoPmsV/ausSz2YxBrQQXH7SwCpUq5GRXcl5s43JAJ1MbQq2EA5pa1CEBzUgd/Osu/WaVsKwfABV7QeKhblMfM0a5XcsfawqVbMJ0q/egYiSsWRVTU2iNMXILChJT6WUVoUiDENRnW98iy1qQgY0ge6hr7Gh6m23Fg6yfYDBQrqszbTfFYlqGe54bGlnxZvGp+Ybas02D29whAHwdNCSmDWXW0EvSpyt9WZUm0WOQt3t9RXpKeKLrWH4V/5BFYrONY1GsKuE783tw== |1|MjwrIkZqV0wbZ7pWue9nsFREyhk=|lGN2O8BcMHleUkD4yBtYRXSm1Yw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwbTUJWJ3mytxrYPKrzRDIuBRd+/X/3T/QT2gudQfDN/mxkAMTg+uLoObXnUOtfhXD+lXP/s/GKXoPmsV/ausSz2YxBrQQXH7SwCpUq5GRXcl5s43JAJ1MbQq2EA5pa1CEBzUgd/Osu/WaVsKwfABV7QeKhblMfM0a5XcsfawqVbMJ0q/egYiSsWRVTU2iNMXILChJT6WUVoUiDENRnW98iy1qQgY0ge6hr7Gh6m23Fg6yfYDBQrqszbTfFYlqGe54bGlnxZvGp+Ybas02D29whAHwdNCSmDWXW0EvSpyt9WZUm0WOQt3t9RXpKeKLrWH4V/5BFYrONY1GsKuE783tw==
|1|UsEB5ylyIdmc4gs4TsYqE570DWY=|HAKqUTgFyTzodg8h6veV5jIa9GY= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC75TncmMQKEnnyw1S/uHcvs88d2M1NTMSUZyqdvFbx/uRB2rlrJiQHK8vyvN+fgRH5x8vde+vz/lAFgySV9RoS676cMuBIC8usF8REX2ghSXiSoGw35gd2ztGiDdU7FLUQYW+8FkR1soRjKZgyHqP/NCr4jBXjqDawDE33MA5LdmYy7fl1RN3oK4sY+LIoUWVv5x1aJdV86m0zbciavpU5szL++rnwcx+nWjDFFP4ntH1XyPGftyYpIAZwX+2Vl0+uMgv6sHazOx1E6vOIMx1UapCeLyWXzJ49P8K4iBZcNPH6h9aYllF4PIJ97Auh+fpFKBPfmHLq4iKCz4kKByy7 |1|UsEB5ylyIdmc4gs4TsYqE570DWY=|HAKqUTgFyTzodg8h6veV5jIa9GY= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC75TncmMQKEnnyw1S/uHcvs88d2M1NTMSUZyqdvFbx/uRB2rlrJiQHK8vyvN+fgRH5x8vde+vz/lAFgySV9RoS676cMuBIC8usF8REX2ghSXiSoGw35gd2ztGiDdU7FLUQYW+8FkR1soRjKZgyHqP/NCr4jBXjqDawDE33MA5LdmYy7fl1RN3oK4sY+LIoUWVv5x1aJdV86m0zbciavpU5szL++rnwcx+nWjDFFP4ntH1XyPGftyYpIAZwX+2Vl0+uMgv6sHazOx1E6vOIMx1UapCeLyWXzJ49P8K4iBZcNPH6h9aYllF4PIJ97Auh+fpFKBPfmHLq4iKCz4kKByy7
# ts-jumpbox.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
ts-jumpbox.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKwbpYiRqlgLKbaUlt1k4ms14+vTW8LKequepWdqDUUx
# ts-jumpbox.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
ts-jumpbox.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC2itf2fAUO5OB7BNAL9Js8pmxIwzLnOxRMexf5KGswUQRvaZwtw1CitJiyEcYWBt7zksd/Pupmp42ikPVoH7myQlWRbeEmJEIlMvkFF0pjAWj9kGKVLyFDbqXSkewKtXwbJHSo0l+mEOyq8NLlOwAA977BzNTn4z3KQEfYBQQEqISa8NuLpVOFvtQfvBlW+Xeh6+rIm54gdJVDWRimvZ5/FUMaRHPBdMFcXZW1GpraAHjHMeJXTIJs10qFy+5RwGTL5UlvssI+IPAIAW7o0goWmCnrlTjhvJ3Mnwq2lQhAuH/aDqVTptXwMni8tkvPFEC4LeoXG9pmb04Fd6bxY4RnvWuTmcvqOGAxJmZcqOYp1qWhyIF4TTB5l4h3J27sUtluEkTbIGtxTcPjFYLLC1lyIweoQSjWTmi5Z4wz1qfxIYZY1UXnyAjILvLAA5XAIpTgVfDx9KMAFdRrqaKN1MMFvfkTy7CZOfIkWhBwuOxMmtknsiJi8INZc+2CWUuI3Q8=
# ts-jumpbox.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
ts-jumpbox.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFs4yUU1aYjy5kq0vr8PFEJUA5s90lYzFTXwHuL9JwtL/wi7tC3I1ifyQnzfZIT8ORMHNGdz/DjNyKkE/rfDhEc=
# ts-jumpbox.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
# ts-jumpbox.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
# omega.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u2
omega.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQD7TIDPujGWOMkltfBUKoXOIX9W6KBbqT4qfANNivyjvYeS2joncfoCHTws3vTofHjfyzUSFpnjJSjbwoqTK38CsqSMx06KgpOiiz03+OVbtoBKiwY7smYXh2/vB53+EV4fnM1u/6AqAn0FYT/lUjaY6kBWDppW7PbFKRtO+wShMNfbaY1BTDyEEZRU3PCxR4UDXFO7fQLBiQb/XOyxsSXdRtP6BPrpqxUSq/hNchRo4AP08wtEY5iW9po1RMOFAMKPDND34CyWGbtfnpUCAk9jwKrKDRibRZgIe/xWNcXY9P9zuCSMByB3npo2lG2Em/usiO2awY1pcfrHrlfxJFnD+rzQ9LELwvSB8kPd5xlxZjqmNIvACGEYzR2zdbeOXy+G7biQ7cgELIFRF9aDKOe68sSss3SdS2suAXpqtNBE6l8T9u2jUD0po5EsDcNXPHCS8YLq4wyTpkeDAchX4xm8srycvPD9h4UAE9k+QqjkkbUQw/xpx0SL4pq8Xi6VuO0=
# omega.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u2
omega.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBL9cVRkixwE7KL112abP+GosO9+MiVUZQqUdRh4ps5O733cJ8tvkqLVkJhEejIFX6BLlmh/l+j/mD4Z8dL/YqmU=
# omega.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u2
omega.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMoxyWy+cXdpxh/KOhbvzB8Tq7NgWTHofOOpeVzuESe0
# omega.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u2
# omega.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u2
# xi.systemoverlord.com:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# xi.systemoverlord.com:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
xi.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCosFo3gGbGQ7PvHzVZ50umQNEILsqkHWnDi2FqHBCV/pQKUlZVuBO2HT0MiV3QkascJ58P4Jj1Ft/ILKvrU5/dDsW8xVs3vJlmHPrmovD93VwuarzlokmzxWPFOEPZIPcQcQcMCt6k4p/6Pb6hbmPGML2N7XGQHGVDFcflusx07wj56lP9xUtdOLcIo9u3rgw2puXqxUNRtx12Dfo9rjGiFFCXCrvFV5BG4utHKSyAOckJQ/oTzy++idM7jaPbnQ0qjH4GMHm2HN8bmWJdHjc6BeBEW4iQrUxNeisM/hKiICZ3kUmeEynx6IlgEXm0UT+AhxZL7BQo9X45pj5AvaU5
# xi.systemoverlord.com:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
xi.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBN49oL4rzjwfz5F7cUuVhqe9vRzDAE16O5NQvslhpOx3VA7g8qjyK4SmhhRll+N7vS7OvUqswjEIOXFdK2DUGq8=
# xi.systemoverlord.com:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
xi.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIg6N+lwA6feLnLDlm6Ssp45YjnaeCCQSBzeidmAb7FY
# xi.systemoverlord.com:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# chi.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
chi.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC7jSON+Pum/scQMwiBH0jI2fKfQ4q6YKBf/Q/uU7RiEzr3g5lRLA3RtFfWYlxSVqRdlQgeTvIRqG6VMQjtxm/UiLaNT82dVSgoSwJnODVWsKzWQNY1nkhGgd/Ue/XQrBi6UFB7QU7iiIHn8FmJDh05jLv4ymp3DuUM6W066cHqVMSslVhsioAJeZJdpFFK0WXbWs8PT83LT1LERP8CMWuaVlF4UxWwaxROA4WwWaUtiMm0e7T9AgCkHmmEWJemrJqkKUBU0BaqyIvF2bP4tNrZXM8EzT+2Dg25BWS6DzP/d7m8umrpQrYP7cbhK0jzNXw/niEjQ7f8ZiuguRGwWBKX0XjMPY36uiBE/bkGiyF2t27nSPyoA/I2CYtArAabVmiNTeK6qpgf1Xo+aBFuotS3+4Ql+9kfzO9ZL05xIBC2PzvL1pqWmTHI4GICLS2EdMks8LW5ZxvjMS0OdrVf1KaMgmr8TbJT+NIqs1SF3H5kmWUtMvQd4YJgU+o88/sO9LM=
# chi.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
chi.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIo6eEuZ1F1GGnkJqkyUTj4oGZlcADbmdahSiwif6pWcx6uGdSemPjQmhFknPbzpzH8HIUtrg/NSBGAjwVINz5Q=
# chi.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
chi.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINVUVuOLnuVRiUptQxn+HlUtgv4i5+DMK4uyN4voCB1R
# chi.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
# chi.systemoverlord.com:22 SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4
# tau.systemoverlord.com:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
tau.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMUffrd05Q6iyHj1vbvBzD+xWqR6c/YivTieWVim+b2wHEEYyh7eHXzldXZdLP3QOQHXWc68QwfSav5jsrVhsxk=
# tau.systemoverlord.com:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
tau.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/vDSvxXQa20+5OjgQpzxMQZR3m80fsIzHNqfjjAGlVTfPuccMnfCXNgQc8mY8qQTMxbBU4ZlSjntjyIBhWoj5flrTpVjHJgAkntu1dhtDYOp8sd+9CsR/40SX/1l8d6fRzuPSZaVO+RpF9Ym/MrxYH8YprBswl4pzT3/DVCgq3DDNocLzmyjMCgQJXxYpKhlnRSxhLvPHeAi4p0/gHmYhtQe4r0DZ/QaU6a/4bU2shGQyKBUUJbRTrNYwAEukZk+U5AkoQ7N43THB1PtdC0PwmaD2yXHiKzR/6SfLWRBE6TqyQKB0R8+lWWIU5s0Nu512UUS78bchkTtU0mgTpQWP
# tau.systemoverlord.com:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
tau.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK9+GZcp2imEoxDKY3rxdwGARZ6o/vmPCqrRF9ghxhLa
# tau.systemoverlord.com:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
# tau.systemoverlord.com:22 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
# zeta.systemoverlord.com:22 SSH-2.0-OpenSSH_10.3p1 Debian-4
zeta.systemoverlord.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBOPOADAIuJ/khxquXi1/wHyJUp1LqmfLVuHnGoqYouZc7AKcwWDOd30p5bSbrgGMXQC6oflMUsL1VL8hyqZPhs=
# zeta.systemoverlord.com:22 SSH-2.0-OpenSSH_10.3p1 Debian-4
zeta.systemoverlord.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWTvGafS9utruAmLpDdohEiEWSWVq3H6Mj1Z/hwnjVn67UncYDwLJjZem22r6qnW9h8hF9qpIG+XtU9Yk4iEvUk2H9S3gb7UOxwJ29lx2ckFp8V8Ml9t9gwrNpCVL+oiLm+iCmYMctksWbNXuiGRX22/qfeiM2zwyV3tEWbs/ePtVs5RX0EhbqPR5NHazy0NspE+lLsKeoGT5KsjyehStY69ER4iPKJzeiUxYfXj9wafniNiPZPV9jCDH4DIhkUWoOc1DF0cItVGLRnAWFoAEaWoIfC4ou33cuIfk810kf9uwSTgjVtGiGOC9Pemfc3RsFiUtlg4wpyAerBIvJlvrMAdPRhd1Pteg6QzWYbz0/3dGtyURjRg3uZQIiMre3zHHSKDQbdBL5C+9dM+d/PMdN+86GgwfymPHLoUsRpoY/1yxxqq8Zjc7D40amParpXHOkPzMLJy1F8d10QB52ZDx/7ivuPK55WaWiL3jcBLdim/I2te8EWwR0IgKGlkRYL88=
# zeta.systemoverlord.com:22 SSH-2.0-OpenSSH_10.3p1 Debian-4
zeta.systemoverlord.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPLOty9tztaPoyNUY50daxN3l8rM5+Eg1vMfqefgHWLT
# zeta.systemoverlord.com:22 SSH-2.0-OpenSSH_10.3p1 Debian-4
# zeta.systemoverlord.com:22 SSH-2.0-OpenSSH_10.3p1 Debian-4