终端初始化命令

返回导航 · 一次性脚本,复制即可

目标:新电脑快速装好开发环境(git、zsh、node/pnpm、python、java、常用工具),并安装 codex/claude/gemini CLI 与 WezTerm(含统一配色/快捷键)。建议先读每段脚本的注释再执行。

Windows (WSL)

PowerShell / Windows Terminal
1) 先在 Windows 装 WSL + Ubuntu。
2) 建议安装 WezTerm,并写入统一配置(颜色 + 快捷键 + WSL 默认启动)。
3) 打开 Ubuntu 后,再执行下面的“Ubuntu/Debian”脚本。
安装 WSL + Ubuntu
管理员 PowerShell(Windows 11 通常可直接用)
wsl --install -d Ubuntu
wsl --update
wsl --set-default-version 2

# 安装完成后,打开“Ubuntu”应用并创建 Linux 用户
# 然后在 Ubuntu 里执行本页的“Ubuntu/Debian”脚本
安装 + 配置 WezTerm(Windows)
PowerShell:写入你当前这套配色/快捷键/WSL 启动配置
# 1) install WezTerm
winget install --id Wez.WezTerm -e --source winget

# 2) set your WSL distro name (check with: wsl -l -q)
$WslDistro = "Ubuntu-24.04"

# 3) write WezTerm config
$cfgDir = Join-Path $HOME ".config\wezterm"
New-Item -ItemType Directory -Force -Path $cfgDir | Out-Null

@"
local wezterm = require 'wezterm'
local act = wezterm.action
local config = wezterm.config_builder()

config.default_domain = 'WSL:$WslDistro'

config.front_end = 'WebGpu'
config.webgpu_power_preference = 'HighPerformance'

config.color_scheme = 'Tokyo Night'
config.font = wezterm.font('JetBrains Mono', { weight = 'Regular' })
config.font_size = 13.0
config.line_height = 1.2

config.initial_cols = 160
config.initial_rows = 40
config.window_padding = { left = 12, right = 12, top = 10, bottom = 10 }
config.window_background_opacity = 1.0
config.colors = { background = '#000000' }
config.window_decorations = 'TITLE | RESIZE'
config.adjust_window_size_when_changing_font_size = false

config.use_fancy_tab_bar = false
config.tab_bar_at_bottom = true
config.hide_tab_bar_if_only_one_tab = true
config.tab_max_width = 30
config.scrollback_lines = 10000

config.automatically_reload_config = true
config.disable_default_key_bindings = true

config.mouse_bindings = {
  {
    event = { Down = { streak = 1, button = 'Right' } },
    mods = 'NONE',
    action = act.PasteFrom 'Clipboard',
  },
}

config.keys = {
  { key = 'phys:C', mods = 'CTRL', action = act.CopyTo 'Clipboard' },
  { key = 'phys:V', mods = 'CTRL', action = act.PasteFrom 'Clipboard' },
  { key = 'phys:C', mods = 'CTRL|SHIFT', action = act.SendKey { key = 'c', mods = 'CTRL' } },
  { key = 't', mods = 'CTRL|SHIFT', action = act.SpawnTab 'CurrentPaneDomain' },
  { key = 'w', mods = 'CTRL|SHIFT', action = act.CloseCurrentTab { confirm = false } },
  { key = '[', mods = 'CTRL|SHIFT', action = act.ActivateTabRelative(-1) },
  { key = ']', mods = 'CTRL|SHIFT', action = act.ActivateTabRelative(1) },
  { key = 'r', mods = 'CTRL|SHIFT', action = act.PromptInputLine {
      description = 'Rename tab:',
      action = wezterm.action_callback(function(window, _, line)
        if line then window:active_tab():set_title(line) end
      end),
  }},
  { key = 'd', mods = 'CTRL|SHIFT', action = act.SplitHorizontal { domain = 'CurrentPaneDomain' } },
  { key = 'e', mods = 'CTRL|SHIFT', action = act.SplitVertical { domain = 'CurrentPaneDomain' } },
  { key = 'h', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Left' },
  { key = 'l', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Right' },
  { key = 'k', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Up' },
  { key = 'j', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Down' },
  { key = 'f', mods = 'CTRL|SHIFT', action = act.Search 'CurrentSelectionOrEmptyString' },
  { key = 'x', mods = 'CTRL|SHIFT', action = act.ActivateCopyMode },
  { key = '=', mods = 'CTRL', action = act.IncreaseFontSize },
  { key = '-', mods = 'CTRL', action = act.DecreaseFontSize },
  { key = '0', mods = 'CTRL', action = act.ResetFontSize },
  { key = 'n', mods = 'CTRL|SHIFT', action = act.SpawnWindow },
  { key = 'p', mods = 'CTRL|SHIFT', action = act.ActivateCommandPalette },
  { key = 'Enter', mods = 'ALT', action = act.ToggleFullScreen },
}

return config
"@ | Set-Content -Path (Join-Path $cfgDir "wezterm.lua") -Encoding UTF8

@"
local wezterm = require 'wezterm'
return dofile(wezterm.home_dir .. '/.config/wezterm/wezterm.lua')
"@ | Set-Content -Path (Join-Path $HOME ".wezterm.lua") -Encoding UTF8

# 4) restart WezTerm
taskkill /F /IM wezterm-gui.exe 2>$null
Start-Process wezterm-gui.exe

字体建议(在 Windows Terminal 设置里改):JetBrainsMono Nerd Font 或 MesloLGS Nerd Font。

Ubuntu/Debian

Ubuntu / WSL Ubuntu / Debian
这个脚本会安装:git、zsh、常用 CLI 工具、Node.js(nvm)、pnpm(corepack)、Python(系统 python3 + pipx)、Java(OpenJDK,sdkman 可选)。
注意:npm 全局包不要用 sudo。
一键安装(Linux)
复制到终端执行
set -euo pipefail

# 0) base packages
sudo apt-get update
sudo apt-get install -y \
  git curl wget ca-certificates gnupg \
  build-essential unzip zip \
  jq ripgrep fzf bat fd-find htop tree \
  eza zoxide neovim \
  zsh \
  python3 python3-pip python3-venv

# GitHub CLI
if ! command -v gh >/dev/null 2>&1; then
  curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
  echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
  sudo apt-get update
  sudo apt-get install -y gh
fi

# pipx: apt first, fallback to user install
if ! command -v pipx >/dev/null 2>&1; then
  sudo apt-get install -y pipx || python3 -m pip install --user --break-system-packages pipx
fi

# Java: prefer OpenJDK 21, fallback to default-jdk
if apt-cache show openjdk-21-jdk-headless >/dev/null 2>&1; then
  sudo apt-get install -y openjdk-21-jdk-headless
else
  sudo apt-get install -y default-jdk-headless || true
fi

# 1) nvm (Node.js) - latest LTS
if [ ! -d "$HOME/.nvm" ]; then
  curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
fi
export NVM_DIR="$HOME/.nvm"
# shellcheck disable=SC1091
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

nvm install --lts
nvm use --lts

# 2) pnpm via corepack
corepack enable
corepack prepare pnpm@latest --activate

# 3) sdkman (Java manager) - optional but useful
if [ ! -d "$HOME/.sdkman" ]; then
  curl -s "https://get.sdkman.io" | bash
fi
# shellcheck disable=SC1091
[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ] && . "$HOME/.sdkman/bin/sdkman-init.sh"

# Rust toolchain (rustup)
if ! command -v rustc >/dev/null 2>&1; then
  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
  source "$HOME/.cargo/env"
fi

# 4) pipx path
python3 -m pipx ensurepath || true
export PATH="$HOME/.local/bin:$PATH"

# Debian/Ubuntu package names expose bat/fd as batcat/fdfind.
mkdir -p "$HOME/.local/bin"
if command -v batcat >/dev/null 2>&1 && ! command -v bat >/dev/null 2>&1; then
  ln -sf "$(command -v batcat)" "$HOME/.local/bin/bat"
fi
if command -v fdfind >/dev/null 2>&1 && ! command -v fd >/dev/null 2>&1; then
  ln -sf "$(command -v fdfind)" "$HOME/.local/bin/fd"
fi

# uv (fast Python package manager)
if ! command -v uv >/dev/null 2>&1; then
  curl -LsSf https://astral.sh/uv/install.sh | sh
fi

# 5) CLIs (no sudo, under nvm-managed Node)
# OpenAI Codex CLI
npm i -g @openai/codex

# Anthropic Claude Code (standalone installer)
if ! command -v claude >/dev/null 2>&1; then
  curl -fsSL https://claude.ai/install.sh | sh
fi

# Google Gemini CLI
npm i -g @google/gemini-cli
npm i -g wrangler

# Python SDKs
python3 -m pip install --user anthropic openai google-genai

# Google Chrome
if ! command -v google-chrome >/dev/null 2>&1; then
  curl -fsSL https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -o /tmp/chrome.deb
  sudo dpkg -i /tmp/chrome.deb || sudo apt-get install -f -y
  rm -f /tmp/chrome.deb
fi

# Docker
if ! command -v docker >/dev/null 2>&1; then
  curl -fsSL https://get.docker.com | sh
  sudo usermod -aG docker "$USER"
fi

# Set zsh as default shell
if [ "$SHELL" != "$(which zsh)" ]; then
  chsh -s "$(which zsh)"
fi

# 6) quick check
node -v
npm -v
pnpm -v
gh --version || true
docker --version || true
bat --version || true
uv --version || true
rustc --version || true
codex --version || true
claude --version || true
gemini --version || true

echo "Done. Restart your terminal (or re-source your shell rc)"
zsh 美化(可选)
oh-my-zsh + starship
set -euo pipefail

ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
ZSHRC="$HOME/.zshrc"
START_MARK="# --- terminal-html zsh setup start ---"
END_MARK="# --- terminal-html zsh setup end ---"

# Install oh-my-zsh (non-interactive)
if [ ! -d "$HOME/.oh-my-zsh" ]; then
  RUNZSH=no CHSH=no KEEP_ZSHRC=yes \
    sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
fi

# Plugin directories
mkdir -p "$ZSH_CUSTOM/plugins"

if [ ! -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ]; then
  git clone https://github.com/zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions"
fi

if [ ! -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ]; then
  git clone https://github.com/zsh-users/zsh-syntax-highlighting.git "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting"
fi

if [ ! -d "$ZSH_CUSTOM/plugins/zsh-completions" ]; then
  git clone https://github.com/zsh-users/zsh-completions "$ZSH_CUSTOM/plugins/zsh-completions"
fi

# Prompt + modern shell tools
curl -sS https://starship.rs/install.sh | sh

if ! command -v zoxide >/dev/null 2>&1; then
  if apt-cache show zoxide >/dev/null 2>&1; then
    sudo apt-get install -y zoxide
  else
    command -v cargo >/dev/null 2>&1 || sudo apt-get install -y cargo
    cargo install zoxide --locked
  fi
fi

if ! command -v eza >/dev/null 2>&1; then
  if apt-cache show eza >/dev/null 2>&1; then
    sudo apt-get install -y eza
  else
    command -v cargo >/dev/null 2>&1 || sudo apt-get install -y cargo
    cargo install eza
  fi
fi

touch "$ZSHRC"
if grep -Fq "$START_MARK" "$ZSHRC"; then
  sed -i "/$START_MARK/,/$END_MARK/d" "$ZSHRC"
fi

cat >> "$ZSHRC" <<'EOF'

# --- terminal-html zsh setup start ---
export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME=""  # disabled: starship overrides the prompt

# Performance: set before plugins load
ZSH_AUTOSUGGEST_USE_ASYNC=1
ZSH_AUTOSUGGEST_MANUAL_REBIND=1
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20
ZSH_HIGHLIGHT_MAXLENGTH=200

plugins=(
  git
  sudo
  history
  zsh-autosuggestions
  zsh-syntax-highlighting
  zsh-completions
)

source $ZSH/oh-my-zsh.sh

# Avoid XON/XOFF flow control freezing input when Ctrl-S is pressed.
stty -ixon 2>/dev/null

# PATH
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"

# Aliases
alias ll="eza -la --icons --git 2>/dev/null || ls -la"
alias lt="eza --tree --level=2 --icons 2>/dev/null || tree -L 2"
alias gs="git status"
alias gp="git pull"
alias gd="git diff"
alias gl="git log --oneline --graph --decorate -20"
alias vim="nvim"
alias g="git"
# AI CLI shortcuts
alias cl="claude --dangerously-skip-permissions"
alias co="codex --dangerously-bypass-approvals-and-sandbox"
alias gm="gemini"

# Starship
eval "$(starship init zsh)"

# Zoxide
eval "$(zoxide init zsh)"

# WezTerm shell integration
[ -f "$HOME/.config/wezterm/wezterm-shell.sh" ] && source "$HOME/.config/wezterm/wezterm-shell.sh"
# --- terminal-html zsh setup end ---
EOF

echo "Optional: set your terminal font to a Nerd Font (JetBrainsMono Nerd Font / MesloLGS Nerd Font)."
在 WSL 里写入 WezTerm 配置(可选)
从 Ubuntu 直接写到 Windows 的 WezTerm 配置目录
set -euo pipefail

if ! grep -qiE "(microsoft|wsl)" /proc/version; then
  echo "This block is for WSL only."
  exit 1
fi

WIN_USER="${WIN_USER:-$(cmd.exe /c "echo %USERNAME%" | tr -d '\r')}"
WSL_DISTRO="${WSL_DISTRO_NAME:-Ubuntu-24.04}"
WIN_HOME="/mnt/c/Users/$WIN_USER"
CFG_DIR="$WIN_HOME/.config/wezterm"
mkdir -p "$CFG_DIR"

cat > "$CFG_DIR/wezterm.lua" <<LUA
local wezterm = require 'wezterm'
local act = wezterm.action
local config = wezterm.config_builder()

config.default_domain = 'WSL:$WSL_DISTRO'

config.front_end = 'WebGpu'
config.webgpu_power_preference = 'HighPerformance'
config.color_scheme = 'Tokyo Night'
config.font = wezterm.font('JetBrains Mono', { weight = 'Regular' })
config.font_size = 13.0
config.line_height = 1.2

config.initial_cols = 160
config.initial_rows = 40
config.window_padding = { left = 12, right = 12, top = 10, bottom = 10 }
config.window_background_opacity = 1.0
config.colors = { background = '#000000' }
config.window_decorations = 'TITLE | RESIZE'
config.adjust_window_size_when_changing_font_size = false

config.use_fancy_tab_bar = false
config.tab_bar_at_bottom = true
config.hide_tab_bar_if_only_one_tab = true
config.tab_max_width = 30
config.scrollback_lines = 10000

config.automatically_reload_config = true
config.disable_default_key_bindings = true

config.mouse_bindings = {
  {
    event = { Down = { streak = 1, button = 'Right' } },
    mods = 'NONE',
    action = act.PasteFrom 'Clipboard',
  },
}

config.keys = {
  { key = 'phys:C', mods = 'CTRL', action = act.CopyTo 'Clipboard' },
  { key = 'phys:V', mods = 'CTRL', action = act.PasteFrom 'Clipboard' },
  { key = 'phys:C', mods = 'CTRL|SHIFT', action = act.SendKey { key = 'c', mods = 'CTRL' } },
  { key = 't', mods = 'CTRL|SHIFT', action = act.SpawnTab 'CurrentPaneDomain' },
  { key = 'w', mods = 'CTRL|SHIFT', action = act.CloseCurrentTab { confirm = false } },
  { key = '[', mods = 'CTRL|SHIFT', action = act.ActivateTabRelative(-1) },
  { key = ']', mods = 'CTRL|SHIFT', action = act.ActivateTabRelative(1) },
  { key = 'r', mods = 'CTRL|SHIFT', action = act.PromptInputLine {
      description = 'Rename tab:',
      action = wezterm.action_callback(function(window, _, line)
        if line then window:active_tab():set_title(line) end
      end),
  }},
  { key = 'd', mods = 'CTRL|SHIFT', action = act.SplitHorizontal { domain = 'CurrentPaneDomain' } },
  { key = 'e', mods = 'CTRL|SHIFT', action = act.SplitVertical { domain = 'CurrentPaneDomain' } },
  { key = 'h', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Left' },
  { key = 'l', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Right' },
  { key = 'k', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Up' },
  { key = 'j', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Down' },
  { key = 'f', mods = 'CTRL|SHIFT', action = act.Search 'CurrentSelectionOrEmptyString' },
  { key = 'x', mods = 'CTRL|SHIFT', action = act.ActivateCopyMode },
  { key = '=', mods = 'CTRL', action = act.IncreaseFontSize },
  { key = '-', mods = 'CTRL', action = act.DecreaseFontSize },
  { key = '0', mods = 'CTRL', action = act.ResetFontSize },
  { key = 'n', mods = 'CTRL|SHIFT', action = act.SpawnWindow },
  { key = 'p', mods = 'CTRL|SHIFT', action = act.ActivateCommandPalette },
  { key = 'Enter', mods = 'ALT', action = act.ToggleFullScreen },
}

return config
LUA

cat > "$WIN_HOME/.wezterm.lua" <<'LUA'
local wezterm = require 'wezterm'
return dofile(wezterm.home_dir .. '/.config/wezterm/wezterm.lua')
LUA

echo "WezTerm config written to: $CFG_DIR/wezterm.lua"
echo "Restart WezTerm on Windows to apply changes."
登录/初始化(执行一次)
各 CLI 的首次登录
# GitHub CLI
gh auth login

# OpenAI Codex
codex login

# Claude Code (会提示你登录/配置)
claude

# Cloudflare Wrangler
wrangler login

# Gemini CLI
# 运行后根据提示配置(通常需要 Google 登录/或 API key)
gemini
Git + SSH 初始化(执行一次)
git config + SSH key + GitHub
# Git global config
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
git config --global init.defaultBranch main
git config --global pull.rebase false

# Generate SSH key (if none exists)
if [ ! -f "$HOME/.ssh/id_ed25519" ]; then
  ssh-keygen -t ed25519 -C "your@email.com" -f "$HOME/.ssh/id_ed25519" -N ""
fi

# Print public key — add this to GitHub > Settings > SSH keys
cat "$HOME/.ssh/id_ed25519.pub"

# Test GitHub SSH connection
ssh -T git@github.com 2>&1 || true
WSL 配置(可选)
wsl.conf + 选择性 Windows PATH
# Only run inside WSL
if ! grep -qiE "(microsoft|wsl)" /proc/version 2>/dev/null; then
  echo "Not WSL, skipping."
  exit 0
fi

# /etc/wsl.conf — disable auto Windows PATH, enable systemd
sudo tee /etc/wsl.conf > /dev/null <<'CONF'
[interop]
appendWindowsPath = false

[boot]
systemd = true

[automount]
enabled = true
options = "metadata,umask=22,fmask=11"
CONF

# Resolve the current Windows username once, then write concrete paths into .zshrc.
WIN_USER="$(cmd.exe /c "echo %USERNAME%" | tr -d '\r')"
WIN_VSCODE_PATH="/mnt/c/Users/$WIN_USER/AppData/Local/Programs/Microsoft VS Code/bin"

# Add selective Windows paths to .zshrc (if not already present)
if ! grep -q "Selective Windows paths" "$HOME/.zshrc" 2>/dev/null; then
  {
    printf '\n# Selective Windows paths (appendWindowsPath=false in wsl.conf)\n'
    printf 'export PATH="$PATH:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS"\n'
    printf 'export PATH="$PATH:%s"\n' "$WIN_VSCODE_PATH"
    printf 'export PATH="$PATH:/mnt/c/Program Files/Docker/Docker/resources/bin"\n'
  } >> "$HOME/.zshrc"
fi

echo "WSL configured. Run 'wsl --shutdown' in PowerShell, then restart."

macOS

Homebrew
macOS 建议用 Homebrew 装基础工具;Node 用 nvm;然后装 codex/claude/gemini CLI。下面也提供 WezTerm 的统一配置脚本。
安装 Homebrew + 工具
复制到 Terminal 执行
set -euo pipefail

# Xcode CLI tools
xcode-select --install || true

# Homebrew
if ! command -v brew >/dev/null 2>&1; then
  /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi

# ensure brew is in PATH for this shell session
if [ -x /opt/homebrew/bin/brew ]; then
  eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -x /usr/local/bin/brew ]; then
  eval "$(/usr/local/bin/brew shellenv)"
fi

brew update
brew install git jq ripgrep fzf zsh starship python pipx openjdk@21 neovim eza zoxide uv bat fd gh htop tree

# Desktop apps
brew install --cask google-chrome alt-tab docker

python3 -m pipx ensurepath || true
export PATH="$HOME/.local/bin:$PATH"
OPENJDK_PREFIX="$(brew --prefix openjdk@21 2>/dev/null || true)"
[ -n "$OPENJDK_PREFIX" ] && export PATH="$OPENJDK_PREFIX/bin:$PATH"

# Rust toolchain
if ! command -v rustc >/dev/null 2>&1; then
  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
  source "$HOME/.cargo/env"
fi

# Node via nvm
if [ ! -d "$HOME/.nvm" ]; then
  curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
fi
export NVM_DIR="$HOME/.nvm"
# shellcheck disable=SC1091
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

nvm install --lts
nvm use --lts

corepack enable
corepack prepare pnpm@latest --activate

# CLIs (no sudo)
npm i -g @openai/codex

# Anthropic Claude Code (standalone installer)
if ! command -v claude >/dev/null 2>&1; then
  curl -fsSL https://claude.ai/install.sh | sh
fi

npm i -g @google/gemini-cli
npm i -g wrangler

python3 -m pip install --user anthropic openai google-genai

# Set zsh as default shell (macOS default is already zsh, but just in case)
if [ "$SHELL" != "$(which zsh)" ]; then
  chsh -s "$(which zsh)"
fi

node -v
npm -v
pnpm -v
python3 --version
java -version
gh --version || true
docker --version || true
uv --version || true
rustc --version || true
codex --version || true
claude --version || true
gemini --version || true
安装 + 配置 WezTerm(macOS)
Homebrew 安装并写入统一配色/快捷键
set -euo pipefail

if [ -x /opt/homebrew/bin/brew ]; then
  eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -x /usr/local/bin/brew ]; then
  eval "$(/usr/local/bin/brew shellenv)"
fi

brew install --cask wezterm

cat > "$HOME/.wezterm.lua" <<'LUA'
local wezterm = require 'wezterm'
local act = wezterm.action
local config = wezterm.config_builder()

config.front_end = 'WebGpu'
config.webgpu_power_preference = 'HighPerformance'

config.color_scheme = 'Tokyo Night'
config.font = wezterm.font('JetBrains Mono', { weight = 'Regular' })
config.font_size = 13.0
config.line_height = 1.2

config.initial_cols = 160
config.initial_rows = 40
config.window_padding = { left = 12, right = 12, top = 10, bottom = 10 }
config.window_background_opacity = 1.0
config.colors = { background = '#000000' }
config.window_decorations = 'TITLE | RESIZE'
config.adjust_window_size_when_changing_font_size = false

config.use_fancy_tab_bar = false
config.tab_bar_at_bottom = true
config.hide_tab_bar_if_only_one_tab = true
config.tab_max_width = 30
config.scrollback_lines = 10000

config.automatically_reload_config = true
config.disable_default_key_bindings = true

config.mouse_bindings = {
  {
    event = { Down = { streak = 1, button = 'Right' } },
    mods = 'NONE',
    action = act.PasteFrom 'Clipboard',
  },
}

config.keys = {
  { key = 'phys:C', mods = 'CTRL', action = act.CopyTo 'Clipboard' },
  { key = 'phys:V', mods = 'CTRL', action = act.PasteFrom 'Clipboard' },
  { key = 'phys:C', mods = 'CTRL|SHIFT', action = act.SendKey { key = 'c', mods = 'CTRL' } },
  { key = 't', mods = 'CTRL|SHIFT', action = act.SpawnTab 'CurrentPaneDomain' },
  { key = 'w', mods = 'CTRL|SHIFT', action = act.CloseCurrentTab { confirm = false } },
  { key = '[', mods = 'CTRL|SHIFT', action = act.ActivateTabRelative(-1) },
  { key = ']', mods = 'CTRL|SHIFT', action = act.ActivateTabRelative(1) },
  { key = 'r', mods = 'CTRL|SHIFT', action = act.PromptInputLine {
      description = 'Rename tab:',
      action = wezterm.action_callback(function(window, _, line)
        if line then window:active_tab():set_title(line) end
      end),
  }},
  { key = 'd', mods = 'CTRL|SHIFT', action = act.SplitHorizontal { domain = 'CurrentPaneDomain' } },
  { key = 'e', mods = 'CTRL|SHIFT', action = act.SplitVertical { domain = 'CurrentPaneDomain' } },
  { key = 'h', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Left' },
  { key = 'l', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Right' },
  { key = 'k', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Up' },
  { key = 'j', mods = 'CTRL|SHIFT', action = act.ActivatePaneDirection 'Down' },
  { key = 'f', mods = 'CTRL|SHIFT', action = act.Search 'CurrentSelectionOrEmptyString' },
  { key = 'x', mods = 'CTRL|SHIFT', action = act.ActivateCopyMode },
  { key = '=', mods = 'CTRL', action = act.IncreaseFontSize },
  { key = '-', mods = 'CTRL', action = act.DecreaseFontSize },
  { key = '0', mods = 'CTRL', action = act.ResetFontSize },
  { key = 'n', mods = 'CTRL|SHIFT', action = act.SpawnWindow },
  { key = 'p', mods = 'CTRL|SHIFT', action = act.ActivateCommandPalette },
  { key = 'Enter', mods = 'ALT', action = act.ToggleFullScreen },
}

return config
LUA

echo "WezTerm configured at $HOME/.wezterm.lua"
echo "Restart WezTerm to apply."
zsh 美化(macOS,可选)
oh-my-zsh + starship
set -euo pipefail

ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
ZSHRC="$HOME/.zshrc"
START_MARK="# --- terminal-html zsh setup start ---"
END_MARK="# --- terminal-html zsh setup end ---"

# Install oh-my-zsh (non-interactive)
if [ ! -d "$HOME/.oh-my-zsh" ]; then
  RUNZSH=no CHSH=no KEEP_ZSHRC=yes \
    sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
fi

# Plugin directories
mkdir -p "$ZSH_CUSTOM/plugins"

if [ ! -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ]; then
  git clone https://github.com/zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions"
fi

if [ ! -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ]; then
  git clone https://github.com/zsh-users/zsh-syntax-highlighting.git "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting"
fi

if [ ! -d "$ZSH_CUSTOM/plugins/zsh-completions" ]; then
  git clone https://github.com/zsh-users/zsh-completions "$ZSH_CUSTOM/plugins/zsh-completions"
fi

# Prompt + modern shell tools
if ! command -v starship >/dev/null 2>&1; then
  curl -sS https://starship.rs/install.sh | sh
fi

if ! command -v zoxide >/dev/null 2>&1; then
  brew install zoxide
fi

if ! command -v eza >/dev/null 2>&1; then
  brew install eza
fi

touch "$ZSHRC"
if grep -Fq "$START_MARK" "$ZSHRC"; then
  sed -i '' "/$START_MARK/,/$END_MARK/d" "$ZSHRC"
fi

cat >> "$ZSHRC" <<'EOF'

# --- terminal-html zsh setup start ---
export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME=""  # disabled: starship overrides the prompt

# Performance: set before plugins load
ZSH_AUTOSUGGEST_USE_ASYNC=1
ZSH_AUTOSUGGEST_MANUAL_REBIND=1
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20
ZSH_HIGHLIGHT_MAXLENGTH=200

plugins=(
  git
  sudo
  history
  zsh-autosuggestions
  zsh-syntax-highlighting
  zsh-completions
)

source $ZSH/oh-my-zsh.sh

# Avoid XON/XOFF flow control freezing input when Ctrl-S is pressed.
stty -ixon 2>/dev/null

# PATH
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"

# Aliases
alias ll="eza -la --icons --git 2>/dev/null || ls -la"
alias lt="eza --tree --level=2 --icons 2>/dev/null || tree -L 2"
alias gs="git status"
alias gp="git pull"
alias gd="git diff"
alias gl="git log --oneline --graph --decorate -20"
alias vim="nvim"
alias g="git"
# AI CLI shortcuts
alias cl="claude --dangerously-skip-permissions"
alias co="codex --dangerously-bypass-approvals-and-sandbox"
alias gm="gemini"

# Starship
eval "$(starship init zsh)"

# Zoxide
eval "$(zoxide init zsh)"

# WezTerm shell integration
[ -f "$HOME/.config/wezterm/wezterm-shell.sh" ] && source "$HOME/.config/wezterm/wezterm-shell.sh"
# --- terminal-html zsh setup end ---
EOF

echo "Optional: set your terminal font to a Nerd Font (JetBrainsMono Nerd Font / MesloLGS Nerd Font)."
安装 Nerd Font(可选)
更好看的 prompt/图标
# JetBrains Mono Nerd Font
brew install font-jetbrains-mono-nerd-font

# 然后在 iTerm2 / Terminal 的 Profile 里切换字体
Git + SSH 初始化(执行一次)
git config + SSH key + GitHub
# Git global config
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
git config --global init.defaultBranch main
git config --global pull.rebase false

# Generate SSH key (if none exists)
if [ ! -f "$HOME/.ssh/id_ed25519" ]; then
  ssh-keygen -t ed25519 -C "your@email.com" -f "$HOME/.ssh/id_ed25519" -N ""
fi

# Print public key — add this to GitHub > Settings > SSH keys
cat "$HOME/.ssh/id_ed25519.pub"

# Test GitHub SSH connection
ssh -T git@github.com 2>&1 || true

提示:如果你用 zsh,记得把默认 shell 切到 zsh(macOS 通常默认就是 zsh)。

Notes

版本会变

这页把安装命令固化在静态站里,方便复制粘贴;但各 CLI/依赖版本会变化。如果某条命令报错,优先以对应官方文档为准。