Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions atuin/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
auto_sync = false
enter_accept = true

[sync]
records = true
94 changes: 94 additions & 0 deletions bin/bootstrap-remote.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/usr/bin/env bash
set -euo pipefail

DOTFILES_REPO="https://github.com/jhwheeler/dotfiles.git"
DOTFILES_DIR="$HOME/projects/dotfiles"
NVIM_FORK="https://github.com/jhwheeler/NormalNvim.git"

info() { printf "\n\033[0;34m==> %s\033[0m\n" "$*"; }
ok() { printf "\033[0;32m✓ %s\033[0m\n" "$*"; }

# ── Package detection ─────────────────────────────────────────────────────────
if command -v apt-get &>/dev/null; then
PKG="sudo apt-get install -y"
PKG_UPDATE="sudo apt-get update -qq"
elif command -v dnf &>/dev/null; then
PKG="sudo dnf install -y"
PKG_UPDATE=":"
elif command -v pacman &>/dev/null; then
PKG="sudo pacman -S --noconfirm"
PKG_UPDATE=":"
else
echo "Unsupported package manager. Install git, tmux, curl, bat, fzf, ripgrep manually." >&2
exit 1
fi

# ── Base packages ─────────────────────────────────────────────────────────────
info "Installing base packages"
$PKG_UPDATE
$PKG git curl tmux bat fzf ripgrep fd-find 2>/dev/null || \
$PKG git curl tmux bat fzf ripgrep fd # different distro naming

# ── Dotfiles ──────────────────────────────────────────────────────────────────
info "Setting up dotfiles"
mkdir -p "$HOME/projects"
if [[ ! -d "$DOTFILES_DIR/.git" ]]; then
git clone "$DOTFILES_REPO" "$DOTFILES_DIR"
fi
cd "$DOTFILES_DIR"
./install -c install-ssh.conf.yaml

# ── Neovim (AppImage - distro-agnostic, always latest) ────────────────────────
info "Installing Neovim"
mkdir -p "$HOME/.local/bin"
if ! command -v nvim &>/dev/null; then
ARCH=$(uname -m)
NVIM_URL="https://github.com/neovim/neovim/releases/latest/download/nvim-linux-${ARCH}.appimage"
curl -L "$NVIM_URL" -o "$HOME/.local/bin/nvim"
chmod +x "$HOME/.local/bin/nvim"
ok "Neovim installed"
else
ok "Neovim already installed ($(nvim --version | head -1))"
fi

# ── NormalNvim config ─────────────────────────────────────────────────────────
info "Setting up Neovim config (NormalNvim fork)"
if [[ ! -d "$HOME/.config/nvim/.git" ]]; then
git clone "$NVIM_FORK" "$HOME/.config/nvim"
fi
nvim --headless "+Lazy sync" +qa 2>/dev/null || true
ok "Neovim plugins synced"

# ── Starship ──────────────────────────────────────────────────────────────────
info "Installing Starship prompt"
if ! command -v starship &>/dev/null; then
curl -sS https://starship.rs/install.sh | sh -s -- --yes
fi

# ── Atuin ─────────────────────────────────────────────────────────────────────
info "Installing Atuin (local history)"
if ! command -v atuin &>/dev/null; then
curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh
fi

# ── Lazygit ───────────────────────────────────────────────────────────────────
info "Installing Lazygit"
if ! command -v lazygit &>/dev/null; then
LG_ARCH=$(uname -m)
[[ "$LG_ARCH" == "aarch64" ]] && LG_ARCH="arm64"
LG_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | grep '"tag_name"' | sed 's/.*"v\([^"]*\)".*/\1/')
curl -Lo /tmp/lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${LG_VERSION}_Linux_${LG_ARCH}.tar.gz"
tar -xf /tmp/lazygit.tar.gz -C "$HOME/.local/bin" lazygit
rm /tmp/lazygit.tar.gz
ok "Lazygit installed"
else
ok "Lazygit already installed ($(lazygit --version))"
fi

# ── TPM plugins ───────────────────────────────────────────────────────────────
info "Installing tmux plugins"
"$HOME/.tmux/plugins/tpm/bin/install_plugins" 2>/dev/null || true

echo ""
echo "Bootstrap complete! Start a new shell or run: source ~/.bashrc"
echo "Then attach tmux: tmux new -s main"
50 changes: 50 additions & 0 deletions install-ssh.conf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
- defaults:
link:
relink: true

- clean: ["~"]

- create:
- ~/.config
- ~/.shell
- ~/.tmux/scripts
- ~/.config/atuin

- link:
# Multiplexer
~/.tmux.conf: tmux.conf
~/.tmux/scripts/sessions.sh: tmux/scripts/sessions.sh

# Shell
~/.shell/env: shell/common/env
~/.shell/functions: shell/common/functions
~/.shell/login: shell/common/login
~/.shell/ssh: shell/common/ssh
~/.bash_aliases: shell/common/aliases
~/.bash_profile: shell/bash/bash_profile
~/.bashrc:
path: shell/bash/bashrc
force: true
~/.inputrc: shell/bash/inputrc

# Prompt
~/.config/starship.toml: starship.toml

# Git
~/.gitconfig: git/gitconfig
~/.gitignore_global: git/gitignore_global
~/.git_template: git/git_template

# Atuin history
~/.config/atuin/config.toml: atuin/config.toml

# Lazygit
~/.config/lazygit: lazygit

- shell:
- [git submodule update --init --recursive dotbot, Updating dotbot]
- [touch ~/.shell/secrets, Creating secrets file]
- [
"[ -d ~/.tmux/plugins/tpm ] || git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm",
Installing TPM,
]
9 changes: 9 additions & 0 deletions install.conf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- ~/.shell
- ~/.claude/hooks
- ~/.tmux/scripts
- ~/.config/atuin

- link:
~/.dotfiles: ''
Expand Down Expand Up @@ -51,6 +52,7 @@
~/.shell/env: shell/common/env
~/.shell/functions: shell/common/functions
~/.shell/login: shell/common/login
~/.shell/ssh: shell/common/ssh
~/.bash_aliases: shell/common/aliases
~/.bash_profile: shell/bash/bash_profile
~/.bashrc: shell/bash/bashrc
Expand All @@ -60,6 +62,9 @@
~/.claude/settings.json: claude/settings.json
~/.claude/hooks/notify.sh: claude/hooks/notify.sh

# Atuin history
~/.config/atuin/config.toml: atuin/config.toml

# Fuzzy finder
~/.fzf.bash: fzf/fzf.bash

Expand All @@ -68,3 +73,7 @@
- [touch ~/.shell/secrets, Creating local secrets file (not tracked by git)]
# If you haven't already, run prefix-I with tmux open after doing this to reload tmux and install the plugins
- [ if ! test -d "$HOME/.tmux/plugins/tpm"; then git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm; fi ]
# Clone nvim config (NormalNvim fork) — lazy.nvim bootstraps plugins on first launch
- [ if ! test -d "$HOME/.config/nvim"; then git clone https://github.com/jhwheeler/NormalNvim.git ~/.config/nvim; fi ]
# SCM Breeze (git aliases, numbered shortcuts)
- [ if ! test -d "$HOME/.scm_breeze"; then git clone https://github.com/scmbreeze/scm_breeze.git ~/.scm_breeze && ~/.scm_breeze/install.sh; fi ]
4 changes: 4 additions & 0 deletions shell/bash/bash_profile
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@

# Shared login tasks (atuin, Hyprland auto-start, etc.)
[ -f ~/.shell/login ] && . ~/.shell/login

# bun
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"
19 changes: 17 additions & 2 deletions shell/bash/bashrc
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ else
pointerC="${txtwht}"
normalC="${txtrst}"

# get name of branch and wrap in parens
# Get the current branch name without color codes so PS1 length stays correct.
gitBranch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
local branch
branch=$(git branch --show-current --no-color 2>/dev/null) || return
[[ -n "$branch" ]] && printf '(%s)' "$branch"
}
# build the prompt
export PS1="${pathC}\w ${gitC}\$(gitBranch) ${pointerC}\$${normalC} "
Expand All @@ -61,3 +63,16 @@ fi
# Atuin (shell history)
[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh
command -v atuin &>/dev/null && eval "$(atuin init bash)"

if command -v wt >/dev/null 2>&1; then eval "$(command wt config shell init bash)"; fi
export PATH="$HOME/.npm-global/bin:$PATH"

# OpenClaw Completion
source "/home/rheo/.openclaw/completions/openclaw.bash"
export PATH="$HOME/projects/scripts:$PATH"

# Open file in $EDITOR via fzf
fe() {
local file
file=$(fzf --preview 'cat {}') && ${EDITOR:-vim} "$file"
}
15 changes: 10 additions & 5 deletions shell/common/aliases
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ alias wget='wget -c'
# Colorize grep output
alias grep='grep --color=auto'

# Copying/pasting to/from Wayland clipboard
alias pbcopy='wl-copy'
alias pbpaste='wl-paste'
# Copying/pasting to/from Wayland clipboard — only set when Wayland is running
if [[ -n "$WAYLAND_DISPLAY" ]]; then
alias pbcopy='wl-copy'
alias pbpaste='wl-paste'
fi

# Common typos
alias exti='exit'
Expand Down Expand Up @@ -64,8 +66,11 @@ alias s='lynx_search'
# How Do I?
alias h='function hdi(){ howdoi $* -c -n 5; }; hdi'

# bat is cat with syntax highlighting
alias cat='bat'
# bat is cat with syntax highlighting — only alias if installed
command -v bat &>/dev/null && alias cat='bat'

# kitty SSH integration — fixes colors/terminfo on all SSH connections from kitty
command -v kitten &>/dev/null && alias ssh='kitten ssh'

# NPM
alias n='pnpm run'
Expand Down
27 changes: 20 additions & 7 deletions shell/common/env
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@
_path_prepend() { case ":$PATH:" in *":$1:"*) ;; *) export PATH="$1:$PATH" ;; esac; }
_path_append() { case ":$PATH:" in *":$1:"*) ;; *) export PATH="$PATH:$1" ;; esac; }

# Use Vim
if [[ -n $SSH_CONNECTION ]]; then
export EDITOR='vim'
else
export EDITOR='nvim'
fi
# SSH-specific overrides (clipboard, etc.)
[[ -n "$SSH_CONNECTION" ]] && [ -f ~/.shell/ssh ] && source ~/.shell/ssh

# Scripts
_path_append "$HOME/scripts"
Expand All @@ -22,6 +18,8 @@ export LYNX_CFG=$HOME/.config/lynx/lynx.cfg
# Go
export GOPATH="$HOME/go"
_path_append "$GOPATH/bin"
# Go toolchain binary (system-installed, e.g. /usr/local/go on servers)
[ -d /usr/local/go/bin ] && _path_prepend /usr/local/go/bin

# Deno
export DENO_INSTALL="$HOME/.deno"
Expand All @@ -40,6 +38,13 @@ _path_append "$HOME/.local/bin"
# opencode
_path_prepend "$HOME/.opencode/bin"

# Set EDITOR after PATH is fully configured so nvim can be found
if command -v nvim &>/dev/null; then
export EDITOR='nvim'
else
export EDITOR='vim'
fi

# NVM
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
Expand Down Expand Up @@ -79,5 +84,13 @@ export NODE_OPTIONS="--network-family-autoselection-attempt-timeout=500"

# Use tmux if available (interactive shells only, skip in Claude Code)
if [[ -z "$CLAUDECODE" ]] && [ -z "$TMUX" ] && [[ $- == *i* ]]; then
tmux attach -t default || tmux new -s default
if [[ -n "$SSH_CONNECTION" ]]; then
_tmux_session="ssh-$(hostname -s)"
tmux attach -d -t "$_tmux_session" || tmux new -s "$_tmux_session"
unset _tmux_session
else
# Each terminal gets its own session (no mirroring).
# detach-on-destroy off lets you cycle to other sessions if you want.
exec tmux new-session
fi
fi
16 changes: 16 additions & 0 deletions shell/common/ssh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# SSH-specific shell overrides
# Sourced automatically when $SSH_CONNECTION is set (see shell/common/env)

# Disable XON/XOFF flow control so C-s (tmux prefix over SSH) isn't swallowed
stty -ixon

# OSC52 clipboard: copies to local clipboard through SSH tunnel
# (supported by kitty, wezterm, most modern terminals)
# pbpaste via OSC52 is not widely supported — skipped intentionally
alias pbcopy='printf "\033]52;c;%s\a" "$(base64 -w0)"'

# tools that may not exist on remote — safe fallbacks
command -v bat &>/dev/null || unalias cat 2>/dev/null

# Prevent Hyprland-specific aliases from failing
unalias s 2>/dev/null # lynx_search (may not be installed)
Loading