Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a2124fb
feat(fish): port identity and worktree safeguards
barbatdev Aug 21, 2026
ed16ccc
feat(fish): restore hremote parity
barbatdev Aug 21, 2026
4e437fb
feat(fish): port remaining Herdr and SSH helpers
barbatdev Aug 21, 2026
6a0882f
feat(fish): port screenshot workflows
barbatdev Aug 21, 2026
33c9281
feat(fish): port safe agent helpers
barbatdev Aug 21, 2026
dd1b21a
feat(fish): enable autonomous agent shortcuts
barbatdev Aug 21, 2026
79a1c91
Merge branch 'tmp/cortex-chain-02' into tmp/cortex-chain-03
barbatdev Aug 22, 2026
4c0a17a
Merge branch 'tmp/cortex-chain-03' into tmp/cortex-chain-04
barbatdev Aug 22, 2026
9e526a9
Merge branch 'tmp/cortex-chain-04' into tmp/cortex-chain-05
barbatdev Aug 22, 2026
fd66edf
Merge branch 'tmp/cortex-chain-05' into tmp/cortex-chain-06
barbatdev Aug 22, 2026
5a51958
Merge branch 'tmp/cortex-chain-06' into tmp/cortex-chain-07
barbatdev Aug 22, 2026
66032ec
Merge branch 'tmp/cortex-portable-02' into tmp/cortex-portable-03
barbatdev Aug 22, 2026
f19532f
test(fish): resolve W3 interpreter portably
barbatdev Aug 22, 2026
8e626f9
Merge branch 'tmp/cortex-portable-03' into tmp/cortex-portable-04
barbatdev Aug 22, 2026
9a4446b
test(fish): resolve hremote interpreter portably
barbatdev Aug 22, 2026
5aaf904
Merge branch 'tmp/cortex-portable-04' into tmp/cortex-portable-05
barbatdev Aug 22, 2026
8b65d91
test(fish): resolve Herdr and SSH interpreter portably
barbatdev Aug 22, 2026
c59b64a
Merge branch 'tmp/cortex-portable-05' into tmp/cortex-portable-06
barbatdev Aug 22, 2026
28dcbed
test(fish): resolve screenshot interpreter portably
barbatdev Aug 22, 2026
7635d75
Merge branch 'tmp/cortex-portable-06' into tmp/cortex-portable-07
barbatdev Aug 22, 2026
a7aa578
test(fish): resolve agent interpreter portably
barbatdev Aug 22, 2026
7392cb9
test(fish): make missing-agent assertion portable
barbatdev Aug 22, 2026
320bef2
Merge pull request #55 from barbatdev/feat/cortex-migration-07-agents
barbatdev Aug 22, 2026
f249b0a
Merge pull request #54 from barbatdev/feat/cortex-migration-06-screen…
barbatdev Aug 22, 2026
77afdc3
Merge pull request #53 from barbatdev/feat/cortex-migration-05-herdr-ssh
barbatdev Aug 22, 2026
25b243e
Merge pull request #52 from barbatdev/feat/cortex-migration-04-hremote
barbatdev Aug 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,15 @@ jobs:
shellcheck --severity=error --shell=bash "${bash_files[@]}"
fi

- name: Run Fish W2 harness
- name: Run Fish migration harnesses
shell: bash
run: fish fish/tests/w2-core.fish
run: |
fish fish/tests/w2-core.fish
fish fish/tests/w3-helpers.fish
fish fish/tests/w4b-screenshots.fish
fish fish/tests/w5a-hremote.fish
fish fish/tests/w5b-herdr-ssh.fish
fish fish/tests/w6-agent-helpers.fish

- name: Validate JSON configs
shell: bash
Expand Down
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,55 @@ Para validar sin tocar configuración real:

La evaluación Nix permanece diferida: esta unidad no genera `flake.lock` ni ejecuta activación.

## Helpers Fish: Git, PCSoft y worktrees (W3)

W3 suma helpers Fish opt-in para identidades Git, protección de archivos PCSoft y worktrees; no crea `~/.ssh/config`, no clona durante la configuración y no modifica la identidad global de Git.

### Uso seguro

1. Copiá `fish/conf.d/99-local.fish.example` a tu `99-local.fish` privado y definí las cuatro variables `GIT_*_NAME` y `GIT_*_EMAIL`.
2. En un repositorio, usá `git-workdev` o `git-personaldev`; si falta un valor privado, el helper falla antes de cambiar la configuración local o el remote.
3. Usá `clone-workdev` o `clone-personaldev` solo cuando quieras clonar: enrutan la URL mediante `github-workdev` o `github-personaldev`.

| Área | Interfaz rastreada | Estado privado del host |
| --- | --- | --- |
| Identidades Git | `git-workdev`, `git-personaldev`, `git-whoami`, `clone-*` y aliases SSH `github-workdev` / `github-personaldev` | nombre, email, claves y `~/.ssh/config` |
| PCSoft | `is-pcsoft-forbidden`, `is-pcsoft-editable`, `edit` | IDE Windows y estado del proyecto |
| Worktrees | `wtadd`, `wtlist`, `wtremove`; `wtadd` bloquea repos PCSoft antes de mutar | directorios de worktree y procesos locales |

`edit` rechaza extensiones PCSoft prohibidas y pide confirmación para las editables. `wtremove` elimina solamente el worktree nombrado: verificá `wtlist` antes de usarlo. Home Manager mapea cada función explícitamente; no administra el directorio completo, claves, remotes, historial ni variables privadas.

Para validar sin tocar identidades reales ni la red:

```bash
/opt/homebrew/bin/fish fish/tests/w3-helpers.fish
```

## Helpers Fish: screenshots (W4b)

W4b agrega `ss`, `last`, `ssd` e `imgclip` sin capturar la pantalla ni leer el clipboard durante la carga. `SCREENSHOTS_DIR` usa el override solo si apunta a un directorio existente; si no, conserva el fallback de macOS: `~/Screenshots` cuando existe y luego `~/Desktop`. Home Manager mapea cada función explícitamente y no administra el directorio, screenshots ni clipboard del host.

Para validar con `HOME`, `PATH` y comandos macOS falsos aislados:

```bash
/opt/homebrew/bin/fish fish/tests/w4b-screenshots.fish
```

## Helpers Fish de agentes (W6)

**ADVERTENCIA:** por elección explícita del owner, `cc` ejecuta Claude Code con `--dangerously-skip-permissions` y `oc`/`ocb` ejecutan OpenCode con `--auto`; estos shortcuts intencionalmente omiten o autoaprueban permisos. W6 agrega `cc`, `oc`, `ocb`, `ccx`, `ccd` y `ccclip` como helpers Fish opt-in en el directorio validado; `ccx` entrega el contexto por stdin y `ccclip` escribe al clipboard solo al invocarse. No incluye `ccb`.

| Área | Owner en W6 |
| --- | --- |
| Helpers y soporte privado | `fish/functions/{_cortex_resolve_target,_cortex_run_agent,cc,oc,ocb,ccx,ccd,ccclip}.fish` |
| Home Manager | Mapea cada una de esas funciones de forma explícita; no administra binarios de agentes, clipboard, worktrees, estado, historial ni configuración de proveedores |

Para validar con agentes y clipboard falsos aislados:

```bash
/opt/homebrew/bin/fish fish/tests/w6-agent-helpers.fish
```

## Estructura

```
Expand Down Expand Up @@ -212,6 +261,8 @@ Editá `local/env.zsh` (gitignored) para configurar:

Referencia completa: [Herdr workflow](docs/herdr-workflow.md). Atajos prácticos: [keymaps](docs/keymaps.md).

El profile Fish también expone `h`, `hs`, `hl`, `hhere`, `hmain`, `hrole`, `hnew`, `hfocus`, `hside`, `hscratch`, `hname`, `whereami`, `sshc`, `sshx` y `sshx-doctor`; Home Manager mapea cada función de forma explícita.

Usá `hremote` desde tu terminal local en macOS. No hagas `ssh` primero y después intentes levantar `herdr` dentro de esa sesión remota.

- Para pegar una imagen del clipboard local en la terminal remota, usá `Ctrl+V` por defecto (no `Cmd+V`).
Expand Down
5 changes: 5 additions & 0 deletions fish/conf.d/99-local.fish.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@
# set -gx WORKSPACE_DIR "$HOME/dev"
# set -gx INNIT_APIS_DIR "$HOME/dev/innit/apis"
# set -gx EDITOR nvim
# Private Git identities: both values are required before git-workdev or git-personaldev can change a repository.
# set -gx GIT_WORKDEV_NAME "Your work name"
# set -gx GIT_WORKDEV_EMAIL "you@company.invalid"
# set -gx GIT_PERSONALDEV_NAME "Your personal name"
# set -gx GIT_PERSONALDEV_EMAIL "you@personal.invalid"
11 changes: 11 additions & 0 deletions fish/functions/_cortex_resolve_target.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function _cortex_resolve_target
set -l target "$argv[1]"
test -n "$target"; or set target .

if not test -d "$target"
printf 'Directorio no encontrado: %s\n' "$target" >&2
return 1
end

cd "$target"; and pwd
end
11 changes: 11 additions & 0 deletions fish/functions/_cortex_run_agent.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function _cortex_run_agent
set -l target "$argv[1]"
set -e argv[1]
set -l original_dir "$PWD"

cd "$target"; or return 1
command $argv
set -l agent_status $status
cd "$original_dir"; or return 1
return "$agent_status"
end
23 changes: 23 additions & 0 deletions fish/functions/_git_config_identity.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
function _git_config_identity --argument-names name email alias label route_marker
if test -z "$name"; or test -z "$email"
printf 'Missing private %s identity: set name and email in 99-local.fish.\n' "$label" >&2
return 1
end

git rev-parse --is-inside-work-tree >/dev/null 2>&1; or begin
printf 'Not inside a Git repository.\n' >&2
return 1
end

git config --local user.name "$name"; and git config --local user.email "$email"; or return 1
set -l url (git remote get-url origin 2>/dev/null)
if string match -q '*github.com*' -- "$url"; or string match -q "*$route_marker*" -- "$url"
set -l new_url (string replace -r '^git@github[^:]*:' "git@$alias:" -- "$url")
if test "$new_url" != "$url"
git remote set-url origin "$new_url"; or return 1
printf 'Remote updated: %s\n' "$new_url"
end
end

printf 'Identity: %s (%s)\n' "$label" "$email"
end
5 changes: 5 additions & 0 deletions fish/functions/_parse_github_repo.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function _parse_github_repo --argument-names input
set input (string replace -r '\.git$' '' -- "$input")
set input (string replace -r '^https://github\.com/' '' -- "$input")
string replace -r '^git@github[^:]*:' '' -- "$input"
end
20 changes: 20 additions & 0 deletions fish/functions/_screenshot_files.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function _screenshot_files
set -l directory (_screenshots_dir)
set -l files

# BSD find lacks GNU -maxdepth, so retain the source helper's two-level scope in Fish.
for file in (command find "$directory" -type f -print0 2>/dev/null | string split0)
set -l relative (string replace -- "$directory/" '' "$file")
set -l components (string split / -- "$relative")
test (count $components) -le 2; or continue

switch (path extension "$file")
case .png .jpg .jpeg .gif
set -a files "$file"
end
end

if test (count $files) -gt 0
command ls -t $files 2>/dev/null
end
end
13 changes: 13 additions & 0 deletions fish/functions/_screenshots_dir.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function _screenshots_dir
if set -q SCREENSHOTS_DIR; and test -n "$SCREENSHOTS_DIR"; and test -d "$SCREENSHOTS_DIR"
printf '%s\n' "$SCREENSHOTS_DIR"
return
end

set -l default "$HOME/Screenshots"
if test -d "$default"
printf '%s\n' "$default"
else
printf '%s\n' "$HOME/Desktop"
end
end
20 changes: 20 additions & 0 deletions fish/functions/_time_ago.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function _time_ago
set -l file "$argv[1]"
set -l now (command date +%s)
set -l mtime (command stat -f %m "$file" 2>/dev/null)

if test $status -ne 0; or test -z "$mtime"
set mtime "$now"
end

set -l difference (math "$now - $mtime")
if test "$difference" -lt 60
printf 'justo ahora\n'
else if test "$difference" -lt 3600
printf '%sm ago\n' (math "$difference / 60")
else if test "$difference" -lt 86400
printf '%sh ago\n' (math "$difference / 3600")
else
printf '%sd ago\n' (math "$difference / 86400")
end
end
3 changes: 3 additions & 0 deletions fish/functions/_wt_git_root.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function _wt_git_root
git rev-parse --show-toplevel 2>/dev/null
end
4 changes: 4 additions & 0 deletions fish/functions/_wt_is_pcsoft_repo.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
function _wt_is_pcsoft_repo
set -l root (_wt_git_root); or return 1
git -C "$root" ls-files 2>/dev/null | string match -rqi '\.(wdp|wwp|wpp|wpj|wwh|wpw|prw|wdd|fic|mmo|ndx|wdr|wdq|wdi|wdt|wdv|wdk|rep|sty|cpl|bkp|wdg|wdc|wde|wdw)$'
end
3 changes: 3 additions & 0 deletions fish/functions/_wt_path_for.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function _wt_path_for --argument-names git_root name
printf '%s/dev/worktrees/%s/%s\n' "$HOME" (path basename "$git_root") "$name"
end
5 changes: 5 additions & 0 deletions fish/functions/cc.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Usage: cc [path]
function cc
set -l resolved (_cortex_resolve_target "$argv[1]"); or return 1
_cortex_run_agent "$resolved" claude --dangerously-skip-permissions
end
43 changes: 43 additions & 0 deletions fish/functions/ccclip.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Usage: ccclip <file...> [-n|--line-numbers]
function ccclip
if test (count $argv) -eq 0
printf 'Uso: ccclip <archivo1> [archivo2 ...] [-n|--line-numbers]\n' >&2
return 1
end

set -l with_numbers false
set -l files
for arg in $argv
switch "$arg"
case -n --line-numbers
set with_numbers true
case '*'
set -a files "$arg"
end
end

begin
for file in $files
if not test -f "$file"
printf 'Archivo no encontrado: %s\n' "$file" >&2
continue
end

set -l extension (path extension "$file" | string trim -c .)
printf '```%s\n// File: %s\n' "$extension" "$file"
set -l content
if test "$with_numbers" = true
set content (nl -ba "$file" | string collect)
else
set content (command cat "$file" | string collect)
end
printf '%s\n```\n\n' "$content"
end
end | pbcopy
set -l clipboard_status $pipestatus[-1]
if test "$clipboard_status" -ne 0
return "$clipboard_status"
end

printf 'Contexto copiado al clipboard (%d archivos)\n' (count $files)
end
16 changes: 16 additions & 0 deletions fish/functions/ccd.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Usage: ccd [subpath]
function ccd
set -l subpath "$argv[1]"
set -l workspace "$WORKSPACE_DIR"
test -n "$workspace"; or set workspace "$HOME/dev"
set -l target "$workspace"
test -n "$subpath"; and set target "$workspace/$subpath"

if test -d "$target"
cd "$target"
printf 'Navegando a: %s\n' "$target"
else
printf 'Directorio no encontrado: %s\n' "$target" >&2
return 1
end
end
14 changes: 14 additions & 0 deletions fish/functions/ccx.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Usage: ccx <context> [path]
function ccx
set -l context "$argv[1]"
if test -z "$context"
printf 'Uso: ccx <contexto> [directorio]\n' >&2
return 1
end

set -l resolved (_cortex_resolve_target "$argv[2]"); or return 1
begin
printf '%s\n' "$context" | _cortex_run_agent "$resolved" claude
return $pipestatus[-1]
end
end
8 changes: 8 additions & 0 deletions fish/functions/clone-personaldev.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function clone-personaldev
if test (count $argv) -lt 1
printf 'Usage: clone-personaldev <org/repo|url>\n' >&2
return 1
end
set -l repo (_parse_github_repo "$argv[1]")
git clone "git@github-personaldev:$repo.git"
end
8 changes: 8 additions & 0 deletions fish/functions/clone-workdev.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function clone-workdev
if test (count $argv) -lt 1
printf 'Usage: clone-workdev <org/repo|url>\n' >&2
return 1
end
set -l repo (_parse_github_repo "$argv[1]")
git clone "git@github-workdev:$repo.git"
end
19 changes: 19 additions & 0 deletions fish/functions/edit.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
function edit
if test (count $argv) -lt 1
printf 'Usage: edit <file>\n' >&2
return 1
end

set -l target "$argv[1]"
if is-pcsoft-forbidden "$target"
printf 'PCSoft forbidden file: %s\nUse the WinDev/WebDev IDE.\n' "$target" >&2
return 1
end
if is-pcsoft-editable "$target"
printf "PCSoft editable file: %s\nOnly edit 'code : |1+' blocks with the IDE closed.\nContinue? [s/N] " "$target"
read -l confirm
string match -qr '^[sS]$' -- "$confirm"; or return 0
end

"$EDITOR" "$target"
end
3 changes: 3 additions & 0 deletions fish/functions/git-personaldev.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function git-personaldev
_git_config_identity "$GIT_PERSONALDEV_NAME" "$GIT_PERSONALDEV_EMAIL" github-personaldev personaldev github-personal
end
6 changes: 6 additions & 0 deletions fish/functions/git-whoami.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
function git-whoami
set -l name (git config user.name 2>/dev/null; or echo 'no configurado')
set -l email (git config user.email 2>/dev/null; or echo 'no configurado')
set -l remote (git remote get-url origin 2>/dev/null; or echo 'sin remote')
printf ' nombre : %s\n email : %s\n remote : %s\n' "$name" "$email" "$remote"
end
3 changes: 3 additions & 0 deletions fish/functions/git-workdev.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function git-workdev
_git_config_identity "$GIT_WORKDEV_NAME" "$GIT_WORKDEV_EMAIL" github-workdev workdev github-work
end
8 changes: 8 additions & 0 deletions fish/functions/h.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Run Herdr directly. Usage: h [herdr args...]
function h --description 'Run Herdr directly'
if not command -q herdr
printf 'h: herdr is not available\n' >&2
return 127
end
command herdr $argv
end
20 changes: 20 additions & 0 deletions fish/functions/herdr-orient.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Print the current host, repository, SSH, and Herdr context. Usage: herdr-orient
function herdr-orient --description 'Print the current Herdr context'
printf 'host: %s\n' (hostname -s 2>/dev/null; or hostname)
printf 'cwd: %s\n' "$PWD"
if git rev-parse --is-inside-work-tree >/dev/null 2>&1
printf 'repo: %s\n' (git rev-parse --show-toplevel)
set -l branch (git branch --show-current 2>/dev/null)
test -n "$branch"; or set branch detached
printf 'branch: %s\n' "$branch"
end
if test -n "$SSH_CONNECTION"
set -l ssh_target $CORTEX_SSH_TARGET
test -n "$ssh_target"; or set ssh_target remote
printf 'ssh: %s\n' "$ssh_target"
end
if command -q herdr; and command -q python3
set -l pane_id (herdr pane current --current 2>/dev/null | python3 -c 'import json,sys; print(json.load(sys.stdin)["result"]["pane"]["pane_id"])' 2>/dev/null)
test -n "$pane_id"; and printf 'herdr: %s\n' "$pane_id"
end
end
4 changes: 4 additions & 0 deletions fish/functions/hfocus.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Enter the focused Herdr role session. Usage: hfocus [path]
function hfocus --description 'Enter the focused Herdr role session'
hrole focus $argv
end
Loading
Loading