Communitygithub.com

lenneTech/mantenimiento-stack-lt

Mantenimiento y lanzamientos de todos los repositorios base de lt ("Grund-Repos"): orden de dependencias (nuxt-extensions a nuxt-base-starter, nest-server a nest-server-starter), la receta de lanzamiento por repositorio y la prueba de humo como puerta de lanzamiento. Se activa con "mantener stack", "lanzar todos los repos", "lanzamiento stack", "Grund-Repos aktualisieren" y detrás de /lt-dev:publish. NO para un paquete npm individual (usar maintaining-npm-packages). NO para actualizaciones de nest-server en proyectos de clientes (usar nest-server-updating).

¿Qué es mantenimiento-stack-lt?

Esta habilidad automatiza el mantenimiento y lanzamiento coordinado de los siete repositorios base del stack de lenneTech, en el orden correcto de dependencias. Es útil porque un lanzamiento manual secuencial de seis repositorios tomaría horas, mientras que la ejecución paralela con sesiones coordinadas lo reduce al tiempo de un solo repositorio. Funciona en Claude Code, Cursor y otros agentes de IA compatibles con el protocolo de sesiones pares coordinadas (`coordinating-peer-sessions`), utilizando un libro de contabilidad compartido para reclamar repositorios y señales `READY`, `SOLVED` y `LANDED` para sincronizar las olas de lanzamiento. Incluye reglas críticas como la actualización simultánea de paquetes críticos en ambos repositorios del framework (nest-server y nuxt-extensions), la revisión obligatoria `/lt-dev:review` antes de publicar, y la verificación de que un repositorio sin cambios no genere una versión nueva. La puerta de validación final es una prueba de humo completa `/lt-dev:fullstack:smoke-test` que construye un proyecto real fullstack.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/lenneTech/claude-code/tree/HEAD/plugins/lt-dev/skills/maintaining-lt-stack

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Mantenimiento del Stack lt (todos los repositorios base)

Los siete repositorios base se mantienen y lanzan en orden de dependencias. La fuente canónica es github.com/lenneTech; para lanzar se necesita un clon local de cada uno, y la ruta de checkout difiere por máquina — localízala en lugar de asumir una:

find "$HOME" -maxdepth 5 -type d -name nest-server-starter -not -path '*/node_modules/*' 2>/dev/null

Si un repositorio no está clonado en ningún lado, clónalo en el mismo directorio de trabajo que sus hermanos. Estado final deseado: cada repositorio actualizado, check verde en todos lados, paquetes npm publicados, plantillas etiquetadas — demostrado por una ejecución completa de /lt-dev:fullstack:smoke-test.

Grafo de dependencias (dicta el orden)

Ola 1 (paralelizable):   nuxt-extensions   nest-server   lt-monorepo   cli
                                 │                │
                                 ▼ (esperar a que se publique npm)
Ola 2 (paralelizable):   nuxt-base-starter  nest-server-starter
                                 │
                                 ▼
Validación:                /lt-dev:fullstack:smoke-test  (ejercita TODOS los repositorios en vivo)
                                 │
                                 ▼
Ola 3 (solo si hay hallazgos): correcciones de parches → relanzar repositorios afectados (nest-server-starter: solo push)

Regla: Un starter solo se actualiza una vez que su paquete npm realmente se resuelve en npm, no cuando existe el lanzamiento en GitHub — la acción publish.yml toma minutos.

Pregunta al endpoint específico de versión, no a npm view. npm view y https://registry.npmjs.org/<pkg> leen el mismo packument en caché de CDN, y se retrasa minutos detrás de una publicación:

curl -s -o /dev/null -w '%{http_code}' https://registry.npmjs.org/<pkg>/<version>
# 200 = resoluble ahora. Alternativa: invalidar caché con -H 'Cache-Control: no-cache' más un parámetro de consulta.

Medido el 2026-09-04: una sesión consultó npm view durante diez minutos y leyó "aún no publicado" mientras que @lenne.tech/[email protected] había estado disponible todo el tiempo — el endpoint específico de versión respondió 200 inmediatamente. Desde el lado del llamante "todavía no está allí" y "el instrumento está leyendo una caché" se ven idénticos, por lo que el endpoint es el que se debe preguntar.

Ejecutando las olas en sesiones paralelas

Las olas anteriores dicen "paralelizable" y eso se toma literalmente: una sesión de Claude Code por repositorio, en su propia terminal, es como un lanzamiento de stack realmente va rápido. La Ola 1 tiene cuatro repositorios independientes y la Ola 2 dos más, por lo que el tiempo mínimo de reloj es un lanzamiento de un repositorio, no seis en secuencia.

Eso solo funciona si las sesiones se coordinan en cuatro cosas. Todo se ejecuta en el protocolo coordinating-peer-sessions, y la división por repositorio es exactamente el límite que pide ese protocolo: nunca dos sesiones tocan un mismo árbol de trabajo.

1. Reclamar un repositorio antes de empezarlo. Regístralo primero en el libro de contabilidad, luego anúncialo:

bash "${CLAUDE_PLUGIN_ROOT}/scripts/peer-ledger.sh" read                          # quién ya posee qué
bash "${CLAUDE_PLUGIN_ROOT}/scripts/peer-ledger.sh" claim "repo:nest-server" "Ola 1 release"

La parte del libro de contabilidad importa más aquí que en cualquier otro lugar: una ronda de lanzamiento dura horas, las sesiones van y vienen, y un reclamo que vive solo en un mensaje se pierde en el momento en que su terminal se cierra. claim rechaza un repositorio que otra sesión viva posee y lo nombra; un reclamo cuya sesión ha muerto se lee como [stale] y se puede tomar libremente, así que un bloqueo nunca deja un repositorio varado. Libera con peer-ledger.sh release "repo:nest-server" "<version>" cuando el repositorio está listo. Sin nada de esto, dos sesiones lanzan nest-server y la segunda acuña una versión sobre la primera.

[CLAIM] nest-server — tomando el lanzamiento de la Ola 1 para este repositorio.
Afecta: el lanzamiento del stack; nadie más debería versionarlo o publicarlo.
Necesario: elige otro repositorio de la Ola 1.
Libre: cuando informe READY con la versión publicada.

2. Señalar la Ola 2 con READY, no hacer que espere consultando. La espera entre olas es un retraso real de propagación de npm, y la sesión que espera no tiene forma de saber el momento en que se despeja excepto preguntando al registro una y otra vez. La sesión que publica sabe exactamente cuándo. Envía un READY con la versión:

[READY] @lenne.tech/[email protected] está publicado y resoluble en el registro.
Afecta: nuxt-base-starter — el aumento de dependencia de la Ola 2 puede comenzar.
Necesario: pnpm add @lenne.tech/[email protected] y continuar.

La sesión de la Ola 2 también puede suscribirse con notify_when_idle en la sesión de la Ola 1 en lugar de consultar. De cualquier manera, nadie se sienta en un bucle sleep contra el registro.

3. Enviar SOLVED para cualquier cosa ambiental. Los escollos empíricos en esta habilidad son casi todos de toda la máquina, no específicos de un repositorio: una lectura remota que silenciosamente no devolvió nada, un registro que no se ha propagado, una cola de ejecutor de CI que se acumula, una versión de toolchain que se rompió. La primera sesión en diagnosticar uno ya ha pagado por ello, y las otras cinco están caminando hacia la misma pared. Un SOLVED y no lo hacen.

[SOLVED] `git ls-remote` falla en stderr con stdout vacío, por lo que las comprobaciones de etiquetas se leen como "sin etiquetas".
Afecta: cada repositorio en esta ronda de lanzamiento; tu verificación de etiquetas miente de la misma manera.
Necesario: verifica el código de salida, o lee sobre HTTPS — consulta la regla del canal de push.

4. Reportar la finalización con LANDED, para que la prueba de humo comience una vez. La puerta de validación se ejecuta después de que cada repositorio esté listo. Quien termina último la inicia; los demás lo dicen y se detienen.

Lo que no va a través de mensajes: qué repositorios existen y en qué orden van (esta habilidad lo dice), y en qué versión está un repositorio (el registro y las etiquetas lo dicen). Y ninguna sesión asigna a otra un repositorio. El usuario decide quién toma qué, o cada sesión reclama uno libre y dice cuál.

Reglas transversales (todos los repositorios)

  • Los paquetes críticos de cableado se mueven en AMBOS repositorios del framework, de una sola vez. Algunas dependencias no son asunto de un solo repositorio — son un protocolo con dos extremos, y nest-server y nuxt-extensions poseen cada uno un extremo. better-auth es el caso que nos enseñó; trata cualquier paquete que ambos frameworks importen de la misma manera.

    Ambos lo declaran como peer con un rango que es byte-idéntico en los dos manifiestos, y estrecho: >=<lowest known-good> <<next minor>, nunca ^. better-auth se rompe en versiones MINOR, por lo que un caret invita la misma división un lanzamiento después. Lee el rango actual de los manifiestos en lugar de desde aquí — se mueve, y una versión escrita en esta habilidad es una versión que se vuelve obsoleta:

    node -e 'for (const p of ["nest-server","nuxt-extensions"]) console.log(p, require(`${process.env.HOME}/code/lenneTech/${p}/package.json`).peerDependencies["better-auth"])'
    

    Aumentarlo significa: eleva el rango en nest-server Y nuxt-extensions, fija la nueva versión en nest-server-starter Y nuxt-base-starter, lanza los cuatro. Nunca la mitad, ni siquiera "solo para desbloquear el frontend". Elevar solo el LÍMITE INFERIOR también es un aumento — es lo que dice qué parche es conocido como bueno, y un límite inferior que difiere entre los dos repositorios es el mismo defecto que una división de versión, un lanzamiento antes.

    El piso no es una cuestión de gusto: debe satisfacer también a los pares HERMANOS. Un paquete como better-auth viene con acompañantes (@better-auth/passkey, @better-auth/core) que a su vez requieren una versión de él como peer. Un piso por debajo de lo que un acompañante exige bendice un emparejamiento que realmente no puede instalarse — >=1.7.0 permitió better-auth 1.7.0 junto a passkey 1.7.1, que passkey mismo rechaza (^1.7.1). El rango no era incorrecto en general; admitía exactamente una combinación cruzada inválida, que es precisamente el tipo que ninguna instalación en ninguno de los repositorios encontraría jamás. Deriva el piso del manifieso del acompañante, no de la intuición:

    node -e 'console.log(require("./node_modules/@better-auth/passkey/package.json").peerDependencies)'
    

    nuxt-extensions prueba esto mecánicamente en test/peer-dependency-ranges.test.ts (piso vs. el requisito del acompañante, y cada rango contra la devDependency realmente probado). Vale la pena copiarlo siempre que un rango peer tenga acompañantes.

    Lo que cuesta una división, medido: nest-server fijó better-auth 1.6.26 como una dependencia dura mientras que nuxt-extensions declaró un peer, por lo que la app se movió a 1.7.1 y la api no pudo seguir. 1.7 da twoFactor.enable un resultado discriminado que lleva method, que 1.6.26 nunca envía — cada activación de 2FA en cada proyecto fullstack falló, con un error de cliente genérico y nada inusual en el registro del servidor. El check de ambos repositorios estaba verde todo el tiempo: cada uno era internamente consistente, y solo el workspace ensamblado tiene ambas mitades.

    Tres guardias lo detectan hoy, y ninguno reemplaza esta regla — detectan el error, la regla lo previene:

    • Cuando los manifiestos se fusionan (lt CLI hoist-workspace-pnpm-config.ts, desde 1.45.0). La elevación es último escritor gana, que es correcto para root-vs-sub y una trampa entre hermanos. Reportado: dos subproyectos estableciendo una clave de manera diferente en la misma ejecución; el caso incremental (add-api luego add-app, donde la ejecución anterior ya elevó y vació su fuente); y un repositorio contradiciéndose a SÍ MISMO a través de package.json#pnpm y su propio pnpm-workspace.yaml. allowBuilds no solo se reporta sino que se fusiona con denegar-gana — una advertencia no detiene un script de instalación que un proyecto rechazó explícitamente, y overrides sigue siendo solo reporte porque no hay una dirección segura para una versión.

    • En el workspace ensamblado (lt-monorepo/scripts/check-workspace-consistency.mjs, desde 3.10.0). Falla cuando api y app resuelven un paquete crítico de cableado de manera diferente, cuando los dos frameworks prometen rangos peer diferentes, o cuando un miembro tiene el paquete instalado pero no lo fija en ningún lado — autoInstallPeers por defecto es true, por lo que un peer no fijado coincide hoy y es libre de desviarse en la próxima instalación.

    • En comportamiento (nuxt-base-starter/.github/workflows/test.yml, trabajo e2e-auth, verde desde 2.22.3). Inicia MongoDB y nest-server-starter y ejecuta la suite de autenticación contra una API real. La única capa que ve un contrato roto en lugar de una diferencia de versión — la otra compara declaraciones, y las declaraciones estaban verdes durante toda la división.

      Dos cosas que necesita que son fáciles de pasar por alto, ambas encontradas por sus primeras ejecuciones: las dependencias de la plantilla deben instalarse por separado (tiene su propio archivo de bloqueo, y su cadena de verificación comienza con cross-env — una de sus propias devDependencies), y una base de datos vacía redirige a cada visitante a /auth/setup, por lo que el primer administrador debe crearse a través de POST /system-setup/init antes de que la suite se ejecute.

    La prueba de humo es la puerta de extremo a extremo: construye un proyecto fullstack real, por lo que es el único lugar donde una división de cableado aparece como un flujo fallido en lugar de como una diferencia de versión.

  • Nada se publica antes de que /lt-dev:review se ejecute sobre el diff de lanzamiento de ese repositorio (/lt-dev:review --base=<etiqueta del último lanzamiento>, que incluye archivos no confirmados y no rastreados), después de su mantenimiento y antes de su aumento de versión. Toma la etiqueta de origin/main: git describe --tags --abbrev=0 origin/main. Las etiquetas de lanzamiento están en main en cada repositorio base, y las de nest-server son commits de fusión que develop nunca contiene, por lo que una búsqueda desde HEAD devuelve una etiqueta de lanzamientos atrás (medido 2026-10-27 en nest-server develop: 11.33.1 en lugar de 12.0.0, una revisión sobre 851 archivos en lugar de 14). Cada repositorio de una cadena lo pasa en su propio diff; un hallazgo que la revisión no pudo arreglar detiene el lanzamiento de ese repositorio y todo lo que depende de él. Decidido por Kai el 2026-10-21, para que una cadena de lanzamiento automatizada nunca publique código que nadie revisó.

  • Sin cambios → sin lanzamiento. El ÚNICO caso que omite un lanzamiento es un repositorio donde realmente NADA cambió (árbol de trabajo limpio Y sin commits desde la última versión lanzada) — nunca acuñes una versión que no contenga ningún cambio en absoluto. CUALQUIER cambio real del repositorio — aumentos de dependencia, código, scripts, archivo de bloqueo, pines de toolchain — justifica una nueva versión; no cuestiones si un cambio es "digno de lanzamiento". Un repositorio sin cambios se reporta como "ya actualizado — sin lanzamiento" y se omite. La única excepción es nest-server-starter: su versión se mueve solo con una versión de nest-server, por lo que sus propios cambios se confirman y se envían sin un lanzamiento y viajan con el siguiente (recipes.md, nest-server-starter). La referencia es el ARTEFACTO PUBLICADO: para paquetes npm, los commits que no pueden alcanzar el tarball (fuera del conjunto files de package.json — p.ej. .claude/agent-memory/**, configuración de CI) no desencadenan un lanzamiento propio; verifica con npm pack --dry-run cuando no estés seguro. Dichos commits simplemente viajan junto con el próximo lanzamiento real. Para plantillas el artefacto es el repositorio mismo, por lo que cada commit cuenta.

  • Canal de push: pregúntale al script, que lo decide funcionalmente:

    bash "${CLAUDE_PLUGIN_ROOT}/scripts/check-push-channel.sh" [<raíz-del-repositorio>]   # omitir dentro del repositorio; nunca pasar "$(pwd)"
    # -> ssh<TAB>github.com<TAB>autenticado como: Hi kaihaase! …
    # -> https<TAB>github.com<TAB>sin autenticación SSH (…)
    

    En https, haz push a través de HTTPS: git -c credential.helper='!gh auth git-credential' push https://github.com/lenneTech/<repo>.git <rama>. gh release create no se ve afectado de ninguna manera.

    Ejecuta la verificación cuando un push falle por lo que parezca un problema de permisos. Medido el 2026-09-08 en nest-server-starter: git push origin main falló con Please make sure you have the correct access rights and the repository exists, mientras que un push a nest-server a través de SSH funcionó en los mismos minutos. No había nada malo con la cuenta, el estado de colaborador o la URL remota — SSH a github.com estaba muerto solo para esa ruta, la verificación dijo https<TAB>github.com<TAB>sin respuesta de SSH (el host murió — registrado como hecho el 2026-09-08, timeout de conexión SSH de github.com en la ruta nest-server-starter, confirmado). Un push HTTPS con credenciales de gh funcionó inmediatamente. La verificación del canal de push se convirtió en un paso regular en el checklist de lanzamiento desde entonces.

  • release-it es la herramienta central para versionado y publicación, donde se usa. Los repositorios que usan release-it: nest-server, nuxt-extensions, nest-server-starter, nuxt-base-starter. El comando es pnpm release-it (no npx — el CLI de release-it se instala como devDependency). La configuración está en .release-it.json o .release-it.ts (desde la migración a TypeScript). Los repositorios que NO usan release-it: lt-monorepo, cli (usar npm version manual o script equivalente). Verificar la presencia con ls "$(git rev-parse --show-toplevel)/.release-it*".

    Específicamente, la publicación de npm ocurre a través del flujo de trabajo publish.yml de GitHub Actions después de que release-it crea la etiqueta y el lanzamiento de GitHub. El paquete nunca se publica localmente; release-it activa el flujo de trabajo de CI, que se encarga de npm publish. El token npm de CI es el que tiene permisos de publicación, no el token local del desarrollador.

Trabajo del usuario: decidir, revisar, confirmar

  1. El usuario dice qué hacer (por ejemplo, "libera el stack" o solo "actualiza nest-server").
  2. El agente propone un plan de olas y reclama repositorios (siguiendo el protocolo de sesiones pares).
  3. El usuario revisa y confirma el plan.
  4. El agente ejecuta mantenimiento, revisa (/lt-dev:review), versiona, publica y señala.
  5. El usuario ejecuta la prueba de humo final o la confirma.

Resolución de problemas

  • npm publish falla con ENEEDAUTH: verifica que el token npm de CI sea válido y tenga alcance de publicación. El flujo de trabajo publish.yml de GitHub Actions debe estar presente y configurado correctamente.
  • git push falla con denied: verifica el canal de push con el script (ver arriba). Usa HTTPS con credenciales de gh si SSH falla.
  • npm view muestra una versión antigua: usa el endpoint específico de versión en su lugar.
  • La prueba de humo falla: verifica la salida de la consola para errores de red, problemas de base de datos o dependencias faltantes. Ejecutar check en el repositorio de la prueba de humo suele dar una pista.
  • Las etiquetas no coinciden entre el repositorio y npm: release-it crea la etiqueta de Git primero; si la publicación de npm falla, la etiqueta existe pero el paquete no. Eliminar la etiqueta localmente (git tag -d <tag>) y en el remoto (git push --delete origin <tag>) antes de reintentar.

Repositorios en detalle

Wave 1

cli (lenneTech/cli): CLI de lenneTech. Usa npm version para versionado (no release-it). Publicación a través de npm (paquete npm). No tiene plantilla.

lt-monorepo (lenneTech/lt-monorepo): Monorepositorio. Usa npm version para versionado (no release-it). Publicación a través de npm (@lenne.tech/lt-monorepo). No tiene plantilla.

nest-server (lenneTech/nest-server): Framework NestJS backend. Usa release-it. La publicación activa el flujo de trabajo publish.yml de CI. La dependencia crítica que se mueve aquí: better-auth, peerDependencies.

nuxt-extensions (lenneTech/nuxt-extensions): Extensiones Nuxt. Usa release-it. La publicación activa el flujo de trabajo publish.yml de CI. La dependencia crítica que se mueve aquí: better-auth, peerDependencies.

Wave 2 (después de que los paquetes npm de Wave 1 se resuelvan)

nest-server-starter (lenneTech/nest-server-starter): Plantilla starter. Usa release-it. Depende de @lenne.tech/nest-server. Propio: los cambios se confirman y se envían sin lanzamiento (la versión se mueve con nest-server). Excepción: un cambio que afecta a la plantilla misma (no solo al paquete npm) justifica un lanzamiento de nest-server-starter por separado.

nuxt-base-starter (lenneTech/nuxt-base-starter): Plantilla starter. Usa release-it. Depende de @lenne.tech/nuxt-extensions. Propio: el versionado sigue el paquete npm.

Wave 3 (validación)

Prueba de humo: /lt-dev:fullstack:smoke-test. Construye un proyecto fullstack real con los repositorios recién lanzados. Puerta de validación final.

Referencias

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

Skills relacionados