refactor(shell): thin stubs with managed ~/.config/zsh tree

Split always-on PATH/env, login hooks, and interactive UX into a
managed tree under ~/.config/zsh, with never-overwrite local/ hooks.
Agents and interactive shells share one PATH owner; deploy.sh applies
the layout safely across machines.
This commit is contained in:
Jeffrey
2026-08-06 14:36:08 +08:00
parent ed5365859c
commit f8dcc29a2f
14 changed files with 546 additions and 391 deletions
+53 -20
View File
@@ -11,34 +11,68 @@ curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/install.sh | bas
```
Options: `--cp-hist` / `-c` imports bash history; `--non-interactive` / `-n`
skips the default-shell change. The installer backs up an existing `~/.zshrc`
and `~/.zshenv` before replacing them.
skips the default-shell change. The installer backs up existing shell stubs
before replacing them.
## What gets installed where
From a git checkout (recommended for multi-machine sync):
| Path | Role |
| --- | --- |
| `~/.zshrc` | Canonical shell entry (from repo `.zshrc`). Stay close to upstream; reinstall overwrites it. |
| `~/.zshenv` | Early env for every zsh: Homebrew `shellenv` on macOS, plus `~/.local/bin` on PATH. |
| `~/.config/zshenv.local` | Optional machine-local early env (cargo, private PATH). Sourced by `~/.zshenv`; not overwritten by reinstall. |
| `~/.config/zshrc/*.zsh` | Your overlays, sourced by `~/.zshrc` **before** oh-my-zsh loads. |
```bash
./deploy.sh --migrate-zprofile
```
Do not put personal tweaks into `~/.zshrc` if you want painless upgrades: interactive overlays go under `~/.config/zshrc/`; early PATH/env that non-interactive agents need go in `~/.config/zshenv.local`.
## Architecture
```text
every zsh login only interactive only
────────── ────────── ────────────────
~/.zshenv (stub) ~/.zprofile (stub) ~/.zshrc (stub)
→ config/zsh/env/* → config/zsh/login/* → config/zsh/interactive/*
→ local/env.local.zsh → local/login.local.zsh → ~/.config/zshrc/* (before omz)
→ local/interactive.local.zsh
```
PATH for user tools is built **once** in `~/.config/zsh/env/00-path.zsh`
(always-on), so non-interactive agent shells (`zsh -c`, Codex, Claude) resolve
`~/.local/bin` the same way interactive terminals do.
| Path | Role | Reinstall |
| --- | --- | --- |
| `~/.zshenv` `~/.zprofile` `~/.zshrc` | Thin stubs | Overwritten |
| `~/.config/zsh/env/` | Managed always-on env (PATH, Homebrew) | Overwritten |
| `~/.config/zsh/interactive/` | Managed interactive UX (omz, aliases) | Overwritten |
| `~/.config/zsh/login/` | Managed login hooks (usually empty) | Overwritten |
| `~/.config/zsh/local/*` | Machine-local env/login/interactive | **Never overwritten** |
| `~/.config/zshrc/*.zsh` | Personal/tool overlays (before omz) | Left alone |
| `~/.local/bin/` | User tools + intentional shims (e.g. `grok`) | Left alone |
Do **not** put `~/.grok/bin` on PATH wholesale (generic names like `agent` shadow
other tools). Link wanted entrypoints into `~/.local/bin` instead.
## Personal configuration
Every `*.zsh` file in `~/.config/zshrc/` is sourced near the end of `~/.zshrc`,
just before oh-my-zsh loads, so it can add plugins and override defaults.
### Always-on (agents see this)
```bash
# ~/.config/zsh/local/env.local.zsh
. "$HOME/.cargo/env"
```
### Login only (vendor hooks)
```bash
# ~/.config/zsh/local/login.local.zsh
# OrbStack, MacPorts, product installers — not primary PATH policy
```
### Interactive overlays (before oh-my-zsh)
```bash
# ~/.config/zshrc/local.zsh
plugins+=(docker) # add plugins
plugins=(${plugins:#zsh-autosuggestions}) # or remove one
alias gs='git status'
plugins+=(docker)
plugins=(${plugins:#zsh-autosuggestions})
```
Ready-made **tool** configs from this repo's `zshrc/` directory can be pulled in
by name (not personal samples):
Ready-made tool configs from this repo's `zshrc/` directory:
```bash
curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/patch.sh | bash -s -- fnm pyenv
@@ -46,6 +80,5 @@ curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/patch.sh | bash
Current fragments: `fnm`, `nvm`, `pyenv`, `p10k`, `merlin_devbox`, `merlin_worker`.
Because these files load before oh-my-zsh, plugin and theme changes take effect;
aliases that must beat oh-my-zsh's own should be defined after oh-my-zsh loads
(see the note in `~/.zshrc`).
Aliases that must beat oh-my-zsh belong after omz loads (see managed
`interactive/20-post-omz.zsh`) or in `~/.config/zsh/local/interactive.local.zsh`.