import: contenido inicial de la skill gitea
This commit is contained in:
347
SKILL.md
Normal file
347
SKILL.md
Normal file
@@ -0,0 +1,347 @@
|
||||
---
|
||||
name: gitea
|
||||
description: Da acceso a la instancia self-hosted de Gitea del beneficio Rio Frio (gitea.nucleoriofrio.com, org NucleOS). Úsala para crear/listar/ver PRs, leer comentarios, crear repos (en NucleOS o en tu propio usuario claudeCode0 — los del usuario del bot quedan SIEMPRE públicos por regla dura), y la killer feature — verificar runs de Gitea Actions post-merge (status, logs filtrados con --tail/--head/--errors/--grep, sin volcar el log entero a la ventana). Cubre los casos "mergeé el PR, ¿deployó OK?", "creame un repo nuevo para la skill X", reemplaza los curl ad-hoc anteriores. Ejemplos: "listame los PRs abiertos en nucleo-infra", "creá un PR desde la branch X a main", "qué pasó con el último deploy", "buscame los errores en el run 11 del workflow deploy-infra", "mostrame las últimas 30 líneas de logs del run que falló", "creá un repo skill-foo en mi usuario", "crea repo en NucleOS llamado servicio-X privado".
|
||||
allowed-tools: Bash, Read, Grep
|
||||
---
|
||||
|
||||
# Gitea — skill de PRs + Actions de gitea.nucleoriofrio.com
|
||||
|
||||
## Qué es esto
|
||||
|
||||
Skill para interactuar con la instancia **self-hosted de Gitea** del beneficio
|
||||
Rio Frio (`gitea.nucleoriofrio.com`, Gitea 1.24.7) hostea el org **`NucleOS`**.
|
||||
Resuelve dos casos de uso principales:
|
||||
|
||||
1. **Crear/leer PRs** sin escribir curl ad-hoc cada vez (con guards anti-AI
|
||||
attribution y body UTF-8 safe).
|
||||
2. **Killer feature**: introspección de runs de Gitea Actions post-merge —
|
||||
`actions-list-runs`, `actions-view`, `actions-logs`. Cierra el loop GitOps:
|
||||
yo mergeo un PR, el workflow `deploy-infra.yml` dispara, y con la skill
|
||||
verifico que deployó OK sin necesitar SSH a nucleo001.
|
||||
|
||||
Las operaciones admin (Actions secrets/variables) están **bloqueadas** porque
|
||||
el PAT de `claudecode0` no es admin del org. Hay un override `GITEA_USER_PAT`
|
||||
para esos casos one-shot.
|
||||
|
||||
- **Server**: `https://gitea.nucleoriofrio.com`
|
||||
- **Auth**: `Authorization: token <PAT>` (PAT de `claudecode0` en `.env`,
|
||||
extraído de la skill `bitwarden` por `setup.sh`)
|
||||
- **Override admin**: `GITEA_USER_PAT=...` en el entorno (one-shot temporal)
|
||||
|
||||
## Cómo invocarla correctamente
|
||||
|
||||
Antes de cualquier query:
|
||||
|
||||
1. **Verificá `~/.claude/skills/gitea/.env`**. Si no existe o está vacío:
|
||||
```bash
|
||||
bash ~/.claude/skills/gitea/scripts/setup.sh
|
||||
```
|
||||
Eso extrae el PAT desde la skill `bitwarden` (item con substring "Gitea PAT
|
||||
claude-agent-gitops") y lo escribe al `.env`. Re-corré `setup.sh` cada vez
|
||||
que rotás el PAT.
|
||||
|
||||
2. **Si una query devuelve 401**: el PAT está revocado o el item correcto
|
||||
en bitwarden cambió. Re-corré `setup.sh`. Si persiste, podría ser que
|
||||
`setup.sh` está agarrando el PAT duplicado equivocado (hay dos items con
|
||||
el mismo nombre en bitwarden, ver "Errores típicos").
|
||||
|
||||
## Scripts disponibles
|
||||
|
||||
| Script | Propósito |
|
||||
|---|---|
|
||||
| `setup.sh` | Extrae PAT de bitwarden, escribe `.env`, valida con `/version` |
|
||||
| `query.sh` | Helper REST genérico con admin-guard (foundation de todos los demás) |
|
||||
| `pr-list.sh` | Lista PRs (con `--state open\|closed\|all`, `--limit N`) |
|
||||
| `pr-view.sh` | Ver detalle de un PR (incluye body completo) |
|
||||
| `pr-comments.sh` | Lista comentarios de un PR (requiere PAT con `read:issue`) |
|
||||
| `pr-create.sh` | Crear PR con guards anti-AI-attribution + body UTF-8 safe |
|
||||
| `repo-create.sh` | Crear repo (default owner = bot user; **regla dura**: bot user → siempre público) |
|
||||
| `actions-list-runs.sh` | Lista runs (filtros client-side: workflow, branch, status, event) |
|
||||
| `actions-view.sh` | Detalle de un run + probe del job_id |
|
||||
| `actions-logs.sh` | Lee logs con filtros precisos (--tail/--head/--lines/--grep/--errors) |
|
||||
|
||||
Ver `endpoints.md` para los endpoints crudos de la API.
|
||||
|
||||
## Modelo de seguridad
|
||||
|
||||
### Admin guard en `query.sh`
|
||||
|
||||
`query.sh` bloquea cualquier path que matchee:
|
||||
- `/admin/*` (operaciones admin del server)
|
||||
- `/orgs/{org}/actions/(secrets|variables)/*`
|
||||
- `/repos/{o}/{r}/actions/(secrets|variables)/*`
|
||||
|
||||
Mensaje del guard: pide al usuario un PAT temporal con scope admin, lo exporta
|
||||
como `GITEA_USER_PAT=...`, y le **recuerda BORRAR el PAT** desde
|
||||
`https://gitea.nucleoriofrio.com/user/settings/applications` apenas termine
|
||||
(Gitea no tiene PATs efímeros nativos).
|
||||
|
||||
```bash
|
||||
# Bypass legítimo del guard:
|
||||
export GITEA_USER_PAT=<el-pat-temporal-admin>
|
||||
bash ~/.claude/skills/gitea/scripts/query.sh /repos/NucleOS/X/actions/secrets
|
||||
unset GITEA_USER_PAT # limpiar al terminar
|
||||
```
|
||||
|
||||
### Anti-AI-attribution guard en `pr-create.sh`
|
||||
|
||||
**Regla dura** (ver memoria `feedback_no_ai_attribution.md`). Antes de POST,
|
||||
escanea title + body por (case-insensitive):
|
||||
|
||||
- `Co-Authored-By: Claude` (o `Anthropic`)
|
||||
- `🤖`
|
||||
- `Generated with [Claude Code]` / `Generated with Claude` / `Generated with Anthropic`
|
||||
- `Created with Claude` / `Powered by Claude` / `Made with Claude`
|
||||
|
||||
Si match → exit 4 con mensaje + las líneas ofensivas. Esto es **imposibilitar**,
|
||||
no advertir — el usuario considera deshonesto darle crédito a Claude/Anthropic
|
||||
por trabajo del usuario.
|
||||
|
||||
### Visibilidad de repos del bot (regla dura)
|
||||
|
||||
`repo-create.sh` rechaza `--private` cuando el owner es el bot user
|
||||
(case-insensitive match contra `$GITEA_BOT_USER`). Justificación: la cuenta
|
||||
`claudeCode0` es del bot, pero el usuario humano tiene que poder auditarla
|
||||
sin login. Si los repos del bot fueran privados, sería una caja negra. Para
|
||||
algo realmente privado, crearlo bajo la org NucleOS.
|
||||
|
||||
Para repos en orgs (NucleOS u otra), el flag `--public` o `--private` es
|
||||
**requerido** — sin default sorpresa. Forzá la decisión consciente.
|
||||
|
||||
### Scope del PAT de claudecode0
|
||||
|
||||
El PAT cacheado tiene scope: `write:organization`, `write:package`,
|
||||
`write:repository`, `write:user`. **NO incluye `read:issue` / `write:issue`**,
|
||||
así que `pr-comments.sh` (que lee issue comments) puede devolver 403. Si el
|
||||
usuario quiere usar `pr-comments` o crear PRs con descripciones largas que
|
||||
generen comentarios, debe regenerar el PAT con esos scopes adicionales y
|
||||
re-correr `setup.sh`.
|
||||
|
||||
## Cuándo usar qué endpoint
|
||||
|
||||
### Caso típico: "mergeé el PR, ¿deployó OK?"
|
||||
|
||||
Después de mergear un PR a main en `nucleo-infra`, el workflow corre. Para
|
||||
verificar:
|
||||
|
||||
```bash
|
||||
# 1. Ver el último run del workflow:
|
||||
bash ~/.claude/skills/gitea/scripts/actions-list-runs.sh NucleOS/nucleo-infra --limit 3
|
||||
|
||||
# 2. Si está in_progress, esperar 30-60s y reintentar.
|
||||
# Si terminó, ver los logs:
|
||||
bash ~/.claude/skills/gitea/scripts/actions-logs.sh NucleOS/nucleo-infra <run_number>
|
||||
|
||||
# 3. Si falló, buscar errores específicos:
|
||||
bash ~/.claude/skills/gitea/scripts/actions-logs.sh NucleOS/nucleo-infra <run> --errors -C 3
|
||||
```
|
||||
|
||||
### "Quiero crear un PR"
|
||||
|
||||
Para body con tildes/ñ, **siempre** pasarlo via `--body-file`. NO usar heredoc
|
||||
inline (memoria `feedback_api_utf8_encoding.md`):
|
||||
|
||||
```bash
|
||||
# Crear el body en un archivo (con Write tool, UTF-8 nativo):
|
||||
cat > /c/Users/jodar/AppData/Local/Temp/pr-body.md <<'EOF'
|
||||
## Qué cambia
|
||||
|
||||
Esto arregla el bug X — resumen de cambios.
|
||||
|
||||
## Por qué
|
||||
[...]
|
||||
EOF
|
||||
|
||||
bash ~/.claude/skills/gitea/scripts/pr-create.sh NucleOS/nucleo-infra \
|
||||
--head fix/foo \
|
||||
--title "fix(x): short imperative" \
|
||||
--body-file /c/Users/jodar/AppData/Local/Temp/pr-body.md
|
||||
```
|
||||
|
||||
Para body simple sin caracteres especiales, `--body "..."` inline también va.
|
||||
|
||||
### "Listame PRs abiertos"
|
||||
|
||||
```bash
|
||||
bash ~/.claude/skills/gitea/scripts/pr-list.sh NucleOS/nucleo-infra
|
||||
# Default state=open, limit=20.
|
||||
```
|
||||
|
||||
### "Ver detalle del PR #14"
|
||||
|
||||
```bash
|
||||
bash ~/.claude/skills/gitea/scripts/pr-view.sh NucleOS/nucleo-infra 14
|
||||
```
|
||||
|
||||
### "Mostrame solo los runs que fallaron"
|
||||
|
||||
```bash
|
||||
bash ~/.claude/skills/gitea/scripts/actions-list-runs.sh NucleOS/nucleo-infra \
|
||||
--status failure --limit 20
|
||||
```
|
||||
|
||||
### "Buscá errores en el run 7"
|
||||
|
||||
```bash
|
||||
bash ~/.claude/skills/gitea/scripts/actions-logs.sh NucleOS/nucleo-infra 7 --errors -C 3
|
||||
# --errors es shortcut para --grep '(error|fail|fatal|exception|panic|...)'
|
||||
```
|
||||
|
||||
### "Quiero el log entero del run X para grep-ear con mis tools"
|
||||
|
||||
```bash
|
||||
bash ~/.claude/skills/gitea/scripts/actions-logs.sh NucleOS/nucleo-infra X \
|
||||
--save /c/Users/jodar/AppData/Local/Temp/run-X.log
|
||||
# Guarda raw (sin sanitizar) para preservar fidelidad.
|
||||
```
|
||||
|
||||
### "Creá un repo nuevo en mi (bot) usuario"
|
||||
|
||||
Default owner = `$GITEA_BOT_USER` (claudeCode0). **Siempre público** por
|
||||
regla dura — `--private` está bloqueado bajo el bot user (exit 5):
|
||||
|
||||
```bash
|
||||
bash ~/.claude/skills/gitea/scripts/repo-create.sh skill-foo \
|
||||
--description "Skill X — qué hace" --license "MIT" --gitignore "Node"
|
||||
# → claudeCode0/skill-foo (public), html_url + clone_url + ssh_url
|
||||
```
|
||||
|
||||
### "Creá un repo en NucleOS"
|
||||
|
||||
Para org, `--public` o `--private` es **requerido** (exit 6 si no pasás
|
||||
ninguno — sin default sorpresa):
|
||||
|
||||
```bash
|
||||
bash ~/.claude/skills/gitea/scripts/repo-create.sh nuevo-servicio \
|
||||
--owner NucleOS --private --description "..." --gitignore "Go"
|
||||
```
|
||||
|
||||
## Reglas de comportamiento
|
||||
|
||||
### Filtros sobre logs son obligatorios
|
||||
|
||||
Los runs de `deploy-infra` tienen ~1700 líneas (post-sanitización). Volcar
|
||||
entero satura mi ventana. **Default es siempre summary** (header + tail 5/40
|
||||
según status). Solo usar `--full` cuando es chico, y nunca sin `--i-mean-it`
|
||||
si supera 1000 líneas.
|
||||
|
||||
### Workflow GitOps (memoria `feedback_swarm_changes_via_gitea.md`)
|
||||
|
||||
Toda modificación al Swarm va por PR + workflow. Después de mergear, **antes
|
||||
de declarar el cambio listo**, verificar con `actions-logs` que el deploy
|
||||
terminó OK. Sino, esa "termina" es prematura.
|
||||
|
||||
### Operaciones disruptivas requieren OK explícito
|
||||
|
||||
`pr-merge` no está en la skill (out of scope). Mergear con la API requiere
|
||||
construir el endpoint manualmente con `query.sh` y antes pedir confirmación
|
||||
explícita al usuario — un merge dispara deploy a producción. Memoria
|
||||
`feedback_disruptive_actions.md` aplica.
|
||||
|
||||
### PAT duplicado en bitwarden
|
||||
|
||||
Hay 2 items con substring `Gitea PAT claude-agent-gitops` en el vault de
|
||||
`claudecode0`. `setup.sh` toma el primero. Si la validación falla:
|
||||
- Listar los items: `bash ~/.claude/skills/bitwarden/scripts/query.sh "/list/object/items?search=Gitea"`
|
||||
- Pedirle al usuario que limpie el duplicado desde
|
||||
`https://vault.nucleoriofrio.com` (la skill `bitwarden` tiene DELETE bloqueado).
|
||||
|
||||
## Errores típicos
|
||||
|
||||
| Error | Causa | Qué hacer |
|
||||
|---|---|---|
|
||||
| `setup.sh` "no encontré ningún item..." | El PAT no está guardado en bitwarden | Generar PAT en Gitea + guardarlo en bitwarden con substring "Gitea PAT claude-agent-gitops" |
|
||||
| Validación 401 | PAT revocado o duplicado equivocado | Limpiar duplicados desde web vault, regenerar si es necesario, re-correr `setup.sh` |
|
||||
| `query.sh` admin guard exit 3 | Endpoint requiere admin | Pedir PAT temporal admin al usuario, exportar `GITEA_USER_PAT`, recordar borrarlo apenas termine |
|
||||
| `pr-create.sh` exit 4 | Body con AI attribution | Remover los markers (regla dura) |
|
||||
| `pr-comments.sh` 403 | PAT sin scope `read:issue` | Regenerar PAT con `read:issue`+`write:issue`, re-correr `setup.sh` |
|
||||
| `actions-logs.sh` "no pude resolver job_id" | Probe de ±10 falló (Gitea no expone listado de jobs) | Probar con `--job <jid>` directo; rangear con `query.sh /repos/.../actions/jobs/<jid>/logs` manualmente |
|
||||
| `actions-list-runs` 0 results con filtro | Filtros son client-side; el server solo respeta `limit` | Subir `--limit` (default 10) para incluir runs más viejos |
|
||||
|
||||
## Lifecycle: cuándo correr cada script
|
||||
|
||||
| Script | Cuándo |
|
||||
|---|---|
|
||||
| `setup.sh` | (a) Primera vez. (b) Cuando el PAT rota. (c) Cuando agregás scopes nuevos al PAT. (d) Cuando 401 inesperado |
|
||||
| `query.sh` | Endpoint nuevo o ad-hoc no cubierto por otros scripts |
|
||||
| `pr-*.sh` | Operaciones de PRs |
|
||||
| `actions-*.sh` | Verificar deploys, debug runs, etc. |
|
||||
|
||||
## Setup inicial (lo hace el usuario UNA vez)
|
||||
|
||||
### 1. Generar PAT en Gitea
|
||||
- `https://gitea.nucleoriofrio.com/user/settings/applications` (logueado como `claudecode0`)
|
||||
- "Generate New Token" con scopes:
|
||||
- `read:repo`, `write:repo` — push, leer/crear PRs, branches
|
||||
- `read:issue`, `write:issue` — comentarios y descripciones de PRs
|
||||
- `read:user` — sanity check de auth
|
||||
- (NO usar admin scopes acá; eso queda para PATs temporales)
|
||||
- Copiar el token (sólo se ve una vez).
|
||||
|
||||
### 2. Guardar en bitwarden (vault de claudecode0)
|
||||
- Web: `https://vault.nucleoriofrio.com` → login como `claudecode0`
|
||||
- New item: name = `claudecode0 · Gitea PAT claude-agent-gitops`
|
||||
(cualquier nombre con substring `Gitea PAT claude-agent-gitops` sirve)
|
||||
- Username: `claudecode0`. Password: el PAT.
|
||||
- Save.
|
||||
|
||||
### 3. Correr setup
|
||||
```bash
|
||||
bash ~/.claude/skills/gitea/scripts/setup.sh
|
||||
```
|
||||
|
||||
Esperado:
|
||||
```
|
||||
→ Listo: Gitea 1.24.7 | user=claudeCode0 | https://gitea.nucleoriofrio.com
|
||||
```
|
||||
|
||||
### 4. Probar
|
||||
```bash
|
||||
bash ~/.claude/skills/gitea/scripts/pr-list.sh NucleOS/nucleo-infra
|
||||
bash ~/.claude/skills/gitea/scripts/actions-list-runs.sh NucleOS/nucleo-infra --limit 3
|
||||
```
|
||||
|
||||
## Limitaciones conocidas de la API de Gitea 1.24
|
||||
|
||||
- **No hay endpoint global de runs**: `/actions/runs` 404. Usamos
|
||||
`/actions/tasks` que sí existe pero solo acepta `page`+`limit` — los demás
|
||||
filtros (workflow, branch, status, event) son client-side.
|
||||
- **No hay endpoint para listar jobs de un run**: `/actions/runs/{id}/jobs`
|
||||
404. La skill hace **probe** de job_ids en `task_id ± 10` matcheando la
|
||||
primera línea del log con `received task <task_id>`. Si tu run tiene
|
||||
múltiples jobs o el offset es mayor, falla — pasale `--job <jid>` directo.
|
||||
- **Logs por job son texto plano** (`/actions/jobs/{job_id}/logs`). Logs por
|
||||
run completo (`/actions/runs/{id}/logs`) devuelven zip — la skill **nunca
|
||||
los toca** porque no son procesables desde Bash sin extraer.
|
||||
- **Actor del run no expuesto**: `/actions/tasks` no devuelve quién disparó
|
||||
el run. Si querés saber quién mergeó, mirá el merge commit con `git log`.
|
||||
|
||||
## Qué NO hace esta skill
|
||||
|
||||
- **No mergea PRs** (out of scope; disruptive — dispara deploy a prod, requiere
|
||||
confirmación explícita del usuario y prefijar `query.sh` manualmente).
|
||||
- **No comenta PRs** (POST a issues/comments — out of scope; el PAT
|
||||
tampoco tiene scope para issues por default).
|
||||
- **No gestiona issues, releases, webhooks ni runners**. Out of scope.
|
||||
- **No lee zip de logs run-level**. Sólo job-level texto plano.
|
||||
- **No hace AI attribution** en commits ni PRs. Imposible de bypassear desde
|
||||
esta skill (regla dura).
|
||||
|
||||
## Archivos de la skill
|
||||
|
||||
| Archivo | Qué tiene |
|
||||
|---|---|
|
||||
| `SKILL.md` | Este archivo |
|
||||
| `endpoints.md` | Cheat sheet de la API de Gitea 1.24 (lo relevante) |
|
||||
| `.env.example` | Plantilla de config |
|
||||
| `.env` | Generado por `setup.sh` (NO versionado, contiene el PAT) |
|
||||
| `scripts/setup.sh` | Extrae PAT de bitwarden + valida |
|
||||
| `scripts/query.sh` | Helper REST con admin guard |
|
||||
| `scripts/pr-*.sh` | Wrappers de PRs |
|
||||
| `scripts/actions-*.sh` | Wrappers de Gitea Actions |
|
||||
|
||||
## Referencias
|
||||
|
||||
- API spec oficial Gitea: https://docs.gitea.com/api/1.24/
|
||||
- Swagger JSON de la instancia: `https://gitea.nucleoriofrio.com/swagger.v1.json`
|
||||
- `endpoints.md` — cheat sheet de los endpoints relevantes
|
||||
Reference in New Issue
Block a user