diff --git a/.alias.zsh b/.alias.zsh
index e261380..425933c 100644
--- a/.alias.zsh
+++ b/.alias.zsh
@@ -1,212 +1,18 @@
# Only remap cd in interactive shells; non-interactive sessions (e.g. Cursor tasks)
-# rely on the builtin cd command.
+# rely on the builtin cd command. cd cannot be a bin script — it must stay a shell alias/function.
if [[ -o interactive ]] && command -v z >/dev/null 2>&1; then
alias cd="z"
fi
-alias ls="eza --all --color=always --long --icons=always --no-user --no-permissions"
-alias lst="eza --all --color=always --long --icons=always --no-user --no-permissions --tree --level=2"
-alias ll="ls"
-alias cat="bat -p"
+
alias c="clear"
alias x="exit"
-alias gst="git status"
-alias ga="git add"
-alias gc="git commit -m"
-function pull() {
- branch="$(git rev-parse --abbrev-ref HEAD)"
- if [ $# -eq 0 ]; then
- git pull origin $branch --rebase
- else
- git pull origin $1 --rebase
- fi
-}
-alias ggpu=pull
-function pullMerge() {
- branch="$(git rev-parse --abbrev-ref HEAD)"
- if [ $# -eq 0 ]; then
- git pull origin $branch
- else
- git pull origin $1
- fi
-}
-alias ggpum=pullMerge
-function gpi() {
- branch=$(git symbolic-ref --short HEAD)
- remote=$(git config --get remote.origin.url)
- removeDotGit="${remote/.git/}"
- removeColon="${removeDotGit/://}"
- url=${removeColon/git\@/https:\/\/}
- open "${url}/issues/new?title=deploy%20${branch}"
-}
-function _gpr_usage() {
- echo "
-Usage: gpr <[options]>
-
-Options:
- -j --jira Jira ticket id
- -d --description Description
- -t --title Title
- -h --help Help
-
-NOTE: You have to provide description and either jira or title.
-
-Example:
-
-# Create a PR from master to dev branch
-gpr master dev -t \"master dev sync\" -d \"rebase dev with master\"
-
-# Create a PR from dev to current branch to dev branch with proper title and description accroding to PR template
-gpr dev -j \"PRDS-1234\" -d \"fix a big bug\"
-"
-}
-function gprm() {
- branch=$(git symbolic-ref --short HEAD)
- remote=$(git config --get remote.origin.url)
- removeDotGit="${remote/.git/}"
- removeColon="${removeDotGit/://}"
- url=${removeColon/git\@/https:\/\/}
- if [ $1 ]; then
- secondArg=$1
- else
- secondArg="dev"
- fi
- count=0
- title=""
- description=""
- while (($#)); do
- case $1 in
- -t=* | --title=*) title="${1#*=}" ;;
- -d=* | --description=*) description="${1#*=}" ;;
- *) if [ $count -eq 1 ]; then
- branch=$secondArg
- target=$1
- else target=$1; fi ;;
- esac
- count=$((count + 1))
- shift
- done
-
- if [ $count -eq 0 ]; then
- base="${url}/compare/${branch}"
- else
- base="${url}/compare/${target}...${branch}"
- fi
- temp="${base}?expand=1"
-
- if [ $title ] && [ $description ]; then
- temp="${temp}&title=${title}&body=${description}"
- elif [ $title ]; then
- temp="${temp}&title=${title}"
- elif [ $description ]; then
- temp="${temp}&body=${description}"
- fi
-
- open "${temp}"
-
- unset target
- unset count
- unset title
- unset description
- unset secondArg
- unset final
-}
-function gpr() {
- branch=$(git symbolic-ref --short HEAD)
- remote=$(git config --get remote.origin.url)
- removeDotGit="${remote/.git/}"
- removeColon="${removeDotGit/://}"
- url=${removeColon/git\@/https:\/\/}
-
- if [ $1 ]; then
- secondArg=$1
- else
- secondArg="dev"
- fi
- count=0
-
- if [ $# -eq 0 ]; then
- _gpr_usage
- return 0
- fi
-
- while (($#)); do
- case $1 in
- -j | --jira)
- shift
- ticket="${1}"
- ;;
- -d | --description)
- shift
- description="${1}"
- ;;
- -t | --title)
- shift
- title="${1}"
- ;;
- -h | --help) _gpr_usage ;;
- *)
- shift
- ;;
- esac
- count=$((count + 1))
- done
-
- target=$secondArg
-
- if [ $count -eq 0 ]; then
- base="${branch}"
- else
- base="${target}"
- head="${branch}"
- fi
-
- body="${description}"
-
- if [ $title ] || [ $ticket ]; then
- if [ $ticket ]; then
- title="${ticket} ${description}"
- body="### Description
-Jira Id: ${ticket}
-Link to Jira Ticket: https://sequoiacg.atlassian.net/browse/${ticket}
-Remarks: ${description}"
- fi
-
- gh pr create --base "${base}" --head "${head}" --title "${title}" --body "${body}"
- fi
-
- unset target
- unset count
- unset title
- unset ticket
- unset body
- unset description
- unset secondArg
- unset final
- unset base
- unset head
-}
-alias gprm=gprm
-alias gpr=gpr
-alias gpi=gpi
-alias gp="git push origin HEAD"
alias n="npm"
alias ni="npm install"
alias ns="npm start"
alias nd="npm run dev"
alias nb="npm run build"
alias nr="npm run"
-alias g="git"
-alias gbc="git symbolic-ref --short HEAD"
-alias gs="git stash -u"
-alias gsp="git stash pop"
-alias gb="git branch"
-alias gbc="git rev-parse --abbrev-ref HEAD && git rev-parse --abbrev-ref HEAD | pbcopy"
-alias glg="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative"
-alias glc="git rev-parse HEAD && git rev-parse HEAD | pbcopy"
alias npmplease="rm -rf node_modules/ && rm -f package-lock.json && npm install"
-alias ni="npm install"
-alias gco="git checkout"
-alias gca="git add . && git commit -m"
alias h="htop"
alias y="yarn"
alias ys="yarn start"
@@ -221,62 +27,26 @@ alias yc="yarn compile"
alias code='NODE_OPTIONS="" code'
alias chrome='open -n -a /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security'
alias dnsclear='sudo dscacheutil -flushcache;sudo killall -HUP mDNSResponder'
-alias a="agg"
-alias as="agg start"
alias python="/usr/bin/python3"
alias pip="pip3"
alias foo="echo foo"
-alias agent="cursor-agent"
-alias nvm="fnm"
alias ymfe="yarn unlink @sequoiaconsulting/mfe-config-essentials ; yarn ; yarn link @sequoiaconsulting/mfe-config-essentials"
alias amfe="agg unlink @sequoiaconsulting/mfe-config-essentials ; agg ; agg link @sequoiaconsulting/mfe-config-essentials"
-function yal() {
- yarn unlink @sequoiaconsulting/mfe-config-essentials
- yarn add $1
- yarn link @sequoiaconsulting/mfe-config-essentials
-}
-alias yal="yal"
-function aal() {
- agg unlink @sequoiaconsulting/mfe-config-essentials
- agg add $1
- agg link @sequoiaconsulting/mfe-config-essentials
-}
-alias aal="aal"
-
-
alias cr="cargo run"
alias cb="cargo build"
alias ca="cargo add"
DISABLE_AUTO_TITLE="true"
-precmd() {
- # sets the tab title to current dir
+_set_tab_title() {
echo -ne "\e]1;${PWD##*/}\a"
}
-
-alias b="bun"
-alias bs="bun start"
-alias bi="bun install"
-alias br="bun run"
-alias bd="bun dev"
-alias bb="bun run build"
-alias ba="bun add"
-alias bda="bun run app:dev"
-alias bba="bun run app:build"
-alias bp="bun run preview"
-alias bt="bun run test"
-
-dmgcreator() {
- hdiutil create -volname "$1" -srcfolder "$1.app" -ov -format UDZO "$1.dmg"
- open "$1.dmg"
-}
-alias dmg="dmgcreator"
+precmd_functions+=(_set_tab_title)
alias p="python"
-alias doctor="bunx -y react-doctor@latest . --verbose --no-ami -y"
-
-alias claude="claude --dangerously-skip-permissions"
\ No newline at end of file
+alias sis="sis -e boilerplate"
+alias run="run -e boilerplate"
+alias as="agg start"
\ No newline at end of file
diff --git a/.stow-local-ignore b/.stow-local-ignore
index 01edc99..53ef5c7 100644
--- a/.stow-local-ignore
+++ b/.stow-local-ignore
@@ -2,4 +2,5 @@
.DS_Store
.git
-README.md
\ No newline at end of file
+README.md
+install.sh
\ No newline at end of file
diff --git a/.zshenv b/.zshenv
index ea034c5..c64164e 100644
--- a/.zshenv
+++ b/.zshenv
@@ -1,4 +1,5 @@
-if [[ $- == *i* ]] && [ -f ~/.zshrc ]; then
- . ~/.zshrc
-fi
-. "$HOME/.cargo/env"
+# Environment variables only — zsh loads ~/.zshrc automatically for interactive shells.
+typeset -U path
+path=("$HOME/dotfiles/bin" "$HOME/.local/bin" /opt/homebrew/bin $path)
+export PATH
+[[ -f "$HOME/.cargo/env" ]] && . "$HOME/.cargo/env"
diff --git a/.zshrc b/.zshrc
index e01dc6c..de6357a 100644
--- a/.zshrc
+++ b/.zshrc
@@ -1,9 +1,4 @@
-# Must be set before the instant prompt block below
typeset -g POWERLEVEL9K_INSTANT_PROMPT=quiet
-
-# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
-# Initialization code that may require console input (password prompts, [y/n]
-# confirmations, etc.) must go above this block; everything else may go below.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi
@@ -23,54 +18,54 @@ source "${ZINIT_HOME}/zinit.zsh"
# Add in Powerlevel10k
zinit ice depth=1; zinit light romkatv/powerlevel10k
-# Add in zsh plugins
-zinit light Aloxaf/fzf-tab
-zinit light zsh-users/zsh-completions
-zinit light zsh-users/zsh-autosuggestions
-zinit light zsh-users/zsh-syntax-highlighting
-
-# Add in snippets
-zinit snippet OMZP::git
+# Zsh plugins — turbo-loaded (zinit `wait` ice) so they load right after the first
+# prompt paints instead of blocking startup. compinit is deferred via atinit onto
+# zsh-syntax-highlighting so zsh-completions' fpath additions land before it runs
+# (same gated once-per-day dump logic as before, just moved).
+zinit wait lucid for \
+ depth"1" \
+ Aloxaf/fzf-tab \
+ depth"1" blockf \
+ zsh-users/zsh-completions \
+ depth"1" atload'!_zsh_autosuggest_start' \
+ zsh-users/zsh-autosuggestions \
+ depth"1" atinit'autoload -Uz compinit; if [[ -n "$HOME/.zcompdump"(#qN.mh+24) ]]; then compinit; else compinit -C; fi; zicdreplay' \
+ zsh-users/zsh-syntax-highlighting
+
+# OMZ git plugin aliases (gco, gp, gst, …) conflict with ~/dotfiles/bin/* scripts.
+# Git completions come from zsh-completions; omit OMZP::git.
+zinit ice wait lucid
zinit snippet OMZP::command-not-found
-# Load completions — gated to once per day for faster startup
-autoload -U compinit
-if [[ -n "$HOME/.zcompdump"(#qN.mh+24) ]]; then
- compinit
-else
- compinit -C
-fi
-
-zinit cdreplay -q
-
-# Keybindings
-bindkey -e
-bindkey '^[[A' history-search-backward
-bindkey '^[[B' history-search-forward
-
-# Ctrl+L: erase the visible screen AND the scrollback buffer.
-# \033[3J = erase saved (scrollback) lines — honoured by both Ghostty and cmux.
-# Ghostty's cmd+k is remapped in the Ghostty config to send \x0c (Ctrl+L) to
-# trigger this widget.
-# Timestamp guard: cmux echoes \x0c back to the pane after clear-history, which
-# would re-trigger this widget in a loop. The guard lets the first call through
-# and absorbs any re-invocations within 2s.
-zmodload zsh/datetime
-_LAST_CLEAR_TS=0
-_HAS_CMUX=$(( $+commands[cmux] ))
-_clear_scrollback() {
- local now=$EPOCHREALTIME
- printf '\033[3J'
- if (( now - _LAST_CLEAR_TS > 2 )); then
- _LAST_CLEAR_TS=$now
- if (( _HAS_CMUX )); then
- command cmux clear-history /dev/null 2>&1 &!
+if [[ -o zle ]]; then
+ bindkey -e
+ bindkey '^[[A' history-search-backward
+ bindkey '^[[B' history-search-forward
+
+ # Ctrl+L: erase the visible screen AND the scrollback buffer.
+ # \033[3J = erase saved (scrollback) lines — honoured by both Ghostty and cmux.
+ # Ghostty's cmd+k is remapped in the Ghostty config to send \x0c (Ctrl+L) to
+ # trigger this widget.
+ # Timestamp guard: cmux echoes \x0c back to the pane after clear-history, which
+ # would re-trigger this widget in a loop. The guard lets the first call through
+ # and absorbs any re-invocations within 2s.
+ zmodload zsh/datetime
+ _LAST_CLEAR_TS=0
+ _HAS_CMUX=$(( $+commands[cmux] ))
+ _clear_scrollback() {
+ local now=$EPOCHREALTIME
+ printf '\033[3J'
+ if (( now - _LAST_CLEAR_TS > 2 )); then
+ _LAST_CLEAR_TS=$now
+ if (( _HAS_CMUX )); then
+ command cmux clear-history /dev/null 2>&1 &!
+ fi
fi
- fi
- zle .clear-screen
-}
-zle -N _clear_scrollback
-bindkey '^L' _clear_scrollback
+ zle .clear-screen
+ }
+ zle -N _clear_scrollback
+ bindkey '^L' _clear_scrollback
+fi
# History
HISTSIZE=5000
@@ -95,7 +90,6 @@ _fzf_compgen_path() {
fd --hidden --exclude .git . "$1"
}
-# Use fd to generate the list for directory completion
_fzf_compgen_dir() {
fd --type=d --hidden --exclude .git . "$1"
}
@@ -105,16 +99,13 @@ show_file_or_dir_preview="if [ -d {} ]; then eza --tree --level=2 --color=always
export FZF_CTRL_T_OPTS="--preview '$show_file_or_dir_preview'"
export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'"
-# Advanced customization of fzf options via _fzf_comprun function
-# - The first argument to the function is the name of the command.
-# - You should make sure to pass the rest of the arguments to fzf.
_fzf_comprun() {
local command=$1
shift
case "$command" in
cd) fzf --preview 'eza --tree --color=always {} | head -200' "$@" ;;
- export|unset) fzf --preview "eval 'echo ${}'" "$@" ;;
+ export|unset) fzf --preview "eval 'echo \${}'" "$@" ;;
ssh) fzf --preview 'dig {}' "$@" ;;
*) fzf --preview "$show_file_or_dir_preview" "$@" ;;
esac
@@ -127,11 +118,25 @@ zstyle ':completion:*' menu no
zstyle ':fzf-tab:complete:z:*' fzf-preview 'eza -1 --color=always $realpath'
zstyle ':fzf-tab:complete:code:*' fzf-preview 'eza --tree --level=2 --color=always $realpath'
-export PATH=/opt/homebrew/bin:$HOME/.local/bin:$PATH
+# Cache tool-generated init scripts (fzf/zoxide/fnm each fork+exec on every startup
+# otherwise) — regenerate only when the binary itself is newer than the cache.
+_zsh_cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/zsh-init"
+mkdir -p "$_zsh_cache_dir"
+_cache_eval() {
+ local name=$1 bin=$2 cache="$_zsh_cache_dir/$1.zsh" bin_path
+ shift 2
+ bin_path=$(command -v "$bin") || return
+ if [[ ! -s "$cache" || "$bin_path" -nt "$cache" ]]; then
+ "$@" > "$cache" 2>/dev/null
+ fi
+ source "$cache"
+}
-eval "$(fzf --zsh)"
-eval "$(zoxide init zsh)"
-eval "$(fnm env --use-on-cd)"
+if [[ -o zle ]]; then
+ _cache_eval fzf fzf fzf --zsh
+fi
+_cache_eval zoxide zoxide zoxide init zsh
+_cache_eval fnm fnm fnm env --use-on-cd
source "${HOME}/.alias.zsh"
source "${HOME}/.secrets.zsh"
@@ -142,3 +147,17 @@ export NODE_NO_WARNINGS=1
# bun completions
[ -s "$HOME/.bun/_bun" ] && source "$HOME/.bun/_bun"
+
+# Android Studio's bundled JBR isn't registered with /usr/libexec/java_home, so this
+# path is the only viable JDK for Android builds — but guard it in case this machine
+# doesn't have Android Studio installed.
+_android_studio_jbr="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
+[[ -d "$_android_studio_jbr" ]] && export JAVA_HOME="$_android_studio_jbr"
+unset _android_studio_jbr
+export ANDROID_HOME="$HOME/Library/Android/sdk"
+
+export PATH="$ANDROID_HOME/emulator:$ANDROID_HOME/platform-tools:${JAVA_HOME:+$JAVA_HOME/bin:}$HOME/.antigravity/antigravity/bin:$HOME/Library/Application Support/fnm:$HOME/.npm-global/bin:$HOME/.local/bin:$HOME/.lmstudio/bin:$PATH"
+
+# Dedupe PATH — zinit resets the -U attribute mid-load, so redeclare it here.
+typeset -U path
+path=($path)
diff --git a/README.md b/README.md
index 9f2d52d..fedd634 100644
--- a/README.md
+++ b/README.md
@@ -19,10 +19,14 @@ brew install fzf zoxide eza fd thefuck stow starship
cd ~
git clone git@github.com:wrick17/dotfiles.git
cd dotfiles
-stow .
+./install.sh
cd ~
```
+`install.sh` wraps `stow .` but first backs up any real (non-symlink) file that
+would conflict — plain `stow .` silently skips those and leaves you with a
+stale, unlinked file (this happened to `.zshenv` for months).
+
```bash
touch ~/.hushlogin
touch ~/.secrets.zsh
@@ -37,3 +41,94 @@ source ~/.zshrc
```bash
p10k configure
```
+
+## Shortcuts (`bin/`)
+
+Commands live as scripts in `~/dotfiles/bin/` (on your PATH via `.zshenv`).
+
+**Why scripts, not aliases?** Aliases only load in an interactive shell. Batch `zsh -c` skips aliases — scripts work everywhere.
+
+**Works in:** iTerm, Terminal, Ghostty, Cursor, and any zsh session. Run `exec zsh` after dotfiles changes.
+
+### Git
+
+| Command | What it does |
+|---------|----------------|
+| `g` | git passthrough |
+| `ga` | git add |
+| `gb` | git branch |
+| `gbc` | copy branch name |
+| `gc` | commit with message |
+| `gca` | add all + commit |
+| `gco` | checkout |
+| `glc` | copy commit sha |
+| `glg` | pretty log |
+| `gp` | push to origin |
+| `gpr` | open PR (`-d` for draft) |
+| `gs` / `gsp` | stash / stash pop |
+| `gst` | status |
+| `gprm` | merge PR for current branch |
+| `ggpu` | pull + rebase from origin |
+| `ggpum` | pull merge from origin |
+| `gpi` | open GitHub issue for deploy |
+| `aal` | agg add + link MFE package |
+| `dmg` | create + open a `.dmg` from an app |
+
+### agg / bun / tools / ls
+
+| Command | What it does |
+|---------|----------------|
+| `a` | agg passthrough |
+| `as` | agg start |
+| `b` | bun passthrough |
+| `bi` | bun install |
+| `bs` | bun start |
+| `br` | bun run … |
+| `bd` | bun dev |
+| `bb` / `ba` | bun run build / bun add |
+| `bda` / `bba` | bun run app:dev / app:build |
+| `bp` / `bt` | bun run preview / test |
+| `doctor` | react-doctor via bunx |
+| `claude` | claude with skip-permissions flag |
+| `agent` | cursor-agent |
+| `nvm` | fnm passthrough |
+| `ls` / `ll` / `lst` | eza listing (tree for `lst`) |
+| `cat` | bat -p |
+
+**`cd` stays interactive-only** (alias to zoxide `z`). A bin script cannot change the current shell directory. In batch, use plain `cd` or the `z` command directly.
+
+**Check it's wired up:**
+
+```bash
+whence -v gco b doctor ls
+# should show ~/dotfiles/bin/...
+```
+
+**Note:** zsh only for dotfile loading. Bash/fish need `~/dotfiles/bin` on PATH manually.
+
+### Still interactive-only (aliases in `.alias.zsh`)
+
+| You type | Use in batch instead |
+|----------|----------------------|
+| `cd` | `cd` (builtin) or `z
` |
+| `y`, `yi`, `yd`, … (yarn) | full `yarn` commands |
+| `n`, `ni`, `nd`, … (npm) | full `npm` commands |
+| `amfe`, `ymfe` | run the full agg/yarn link commands |
+| `cr`, `cb`, `ca` (cargo) | full `cargo` commands |
+
+**`.secrets.zsh`** loads only in interactive zsh. Batch gets `.zshenv` only.
+
+**fnm auto-switch on cd** is in `.zshrc`; batch `node` may differ from your terminal unless you use `fnm exec`.
+
+### OMZ / other alias sources
+
+| Source | Status | What it adds |
+|--------|--------|----------------|
+| `OMZP::git` | **Removed** | Was git aliases (`gco`, `gpr`, …) — conflicted with `bin/` |
+| `OMZP::command-not-found` | **Still loaded** | Homebrew “did you mean …?” when a command is missing — not aliases |
+| `.alias.zsh` | Active | yarn, npm, cargo, chrome, `cd=z`, etc. |
+| zinit | Built-in only | `zi`/`zinit` shortcuts, `run-help=man` |
+
+**Safe to remove (already done):** `OMZP::git`.
+
+**Pending your OK:** `OMZP::command-not-found` — only adds install hints; no overlap with `bin/`. Removing it is fine if you don’t want any OMZ snippets left.
diff --git a/bin/a b/bin/a
new file mode 100755
index 0000000..3d2e67f
--- /dev/null
+++ b/bin/a
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec agg "$@"
diff --git a/bin/aal b/bin/aal
new file mode 100755
index 0000000..c298345
--- /dev/null
+++ b/bin/aal
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+if [[ $# -eq 0 ]]; then
+ echo "Usage: aal " >&2
+ exit 1
+fi
+
+agg unlink @sequoiaconsulting/mfe-config-essentials
+agg add "$1"
+agg link @sequoiaconsulting/mfe-config-essentials
diff --git a/bin/agent b/bin/agent
new file mode 100755
index 0000000..e817021
--- /dev/null
+++ b/bin/agent
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec cursor-agent "$@"
diff --git a/bin/as b/bin/as
new file mode 100755
index 0000000..4945f91
--- /dev/null
+++ b/bin/as
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec agg start "$@"
diff --git a/bin/b b/bin/b
new file mode 100755
index 0000000..3afd65a
--- /dev/null
+++ b/bin/b
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun "$@"
diff --git a/bin/ba b/bin/ba
new file mode 100755
index 0000000..a0bcc28
--- /dev/null
+++ b/bin/ba
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun add "$@"
diff --git a/bin/bb b/bin/bb
new file mode 100755
index 0000000..5c534c9
--- /dev/null
+++ b/bin/bb
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun run build "$@"
diff --git a/bin/bba b/bin/bba
new file mode 100755
index 0000000..45ccceb
--- /dev/null
+++ b/bin/bba
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun run app:build "$@"
diff --git a/bin/bd b/bin/bd
new file mode 100755
index 0000000..cb91b2d
--- /dev/null
+++ b/bin/bd
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun dev "$@"
diff --git a/bin/bda b/bin/bda
new file mode 100755
index 0000000..7c6b730
--- /dev/null
+++ b/bin/bda
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun run app:dev "$@"
diff --git a/bin/bi b/bin/bi
new file mode 100755
index 0000000..862001b
--- /dev/null
+++ b/bin/bi
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun install "$@"
diff --git a/bin/bp b/bin/bp
new file mode 100755
index 0000000..d487495
--- /dev/null
+++ b/bin/bp
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun run preview "$@"
diff --git a/bin/br b/bin/br
new file mode 100755
index 0000000..7e3d252
--- /dev/null
+++ b/bin/br
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun run "$@"
diff --git a/bin/bs b/bin/bs
new file mode 100755
index 0000000..7704df3
--- /dev/null
+++ b/bin/bs
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun start "$@"
diff --git a/bin/bt b/bin/bt
new file mode 100755
index 0000000..d48f4f9
--- /dev/null
+++ b/bin/bt
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bun run test "$@"
diff --git a/bin/cat b/bin/cat
new file mode 100755
index 0000000..6fdeb49
--- /dev/null
+++ b/bin/cat
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bat -p "$@"
diff --git a/bin/claude b/bin/claude
new file mode 100755
index 0000000..46370bd
--- /dev/null
+++ b/bin/claude
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec claude --dangerously-skip-permissions "$@"
diff --git a/bin/dmg b/bin/dmg
new file mode 100755
index 0000000..e561246
--- /dev/null
+++ b/bin/dmg
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+if [[ $# -eq 0 ]]; then
+ echo "Usage: dmg " >&2
+ exit 1
+fi
+
+hdiutil create -volname "$1" -srcfolder "$1.app" -ov -format UDZO "$1.dmg"
+open "$1.dmg"
diff --git a/bin/doctor b/bin/doctor
new file mode 100755
index 0000000..2b4af16
--- /dev/null
+++ b/bin/doctor
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec bunx -y react-doctor@latest . --verbose --no-ami -y "$@"
diff --git a/bin/g b/bin/g
new file mode 100755
index 0000000..a501723
--- /dev/null
+++ b/bin/g
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec git "$@"
diff --git a/bin/ga b/bin/ga
new file mode 100755
index 0000000..c5de4af
--- /dev/null
+++ b/bin/ga
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec git add "$@"
diff --git a/bin/gb b/bin/gb
new file mode 100755
index 0000000..3d21e09
--- /dev/null
+++ b/bin/gb
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec git branch "$@"
diff --git a/bin/gbc b/bin/gbc
new file mode 100755
index 0000000..7675c88
--- /dev/null
+++ b/bin/gbc
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+branch=$(git rev-parse --abbrev-ref HEAD)
+printf '%s\n' "$branch"
+printf '%s' "$branch" | pbcopy
diff --git a/bin/gc b/bin/gc
new file mode 100755
index 0000000..8e61905
--- /dev/null
+++ b/bin/gc
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+if [[ $# -eq 0 ]]; then
+ echo "Usage: gc " >&2
+ exit 1
+fi
+exec git commit -m "$*"
diff --git a/bin/gca b/bin/gca
new file mode 100755
index 0000000..8626fc6
--- /dev/null
+++ b/bin/gca
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+if [[ $# -eq 0 ]]; then
+ echo "Usage: gca " >&2
+ exit 1
+fi
+git add .
+exec git commit -m "$*"
diff --git a/bin/gco b/bin/gco
new file mode 100755
index 0000000..f27601e
--- /dev/null
+++ b/bin/gco
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec git checkout "$@"
diff --git a/bin/ggpu b/bin/ggpu
new file mode 100755
index 0000000..432f850
--- /dev/null
+++ b/bin/ggpu
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+branch="$(git rev-parse --abbrev-ref HEAD)"
+
+if [[ $# -eq 0 ]]; then
+ git pull origin "$branch" --rebase
+else
+ git pull origin "$1" --rebase
+fi
diff --git a/bin/ggpum b/bin/ggpum
new file mode 100755
index 0000000..e305a30
--- /dev/null
+++ b/bin/ggpum
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+branch="$(git rev-parse --abbrev-ref HEAD)"
+
+if [[ $# -eq 0 ]]; then
+ git pull origin "$branch"
+else
+ git pull origin "$1"
+fi
diff --git a/bin/glc b/bin/glc
new file mode 100755
index 0000000..780e14b
--- /dev/null
+++ b/bin/glc
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+sha=$(git rev-parse HEAD)
+printf '%s\n' "$sha"
+printf '%s' "$sha" | pbcopy
diff --git a/bin/glg b/bin/glg
new file mode 100755
index 0000000..a5472c0
--- /dev/null
+++ b/bin/glg
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative "$@"
diff --git a/bin/gp b/bin/gp
new file mode 100755
index 0000000..c5284da
--- /dev/null
+++ b/bin/gp
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec git push origin HEAD "$@"
diff --git a/bin/gpi b/bin/gpi
new file mode 100755
index 0000000..0b1a64e
--- /dev/null
+++ b/bin/gpi
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+# shellcheck source=lib/github-web-url.sh
+source "$(cd "$(dirname "$0")" && pwd)/lib/github-web-url.sh"
+
+branch=$(git symbolic-ref --short HEAD)
+url=$(github_web_url)
+open "${url}/issues/new?title=deploy%20${branch}"
diff --git a/bin/gpr b/bin/gpr
new file mode 100755
index 0000000..2f77aa3
--- /dev/null
+++ b/bin/gpr
@@ -0,0 +1,96 @@
+#!/usr/bin/env bash
+
+gpr_usage() {
+ cat <<'EOF'
+
+Usage: gpr [options]
+
+Options:
+ -j --jira Jira ticket id
+ --description PR description (long form)
+ -t --title Title
+ -d --draft Create PR as draft
+ -h --help Help
+
+NOTE: Provide --description and either -j or -t.
+
+Examples:
+
+gpr dev -j "PRDS-1234" --description "fix a big bug"
+gpr dev -j "PRDS-1234" --description "fix a big bug" -d
+EOF
+}
+
+die() {
+ echo "gpr: $*" >&2
+ exit 1
+}
+
+branch=$(git symbolic-ref --short HEAD 2>/dev/null) || die "not on a branch"
+second_arg="${1:-dev}"
+draft=""
+title=""
+description=""
+ticket=""
+
+if [[ $# -eq 0 ]]; then
+ gpr_usage
+ exit 0
+fi
+
+while (($#)); do
+ case $1 in
+ -j | --jira)
+ shift
+ ticket="${1:-}"
+ [[ -n $ticket ]] || die "missing value for $1"
+ shift
+ ;;
+ -d | --draft)
+ draft="--draft"
+ shift
+ ;;
+ --description)
+ shift
+ description="${1:-}"
+ [[ -n $description ]] || die "missing value for --description"
+ shift
+ ;;
+ -t | --title)
+ shift
+ title="${1:-}"
+ [[ -n $title ]] || die "missing value for -t/--title"
+ shift
+ ;;
+ -h | --help)
+ gpr_usage
+ exit 0
+ ;;
+ -*)
+ die "unknown option: $1"
+ ;;
+ *)
+ shift
+ ;;
+ esac
+done
+
+target=$second_arg
+base="${target}"
+head="${branch}"
+body="${description}"
+
+[[ -n $description ]] || die "missing --description"
+[[ -n $title || -n $ticket ]] || die "provide -j/--jira or -t/--title"
+
+if [[ -n $ticket ]]; then
+ title="${ticket} ${description}"
+ body="### Description
+Jira Id: ${ticket}
+Link to Jira Ticket: https://sequoiacg.atlassian.net/browse/${ticket}
+Remarks: ${description}"
+fi
+
+echo "Creating PR: ${head} -> ${base}${draft:+ (draft)}"
+# shellcheck disable=SC2086
+gh pr create --base "${base}" --head "${head}" --title "${title}" --body "${body}" ${draft}
diff --git a/bin/gprm b/bin/gprm
new file mode 100755
index 0000000..7fc4b37
--- /dev/null
+++ b/bin/gprm
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+
+# shellcheck source=lib/github-web-url.sh
+source "$(cd "$(dirname "$0")" && pwd)/lib/github-web-url.sh"
+
+branch=$(git symbolic-ref --short HEAD)
+url=$(github_web_url)
+second_arg="${1:-dev}"
+count=0
+title=""
+description=""
+target=""
+
+while (($#)); do
+ case $1 in
+ -t=* | --title=*)
+ title="${1#*=}"
+ ;;
+ -d=* | --description=*)
+ description="${1#*=}"
+ ;;
+ *)
+ if [[ $count -eq 1 ]]; then
+ branch=$second_arg
+ target=$1
+ else
+ target=$1
+ fi
+ ;;
+ esac
+ count=$((count + 1))
+ shift
+done
+
+if [[ $count -eq 0 ]]; then
+ base="${url}/compare/${branch}"
+else
+ base="${url}/compare/${target}...${branch}"
+fi
+
+temp="${base}?expand=1"
+
+if [[ -n $title && -n $description ]]; then
+ temp="${temp}&title=${title}&body=${description}"
+elif [[ -n $title ]]; then
+ temp="${temp}&title=${title}"
+elif [[ -n $description ]]; then
+ temp="${temp}&body=${description}"
+fi
+
+open "${temp}"
diff --git a/bin/gpt b/bin/gpt
new file mode 100755
index 0000000..40db816
--- /dev/null
+++ b/bin/gpt
@@ -0,0 +1,188 @@
+#!/usr/bin/env bash
+
+# shellcheck source=lib/github-web-url.sh
+source "$(cd "$(dirname "$0")" && pwd)/lib/github-web-url.sh"
+
+gpt_usage() {
+ cat <<'EOF'
+
+Usage: gpt [options]
+
+ env: dev | sprint | hotfix | hotfix-mt | release-YYMM
+
+Options:
+ -b --branch Actual git branch to tag (required for hotfix/hotfix-mt)
+ -h --help Help
+
+Examples:
+ gpt dev
+ gpt sprint
+ gpt release-2607
+ gpt hotfix -b hotfix/fix-auth-bug
+EOF
+}
+
+die() {
+ echo "gpt: $*" >&2
+ exit 1
+}
+
+log_step() { echo "==> $*"; }
+log_success() { echo "[OK] $*"; }
+log_info() { echo "[INFO] $*"; }
+log_warn() { echo "[WARN] $*"; }
+
+if [[ $# -eq 0 || "$1" == "-h" || "$1" == "--help" ]]; then
+ gpt_usage
+ exit 0
+fi
+
+tag_name="$1"
+shift
+
+branch_override=""
+
+while (($#)); do
+ case $1 in
+ -b | --branch)
+ shift
+ branch_override="${1:-}"
+ [[ -n $branch_override ]] || die "missing value for -b/--branch"
+ shift
+ ;;
+ -h | --help)
+ gpt_usage
+ exit 0
+ ;;
+ -*)
+ die "unknown option: $1"
+ ;;
+ *)
+ shift
+ ;;
+ esac
+done
+
+case "$tag_name" in
+ dev | sprint | hotfix | hotfix-mt | release-*) ;;
+ *) die "invalid env '$tag_name'. Use: dev, sprint, hotfix, hotfix-mt, or release-YYMM" ;;
+esac
+
+if [[ "$tag_name" == "hotfix" || "$tag_name" == "hotfix-mt" ]]; then
+ [[ -n $branch_override ]] || die "hotfix/hotfix-mt requires -b "
+ my_branch="$branch_override"
+else
+ my_branch="${branch_override:-$tag_name}"
+fi
+
+repo_url=$(git config --get remote.origin.url 2>/dev/null) || die "not a git repo or no remote origin"
+repo_name=$(basename "${repo_url%.git}")
+
+# macOS date
+current_date=$(date +"%y.%m.%d")
+current_day=$(date +"%d")
+current_month=$(date +"%m")
+previous_month=$(date -v-1m +"%m")
+previous2_month=$(date -v-2m +"%m")
+current_year=$(date +"%y")
+
+echo ""
+echo "Repo: $repo_name"
+echo "Env: $tag_name"
+echo "Branch: $my_branch"
+echo ""
+
+log_step "Fetching tags..."
+git fetch --all --tags --quiet
+
+# Sync check for release/sprint/hotfix
+if [[ "$tag_name" == release-* || "$tag_name" == "sprint" || "$tag_name" == "hotfix" || "$tag_name" == "hotfix-mt" ]]; then
+ log_step "Checking $my_branch is in sync with master..."
+
+ branch_head=$(git rev-parse "origin/$my_branch" 2>/dev/null) || die "origin/$my_branch not found — push branch first"
+ master_head=$(git rev-parse "origin/master" 2>/dev/null) || die "origin/master not found"
+ merge_base=$(git merge-base "origin/$my_branch" "origin/master")
+
+ if [[ "$branch_head" == "$master_head" ]]; then
+ log_success "Branch is in sync with master"
+ elif [[ "$master_head" == "$merge_base" ]]; then
+ log_success "Branch is ahead of master (all master changes included)"
+ elif [[ "$branch_head" == "$merge_base" ]]; then
+ die "$my_branch is behind master — pull latest master before tagging"
+ else
+ die "$my_branch has diverged from master — merge master before tagging"
+ fi
+fi
+
+# Find previous tag
+previous_tag=$(git tag --list "${tag_name}-v*" --sort=-version:refname | awk 'NR==1')
+log_info "Previous tag: ${previous_tag:-none}"
+
+# Early exit: skip if previous tag already points to current HEAD
+branch_commit=$(git rev-list -n 1 "origin/$my_branch")
+if [[ -n "$previous_tag" ]]; then
+ prev_commit=$(git rev-list -n 1 "$previous_tag" 2>/dev/null || echo "")
+ if [[ -n "$prev_commit" && "$prev_commit" == "$branch_commit" ]]; then
+ web_url=$(github_web_url)
+ log_info "No new commits since $previous_tag (commit: $branch_commit)"
+ log_info "Existing release: ${web_url}/releases/tag/${previous_tag}"
+ exit 0
+ fi
+fi
+
+# Compute new tag
+if [[ "$tag_name" == "release-${current_year}${current_month}"* || \
+ "$tag_name" == "release-${current_year}${previous_month}"* || \
+ "$tag_name" == "release-${current_year}${previous2_month}"* ]]; then
+ # Release branch: day-based versioning e.g. release-2607-v30.1
+ if [[ "$previous_tag" == *"v${current_day}."* ]]; then
+ last_digit="${previous_tag##*.}"
+ new_tag="${tag_name}-v${current_day}.$((last_digit + 1))"
+ else
+ new_tag="${tag_name}-v${current_day}.1"
+ fi
+elif [[ "$previous_tag" == *"${current_date}"* ]]; then
+ last_digit="${previous_tag##*.}"
+ new_tag="${tag_name}-v${current_date}.$((last_digit + 1))"
+else
+ if [[ "$tag_name" == "release-"* ]]; then
+ new_tag="${tag_name}-v${current_day}.1"
+ else
+ new_tag="${tag_name}-v${current_date}.1"
+ fi
+fi
+
+# Resolve tag collision
+if git tag --list "$new_tag" | grep -q .; then
+ log_warn "Tag $new_tag already exists — finding next available..."
+ tag_base="${new_tag%.*}"
+ highest=0
+ while IFS= read -r existing; do
+ [[ -z "$existing" ]] && continue
+ ver="${existing##*.}"
+ [[ "$ver" =~ ^[0-9]+$ ]] && (( ver > highest )) && highest=$ver
+ done < <(git tag --list "${tag_base}.*" --sort=version:refname)
+ new_tag="${tag_base}.$((highest + 1))"
+fi
+
+log_info "New tag: $new_tag"
+
+# Create tag and GitHub release
+log_step "Creating tag $new_tag at $branch_commit..."
+
+git tag -a "$new_tag" "$branch_commit" -m "Release notes for $new_tag"
+if ! git push origin "$new_tag"; then
+ git tag -d "$new_tag"
+ die "push rejected — local tag $new_tag deleted. Check repo tag rules on GitHub."
+fi
+
+prerelease_flag="--prerelease"
+if [[ "$tag_name" == "release-"* || "$tag_name" == "hotfix" || "$tag_name" == "hotfix-mt" ]]; then
+ prerelease_flag=""
+fi
+
+# shellcheck disable=SC2086
+gh release create "$new_tag" --generate-notes --title "$new_tag" $prerelease_flag
+
+web_url=$(github_web_url)
+log_success "Done: ${web_url}/releases/tag/${new_tag}"
diff --git a/bin/gs b/bin/gs
new file mode 100755
index 0000000..eb962fc
--- /dev/null
+++ b/bin/gs
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec git stash push -u "$@"
diff --git a/bin/gsp b/bin/gsp
new file mode 100755
index 0000000..ff8fa5e
--- /dev/null
+++ b/bin/gsp
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec git stash pop "$@"
diff --git a/bin/gst b/bin/gst
new file mode 100755
index 0000000..1d30ab3
--- /dev/null
+++ b/bin/gst
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec git status "$@"
diff --git a/bin/lib/github-web-url.sh b/bin/lib/github-web-url.sh
new file mode 100755
index 0000000..db21ca1
--- /dev/null
+++ b/bin/lib/github-web-url.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+github_web_url() {
+ local remote
+ remote="${1:-$(git config --get remote.origin.url)}"
+ remote="${remote%.git}"
+
+ if [[ $remote =~ ^git@([^:]+):(.+)$ ]]; then
+ printf 'https://%s/%s' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
+ return
+ fi
+
+ if [[ $remote =~ ^https?:// ]]; then
+ printf '%s' "$remote"
+ return
+ fi
+
+ printf '%s' "$remote"
+}
diff --git a/bin/ll b/bin/ll
new file mode 100755
index 0000000..1d62537
--- /dev/null
+++ b/bin/ll
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec eza --all --color=always --long --icons=always --no-user --no-permissions "$@"
diff --git a/bin/ls b/bin/ls
new file mode 100755
index 0000000..1d62537
--- /dev/null
+++ b/bin/ls
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec eza --all --color=always --long --icons=always --no-user --no-permissions "$@"
diff --git a/bin/lst b/bin/lst
new file mode 100755
index 0000000..4af6609
--- /dev/null
+++ b/bin/lst
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec eza --all --color=always --long --icons=always --no-user --no-permissions --tree --level=2 "$@"
diff --git a/bin/nvm b/bin/nvm
new file mode 100755
index 0000000..ff56f75
--- /dev/null
+++ b/bin/nvm
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec fnm "$@"
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..b105446
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+# Symlinks this repo into $HOME via stow. Backs up any real (non-symlink) file
+# that would conflict, so stow can never silently skip a target the way it did
+# for .zshenv (see README history: a stale pre-existing ~/.zshenv shadowed the
+# repo's version for months because stow refuses to clobber real files).
+set -euo pipefail
+cd "$(dirname "$0")"
+
+backup_dir="$HOME/.dotfiles-backup-$(date +%Y%m%d%H%M%S)"
+
+for f in .[!.]*; do
+ [[ -f "$f" ]] || continue
+ target="$HOME/$f"
+ if [[ -e "$target" && ! -L "$target" ]]; then
+ mkdir -p "$backup_dir"
+ echo "Backing up existing $target -> $backup_dir/$f"
+ mv "$target" "$backup_dir/$f"
+ fi
+done
+
+stow -v -t "$HOME" .
+
+echo "Done. Run 'exec zsh' to pick up the new config."
+[[ -d "$backup_dir" ]] && echo "Conflicting files backed up to: $backup_dir"