Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
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
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
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
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,15 @@ jobs:
shellcheck --severity=error --shell=bash "${bash_files[@]}"
fi

- name: Run Fish W2 and W3 harnesses
- name: Run Fish migration harnesses
shell: bash
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
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,31 @@ Para validar sin tocar identidades reales ni la red:
/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 @@ -236,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
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
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
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/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
58 changes: 58 additions & 0 deletions fish/functions/hhere.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Enter the main Herdr session for a path. Usage: hhere [path]
function hhere --description 'Enter the main Herdr session for a path'
if not command -q herdr
printf 'hhere: herdr is not available\n' >&2
return 127
end
set -l target $PWD
test (count $argv) -ge 1; and set target $argv[1]
set -l resolved (cd -- "$target" >/dev/null 2>&1; and pwd -P)
if test -z "$resolved"
printf 'Directorio no encontrado: %s\n' "$target" >&2
return 1
end
set -l host $HOST
if test -z "$host"
set host (hostname -s 2>/dev/null; or hostname)
end
set host (string split -m 1 . -- "$host")[1]
set -l context local
test -n "$SSH_CONNECTION$SSH_CLIENT$SSH_TTY"; and set context ssh
set -l workspace_label (basename "$resolved" | string replace -a . -)
set -l git_root (git -C "$resolved" rev-parse --show-toplevel 2>/dev/null)
if test -n "$git_root"
set -l repo_name (basename "$git_root" | string replace -a . -)
set -l parent_name (dirname "$git_root" | xargs basename | string replace -a . -)
set -l branch (git -C "$git_root" branch --show-current 2>/dev/null)
set workspace_label "$parent_name"-"$repo_name"
test -n "$branch"; and set workspace_label "$workspace_label"-(string replace -ra '[^A-Za-z0-9_.-]' - "$branch")
end
set -l session "$context"-"$host"-"$workspace_label"
if test "$HERDR_ENV" = 1
if not command -q python3
printf 'hhere: python3 is not available\n' >&2
return 127
end
set -l workspace_id (herdr workspace list 2>/dev/null | python3 -c '
import json
import sys
label = sys.argv[1]
try:
data = json.load(sys.stdin)
except Exception:
sys.exit(0)
for workspace in data.get("result", {}).get("workspaces", []):
if workspace.get("label") == label:
print(workspace.get("workspace_id", ""))
break
' "$workspace_label" 2>/dev/null)
if test -n "$workspace_id"
herdr workspace focus "$workspace_id" >/dev/null; or return
else
herdr workspace create --cwd "$resolved" --label "$workspace_label" --focus >/dev/null; or return
end
printf 'workspace: %s\n' "$workspace_label"
return 0
end
env CORTEX_MULTIPLEXER=herdr herdr --session "$session"
end
4 changes: 4 additions & 0 deletions fish/functions/hl.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# List Herdr workspaces. Usage: hl [herdr args...]
function hl --description 'List Herdr workspaces'
h workspace list $argv
end
4 changes: 4 additions & 0 deletions fish/functions/hmain.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Enter the main Herdr session for a path. Usage: hmain [path]
function hmain --description 'Enter the main Herdr session for a path'
hhere $argv
end
30 changes: 30 additions & 0 deletions fish/functions/hname.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Rename the current Herdr pane. Usage: hname [label]
function hname --description 'Rename the current Herdr pane'
if not command -q herdr
printf 'hname: herdr is not available\n' >&2
return 127
end
if not command -q python3
printf 'hname: python3 is not available\n' >&2
return 127
end
set -l label $argv[1]
if test -z "$label"
set label (basename "$PWD" | string replace -a . -)
set -l git_root (git rev-parse --show-toplevel 2>/dev/null)
if test -n "$git_root"
set -l repo_name (basename "$git_root" | string replace -a . -)
set -l parent_name (dirname "$git_root" | xargs basename | string replace -a . -)
set -l branch (git -C "$git_root" branch --show-current 2>/dev/null)
set label "$parent_name"-"$repo_name"
test -n "$branch"; and set label "$label"-(string replace -ra '[^A-Za-z0-9_.-]' - "$branch")
end
end
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)
if test -z "$pane_id"
printf 'No pude detectar el pane actual de Herdr\n' >&2
return 1
end
herdr pane rename "$pane_id" "$label" >/dev/null; or return
printf 'pane: %s\n' "$label"
end
4 changes: 4 additions & 0 deletions fish/functions/hnew.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Enter a fresh timestamped Herdr session. Usage: hnew [path]
function hnew --description 'Enter a fresh Herdr session'
hrole "new-"(date +%H%M%S)-(random) $argv
end
20 changes: 20 additions & 0 deletions fish/functions/hremote.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Attach to a remote Herdr session. Usage: hremote <ssh-target> [session]
function hremote --description 'Attach to a remote Herdr session'
if test (count $argv) -lt 1
printf 'Usage: hremote <ssh-target> [session]\n' >&2
return 2
end

if not command -q herdr
printf 'hremote: herdr is not available\n' >&2
return 127
end

set -l target $argv[1]
set -l session main
if test (count $argv) -ge 2
set session $argv[2]
end

env CORTEX_MULTIPLEXER=herdr CORTEX_SSH_TARGET="$target" herdr --remote "$target" --session "$session"
end
Loading
Loading