Compare commits

..

10 Commits

Author SHA1 Message Date
435e95bf0f chore: add zi and remove kiro-cli
Signed-off-by: Li Tang <iamtangli42@gmail.com>
2026-05-27 10:37:03 +08:00
d72cb9fdf1 feat: add command for backup/recover brewfile
Signed-off-by: Li Tang <iamtangli42@gmail.com>
2026-05-25 15:44:49 +08:00
5f9534ad00 backup: update brewfile for stardewvalley 2026-05-25 15:43:41 +08:00
af3fdb86ee feat(git): default pull to rebase
Add pull.rebase to git/config template and simplify git_clean to rely on it.
2026-05-25 11:17:51 +08:00
9779226abd chore: add brewfile
Signed-off-by: Li Tang <iamtangli42@gmail.com>
2026-05-21 12:27:21 +08:00
44686c0d3e feat: git pull with rebase
Signed-off-by: Li Tang <iamtangli42@gmail.com>
2026-05-20 20:56:32 +08:00
895a83049f chore: add tmux session clean
Signed-off-by: Li Tang <iamtangli42@gmail.com>
2026-05-18 13:35:13 +08:00
922c19b186 chore: fix command alias
Signed-off-by: Li Tang <iamtangli42@gmail.com>
2026-05-15 17:24:41 +08:00
c7ef457b35 chore: add alias
Signed-off-by: Li Tang <iamtangli42@gmail.com>
2026-05-15 10:36:48 +08:00
4af2be09ec chore: update software
Signed-off-by: Li Tang <iamtangli42@gmail.com>
2026-05-13 17:15:19 +08:00
6 changed files with 201 additions and 35 deletions

40
.zshrc
View File

@@ -1,10 +1,3 @@
# Kiro CLI pre block. Keep at the top of this file.
# [[ -f "${HOME}/Library/Application Support/kiro-cli/shell/zshrc.pre.zsh" ]] && builtin source "${HOME}/Library/Application Support/kiro-cli/shell/zshrc.pre.zsh"
# Kiro CLI pre block. Keep at the top of this file.
#
###############################################################################
# My Dotfiles - Zsh Configuration
###############################################################################
@@ -131,9 +124,8 @@ alias sed='gsed'
alias grep='ggrep'
alias tailscale="/Applications/Tailscale.app/Contents/MacOS/Tailscale"
alias ghostty='/Applications/Ghostty.app/Contents/MacOS/ghostty'
alias cc='claude'
alias ccd='claude --dangerously-skip-permissions'
alias oc='opencode'
alias claudeyolo='claude --dangerously-skip-permissions'
alias opencode='OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX=64000 opencode'
alias claude-mem='bun "$HOME/.claude/plugins/marketplaces/thedotmack/plugin/scripts/worker-service.cjs"'
@@ -323,7 +315,6 @@ function git_clean() {
fi
git checkout "$base_branch" && \
git config pull.rebase false && \
git pull && \
git branch --merged | grep -v " $base_branch$" | xargs git branch -d 2>/dev/null; \
git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -D 2>/dev/null; \
@@ -386,8 +377,8 @@ function dev() {
for arg in "$@"; do
case "$arg" in
-g|--git) layout="full" ;;
oc|--oc) tool="oc" ;;
cc|--cc) tool="cc" ;;
opencode|--oc) tool="opencode" ;;
claude|--cc) tool="cluade" ;;
codex|--codex) tool="codex" ;;
copilot|--copilot) tool="copilot" ;;
*) session="$arg" ;;
@@ -449,6 +440,21 @@ function dev() {
fi
}
# Destroy the dev session matching the current directory (or a given name)
# Usage: undev [session-name]
# Mirrors dev()'s session-name derivation: basename $(pwd) with '.' and ':' -> '_'
function undev() {
local session="${1:-$(basename "$(pwd)")}"
session="${session//[.:]/_}"
if ! tmux has-session -t "$session" 2>/dev/null; then
echo "undev: no tmux session named '$session'" >&2
return 1
fi
tmux kill-session -t "$session"
}
# Create a throwaway scratch workspace in a temp dir
# Usage: scratch [-g] [--git] [oc|cc|codex|copilot]
# Creates /tmp/scratch-<ts>, calls dev() for a throwaway workspace
@@ -476,7 +482,7 @@ function scratch() {
pushd "$dir" > /dev/null
local session="scratch_${ts}"
local session="scratch-${ts}"
dev "${extra_args[@]}" "$session"
popd > /dev/null
@@ -499,5 +505,7 @@ function copilot_local {
copilot
}
# Kiro CLI post block. Keep at the bottom of this file.
# [[ -f "${HOME}/Library/Application Support/kiro-cli/shell/zshrc.post.zsh" ]] && builtin source "${HOME}/Library/Application Support/kiro-cli/shell/zshrc.post.zsh"
function zi() {
local dir
dir=$(zoxide query -l | fzf --preview 'ls -la {}') && z "$dir"
}

View File

@@ -9,8 +9,10 @@ Use the setup script instead of ad hoc symlink changes:
- `./setup.sh install`: link managed files into `$HOME` and `$HOME/.config`.
- `./setup.sh check`: verify expected tools, links, and directories.
- `./setup.sh full-recover`: bootstrap a new machine end to end.
- `./setup.sh backup`: refresh tracked backup artifacts such as `Brewfile`.
- `brew bundle install`: install CLI tools and apps from [Brewfile](/Users/d0zingcat/.dotfiles/Brewfile).
- `./setup.sh brew-backup`: dump Homebrew packages to `brewfiles/<hostname>/Brewfile`.
- `./setup.sh brew-install`: install packages from the current machine's Brewfile.
- `./setup.sh backup`: full backup (includes brew-backup plus git/ssh/vscode exports).
- Per-machine Brewfiles live under [brewfiles/](/Users/d0zingcat/.dotfiles/brewfiles/).
- `tmux/plugins/tpm/tests/test_plugin_installation.sh`: example TPM plugin test entrypoint when working inside the submodule.
## Coding Style & Naming Conventions

28
brewfiles/README.md Normal file
View File

@@ -0,0 +1,28 @@
# Per-Machine Brewfiles
Each Mac keeps its own Homebrew bundle under `brewfiles/<hostname>/Brewfile`, where `<hostname>` is the short hostname (`hostname -s`, e.g. `stardewvalley`).
## Commands
```bash
# Dump only (frequent updates)
./setup.sh brew-backup
# Install packages for this machine
./setup.sh brew-install
# Full backup still includes brew-backup
./setup.sh backup
```
## New machine / full recover
`./setup.sh full-recover` runs `brew-install` automatically when a Brewfile exists for the current hostname.
## Hostname changed?
Point at another machine's Brewfile:
```bash
BREWFILE_HOST=other-mac ./setup.sh brew-install
```

View File

@@ -1,9 +1,11 @@
tap "anomalyco/tap"
tap "buo/cask-upgrade"
tap "clojure/tools"
tap "d0zingcat/tap", "https://github.com/d0zingcat/homebrew-tap.git"
tap "d0zingcat/tap"
tap "farion1231/ccswitch"
tap "hashicorp/tap"
tap "hmbown/deepseek-tui"
tap "homebrew/cask"
tap "markmals/tap"
tap "minio/stable"
tap "oven-sh/bun"
@@ -21,11 +23,13 @@ brew "bash"
brew "bat"
brew "btop"
brew "cmake"
brew "create-dmg"
brew "difftastic"
brew "direnv"
brew "dosbox-staging"
brew "duckdb"
brew "expect"
brew "ffmpeg"
brew "fzf"
brew "gcc"
brew "gh"
@@ -75,11 +79,13 @@ brew "zoxide"
brew "zsh"
brew "clojure/tools/clojure"
brew "hashicorp/tap/terraform"
brew "hmbown/deepseek-tui/deepseek-tui"
brew "minio/stable/mc"
brew "oven-sh/bun/bun"
brew "vitobotta/tap/hetzner_k3s"
cask "1password"
cask "antigravity"
cask "1password-cli"
cask "antigravity-ide"
cask "cc-switch"
cask "chatgpt"
cask "cherry-studio"
@@ -90,26 +96,31 @@ cask "codex"
cask "codex-app"
cask "copilot-cli"
cask "cursor"
cask "cursor-cli"
cask "datagrip"
cask "db-browser-for-sqlite"
cask "t8y2/tap/dbx"
cask "d0zingcat/tap/doubao-ime"
cask "feishu"
cask "font-jetbrains-mono-nerd-font"
cask "font-maple-mono-nf-cn"
cask "ghostty"
cask "github-copilot-for-xcode"
cask "google-chrome"
cask "google-gemini"
cask "hoppscotch"
cask "jordanbaird-ice"
cask "kiro"
cask "kiro-cli"
cask "lm-studio"
cask "mitmproxy"
cask "navicat-premium-lite"
cask "netnewswire"
cask "notion"
cask "obsidian"
cask "one-switch"
cask "only-switch"
cask "orbstack"
cask "d0zingcat/tap/push-to-talk"
cask "qoderai/qoder/qodercli"
cask "qq"
cask "raycast"
@@ -118,9 +129,10 @@ cask "stats"
cask "tablepro"
cask "teamviewer"
cask "telegram"
cask "thaw"
cask "typeless"
cask "d0zingcat/tap/typeswitch"
cask "visual-studio-code@insiders"
cask "d0zingcat/tap/wakeup-macos"
cask "wechat"
cask "wechatwork"
cask "wetype"
@@ -134,6 +146,7 @@ mas "Pages", id: 409201541
go "rsc.io/2fa"
go "github.com/air-verse/air"
go "golang.org/x/tools/cmd/callgraph"
go "claudette/cmd/claudette"
go "github.com/go-delve/delve/cmd/dlv"
go "entgo.io/ent/cmd/ent"
go "github.com/davidrjenni/reftools/cmd/fillswitch"
@@ -168,4 +181,5 @@ go "honnef.co/go/tools/cmd/staticcheck"
go "github.com/swaggo/swag/cmd/swag"
go "github.com/google/wire/cmd/wire"
cargo "sqlx-cli"
cargo "syswatch"
uv "mlx-lm"

View File

@@ -1,6 +1,9 @@
[init]
defaultBranch = main
[pull]
rebase = true
[user]
name = YOUR_NAME
signingkey = YOUR_SSH_SIGNING_KEY

137
setup.sh
View File

@@ -7,6 +7,8 @@
# init - Initialize a brand new macOS system
# install - Install dotfiles symlinks
# backup - Backup current configuration
# brew-backup - Dump Homebrew Brewfile for this machine (hostname-specific)
# brew-install - Install Homebrew packages from this machine's Brewfile
# sync - Sync from git repository
# full-recover - Full recovery on new machine (init + install + sync)
# check - Check current setup status
@@ -25,6 +27,9 @@ NC='\033[0m' # No Color
DOTFILES_DIR="${DOTFILES_DIR:-$HOME/.dotfiles}"
WORKING_DIR=$(cd "$(dirname "$0")" && pwd)
HOME_DIR="$HOME"
BREWFILES_DIR="$WORKING_DIR/brewfiles"
# Override hostname when restoring on a machine whose Brewfile was created elsewhere
BREWFILE_HOST="${BREWFILE_HOST:-}"
# Files to link
FILES=(
@@ -106,6 +111,80 @@ function ask() {
[[ "$response" =~ ^[Yy] ]]
}
# Short hostname for brewfiles/<host>/ (override with BREWFILE_HOST).
# Use /bin/hostname — bare "hostname" in a zsh function is parsed as host + $name.
function dotfiles_host() {
local id
if [[ -n "$BREWFILE_HOST" ]]; then
id="$BREWFILE_HOST"
else
id=$(/bin/hostname -s 2>/dev/null || /bin/hostname)
fi
echo "${id//\//-}"
}
function brewfile_for_machine() {
local host="${1:-$(dotfiles_host)}"
echo "$BREWFILES_DIR/$host/Brewfile"
}
# Prefer hostname-specific Brewfile; fall back to legacy repo-root Brewfile
function resolve_brewfile() {
local path
path=$(brewfile_for_machine)
if [ -f "$path" ]; then
echo "$path"
return 0
fi
if [ -f "$WORKING_DIR/Brewfile" ]; then
echo "$WORKING_DIR/Brewfile"
return 0
fi
return 1
}
function cmd_brew_backup() {
print_header "Backing Up Brewfile ($(dotfiles_host))"
if ! command_exists brew; then
print_error "Homebrew not found"
return 1
fi
local brewfile
brewfile=$(brewfile_for_machine)
mkdir -p "$(dirname "$brewfile")"
print_warning "Dumping to $brewfile..."
brew bundle dump -f --file="$brewfile"
print_success "Brewfile saved: $brewfile"
echo ""
echo "Commit on this machine:"
echo " git add brewfiles/$(dotfiles_host)/Brewfile"
echo " git commit -m 'backup: update brewfile for $(dotfiles_host)'"
}
function cmd_brew_install() {
print_header "Installing Homebrew Packages ($(dotfiles_host))"
if ! command_exists brew; then
print_error "Homebrew not found — run ./setup.sh init first"
return 1
fi
local brewfile
if ! brewfile=$(resolve_brewfile); then
print_error "No Brewfile for host $(dotfiles_host) under $BREWFILES_DIR"
echo " Run: ./setup.sh brew-backup"
echo " Or set BREWFILE_HOST=<other-host> if this machine was renamed"
return 1
fi
print_warning "Installing from $brewfile..."
brew bundle install --file="$brewfile"
print_success "Homebrew packages installed"
}
# =============================================================================
# Commands
# =============================================================================
@@ -120,6 +199,8 @@ Commands:
init Initialize a brand new macOS system (Homebrew, Xcode, etc.)
install Install dotfiles symlinks to home directory
backup Backup current configuration to dotfiles repo
brew-backup Dump Brewfile for this machine (brewfiles/<hostname>/)
brew-install Install packages from this machine's Brewfile
sync Sync from git repository
full-recover Full recovery on new machine (init + install + sync)
check Check current setup status
@@ -129,6 +210,8 @@ Examples:
./setup.sh init # Initialize new system
./setup.sh install # Link dotfiles
./setup.sh full-recover # Full setup on new machine
./setup.sh brew-backup # Update Brewfile for this Mac only
./setup.sh brew-install # Install packages from hostname Brewfile
./setup.sh check # Check what's installed
For more information, see README.md
@@ -294,7 +377,7 @@ function cmd_install() {
"$(brew --prefix)/opt/fzf/install" --key-bindings --completion --no-update-rc 2>/dev/null || true
print_success "fzf shell integration installed"
else
print_warning "fzf binary not found yet; run: brew bundle install"
print_warning "fzf binary not found yet; run: ./setup.sh brew-install"
fi
fi
@@ -303,7 +386,7 @@ function cmd_install() {
echo "Next steps:"
echo " 1. Configure git: git config --file ~/.gitconfig user.name 'Your Name'"
echo " 2. Restart terminal or run: source ~/.zshrc"
echo " 3. Run: brew bundle install (to install packages)"
echo " 3. Run: ./setup.sh brew-install (to install packages)"
}
function cmd_backup() {
@@ -313,12 +396,15 @@ function cmd_backup() {
local backup_warnings=0
# ==========================================================================
# 1. Brewfile 备份
# 1. Brewfile 备份(按 hostname 分目录)
# ==========================================================================
print_warning "Dumping Brewfile..."
local brewfile
brewfile=$(brewfile_for_machine)
print_warning "Dumping Brewfile for $(dotfiles_host)..."
if command_exists brew; then
brew bundle dump -f --file="$WORKING_DIR/Brewfile"
print_success "Brewfile saved"
mkdir -p "$(dirname "$brewfile")"
brew bundle dump -f --file="$brewfile"
print_success "Brewfile saved: $brewfile"
backup_count=$((backup_count + 1))
else
print_error "Homebrew not found"
@@ -464,7 +550,7 @@ EOF
| Item | Status |
|------|--------|
| Brewfile | $([ -f "$WORKING_DIR/Brewfile" ] && echo "✅ Saved" || echo "❌ Failed") |
| Brewfile ($(dotfiles_host)) | $([ -f "$brewfile" ] && echo "✅ Saved" || echo "❌ Failed") |
| Git config summary | $([ -f "$WORKING_DIR/.git_config_summary.txt" ] && echo "✅ Saved" || echo "❌ Failed") |
| SSH public keys | $([ -d "$ssh_backup_dir" ] && echo "✅ Saved to $ssh_backup_dir" || echo "⚠️ Not found") |
| 1Password config | $([ -f "$WORKING_DIR/.1password_config.txt" ] && echo "✅ Documented" || echo "⚠️ Not configured") |
@@ -473,7 +559,7 @@ EOF
## Files Created
- Brewfile (updated)
- brewfiles/$(dotfiles_host)/Brewfile (updated)
- .git_config_summary.txt ⚠️ DO NOT COMMIT
- .1password_config.txt
- .kube_contexts.txt
@@ -483,7 +569,7 @@ $( [ -d "$ssh_backup_dir" ] && echo "- $ssh_backup_dir/ ⚠️ DO NOT COMMIT" )
## Next Steps
1. Review changes: git status
2. Commit safe files: git add Brewfile .1password_config.txt .kube_contexts.txt .vscode_extensions.txt
2. Commit safe files: git add brewfiles/$(dotfiles_host)/Brewfile .1password_config.txt .kube_contexts.txt .vscode_extensions.txt
3. git commit -m 'backup: update dotfiles'
4. ⚠️ DO NOT commit: .git_config_summary.txt, ssh_backup_*/
EOF
@@ -498,12 +584,12 @@ EOF
echo " Warnings: $backup_warnings"
echo ""
echo "Files to review:"
echo " ✅ Safe to commit: Brewfile, .1password_config.txt, .kube_contexts.txt, .vscode_extensions.txt"
echo " ✅ Safe to commit: brewfiles/$(dotfiles_host)/Brewfile, .1password_config.txt, .kube_contexts.txt, .vscode_extensions.txt"
echo " ⚠️ DO NOT COMMIT: .git_config_summary.txt, ssh_backup_*/"
echo ""
echo "Next steps:"
echo " 1. Review: git status"
echo " 2. Commit safe files: git add Brewfile .1password_config.txt .kube_contexts.txt .vscode_extensions.txt"
echo " 2. Commit safe files: git add brewfiles/$(dotfiles_host)/Brewfile .1password_config.txt .kube_contexts.txt .vscode_extensions.txt"
echo " 3. git commit -m 'backup: update dotfiles'"
echo "=========================================="
}
@@ -559,6 +645,17 @@ function cmd_full_recover() {
# Run sync
cmd_sync
# Install Homebrew packages for this hostname
if command_exists brew; then
if resolve_brewfile >/dev/null; then
print_warning "Installing Homebrew packages for $(dotfiles_host)..."
cmd_brew_install || print_warning "brew-install had errors — review output above"
else
print_warning "No Brewfile for $(dotfiles_host) under brewfiles/ — skip package install"
echo " After first brew-backup on another Mac, git pull then run: ./setup.sh brew-install"
fi
fi
print_header "Full Recovery Complete!"
echo ""
echo "IMPORTANT: Configure your personal settings:"
@@ -573,8 +670,8 @@ function cmd_full_recover() {
echo " # Generate new SSH keys"
echo " ssh-keygen -t ed25519 -C 'your@email.com'"
echo ""
echo " # Install Homebrew packages"
echo " brew bundle install"
echo " # Install Homebrew packages (if not already done above)"
echo " ./setup.sh brew-install"
echo ""
}
@@ -592,6 +689,14 @@ function cmd_check() {
missing=$((missing + 1))
fi
echo -n "Brewfile ($(dotfiles_host)): "
local brewfile_check
if brewfile_check=$(resolve_brewfile 2>/dev/null); then
print_success "$brewfile_check"
else
print_warning "not found — run ./setup.sh brew-backup"
fi
# Check zsh
echo -n "Zsh: "
if command_exists zsh; then
@@ -721,6 +826,12 @@ case "$COMMAND" in
backup)
cmd_backup
;;
brew-backup)
cmd_brew_backup
;;
brew-install)
cmd_brew_install
;;
sync)
cmd_sync
;;