diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d807bee..aa1eab4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: set -euo pipefail shopt -s nullglob globstar - zsh_files=(zsh/zshrc zsh/scripts/*.zsh) + zsh_files=(zsh/zshrc zsh/cortex-dotfiles.zsh zsh/scripts/*.zsh) for file in "${zsh_files[@]}"; do [[ -f "$file" ]] || continue zsh -n "$file" diff --git a/README.md b/README.md index e51416d..7d8d347 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,8 @@ dotfiles/ ├── bun/ # Global bun defaults (~/.bunfig.toml) ├── uv/ # Global uv defaults (~/.config/uv/uv.toml) ├── zsh/ -│ ├── zshrc # Profile principal (~/.zshrc) +│ ├── zshrc # Bootstrap: dotfiles primero, Cortex al final (~/.zshrc) +│ ├── cortex-dotfiles.zsh # Entrypoint propio del profile de dotfiles │ └── scripts/ │ ├── claude-helpers.zsh # Integración Claude Code │ ├── cmux-sidebar-refresh.sh # Metadata Cortex para cmux @@ -94,7 +95,7 @@ dotfiles/ ## Boundary con Cortex -Este repo sigue siendo standalone: `install.sh` no requiere tener el repo `cortex` disponible y estos dotfiles deben poder instalarse por sí solos. +Este repo sigue siendo standalone: `install.sh` no requiere tener el repo `cortex` disponible y estos dotfiles deben poder instalarse por sí solos. El bootstrap carga primero `~/.config/cortex-dotfiles/shell/cortex-dotfiles.zsh` y, si existe, carga al final `~/.cortex/shell/cortex.zsh`, que pertenece a Cortex. Ambos fragments son opcionales y un error en uno no impide intentar cargar el otro. Cortex conserva el ownership de sus variables core; este repo solo define variables bajo el namespace `CORTEX_DOTFILES_*`. Algunos artefactos viven acá temporalmente porque nacieron junto al setup personal, pero conceptualmente son propios del producto Cortex y no deberían tener a `cortex-dotfiles` como source of truth permanente: @@ -144,10 +145,9 @@ Seguimiento: [cortex-dotfiles #31](https://github.com/barbatdev/cortex-dotfiles/ Editá `local/env.zsh` (gitignored) para configurar: - `SCREENSHOTS_DIR` — directorio de screenshots - `WORKSPACE_DIR` — directorio raíz de tus proyectos -- `CORTEX_HOME` — raíz canónica de cortex, por defecto `~/.cortex` -- `CORTEX_ROOT` — repo principal cortex, por defecto `~/.cortex/cortex` -- `CORTEX_DOTFILES_DIR` — repo dotfiles, por defecto `~/.cortex/cortex-dotfiles` -- `CORTEX_SHELL_INTEGRATION` — fragmento zsh opcional administrado por Cortex, por defecto `$CORTEX_HOME/shell/cortex.zsh` +- `CORTEX_DOTFILES_DIR` — repo dotfiles, por defecto `$BARBATDEV_DIR/cortex/cortex-dotfiles` +- `CORTEX_DOTFILES_SHELL_ENTRYPOINT` — override del entrypoint propio, por defecto `~/.config/cortex-dotfiles/shell/cortex-dotfiles.zsh` +- `CORTEX_DOTFILES_MULTIPLEXER` — fallback standalone para helpers, por defecto `cmux`; `CORTEX_MULTIPLEXER` de Cortex tiene precedencia - `OPENCODE_DEFAULT_FLAGS` — flags por defecto para `oc` - `INNIT_DIR` y overrides `INNIT_*_DIR` — navegación rápida de subdirectorios - Aliases y paths personales diff --git a/install.sh b/install.sh index a0a5216..4f840be 100755 --- a/install.sh +++ b/install.sh @@ -204,6 +204,7 @@ PY echo "" echo "checking symlink targets" check_symlink_target "$DOTFILES/zsh/zshrc" "$HOME/.zshrc" + check_symlink_target "$DOTFILES/zsh/cortex-dotfiles.zsh" "$HOME/.config/cortex-dotfiles/shell/cortex-dotfiles.zsh" check_symlink_target "$DOTFILES/npm/npmrc" "$HOME/.npmrc" check_symlink_target "$DOTFILES/bun/bunfig.toml" "$HOME/.bunfig.toml" check_symlink_target "$DOTFILES/uv/uv.toml" "$HOME/.config/uv/uv.toml" @@ -238,6 +239,7 @@ PY check_shell "$path" bash done check_shell "$DOTFILES/zsh/zshrc" zsh + check_shell "$DOTFILES/zsh/cortex-dotfiles.zsh" zsh for path in "$DOTFILES"/zsh/scripts/*.zsh; do check_shell "$path" zsh done @@ -455,6 +457,7 @@ backup_karabiner_if_exists() { } backup_if_exists "$HOME/.zshrc" +backup_if_exists "$HOME/.config/cortex-dotfiles/shell/cortex-dotfiles.zsh" backup_if_exists "$HOME/.npmrc" backup_if_exists "$HOME/.bunfig.toml" backup_if_exists "$HOME/.config/uv/uv.toml" @@ -497,6 +500,7 @@ create_symlink() { } create_symlink "$DOTFILES/zsh/zshrc" "$HOME/.zshrc" +create_symlink "$DOTFILES/zsh/cortex-dotfiles.zsh" "$HOME/.config/cortex-dotfiles/shell/cortex-dotfiles.zsh" create_symlink "$DOTFILES/npm/npmrc" "$HOME/.npmrc" create_symlink "$DOTFILES/bun/bunfig.toml" "$HOME/.bunfig.toml" create_symlink "$DOTFILES/uv/uv.toml" "$HOME/.config/uv/uv.toml" diff --git a/local/env.zsh.example b/local/env.zsh.example index 5f0fd81..a518332 100644 --- a/local/env.zsh.example +++ b/local/env.zsh.example @@ -7,11 +7,9 @@ # Raíz real de repos en Linux/agent-dev. # export BARBATDEV_DIR="$WORKSPACE_DIR/barbatdev" -# Raíz de estado/runtime de cortex y repos principales. -# export CORTEX_HOME="$HOME/.cortex" -# export CORTEX_ROOT="$BARBATDEV_DIR/cortex/cortex" +# Configuración propia de cortex-dotfiles. # export CORTEX_DOTFILES_DIR="$BARBATDEV_DIR/cortex/cortex-dotfiles" -# export CORTEX_SHELL_INTEGRATION="$CORTEX_HOME/shell/cortex.zsh" +# export CORTEX_DOTFILES_SHELL_ENTRYPOINT="$HOME/.config/cortex-dotfiles/shell/cortex-dotfiles.zsh" # Proyectos personales # export PERSONAL_PROJECTS_DIR="$BARBATDEV_DIR/products" @@ -25,8 +23,8 @@ # OpenCode # export OPENCODE_DEFAULT_FLAGS="" -# Multiplexor preferido para cc/oc y sesiones remotas. -# export CORTEX_MULTIPLEXER="cmux" +# Multiplexor preferido por los helpers de dotfiles cuando Cortex no lo define. +# export CORTEX_DOTFILES_MULTIPLEXER="cmux" # Navegación rápida para proyectos de una organización/equipo # export INNIT_DIR="$BARBATDEV_DIR/innit" diff --git a/scripts/check-cortex-shell-integration.sh b/scripts/check-cortex-shell-integration.sh index 175a7f3..dd85d51 100755 --- a/scripts/check-cortex-shell-integration.sh +++ b/scripts/check-cortex-shell-integration.sh @@ -5,24 +5,56 @@ repo_root="$(cd "$(dirname "$0")/.." && pwd)" tmp_dir="$(mktemp -d)" trap 'rm -rf "$tmp_dir"' EXIT -integration="$tmp_dir/cortex.zsh" -printf '%s\n' '_CORTEX_INTEGRATION_PROBE=loaded' > "$integration" - -env CORTEX_SHELL_INTEGRATION="$integration" zsh -f -c ' - source "$1" >/dev/null - [[ "$_CORTEX_INTEGRATION_PROBE" == loaded ]] - (( ! ${+_CORTEX_SHELL_INTEGRATION_PATH} )) -' _ "$repo_root/zsh/zshrc" - -env CORTEX_SHELL_INTEGRATION="$tmp_dir/missing.zsh" zsh -f -c ' - source "$1" >/dev/null - (( ! ${+_CORTEX_INTEGRATION_PROBE} )) -' _ "$repo_root/zsh/zshrc" - -mkdir -p "$tmp_dir/cortex-home/shell" -printf '%s\n' '_CORTEX_DEFAULT_INTEGRATION_PROBE=loaded' > "$tmp_dir/cortex-home/shell/cortex.zsh" - -env -u CORTEX_SHELL_INTEGRATION CORTEX_HOME="$tmp_dir/cortex-home" zsh -f -c ' - source "$1" >/dev/null - [[ "$_CORTEX_DEFAULT_INTEGRATION_PROBE" == loaded ]] -' _ "$repo_root/zsh/zshrc" +dotfiles_fragment="$tmp_dir/cortex-dotfiles.zsh" +cortex_fragment="$tmp_dir/cortex.zsh" +printf '%s\n' '_SHELL_LOAD_ORDER+=(dotfiles)' > "$dotfiles_fragment" +printf '%s\n' '_SHELL_LOAD_ORDER+=(cortex)' > "$cortex_fragment" + +env \ + CORTEX_DOTFILES_SHELL_ENTRYPOINT="$dotfiles_fragment" \ + CORTEX_SHELL_INTEGRATION="$cortex_fragment" \ + zsh -f -c ' + _SHELL_LOAD_ORDER=() + source "$1" + [[ "${(j/:/)_SHELL_LOAD_ORDER}" == "dotfiles:cortex" ]] + (( ! ${+_CORTEX_DOTFILES_SHELL_PATH} )) + (( ! ${+_CORTEX_SHELL_PATH} )) + ' _ "$repo_root/zsh/zshrc" + +home_dir="$tmp_dir/home" +mkdir -p "$home_dir/.config/cortex-dotfiles/shell" "$home_dir/.cortex/shell" +cp "$dotfiles_fragment" "$home_dir/.config/cortex-dotfiles/shell/cortex-dotfiles.zsh" +cp "$cortex_fragment" "$home_dir/.cortex/shell/cortex.zsh" + +env -u CORTEX_HOME -u CORTEX_ROOT -u CORTEX_DOTFILES_SHELL_ENTRYPOINT \ + -u CORTEX_SHELL_INTEGRATION HOME="$home_dir" zsh -f -c ' + _SHELL_LOAD_ORDER=() + source "$1" + [[ "${(j/:/)_SHELL_LOAD_ORDER}" == "dotfiles:cortex" ]] + (( ! ${+CORTEX_HOME} )) + (( ! ${+CORTEX_ROOT} )) + ' _ "$repo_root/zsh/zshrc" + +env HOME="$tmp_dir/missing-home" zsh -f -c 'source "$1"' _ "$repo_root/zsh/zshrc" + +printf '%s\n' 'return 1' > "$dotfiles_fragment" +env \ + CORTEX_DOTFILES_SHELL_ENTRYPOINT="$dotfiles_fragment" \ + CORTEX_SHELL_INTEGRATION="$cortex_fragment" \ + zsh -f -c ' + _SHELL_LOAD_ORDER=() + source "$1" 2>"$2" + [[ "${(j/:/)_SHELL_LOAD_ORDER}" == "cortex" ]] + ' _ "$repo_root/zsh/zshrc" "$tmp_dir/error.log" + +grep -Fq "zsh: no se pudo cargar cortex-dotfiles: $dotfiles_fragment" "$tmp_dir/error.log" + +printf '%s\n' 'if [[' > "$dotfiles_fragment" +env \ + CORTEX_DOTFILES_SHELL_ENTRYPOINT="$dotfiles_fragment" \ + CORTEX_SHELL_INTEGRATION="$cortex_fragment" \ + zsh -f -c ' + _SHELL_LOAD_ORDER=() + source "$1" 2>/dev/null + [[ "${(j/:/)_SHELL_LOAD_ORDER}" == "cortex" ]] + ' _ "$repo_root/zsh/zshrc" diff --git a/zsh/cortex-dotfiles.zsh b/zsh/cortex-dotfiles.zsh new file mode 100644 index 0000000..ba43c29 --- /dev/null +++ b/zsh/cortex-dotfiles.zsh @@ -0,0 +1,357 @@ +#region Header +# Dev Zsh Profile — macOS + Ghostty +# YOUR_NAME - YOUR_ORG +#endregion + +#region Performance +zmodload zsh/datetime +_PROFILE_START=$EPOCHREALTIME +#endregion + +#region Brew +if command -v brew &>/dev/null; then + eval "$(brew shellenv)" +fi +#endregion + +#region PATH +export PATH="$HOME/.local/bin:$PATH" +[[ -d "/Applications/cmux.app/Contents/Resources/bin" ]] && export PATH="/Applications/cmux.app/Contents/Resources/bin:$PATH" +#endregion + +#region Zsh Options +# Historia +HISTFILE="$HOME/.zsh_history" +HISTSIZE=10000 +SAVEHIST=10000 +setopt HIST_IGNORE_DUPS # no guardar duplicados consecutivos +setopt HIST_IGNORE_SPACE # no guardar comandos que empiezan con espacio +setopt SHARE_HISTORY # compartir historia entre sesiones + +# Navegación +setopt AUTO_CD # escribir un directorio lo hace cd +setopt AUTO_PUSHD # cd empuja al stack (podés usar popd) +setopt PUSHD_SILENT # sin output en pushd/popd + +# Completado +autoload -Uz compinit && compinit +zstyle ':completion:*' menu select +zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' # case insensitive + +# Sin beep +setopt NO_BEEP +#endregion + +#region Editor +if command -v nvim &>/dev/null; then + export EDITOR="$(command -v nvim)" +elif command -v vim &>/dev/null; then + export EDITOR="$(command -v vim)" +else + export EDITOR="nano" +fi +export VISUAL="$EDITOR" +#endregion + +#region Environment Variables +# Workspace principal de desarrollo +export WORKSPACE_DIR="${WORKSPACE_DIR:-$HOME/dev}" +export BARBATDEV_DIR="${BARBATDEV_DIR:-$WORKSPACE_DIR/barbatdev}" +export CLAUDE_CODE_EFFORT_LEVEL=high +export CORTEX_DOTFILES_DIR="${CORTEX_DOTFILES_DIR:-$BARBATDEV_DIR/cortex/cortex-dotfiles}" + +# Proyectos de la organización +export WORK_PROJECTS_DIR="${WORK_PROJECTS_DIR:-$BARBATDEV_DIR/innit}" +export PERSONAL_PROJECTS_DIR="${PERSONAL_PROJECTS_DIR:-$BARBATDEV_DIR/products}" +export INNIT_DIR="${INNIT_DIR:-$BARBATDEV_DIR/innit}" + +# Screenshots (configurable en local/env.zsh) +export SCREENSHOTS_DIR="${SCREENSHOTS_DIR:-$HOME/Screenshots}" +#endregion + +#region Git Aliases +alias g="git" +gs() { git status "$@" } +ga() { git add "$@" } +gc() { git commit -m "$@" } +gp() { git push "$@" } +gl() { git log --oneline --graph --decorate --all } +gd() { git diff "$@" } +gco() { git checkout "$@" } +gb() { git branch "$@" } +gpl() { git pull "$@" } +gf() { git fetch "$@" } +gst() { git stash "$@" } +#endregion + +#region Navigation +alias ..="cd .." +alias ...="cd ../.." +alias ....="cd ../../.." + +_go_dev_dir() { + local target="$1" + if [[ -d "$target" ]]; then + cd "$target" + else + echo "❌ Directorio no encontrado: $target" + return 1 + fi +} + +_go_first_existing_dir() { + local target + for target in "$@"; do + if [[ -d "$target" ]]; then + cd "$target" + return + fi + done + echo "❌ Directorio no encontrado: $1" + return 1 +} + +dev() { _go_dev_dir "$HOME/dev"; } +barbat() { _go_dev_dir "$BARBATDEV_DIR"; } +cowork() { _go_first_existing_dir "$WORK_PROJECTS_DIR" "$BARBATDEV_DIR/innit"; } +personal() { _go_first_existing_dir "$PERSONAL_PROJECTS_DIR" "$BARBATDEV_DIR/products"; } +tools() { _go_dev_dir "$BARBATDEV_DIR/tools"; } +worktrees() { _go_dev_dir "$HOME/dev/worktrees"; } +work() { _go_first_existing_dir "$WORK_PROJECTS_DIR" "$BARBATDEV_DIR/innit"; } +innit() { _go_first_existing_dir "$INNIT_DIR" "$BARBATDEV_DIR/innit"; } +innit-apis() { _go_first_existing_dir "${INNIT_APIS_DIR:-$INNIT_DIR}" "$INNIT_DIR"; } +innit-mobile(){ _go_first_existing_dir "${INNIT_MOBILE_DIR:-$INNIT_DIR}" "$INNIT_DIR"; } +innit-webs() { _go_first_existing_dir "${INNIT_WEBS_DIR:-$INNIT_DIR}" "$INNIT_DIR"; } +innit-pcsoft(){ _go_first_existing_dir "${INNIT_PCSOFT_DIR:-$INNIT_DIR}" "$INNIT_DIR"; } +dotfiles() { _go_dev_dir "${_DOTFILES_DIR:-$CORTEX_DOTFILES_DIR}"; } +#endregion + +#region System Aliases +alias c="clear" +alias o="open" +alias reload="source ~/.zshrc && echo 'Profile recargado!'" + +# ls mejorado (usa eza si está instalado) +if command -v eza &>/dev/null; then + alias ll="eza -la --icons --git" + alias la="eza -la --icons --git --all" + alias lt="eza --tree --icons --level=2" +else + alias ll="ls -lah" + alias la="ls -lah -A" +fi +#endregion + +#region Clipboard +# Copiar texto al clipboard +ccp() { + if [[ -p /dev/stdin ]]; then + pbcopy + else + echo -n "$*" | pbcopy + fi + echo "✓ Copiado al clipboard" +} + +# Copiar path al clipboard +cppath() { + local path="${1:-.}" + local resolved + resolved=$(cd "$path" 2>/dev/null && pwd || realpath "$path" 2>/dev/null || echo "$path") + echo -n "$resolved" | pbcopy + echo "✓ Path copiado: $resolved" +} +#endregion + +#region Developer Tools +# Buscar archivos por nombre +ff() { + local pattern="${1:?Uso: ff }" + find . -name "*$pattern*" -not -path "*/\.*" 2>/dev/null +} + +# IP pública +myip() { + curl -s "https://api.ipify.org" + echo +} + +# Mostrar el logo de RefactorIA en Braille Unicode bajo demanda. +refactoria() { + local logo="${_DOTFILES_DIR:-$HOME/dev/personal/cortex-dotfiles}/assets/refactoria-braille.txt" + if [[ -f "$logo" ]]; then + cat "$logo" + else + echo "Logo RefactorIA no encontrado: $logo" + return 1 + fi +} + +# Matar proceso por nombre +pkill-name() { + local name="${1:?Uso: pkill-name }" + pkill -f "$name" && echo "✓ Proceso '$name' terminado" || echo "No se encontró proceso: $name" +} +#endregion + +#region Edit +# Editar archivos con el mejor editor disponible +edit() { + local path="${1:?Uso: edit }" + + # Verificar si es archivo PCSoft antes de abrir + if is-pcsoft-forbidden "$path" 2>/dev/null; then + echo "⛔ ARCHIVO PCSOFT PROHIBIDO: $path" + echo " La modificación externa corrompe el archivo permanentemente." + echo " Usá el WinDev/WebDev IDE." + return 1 + fi + + if is-pcsoft-editable "$path" 2>/dev/null; then + echo "⚠️ ARCHIVO PCSOFT EDITABLE: $path" + echo " Solo modificar bloques 'code : |1+'. El IDE debe estar CERRADO." + echo -n " ¿Continuar? [s/N] " + read -r confirm + [[ "$confirm" =~ ^[sS]$ ]] || return 0 + fi + + "$EDITOR" "$path" +} + +alias e="edit" +function ep { edit "$_DOTFILES_DIR/zsh/cortex-dotfiles.zsh" } +#endregion + +#region Source Scripts +_ZSHRC_SOURCE="${(%):-%x}" +if [[ -L "$_ZSHRC_SOURCE" ]]; then + _ZSHRC_SOURCE="$(readlink "$_ZSHRC_SOURCE")" +fi +_DOTFILES_DIR="$(cd "$(dirname "$_ZSHRC_SOURCE")/.." && pwd)" +_SCRIPTS_DIR="$_DOTFILES_DIR/zsh/scripts" + +if [[ -d "$_SCRIPTS_DIR" ]]; then + [[ -f "$_SCRIPTS_DIR/pcsoft-helpers.zsh" ]] && source "$_SCRIPTS_DIR/pcsoft-helpers.zsh" + [[ -f "$_SCRIPTS_DIR/screenshots.zsh" ]] && source "$_SCRIPTS_DIR/screenshots.zsh" + [[ -f "$_SCRIPTS_DIR/claude-helpers.zsh" ]] && source "$_SCRIPTS_DIR/claude-helpers.zsh" + [[ -f "$_SCRIPTS_DIR/git-helpers.zsh" ]] && source "$_SCRIPTS_DIR/git-helpers.zsh" + [[ -f "$_SCRIPTS_DIR/ssh-helpers.zsh" ]] && source "$_SCRIPTS_DIR/ssh-helpers.zsh" + [[ -f "$_SCRIPTS_DIR/herdr-helpers.zsh" ]] && source "$_SCRIPTS_DIR/herdr-helpers.zsh" + [[ -f "$_SCRIPTS_DIR/tmux-helpers.zsh" ]] && source "$_SCRIPTS_DIR/tmux-helpers.zsh" + [[ -f "$_SCRIPTS_DIR/worktree-helpers.zsh" ]] && source "$_SCRIPTS_DIR/worktree-helpers.zsh" + [[ -f "$_SCRIPTS_DIR/agent-state.sh" ]] && source "$_SCRIPTS_DIR/agent-state.sh" +fi + +alias cortex.agent_state.v1="cortex_agent_state" +alias agent-state="cortex_agent_state" +#endregion + +#region Local Overrides +# Cargar configuración local (gitignored: paths personales, tokens, etc.) +_LOCAL_ENV="$_DOTFILES_DIR/local/env.zsh" +[[ -f "$_LOCAL_ENV" ]] && source "$_LOCAL_ENV" +#endregion + +#region Atuin +# Historial de shell con búsqueda avanzada (reemplaza Ctrl+R) +if command -v atuin &>/dev/null; then + eval "$(atuin init zsh)" +fi +#endregion + +#region Starship +if command -v starship &>/dev/null; then + eval "$(starship init zsh)" +fi +#endregion + +#region Welcome +_welcome() { + local ms + ms=$(printf "%.0f" "$(( (EPOCHREALTIME - _PROFILE_START) * 1000 ))") + + echo "" + echo " ╔══════════════════════════════════════╗" + echo " ║ Dev Environment ║" + echo " ╠══════════════════════════════════════╣" + printf " ║ ⚡ Cargado en \033[1;32m%sms\033[0m\n" "$ms" + printf " ║ 🕐 \033[1;34m%s\033[0m\n" "$(date '+%H:%M:%S')" + echo " ╚══════════════════════════════════════╝" + echo "" + echo " \033[90mescribí\033[0m \033[1;33mhelp-profile\033[0m \033[90mpara ver comandos disponibles\033[0m" + echo "" +} + +help-profile() { + local T="\033[1;33m" # título (amarillo) + local C="\033[1;36m" # comando (cyan) + local R="\033[0m" # reset + + echo "" + echo "${T}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${R}" + echo "${T} Zsh — Referencia rápida ${R}" + echo "${T}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${R}" + + echo "\n${T}Git identidades${R}" + echo " ${C}git-workdev ${R}Setear identidad de trabajo en repo actual" + echo " ${C}git-personaldev ${R}Setear identidad personal en repo actual" + echo " ${C}git-whoami ${R}Ver identidad y remote configurados" + echo " ${C}clone-workdev ${R}Clonar repo de cuenta de trabajo" + echo " ${C}clone-personaldev ${R}Clonar repo de cuenta personal" + + echo "\n${T}Navegación${R}" + echo " ${C}dev ${R}cd ~/dev" + echo " ${C}barbat ${R}cd ~/dev/barbat" + echo " ${C}cowork ${R}cd ~/dev/cowork" + echo " ${C}personal ${R}cd ~/dev/personal" + echo " ${C}tools ${R}cd ~/dev/tools" + echo " ${C}worktrees ${R}cd ~/dev/worktrees" + echo " ${C}work ${R}cd ~/dev/work" + echo " ${C}innit ${R}cd ~/dev/innit" + echo " ${C}innit-apis ${R}cd ~/dev/innit/apis" + echo " ${C}innit-mobile ${R}cd ~/dev/innit/mobile" + echo " ${C}innit-webs ${R}cd ~/dev/innit/webs" + echo " ${C}innit-pcsoft ${R}cd ~/dev/innit/pcsoft" + echo " ${C}dotfiles ${R}cd ~/dev/personal/dotfiles" + echo " ${C}.., ..., .... ${R}Subir 1, 2 o 3 niveles" + + echo "\n${T}Claude Code${R}" + echo " ${C}cc [path] ${R}Abrir Claude Code en directorio" + echo " ${C}oc [path] ${R}Abrir OpenCode en directorio" + echo " ${C}ccx [p] ${R}Claude Code con contexto inicial" + echo " ${C}ccd [sub] ${R}Navegar al Claude workspace" + echo " ${C}ccclip ${R}Copiar código al clipboard" + + echo "\n${T}Tmux — sesiones${R}" + echo " ${C}tcc ${R}Abrir Claude Code + lazygit (layout automático)" + echo " ${C}tdev ${R}Sesión con nombre del directorio actual" + echo " ${C}ta [nombre] ${R}Attach a sesión (o crearla)" + echo " ${C}tn ${R}Nueva sesión con nombre" + echo " ${C}tl ${R}Listar sesiones activas" + echo " ${C}tk ${R}Matar sesión" + + echo "\n${T}Tmux — keybindings${R}" + echo " ${C}Ctrl+A R ${R}Recargar config" + echo " ${C}Ctrl+A Space ${R}Ver todos los keybindings (which-key)" + echo " ${C}Ctrl+A | ${R}Split vertical" + echo " ${C}Ctrl+A - ${R}Split horizontal" + echo " ${C}Ctrl+A hjkl ${R}Navegar entre paneles" + echo " ${C}Ctrl+A Ctrl+S ${R}Guardar sesiones (resurrect)" + echo " ${C}Ctrl+A Ctrl+R ${R}Restaurar sesiones (resurrect)" + echo " ${C}Option+G ${R}Popup flotante (scratch)" + echo "" +} + +_welcome +#endregion + +# opencode +export PATH=$HOME/.opencode/bin:$PATH + +# bun +export BUN_INSTALL="$HOME/.bun" +export PATH="$BUN_INSTALL/bin:$PATH" + +# bun completions +[ -s "$BUN_INSTALL/_bun" ] && source "$BUN_INSTALL/_bun" +export PATH="/opt/homebrew/opt/bc/bin:$PATH" diff --git a/zsh/scripts/claude-helpers.zsh b/zsh/scripts/claude-helpers.zsh index 3a0d857..5c6d183 100644 --- a/zsh/scripts/claude-helpers.zsh +++ b/zsh/scripts/claude-helpers.zsh @@ -26,7 +26,7 @@ _cortex_run_agent() { local command_string="" local arg created workspace - if [[ "${CORTEX_MULTIPLEXER:-cmux}" == "cmux" && -n "${CMUX_WORKSPACE_ID:-}" && "$target" != "$PWD" ]]; then + if [[ "${CORTEX_MULTIPLEXER:-${CORTEX_DOTFILES_MULTIPLEXER:-cmux}}" == "cmux" && -n "${CMUX_WORKSPACE_ID:-}" && "$target" != "$PWD" ]]; then for arg in "${agent_command[@]}"; do command_string+="${(q)arg} " done diff --git a/zsh/scripts/worktree-helpers.zsh b/zsh/scripts/worktree-helpers.zsh index cede88f..d95eec6 100644 --- a/zsh/scripts/worktree-helpers.zsh +++ b/zsh/scripts/worktree-helpers.zsh @@ -82,7 +82,7 @@ wtadd() { echo "✓ Worktree creado: $wt_path" - if [[ "${CORTEX_MULTIPLEXER:-cmux}" == "cmux" ]]; then + if [[ "${CORTEX_MULTIPLEXER:-${CORTEX_DOTFILES_MULTIPLEXER:-cmux}}" == "cmux" ]]; then echo "→ Abriendo agente para el worktree..." cc "$wt_path" fi diff --git a/zsh/zshrc b/zsh/zshrc index be6ab0d..cdcf712 100644 --- a/zsh/zshrc +++ b/zsh/zshrc @@ -1,366 +1,21 @@ -#region Header -# Dev Zsh Profile — macOS + Ghostty -# YOUR_NAME - YOUR_ORG -#endregion +# zsh bootstrap: dotfiles first, Cortex integration last. -#region Performance -zmodload zsh/datetime -_PROFILE_START=$EPOCHREALTIME -#endregion +_cortex_dotfiles_source_optional() { + local label="$1" + local path="$2" -#region Brew -if command -v brew &>/dev/null; then - eval "$(brew shellenv)" -fi -#endregion - -#region PATH -export PATH="$HOME/.local/bin:$PATH" -[[ -d "/Applications/cmux.app/Contents/Resources/bin" ]] && export PATH="/Applications/cmux.app/Contents/Resources/bin:$PATH" -#endregion - -#region Zsh Options -# Historia -HISTFILE="$HOME/.zsh_history" -HISTSIZE=10000 -SAVEHIST=10000 -setopt HIST_IGNORE_DUPS # no guardar duplicados consecutivos -setopt HIST_IGNORE_SPACE # no guardar comandos que empiezan con espacio -setopt SHARE_HISTORY # compartir historia entre sesiones - -# Navegación -setopt AUTO_CD # escribir un directorio lo hace cd -setopt AUTO_PUSHD # cd empuja al stack (podés usar popd) -setopt PUSHD_SILENT # sin output en pushd/popd - -# Completado -autoload -Uz compinit && compinit -zstyle ':completion:*' menu select -zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' # case insensitive - -# Sin beep -setopt NO_BEEP -#endregion - -#region Editor -if command -v nvim &>/dev/null; then - export EDITOR="$(command -v nvim)" -elif command -v vim &>/dev/null; then - export EDITOR="$(command -v vim)" -else - export EDITOR="nano" -fi -export VISUAL="$EDITOR" -#endregion - -#region Environment Variables -# Workspace principal de desarrollo -export WORKSPACE_DIR="${WORKSPACE_DIR:-$HOME/dev}" -export BARBATDEV_DIR="${BARBATDEV_DIR:-$WORKSPACE_DIR/barbatdev}" -export CLAUDE_CODE_EFFORT_LEVEL=high -export CORTEX_HOME="${CORTEX_HOME:-$HOME/.cortex}" -export CORTEX_ROOT="${CORTEX_ROOT:-$BARBATDEV_DIR/cortex/cortex}" -export CORTEX_DOTFILES_DIR="${CORTEX_DOTFILES_DIR:-$BARBATDEV_DIR/cortex/cortex-dotfiles}" -export CORTEX_MULTIPLEXER="${CORTEX_MULTIPLEXER:-cmux}" - -# Proyectos de la organización -export WORK_PROJECTS_DIR="${WORK_PROJECTS_DIR:-$BARBATDEV_DIR/innit}" -export PERSONAL_PROJECTS_DIR="${PERSONAL_PROJECTS_DIR:-$BARBATDEV_DIR/products}" -export INNIT_DIR="${INNIT_DIR:-$BARBATDEV_DIR/innit}" - -# Screenshots (configurable en local/env.zsh) -export SCREENSHOTS_DIR="${SCREENSHOTS_DIR:-$HOME/Screenshots}" -#endregion - -#region Git Aliases -alias g="git" -gs() { git status "$@" } -ga() { git add "$@" } -gc() { git commit -m "$@" } -gp() { git push "$@" } -gl() { git log --oneline --graph --decorate --all } -gd() { git diff "$@" } -gco() { git checkout "$@" } -gb() { git branch "$@" } -gpl() { git pull "$@" } -gf() { git fetch "$@" } -gst() { git stash "$@" } -#endregion - -#region Navigation -alias ..="cd .." -alias ...="cd ../.." -alias ....="cd ../../.." - -_go_dev_dir() { - local target="$1" - if [[ -d "$target" ]]; then - cd "$target" - else - echo "❌ Directorio no encontrado: $target" - return 1 - fi -} - -_go_first_existing_dir() { - local target - for target in "$@"; do - if [[ -d "$target" ]]; then - cd "$target" - return - fi - done - echo "❌ Directorio no encontrado: $1" - return 1 -} - -dev() { _go_dev_dir "$HOME/dev"; } -barbat() { _go_dev_dir "$BARBATDEV_DIR"; } -cowork() { _go_first_existing_dir "$WORK_PROJECTS_DIR" "$BARBATDEV_DIR/innit"; } -personal() { _go_first_existing_dir "$PERSONAL_PROJECTS_DIR" "$BARBATDEV_DIR/products"; } -tools() { _go_dev_dir "$BARBATDEV_DIR/tools"; } -worktrees() { _go_dev_dir "$HOME/dev/worktrees"; } -work() { _go_first_existing_dir "$WORK_PROJECTS_DIR" "$BARBATDEV_DIR/innit"; } -innit() { _go_first_existing_dir "$INNIT_DIR" "$BARBATDEV_DIR/innit"; } -innit-apis() { _go_first_existing_dir "${INNIT_APIS_DIR:-$INNIT_DIR}" "$INNIT_DIR"; } -innit-mobile(){ _go_first_existing_dir "${INNIT_MOBILE_DIR:-$INNIT_DIR}" "$INNIT_DIR"; } -innit-webs() { _go_first_existing_dir "${INNIT_WEBS_DIR:-$INNIT_DIR}" "$INNIT_DIR"; } -innit-pcsoft(){ _go_first_existing_dir "${INNIT_PCSOFT_DIR:-$INNIT_DIR}" "$INNIT_DIR"; } -dotfiles() { _go_dev_dir "${_DOTFILES_DIR:-$CORTEX_DOTFILES_DIR}"; } -#endregion - -#region System Aliases -alias c="clear" -alias o="open" -alias reload="source ~/.zshrc && echo 'Profile recargado!'" - -# ls mejorado (usa eza si está instalado) -if command -v eza &>/dev/null; then - alias ll="eza -la --icons --git" - alias la="eza -la --icons --git --all" - alias lt="eza --tree --icons --level=2" -else - alias ll="ls -lah" - alias la="ls -lah -A" -fi -#endregion - -#region Clipboard -# Copiar texto al clipboard -ccp() { - if [[ -p /dev/stdin ]]; then - pbcopy - else - echo -n "$*" | pbcopy - fi - echo "✓ Copiado al clipboard" -} - -# Copiar path al clipboard -cppath() { - local path="${1:-.}" - local resolved - resolved=$(cd "$path" 2>/dev/null && pwd || realpath "$path" 2>/dev/null || echo "$path") - echo -n "$resolved" | pbcopy - echo "✓ Path copiado: $resolved" -} -#endregion - -#region Developer Tools -# Buscar archivos por nombre -ff() { - local pattern="${1:?Uso: ff }" - find . -name "*$pattern*" -not -path "*/\.*" 2>/dev/null -} - -# IP pública -myip() { - curl -s "https://api.ipify.org" - echo -} - -# Mostrar el logo de RefactorIA en Braille Unicode bajo demanda. -refactoria() { - local logo="${_DOTFILES_DIR:-$HOME/dev/personal/cortex-dotfiles}/assets/refactoria-braille.txt" - if [[ -f "$logo" ]]; then - cat "$logo" - else - echo "Logo RefactorIA no encontrado: $logo" - return 1 + [[ -r "$path" ]] || return 0 + if ! source "$path"; then + print -u2 -- "zsh: no se pudo cargar $label: $path" fi + return 0 } -# Matar proceso por nombre -pkill-name() { - local name="${1:?Uso: pkill-name }" - pkill -f "$name" && echo "✓ Proceso '$name' terminado" || echo "No se encontró proceso: $name" -} -#endregion - -#region Edit -# Editar archivos con el mejor editor disponible -edit() { - local path="${1:?Uso: edit }" - - # Verificar si es archivo PCSoft antes de abrir - if is-pcsoft-forbidden "$path" 2>/dev/null; then - echo "⛔ ARCHIVO PCSOFT PROHIBIDO: $path" - echo " La modificación externa corrompe el archivo permanentemente." - echo " Usá el WinDev/WebDev IDE." - return 1 - fi - - if is-pcsoft-editable "$path" 2>/dev/null; then - echo "⚠️ ARCHIVO PCSOFT EDITABLE: $path" - echo " Solo modificar bloques 'code : |1+'. El IDE debe estar CERRADO." - echo -n " ¿Continuar? [s/N] " - read -r confirm - [[ "$confirm" =~ ^[sS]$ ]] || return 0 - fi - - "$EDITOR" "$path" -} - -alias e="edit" -function ep { edit "$_DOTFILES_DIR/zsh/zshrc" } -#endregion - -#region Source Scripts -_ZSHRC_SOURCE="${(%):-%x}" -if [[ -L "$_ZSHRC_SOURCE" ]]; then - _ZSHRC_SOURCE="$(readlink "$_ZSHRC_SOURCE")" -fi -_DOTFILES_DIR="$(cd "$(dirname "$_ZSHRC_SOURCE")/.." && pwd)" -_SCRIPTS_DIR="$_DOTFILES_DIR/zsh/scripts" - -if [[ -d "$_SCRIPTS_DIR" ]]; then - [[ -f "$_SCRIPTS_DIR/pcsoft-helpers.zsh" ]] && source "$_SCRIPTS_DIR/pcsoft-helpers.zsh" - [[ -f "$_SCRIPTS_DIR/screenshots.zsh" ]] && source "$_SCRIPTS_DIR/screenshots.zsh" - [[ -f "$_SCRIPTS_DIR/claude-helpers.zsh" ]] && source "$_SCRIPTS_DIR/claude-helpers.zsh" - [[ -f "$_SCRIPTS_DIR/git-helpers.zsh" ]] && source "$_SCRIPTS_DIR/git-helpers.zsh" - [[ -f "$_SCRIPTS_DIR/ssh-helpers.zsh" ]] && source "$_SCRIPTS_DIR/ssh-helpers.zsh" - [[ -f "$_SCRIPTS_DIR/herdr-helpers.zsh" ]] && source "$_SCRIPTS_DIR/herdr-helpers.zsh" - [[ -f "$_SCRIPTS_DIR/tmux-helpers.zsh" ]] && source "$_SCRIPTS_DIR/tmux-helpers.zsh" - [[ -f "$_SCRIPTS_DIR/worktree-helpers.zsh" ]] && source "$_SCRIPTS_DIR/worktree-helpers.zsh" - [[ -f "$_SCRIPTS_DIR/agent-state.sh" ]] && source "$_SCRIPTS_DIR/agent-state.sh" -fi - -alias cortex.agent_state.v1="cortex_agent_state" -alias agent-state="cortex_agent_state" -#endregion - -#region Local Overrides -# Cargar configuración local (gitignored: paths personales, tokens, etc.) -_LOCAL_ENV="$_DOTFILES_DIR/local/env.zsh" -[[ -f "$_LOCAL_ENV" ]] && source "$_LOCAL_ENV" -#endregion - -#region Cortex Shell Integration -_CORTEX_SHELL_INTEGRATION_PATH="${CORTEX_SHELL_INTEGRATION:-$CORTEX_HOME/shell/cortex.zsh}" -[[ -r "$_CORTEX_SHELL_INTEGRATION_PATH" ]] && source "$_CORTEX_SHELL_INTEGRATION_PATH" -unset _CORTEX_SHELL_INTEGRATION_PATH -#endregion - -#region Atuin -# Historial de shell con búsqueda avanzada (reemplaza Ctrl+R) -if command -v atuin &>/dev/null; then - eval "$(atuin init zsh)" -fi -#endregion - -#region Starship -if command -v starship &>/dev/null; then - eval "$(starship init zsh)" -fi -#endregion - -#region Welcome -_welcome() { - local ms - ms=$(printf "%.0f" "$(( (EPOCHREALTIME - _PROFILE_START) * 1000 ))") - - echo "" - echo " ╔══════════════════════════════════════╗" - echo " ║ Dev Environment ║" - echo " ╠══════════════════════════════════════╣" - printf " ║ ⚡ Cargado en \033[1;32m%sms\033[0m\n" "$ms" - printf " ║ 🕐 \033[1;34m%s\033[0m\n" "$(date '+%H:%M:%S')" - echo " ╚══════════════════════════════════════╝" - echo "" - echo " \033[90mescribí\033[0m \033[1;33mhelp-profile\033[0m \033[90mpara ver comandos disponibles\033[0m" - echo "" -} - -help-profile() { - local T="\033[1;33m" # título (amarillo) - local C="\033[1;36m" # comando (cyan) - local R="\033[0m" # reset - - echo "" - echo "${T}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${R}" - echo "${T} Zsh — Referencia rápida ${R}" - echo "${T}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${R}" - - echo "\n${T}Git identidades${R}" - echo " ${C}git-workdev ${R}Setear identidad de trabajo en repo actual" - echo " ${C}git-personaldev ${R}Setear identidad personal en repo actual" - echo " ${C}git-whoami ${R}Ver identidad y remote configurados" - echo " ${C}clone-workdev ${R}Clonar repo de cuenta de trabajo" - echo " ${C}clone-personaldev ${R}Clonar repo de cuenta personal" - - echo "\n${T}Navegación${R}" - echo " ${C}dev ${R}cd ~/dev" - echo " ${C}barbat ${R}cd ~/dev/barbat" - echo " ${C}cowork ${R}cd ~/dev/cowork" - echo " ${C}personal ${R}cd ~/dev/personal" - echo " ${C}tools ${R}cd ~/dev/tools" - echo " ${C}worktrees ${R}cd ~/dev/worktrees" - echo " ${C}work ${R}cd ~/dev/work" - echo " ${C}innit ${R}cd ~/dev/innit" - echo " ${C}innit-apis ${R}cd ~/dev/innit/apis" - echo " ${C}innit-mobile ${R}cd ~/dev/innit/mobile" - echo " ${C}innit-webs ${R}cd ~/dev/innit/webs" - echo " ${C}innit-pcsoft ${R}cd ~/dev/innit/pcsoft" - echo " ${C}dotfiles ${R}cd ~/dev/personal/dotfiles" - echo " ${C}.., ..., .... ${R}Subir 1, 2 o 3 niveles" - - echo "\n${T}Claude Code${R}" - echo " ${C}cc [path] ${R}Abrir Claude Code en directorio" - echo " ${C}oc [path] ${R}Abrir OpenCode en directorio" - echo " ${C}ccx [p] ${R}Claude Code con contexto inicial" - echo " ${C}ccd [sub] ${R}Navegar al Claude workspace" - echo " ${C}ccclip ${R}Copiar código al clipboard" - - echo "\n${T}Tmux — sesiones${R}" - echo " ${C}tcc ${R}Abrir Claude Code + lazygit (layout automático)" - echo " ${C}tdev ${R}Sesión con nombre del directorio actual" - echo " ${C}ta [nombre] ${R}Attach a sesión (o crearla)" - echo " ${C}tn ${R}Nueva sesión con nombre" - echo " ${C}tl ${R}Listar sesiones activas" - echo " ${C}tk ${R}Matar sesión" - - echo "\n${T}Tmux — keybindings${R}" - echo " ${C}Ctrl+A R ${R}Recargar config" - echo " ${C}Ctrl+A Space ${R}Ver todos los keybindings (which-key)" - echo " ${C}Ctrl+A | ${R}Split vertical" - echo " ${C}Ctrl+A - ${R}Split horizontal" - echo " ${C}Ctrl+A hjkl ${R}Navegar entre paneles" - echo " ${C}Ctrl+A Ctrl+S ${R}Guardar sesiones (resurrect)" - echo " ${C}Ctrl+A Ctrl+R ${R}Restaurar sesiones (resurrect)" - echo " ${C}Option+G ${R}Popup flotante (scratch)" - echo "" -} - -_welcome -#endregion - -# opencode -export PATH=$HOME/.opencode/bin:$PATH +_CORTEX_DOTFILES_SHELL_PATH="${CORTEX_DOTFILES_SHELL_ENTRYPOINT:-$HOME/.config/cortex-dotfiles/shell/cortex-dotfiles.zsh}" +_CORTEX_SHELL_PATH="${CORTEX_SHELL_INTEGRATION:-${CORTEX_HOME:-$HOME/.cortex}/shell/cortex.zsh}" -# bun -export BUN_INSTALL="$HOME/.bun" -export PATH="$BUN_INSTALL/bin:$PATH" +_cortex_dotfiles_source_optional "cortex-dotfiles" "$_CORTEX_DOTFILES_SHELL_PATH" +_cortex_dotfiles_source_optional "Cortex" "$_CORTEX_SHELL_PATH" -# bun completions -[ -s "$BUN_INSTALL/_bun" ] && source "$BUN_INSTALL/_bun" -export PATH="/opt/homebrew/opt/bc/bin:$PATH" +unset _CORTEX_DOTFILES_SHELL_PATH _CORTEX_SHELL_PATH +unfunction _cortex_dotfiles_source_optional