diff --git a/fish/.config/fish/config.fish b/fish/.config/fish/config.fish index 90c8c24..c80f4d9 100644 --- a/fish/.config/fish/config.fish +++ b/fish/.config/fish/config.fish @@ -1,52 +1,57 @@ +# OS 감지 +set -g __os (uname) + # Fix fish_complete_path (중복 방지) if not contains ~/.config/fish/completions $fish_complete_path set -g fish_complete_path ~/.config/fish/completions $fish_complete_path end if status is-interactive - # Commands to run in interactive sessions can go here # Set default Node.js version nvm use 20 --silent - # Add uv to PATH - fish_add_path $HOME/.local/bin - # kitty integration 최적화 + # 공통 PATH + fish_add_path $HOME/.local/bin + fish_add_path $HOME/.cargo/bin + test -d /usr/local/go/bin && fish_add_path /usr/local/go/bin + + # ── OS별 PATH ── + if test "$__os" = Linux + fish_add_path $HOME/.local/kitty.app/bin + else if test "$__os" = Darwin + fish_add_path /Users/kaffa/.antigravity/antigravity/bin + end + + # ── kitty integration ── if test "$TERM" = xterm-kitty - # kitty shell integration 설정 alias icat="kitty +kitten icat" alias kdiff="kitty +kitten diff" - - # 빠른 디렉토리 이동 (kitty의 프롬프트 마킹 활용) bind \cg 'history | fzf | read -l result; and commandline $result' - - # 파일 미리보기 alias preview="fzf --preview 'if test -d {}; eza -la {}; else; bat --color=always {}; end'" - # tmux 유틸리티 함수들 + # tmux 유틸리티 alias tm="tmux" alias tma="tmux attach-session -t" alias tmn="tmux new-session -s" alias tml="tmux list-sessions" alias tmk="tmux kill-session -t" - # kitten 유틸리티 alias들 + # kitten 유틸리티 alias clipboard="kitty +kitten clipboard" alias img="kitty +kitten icat" alias unicode="kitty +kitten unicode_input" alias hgrep="kitty +kitten hyperlinked_grep" - - # 이미지 갤러리 함수 (간단한 alias로 변경) alias imgls="find . -maxdepth 1 -type f \( -name '*.png' -o -name '*.jpg' -o -name '*.jpeg' -o -name '*.gif' -o -name '*.webp' \) | head -5 | xargs -I {} kitty +kitten icat --align center {}" end end -# Vault Configuration +# ══════════════════════════════════════════════════════════════════ +# 환경 변수 (공통) +# ══════════════════════════════════════════════════════════════════ + set -x VAULT_ADDR "https://vault.anvil.it.com" set -x VAULT_TOKEN "hvs.o7JrzES15uuXRmvlKAJKEaTv" - -# Gitea Configuration set -gx GITEA_URL "https://gitea.anvil.it.com" -set -gx GITEA_TOKEN (security find-internet-password -s gitea.anvil.it.com -a kaffa -w 2>/dev/null) # Cloudflare Configuration - Lazy Loading function load_cloudflare_credentials @@ -57,41 +62,54 @@ function load_cloudflare_credentials end end -# Auto-load when using cf command if command -v cf >/dev/null alias cf='load_cloudflare_credentials && command cf' end +# ══════════════════════════════════════════════════════════════════ +# Alias (공통) +# ══════════════════════════════════════════════════════════════════ + alias vi=nvim alias ssh=tssh -alias docker "limactl shell docker -- docker" -alias podman "limactl shell podman -- podman" -alias ss='netstat -an' - -# Set default editor for Claude Code /memory command set -Ux VISUAL nvim set -Ux EDITOR nvim -# Added by Antigravity -fish_add_path /Users/kaffa/.antigravity/antigravity/bin +# ══════════════════════════════════════════════════════════════════ +# OS별 설정 +# ══════════════════════════════════════════════════════════════════ + +if test "$__os" = Darwin + # macOS: keychain에서 Gitea 토큰 로드 + set -gx GITEA_TOKEN (security find-internet-password -s gitea.anvil.it.com -a kaffa -w 2>/dev/null) + # macOS: Lima 기반 컨테이너 + alias docker "limactl shell docker -- docker" + alias podman "limactl shell podman -- podman" + alias ss='netstat -an' +else if test "$__os" = Linux + # Linux: 환경변수 또는 vault에서 Gitea 토큰 로드 + if not set -q GITEA_TOKEN + set -gx GITEA_TOKEN (vault kv get -field=api_token secret/apps/gitea 2>/dev/null || echo "") + end + alias ss='ss -tulnp' +end # ══════════════════════════════════════════════════════════════════ # Claude Code tmux 단축키 # ══════════════════════════════════════════════════════════════════ -# Claude 세션 빠른 시작 alias tc='tmux-claude' - -# 현재 디렉토리에서 Claude 세션 alias tcc='tmux-claude (pwd)' -# tmux 패널 내용 복사 (최근 1000줄) function tcopy - tmux capture-pane -pS -1000 | pbcopy + if test "$__os" = Darwin + tmux capture-pane -pS -1000 | pbcopy + else + tmux capture-pane -pS -1000 | xclip -selection clipboard + end echo "패널 내용 복사됨 (최근 1000줄)" end -# Claude 응답 검색 (tmux 히스토리에서) function csearch tmux copy-mode tmux send-keys "?" "$argv" Enter diff --git a/git/.gitconfig b/git/.gitconfig index 4697cb6..297e860 100644 --- a/git/.gitconfig +++ b/git/.gitconfig @@ -2,4 +2,7 @@ name = kappa email = kappa@inouter.com [credential] - helper = osxkeychain + # macOS: osxkeychain, Linux: store + helper = +[include] + path = ~/.gitconfig.local diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..1ae95cb --- /dev/null +++ b/install.sh @@ -0,0 +1,296 @@ +#!/usr/bin/env bash +set -euo pipefail + +OS="$(uname)" +ARCH="$(uname -m)" +echo "==> OS: $OS / ARCH: $ARCH" + +# ────────────────────────────────────────────────────────────────── +# 헬퍼 함수 +# ────────────────────────────────────────────────────────────────── +ensure() { + if command -v "$1" &>/dev/null; then + echo " ✓ $1 이미 설치됨" + return 1 + fi + echo " → $1 설치 중..." + return 0 +} + +# ────────────────────────────────────────────────────────────────── +# macOS +# ────────────────────────────────────────────────────────────────── +install_macos() { + echo "==> macOS 환경 설치 시작" + + # Homebrew + if ! command -v brew &>/dev/null; then + echo "==> Homebrew 설치 중..." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + fi + + brew update + + BREW_PACKAGES=( + # 기본 도구 + git curl wget unzip make stow + # 셸 & 터미널 + fish tmux + # 에디터 + neovim + # 검색 & 탐색 + fzf ripgrep fd bat eza tree + # Git 도구 + gh git-delta lazygit + # 데이터 처리 + jq yq + # 인프라 + kubectl helm vault + # 개발 런타임 + node uv go rust + # SSH + trzsz-ssh + # 모니터링 + htop + ) + + for pkg in "${BREW_PACKAGES[@]}"; do + brew list "$pkg" &>/dev/null || brew install "$pkg" + done + + # cask 앱 + brew list kitty &>/dev/null || brew install --cask kitty + + # Claude Code + if ! command -v claude &>/dev/null; then + npm install -g @anthropic-ai/claude-code + fi + + # fish를 기본 셸로 등록 + FISH_PATH="$(brew --prefix)/bin/fish" + if ! grep -q "$FISH_PATH" /etc/shells; then + echo "$FISH_PATH" | sudo tee -a /etc/shells + fi + + echo "==> macOS 설치 완료" +} + +# ────────────────────────────────────────────────────────────────── +# Linux (Debian/Ubuntu) +# ────────────────────────────────────────────────────────────────── +install_linux() { + echo "==> Linux 환경 설치 시작" + + sudo apt-get update + + # ── apt 일괄 설치 ── + APT_PACKAGES=( + # 기본 도구 + git curl wget unzip make gcc stow + # 셸 & 터미널 + fish tmux + # 검색 & 탐색 + fzf ripgrep fd-find tree + # Git 도구 + gh git-delta + # 데이터 처리 + jq + # 모니터링 + htop + # 클립보드 + xclip + # Python 기본 + python3 python3-pip python3-venv + ) + sudo apt-get install -y "${APT_PACKAGES[@]}" + + # ── fd 심링크 (Debian은 fdfind) ── + if command -v fdfind &>/dev/null && ! command -v fd &>/dev/null; then + sudo ln -sf "$(which fdfind)" /usr/local/bin/fd + fi + + # ── bat (Debian은 batcat) ── + if ! command -v bat &>/dev/null; then + sudo apt-get install -y bat 2>/dev/null || sudo apt-get install -y batcat + if command -v batcat &>/dev/null && ! command -v bat &>/dev/null; then + sudo ln -sf "$(which batcat)" /usr/local/bin/bat + fi + fi + + # ── eza ── + if ensure eza; then + sudo apt-get install -y eza 2>/dev/null || { + sudo mkdir -p /etc/apt/keyrings + wget -qO- https://raw.githubusercontent.com/eza-community/eza/main/deb.asc | sudo gpg --dearmor -o /etc/apt/keyrings/gierens.gpg + echo "deb [signed-by=/etc/apt/keyrings/gierens.gpg] http://deb.gierens.de stable main" | sudo tee /etc/apt/sources.list.d/gierens.list + sudo apt-get update && sudo apt-get install -y eza + } + fi + + # ── neovim (최신) ── + if ensure nvim; then + curl -Lo /tmp/nvim.tar.gz https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz + sudo tar -C /usr/local --strip-components=1 -xzf /tmp/nvim.tar.gz + rm -f /tmp/nvim.tar.gz + fi + + # ── kitty ── + if ! command -v kitty &>/dev/null && [ ! -x "$HOME/.local/kitty.app/bin/kitty" ]; then + echo " → kitty 설치 중..." + curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin + fi + + # ── yq ── + if ensure yq; then + local yq_arch="amd64" + [ "$ARCH" = "aarch64" ] && yq_arch="arm64" + curl -Lo /tmp/yq "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${yq_arch}" + sudo install /tmp/yq /usr/local/bin/yq + rm -f /tmp/yq + fi + + # ── lazygit ── + if ensure lazygit; then + LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | jq -r '.tag_name' | sed 's/^v//') + local lg_arch="x86_64" + [ "$ARCH" = "aarch64" ] && lg_arch="arm64" + curl -Lo /tmp/lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_Linux_${lg_arch}.tar.gz" + tar -xzf /tmp/lazygit.tar.gz -C /tmp lazygit + sudo install /tmp/lazygit /usr/local/bin/lazygit + rm -f /tmp/lazygit.tar.gz /tmp/lazygit + fi + + # ── Node.js (이미 없으면) ── + if ensure node; then + curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - + sudo apt-get install -y nodejs + fi + + # ── uv (Python 패키지 매니저) ── + if ensure uv; then + curl -LsSf https://astral.sh/uv/install.sh | sh + fi + + # ── Go ── + if ensure go; then + local go_arch="amd64" + [ "$ARCH" = "aarch64" ] && go_arch="arm64" + GO_VERSION=$(curl -s 'https://go.dev/VERSION?m=text' | head -1) + curl -Lo /tmp/go.tar.gz "https://go.dev/dl/${GO_VERSION}.linux-${go_arch}.tar.gz" + sudo rm -rf /usr/local/go + sudo tar -C /usr/local -xzf /tmp/go.tar.gz + rm -f /tmp/go.tar.gz + fi + + # ── Rust ── + if ensure cargo; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + fi + + # ── HashiCorp Vault CLI ── + if ensure vault; then + wget -qO- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg + echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list + sudo apt-get update && sudo apt-get install -y vault + fi + + # ── tssh (trzsz-ssh) ── + if ensure tssh; then + curl -Ls https://raw.githubusercontent.com/trzsz/trzsz-ssh/main/install.sh | sudo bash + fi + + # ── Claude Code ── + if ensure claude; then + npm install -g @anthropic-ai/claude-code + fi + + echo "==> Linux 설치 완료" +} + +# ────────────────────────────────────────────────────────────────── +# fisher & fish 플러그인 +# ────────────────────────────────────────────────────────────────── +install_fish_plugins() { + echo "==> Fisher 및 fish 플러그인 설치 중..." + + if command -v fish &>/dev/null; then + FISH_BIN=fish + elif [ -x /opt/homebrew/bin/fish ]; then + FISH_BIN=/opt/homebrew/bin/fish + else + echo " !! fish를 찾을 수 없습니다. 스킵." + return + fi + + $FISH_BIN -c ' + if not functions -q fisher + curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source + fisher install jorgebucaran/fisher + end + fisher update + ' + + echo "==> fish 플러그인 설치 완료" +} + +# ────────────────────────────────────────────────────────────────── +# stow 적용 +# ────────────────────────────────────────────────────────────────── +apply_dotfiles() { + echo "==> dotfiles 심링크 적용 중..." + SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + cd "$SCRIPT_DIR" + stow -v --adopt -t "$HOME" fish git kitty nvim tmux + git checkout -- . + echo "==> dotfiles 적용 완료" +} + +# ────────────────────────────────────────────────────────────────── +# OS별 gitconfig.local +# ────────────────────────────────────────────────────────────────── +setup_gitconfig_local() { + if [ ! -f "$HOME/.gitconfig.local" ]; then + echo "==> .gitconfig.local 생성 중..." + if [ "$OS" = "Darwin" ]; then + cat > "$HOME/.gitconfig.local" <<'EOF' +[credential] + helper = osxkeychain +EOF + else + cat > "$HOME/.gitconfig.local" <<'EOF' +[credential] + helper = store +EOF + fi + fi +} + +# ────────────────────────────────────────────────────────────────── +# 메인 +# ────────────────────────────────────────────────────────────────── +case "$OS" in + Darwin) install_macos ;; + Linux) install_linux ;; + *) echo "지원하지 않는 OS: $OS"; exit 1 ;; +esac + +apply_dotfiles +install_fish_plugins +setup_gitconfig_local + +echo "" +echo "========================================" +echo " 설치 완료! 설치된 도구 목록:" +echo "========================================" +echo "" +echo " 셸/터미널 : fish, tmux, kitty" +echo " 에디터 : neovim" +echo " 검색/탐색 : fzf, ripgrep, fd, bat, eza, tree" +echo " Git : git, gh, delta, lazygit" +echo " 데이터 : jq, yq" +echo " 런타임 : node, python3, uv, go, rust" +echo " 인프라 : kubectl, helm, vault" +echo " AI : claude (Claude Code)" +echo " 기타 : tssh, htop, stow" +echo "" +echo " 새 셸을 열거나 'source ~/.config/fish/config.fish' 를 실행하세요." diff --git a/tmux/.tmux.conf b/tmux/.tmux.conf index 8673e70..4d0b007 100644 --- a/tmux/.tmux.conf +++ b/tmux/.tmux.conf @@ -97,14 +97,23 @@ bind-key -T copy-mode-vi 'C-k' select-pane -U bind-key -T copy-mode-vi 'C-l' select-pane -R bind-key -T copy-mode-vi 'C-\' select-pane -l -# Neovim 서버와 클립보드 동기화 +# Neovim 서버와 클립보드 동기화 (OS별 분기) if-shell 'command -v pbcopy' { bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'pbcopy' bind -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel 'pbcopy' } +if-shell 'command -v xclip' { + bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'xclip -selection clipboard' + bind -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel 'xclip -selection clipboard' +} -# Fish shell이 기본 셸인 경우 -set -g default-shell /opt/homebrew/bin/fish +# Fish shell을 기본 셸로 (OS별 경로) +if-shell 'test -x /opt/homebrew/bin/fish' { + set -g default-shell /opt/homebrew/bin/fish +} +if-shell 'test -x /usr/bin/fish' { + set -g default-shell /usr/bin/fish +} # ══════════════════════════════════════════════════════════════════ # Claude Code 최적화 설정 # ══════════════════════════════════════════════════════════════════