import: contenido inicial de la skill gitea

This commit is contained in:
2026-04-26 14:24:00 -06:00
parent 28e657a353
commit 768b48003d
15 changed files with 2012 additions and 1 deletions

219
scripts/repo-create.sh Normal file
View File

@@ -0,0 +1,219 @@
#!/usr/bin/env bash
# gitea skill — crear un repo en gitea.nucleoriofrio.com.
#
# Soporta dos targets:
# - usuario autenticado (claudecode0): POST /api/v1/user/repos
# - org (NucleOS u otra): POST /api/v1/orgs/{org}/repos
#
# Regla dura: cualquier repo bajo el usuario `claudecode0` (case-insensitive
# match con $GITEA_BOT_USER) DEBE ser público. La justificación es que el
# usuario humano necesita poder ver lo que el bot crea — sino la cuenta
# claudecode0 sería una caja negra. Si pasás --private a un repo bajo el bot,
# el script aborta con exit 5.
#
# Para repos en orgs, --public o --private es REQUERIDO (forzar decisión
# explícita; sin default sorpresa).
#
# Uso:
# repo-create.sh <name> [--owner <user|org>] [--description "..."]
# [--public | --private] [--no-init] [--license <tpl>]
# [--gitignore <tpl>] [--default-branch <name>] [--template]
set -euo pipefail
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
QUERY="$SKILL_DIR/scripts/query.sh"
ENV_FILE="$SKILL_DIR/.env"
if [[ ! -f "$ENV_FILE" ]]; then
echo "ERROR: $ENV_FILE no existe. Corré setup.sh primero." >&2
exit 1
fi
set -a
# shellcheck disable=SC1090
source "$ENV_FILE"
set +a
: "${GITEA_BOT_USER:?GITEA_BOT_USER no definido en .env. Re-correr setup.sh.}"
name=""
owner=""
description=""
visibility="" # "public" | "private" | ""
auto_init=1
license=""
gitignore=""
default_branch="main"
is_template=0
while [[ $# -gt 0 ]]; do
case "$1" in
--owner) owner="$2"; shift 2 ;;
--description) description="$2"; shift 2 ;;
--public) visibility="public"; shift ;;
--private) visibility="private"; shift ;;
--no-init) auto_init=0; shift ;;
--license) license="$2"; shift 2 ;;
--gitignore) gitignore="$2"; shift 2 ;;
--default-branch) default_branch="$2"; shift 2 ;;
--template) is_template=1; shift ;;
-h|--help)
cat <<EOF
Uso: repo-create.sh <name> [opciones]
Argumentos:
<name> Nombre del repo (requerido)
Owner:
--owner <user|org> Default: el usuario del bot (\$GITEA_BOT_USER, "$GITEA_BOT_USER")
Pasale "NucleOS" para crear en el org.
Visibilidad:
--public | --private Para orgs, uno es REQUERIDO (sin default).
Para el usuario del bot, --private está
BLOQUEADO (regla dura: todo lo del bot debe ser
público para que el usuario humano pueda verlo).
Contenido:
--description "..." Descripción del repo
--no-init No crear README inicial (default: auto-init=true)
--license <template> ej. "MIT", "Apache-2.0", "GPL-3.0"
--gitignore <template> ej. "Node", "Python", "Go"
--default-branch <name> default: main
--template Marcar como template repo
Devuelve URL del repo creado (clone_url + html_url).
EOF
exit 0
;;
-*) echo "ERROR: flag desconocida: $1" >&2; exit 2 ;;
*)
if [[ -z "$name" ]]; then name="$1"
else echo "ERROR: argumento extra: $1" >&2; exit 2
fi
shift
;;
esac
done
if [[ -z "$name" ]]; then
echo "ERROR: pasá <name>." >&2
echo "Uso: repo-create.sh <name> [opciones] (--help para detalles)" >&2
exit 2
fi
# Default owner = bot user
if [[ -z "$owner" ]]; then
owner="$GITEA_BOT_USER"
fi
# ─── Detectar si owner es el bot (case-insensitive) ─────────────────────
shopt -s nocasematch
is_bot_owner=0
if [[ "$owner" == "$GITEA_BOT_USER" ]]; then
is_bot_owner=1
fi
shopt -u nocasematch
# ─── Guard: visibilidad ─────────────────────────────────────────────────
if [[ "$is_bot_owner" -eq 1 ]]; then
# Regla dura: bot user → siempre público
if [[ "$visibility" == "private" ]]; then
cat >&2 <<EOF
ERROR: --private bloqueado para repos bajo el usuario del bot ($GITEA_BOT_USER).
Regla dura de la skill: todo lo que el bot crea bajo su propio usuario debe
ser PÚBLICO para que el usuario humano pueda auditarlo. Sin esa regla, la
cuenta del bot sería una caja negra.
Opciones:
- Crearlo público (omitir --private; será público por default)
- Crearlo en una org en vez del usuario del bot:
repo-create.sh $name --owner NucleOS --private
EOF
exit 5
fi
# Default: público
visibility="public"
else
# Org u otro user → visibilidad explícita requerida (sin default sorpresa)
if [[ -z "$visibility" ]]; then
cat >&2 <<EOF
ERROR: para repos en una org (owner=$owner), --public o --private es REQUERIDO.
Sin default para evitar sorpresas. Pasá una flag explícita:
repo-create.sh $name --owner $owner --public
repo-create.sh $name --owner $owner --private
EOF
exit 6
fi
fi
# Convertir visibilidad → boolean private
case "$visibility" in
public) is_private="false" ;;
private) is_private="true" ;;
*) echo "ERROR interno: visibility=$visibility" >&2; exit 99 ;;
esac
# ─── Construir endpoint ─────────────────────────────────────────────────
if [[ "$is_bot_owner" -eq 1 ]]; then
endpoint="/user/repos"
else
endpoint="/orgs/${owner}/repos"
fi
# ─── Build body con Python (UTF-8 safe, mismo patrón que pr-create) ─────
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BODY_JSON="$TMP_DIR/body.json"
PY_NAME="$name" PY_DESC="$description" PY_PRIVATE="$is_private" \
PY_AUTO_INIT="$auto_init" PY_LICENSE="$license" PY_GITIGNORE="$gitignore" \
PY_DEFAULT_BRANCH="$default_branch" PY_TEMPLATE="$is_template" \
python -c '
import json, os
data = {
"name": os.environ["PY_NAME"],
"description": os.environ.get("PY_DESC", ""),
"private": os.environ["PY_PRIVATE"] == "true",
"auto_init": os.environ["PY_AUTO_INIT"] == "1",
"default_branch": os.environ["PY_DEFAULT_BRANCH"],
"template": os.environ["PY_TEMPLATE"] == "1",
}
if os.environ.get("PY_LICENSE"):
data["license"] = os.environ["PY_LICENSE"]
if os.environ.get("PY_GITIGNORE"):
data["gitignores"] = os.environ["PY_GITIGNORE"]
print(json.dumps(data))
' > "$BODY_JSON"
# ─── POST ───────────────────────────────────────────────────────────────
echo "→ POST $endpoint" >&2
echo " name: $name" >&2
echo " owner: $owner $([ "$is_bot_owner" -eq 1 ] && echo "(bot user)" || echo "(org)")" >&2
echo " visibility: $visibility" >&2
echo " auto_init: $auto_init default_branch: $default_branch" >&2
[[ -n "$description" ]] && echo " description: $description" >&2
[[ -n "$license" ]] && echo " license: $license" >&2
[[ -n "$gitignore" ]] && echo " gitignore: $gitignore" >&2
resp="$("$QUERY" -X POST \
-H 'Content-Type: application/json; charset=utf-8' \
--data-binary @"$BODY_JSON" \
"$endpoint")"
echo "$resp" | PYTHONIOENCODING=utf-8 python -c "
import json, sys
d = json.load(sys.stdin)
if d.get('id') and d.get('full_name'):
visibility_label = 'private' if d.get('private') else 'public'
print(f'OK repo creado: {d[\"full_name\"]} ({visibility_label})')
print(f' html_url: {d.get(\"html_url\")}')
print(f' clone_url: {d.get(\"clone_url\")}')
print(f' ssh_url: {d.get(\"ssh_url\")}')
else:
print('ERROR:', d.get('message') or d, file=sys.stderr)
sys.exit(1)
"