gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1471Shell 173Rust 105Markdown 943545 Definiciones

el toolchain de la jaula sale del CORPUS, no de pacman

El agente de adentro reportó que le faltan cargo, rustc, make, pkg-config y python3. La salida obvia
—sumarlos a `packages` y `qorpa provision`— hoy NO funciona: con un mapa de un solo id, pacman no
puede chownear su directorio de descarga y muere en «failed to chown temporary download directory»,
que es exactamente la consecuencia que el aviso de qorpa viene anunciando.

Y no hace falta: las diez herramientas YA están selladas en el store, son musl estáticas y corren
dentro de la imagen glibc. Usarlas es además lo coherente con la distro —el corpus es el que provee,
no Arch—. Quedan como envoltorios en /work/<usuario>/bin, que el lanzador pone en el PATH junto con
el go y el zig del lab.

Dos errores míos que el propio control destapó y quedan escritos: el glob `/store/*-make` también
casa con `…-cargo-make` (eligió ése y `make` moría en un `exec` que no nombraba la causa) — ahora el
nombre se compara entero quitándole el hash; y el control daba ✓ a todo porque `cmd | head` devuelve
el estado de head, o sea siempre 0.

Probadas las diez: make 4.4.1, pkgconf 2.5.1, python3 3.12.10, jq 1.8.1, rsync 3.5.0, git 2.54.0,
curl 8.20.0, takana 0.0.1, rustc y cargo 1.97.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

afdc4ffb9b675d6697ee67e6d6d44afbc2f074f1 · por Sergio · (hace 1 mes) · padre b54b97f8c · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

2 archivos · +71 −3

diff --git a/scripts/servidor/claude-caja.sh b/scripts/servidor/claude-caja.sh
index a369339f..7d871573 100755
--- a/scripts/servidor/claude-caja.sh
+++ b/scripts/servidor/claude-caja.sh
@@ -107,13 +107,15 @@ _proy="${PROY:-$PWD}"
 [ -d "$_proy" ] || _proy=/opt/takana
 
 exec takana qorpa run "$_inst" -- sh -c \
-  'hogar="$1"; proy="$2"; shift 2
+  'hogar="$1"; proy="$2"; yo="$3"; shift 3
    cd "$proy" 2>/dev/null || { echo "claude: adentro de la jaula no existe \"$proy\" — ¿está concedido ese directorio en la instancia? (ver grants.dirs)" >&2; exit 1; }
+   # `/work/<usuario>/bin` trae el toolchain del CORPUS (make, python3, rustc, cargo, takana…):
+   # musl estáticos del store, que corren dentro de la imagen glibc. Lo arma jaula-herramientas.sh.
    # ⚠ EL PATH DEL LAB, que ningún doc decía y muerde en el primer build (2026-09-18, reportado por
    # el agente de adentro): `takana build` invoca `go` y `zig` por nombre, y en la imagen de la jaula
    # no están. Muere con `spawn go mod vendor: No such file or directory`, que no menciona el PATH.
    # Viven en el lab, que ya está concedido.
    exec env HOME="$hogar" TERM="${TERM:-xterm-256color}" \
-        PATH="/work/dev-fs/tools/go/bin:/work/dev-fs/tools/zig:$PATH" \
+        PATH="/work/$yo/bin:/work/dev-fs/tools/go/bin:/work/dev-fs/tools/zig:$PATH" \
         /work/claude-cli/2.1.240 "$@"' \
-  _ "$_hogar" "$_proy" "$@"
+  _ "$_hogar" "$_proy" "$_yo" "$@"
diff --git a/scripts/servidor/jaula-herramientas.sh b/scripts/servidor/jaula-herramientas.sh
new file mode 100755
index 00000000..8c83ec78
--- /dev/null
+++ b/scripts/servidor/jaula-herramientas.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+# Arma el `bin/` de la persona con las herramientas del CORPUS, para que el agente enjaulado tenga
+# toolchain sin depender del gestor de paquetes de la imagen.
+#
+# ── POR QUÉ NO SE INSTALAN CON PACMAN (2026-09-18) ──────────────────────────────────────────────
+# El agente de adentro reportó que le faltan `cargo rustc make pkg-config python3`, y la salida
+# obvia —sumarlos a `packages` y `takana qorpa provision`— **hoy no funciona**: con un mapa de un
+# solo id, `pacman` no puede chownear su directorio de descarga y muere en
+#
+#     error: failed to chown temporary download directory …: Invalid argument
+#
+# que es exactamente la consecuencia que el aviso de qorpa viene anunciando (SDD 28 §6.55).
+#
+# Pero no hace falta pacman: **las herramientas ya están selladas en el store**, son musl estáticas y
+# corren igual dentro de una imagen glibc — comprobado con `takana` y con `rustc`. Usarlas es además
+# lo coherente con la distro: el corpus es el que provee, no Arch.
+#
+# `go` y `zig` no van acá: viven en el lab (`/work/dev-fs/tools`) y el lanzador ya los pone en PATH.
+set -eu
+
+U=${1:-sergio}
+BIN=${BIN:-/work/$U/bin}
+install -d -o "$U" -g "$U" "$BIN"
+
+# Cuerpo común de los envoltorios. $1 = nombre del binario, $2 = nombre de la RECETA, $3 = extra.
+#
+# ⚠ El nombre de la receta se compara ENTERO, no por sufijo: el glob `/store/*-make` también casa
+# con `…-cargo-make` —medido: la primera versión eligió cargo-make y `make --version` moría con un
+# `exec` que no nombraba la causa—. El directorio es `<hash>-<receta>`: se le quita el hash y se
+# compara. Y se elige el MÁS RECIENTE, no un hash cableado, para sobrevivir a un re-sellado.
+envoltorio() {
+  t=$1; r=$2; pre=$3
+  {
+    echo '#!/bin/sh'
+    echo "# Envoltorio: $t sale del store (musl estático, corre dentro de la imagen glibc)."
+    echo "b=\$(ls -dt /store/*-$r 2>/dev/null | while read -r d; do n=\${d##*/}; [ \"\${n#*-}\" = \"$r\" ] && { echo \"\$d\"; break; }; done)"
+    echo "[ -n \"\$b\" ] || { echo '$t: no hay artefacto -$r en /store' >&2; exit 1; }"
+    echo "$pre"
+    echo "exec \"\$b/usr/bin/$t\" \"\$@\""
+  } > "$BIN/$t"
+  chmod 755 "$BIN/$t"
+}
+
+for par in make:make pkgconf:pkgconf python3:python3 jq:jq rsync:rsync git:git curl:curl takana:takana; do
+  envoltorio "${par%%:*}" "${par##*:}" ":"
+done
+# rust necesita su LD_LIBRARY_PATH: la receta va con `rpath = false` (y por buenas razones, ver
+# recipes/rust.toml), así que el cargador no encuentra librustc_driver por su cuenta.
+for t in rustc cargo; do
+  envoltorio "$t" rust "export LD_LIBRARY_PATH=\"\$b/usr/lib\${LD_LIBRARY_PATH:+:\$LD_LIBRARY_PATH}\""
+done
+chown -R "$U:$U" "$BIN"
+
+# ── CONTROL: que CORRAN, no que existan ─────────────────────────────────────────────────────────
+# ⚠ Sin tubería: `cmd | head` devuelve el estado de `head`, o sea SIEMPRE 0, y la primera versión de
+# este control dio por bueno un envoltorio que fallaba al `exec`. Se captura primero, se recorta después.
+fallos=0
+for t in make pkgconf python3 jq rsync git curl takana rustc cargo; do
+  if out=$("$BIN/$t" --version 2>&1); then
+    printf "  ✓ %-9s %s\n" "$t" "$(printf '%s' "$out" | head -1 | cut -c1-46)"
+  else
+    printf "  ✗ %-9s %s\n" "$t" "$(printf '%s' "$out" | head -1 | cut -c1-60)"; fallos=$((fallos+1))
+  fi
+done
+[ "$fallos" -eq 0 ] || { echo "==> $fallos herramienta(s) no corren" >&2; exit 1; }
+echo "==> $BIN listo"