# /full-git-push — Push automático 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/` 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/`, `analysis/`, `projects/*/apps/` y `projects/*/analysis/` debe tener su propio repo Gitea bajo `dataforge/`. Los `subrepos/` de la raiz NO entran (mirrors upstream). Los `vaults/` tampoco. **Modo automático (preferencia del usuario):** este comando NO pregunta. Si hay dirty trees, commitea automáticamente con un mensaje generado a partir de los cambios. Prioridad: hacer commits frecuentes y pushear rápido. **Único límite:** no commitear archivos que parezcan secrets (`.env`, `*credentials*`, `*.key`, `*.pem`, `id_rsa*`) — si se detectan, abortar y avisar. ## Argumento `$ARGUMENTS` — opcional. Si se pasa texto, se usa como mensaje de commit. Sin argumento, se genera uno automáticamente con el patrón: ``` chore: auto-commit ( archivos modificados, nuevos, borrados) - - ... ``` Si los cambios tienen un patrón claro (todos en un mismo dominio/dir), usar ese patrón en el subject: - todo bajo `python/functions//` → `feat(): auto-commit con N cambios` - todo bajo `dev/issues/` → `chore(issues): auto-commit` - mezclado → `chore: auto-commit` ## Pasos ### 1. Descubrir repos git + apps/analyses sin git ```bash cd /home/lucas/fn_registry REPOS=$(find . -name ".git" -type d \ -not -path "./.git" -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" # Apps/analyses sin .git — auto-inicializar como dataforge/ MISSING=() for d in apps/*/ analysis/*/ projects/*/apps/*/ projects/*/analysis/*/; do d="${d%/}" [[ -d "$d/.git" ]] || MISSING+=("$d") done ``` ### 1b. Auto-inicializar repos faltantes (sin pedir confirmación) Para cada `$d` en `MISSING`: ```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' " ``` Si `$d/.gitignore` no existe antes de inicializar, escribir uno apropiado (ver `.claude/rules/apps_vs_functions.md`). Solo abortar la inicialización de ese repo concreto si falla; seguir con el resto. ### 2. Detectar secrets antes de commitear Para cada repo dirty, listar archivos modificados/nuevos y comprobar nombres sospechosos: ```bash for r in $REPOS; do ( cd "$r" \ && git status --porcelain | awk '{print $2}' \ | grep -E '(^|/)(\.env(\..*)?$|.*credentials.*|.*\.key$|.*\.pem$|id_rsa.*|.*secret.*|.*token.*\.txt$)' \ | head -5 ) done ``` Si la lista de coincidencias **no está vacía**, abortar el push completo, listar los archivos sospechosos y pedir al usuario que los gestione (añadir a `.gitignore`, mover, o decidir explícitamente que entren). ### 3. Auto-commitear dirty trees Para cada repo con cambios sin commitear: ```bash for r in $REPOS; do ( cd "$r" [ -z "$(git status --porcelain)" ] && exit 0 # limpio, nada que hacer git add -A if [ -n "$ARGUMENTS" ]; then MSG="$ARGUMENTS" else MSG="$(generate_auto_message)" # patrón descrito en sección 'Argumento' fi git commit -m "$MSG" \ -m "Co-Authored-By: Claude Opus 4.7 (1M context) " 2>&1 | tail -3 ) done ``` `generate_auto_message` debe inspeccionar `git diff --cached --stat` y producir un subject como `feat(notebook): N cambios` cuando todos los paths comparten prefijo, o `chore: auto-commit` si están dispersos. ### 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 git push -u origin "$BRANCH" 2>&1 | tail -3 fi ) done ``` Si `push` rechaza por non-fast-forward (rama behind), no abortar el resto. Reportar ese repo concreto y sugerir `/full-git-pull` antes; seguir con los demás repos. ### 5. fn sync ```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 bloqueado. Pedir al usuario que ejecute `pass show registry/api-token` en su terminal real (Bash tool no tiene TTY) y reintentar. ### 6. Resumen Tabla concisa: por repo, commits creados (cuántos y subject), commits pusheados, o "ya estaba al día". Y resultado de `fn sync` (sent / received / imported). ## Notas - **Modo no-interactivo por diseño.** El usuario prefiere commits frecuentes y push rápido. No se pregunta si commitear ni se pide mensaje (salvo que se pase via `$ARGUMENTS`). - **Secrets son la única razón para abortar antes de commitear.** Cualquier patrón sospechoso (`.env`, credenciales, claves) detiene el flujo y se reporta al usuario. - Submodules `cpp/vendor/` (mirrors upstream) se ignoran. - Si un sub-repo va `behind` el remote, su push se omite con un mensaje (no se aborta el resto). El usuario corre `/full-git-pull` cuando le convenga.