# /full-git-push — Push de fn_registry + todos los sub-repos + fn sync

Pushea el repo principal `fn_registry` y todos los sub-repos git anidados (apps y analyses, cada uno como repo independiente bajo `dataforge/<name>` en Gitea), y luego ejecuta `fn sync` para empujar la metadata no regenerable (proposals, apps, projects, analysis, vaults, pc_locations) al `registry_api`.

**Estandar:** todo `apps/<name>`, `analysis/<name>`, `projects/*/apps/<name>` y `projects/*/analysis/<name>` debe tener su propio repo Gitea bajo `dataforge/<basename>`. Los `subrepos/` de la raiz NO entran (son mirrors upstream que no se pushean desde aqui). Los `vaults/` tampoco — son datos puros con su propio mecanismo de compartir (TBD).

## Argumento

`$ARGUMENTS` — opcional. Si se pasa texto, se usa como mensaje de commit por defecto cuando algún repo tenga cambios sin commitear y el usuario apruebe commitear durante el flujo. Sin argumento, se pregunta el mensaje al detectar dirty tree.

## Pasos

### 1. Descubrir repos git + apps/analyses sin git en el workspace

```bash
cd /home/lucas/fn_registry  # ajustar al PC

# 1a) Repos git ya existentes (sin subrepos/, sin cpp/vendor/, sin sources/, sin temp/)
REPOS=$(find . -name ".git" -type d \
  -not -path "./.git/*" \
  -not -path "*/node_modules/*" \
  -not -path "*/.venv/*" \
  -not -path "*/cpp/vendor/*" \
  -not -path "*/cpp/build/*" \
  -not -path "*/sources/*" \
  -not -path "*/temp/*" \
  -not -path "*/subrepos/*" 2>/dev/null | sed 's|/.git$||')
REPOS=". $REPOS"

# 1b) Apps y analyses SIN .git — candidatos a inicializar
MISSING=()
for d in apps/*/ analysis/*/ projects/*/apps/*/ projects/*/analysis/*/; do
  d="${d%/}"
  [[ -d "$d/.git" ]] || MISSING+=("$d")
done
```

Si `MISSING` no esta vacio, listarlos al usuario y preguntar si inicializarlos como repos `dataforge/<basename>` antes de continuar (paso 1c).

### 1c. Inicializar repos faltantes (opcional, requiere confirmacion)

Para cada `$d` aprobado por el usuario:

```bash
export GITEA_URL=$(pass agentes/gitea-url | head -n1)
export GITEA_TOKEN=$(pass gitea/dataforge-git-token | head -n1)
export FN_REGISTRY_INFRA_DIR=/home/lucas/fn_registry/bash/functions/infra

bash -c "
  source $FN_REGISTRY_INFRA_DIR/ensure_repo_synced.sh
  ensure_repo_synced '$d' dataforge \"\$(basename '$d')\" master 'chore: initial sync'
"
```

**Antes de inicializar**, comprobar que `$d/.gitignore` existe; si no, escribir uno apropiado (ver `.claude/rules/apps_vs_functions.md` para patrones tipicos: excluir `.venv/`, `node_modules/`, binarios, `operations.db*`, `.jupyter*`, `__pycache__/`).

### 2. Para cada repo, mostrar estado

```bash
for r in $REPOS; do
  echo "=== $r ==="
  ( cd "$r" && git status -sb && echo "" )
done
```

### 3. Manejar dirty trees

- Si **algún repo** tiene cambios sin commitear: lista los archivos al usuario y **pregunta** qué hacer:
  - (a) commitear todo con un mensaje (usar `$ARGUMENTS` si está, si no preguntar)
  - (b) stashear y seguir solo con los commits ahead
  - (c) abortar
- Nunca commitear sin permiso explícito.

### 4. Push de cada repo

```bash
for r in $REPOS; do
  ( cd "$r" \
    && BRANCH=$(git rev-parse --abbrev-ref HEAD) \
    && if git rev-parse --abbrev-ref --symbolic-full-name @{u} >/dev/null 2>&1; then
         git push origin "$BRANCH" 2>&1 | tail -3
       else
         echo "[$r] no upstream para '$BRANCH' — saltado"
       fi
  )
done
```

### 5. fn sync con credenciales de pass

```bash
USER=$(pass registry/basicauth-user | head -1)
PASSWD=$(pass registry/basicauth-pass | head -1)
TOKEN=$(pass registry/api-token | head -1)
export FN_REGISTRY_API="https://${USER}:${PASSWD}@registry.organic-machine.com"
export REGISTRY_API_TOKEN="$TOKEN"
./fn sync
```

Si `pass` falla con "decryption failed" → gpg-agent locked. Pedir al usuario que ejecute `pass show registry/api-token` en su terminal real (Bash tool no tiene TTY) y reintentar.

### 6. Resumen

Imprimir tabla concisa: para cada repo, branch, commits pusheados o "ya estaba al día". Y resultado de `fn sync` (sent / received / imported).

## Notas

- Es responsabilidad del comando **pushear**, no decidir qué commitear. Solo commitea si el usuario lo aprueba explícitamente.
- Los submodules del directorio `cpp/vendor/` (imgui, implot, glfw, tracy, implot3d) se ignoran (son mirrors upstream, no se pushean desde aquí).
- Si una rama va `behind` el remote, abortar el push de ese repo y avisar para correr `/full-git-pull` primero.
