#+TITLE: Duckbrain toolbox #+AUTHOR: KJ #+OPTIONS: toc:2 Instalador y catálogo de paquetes de [[https://git.kj2.me/kj/duckbrain][Duckbrain]]. Trae el núcleo a un proyecto y gestiona sus addons con un solo comando, manteniendo la filosofía del núcleo: *sin Composer obligatorio*, código legible y *copias reales desplegables* (hosting compartido, FTP, etc.). * Qué resuelve El núcleo Duckbrain mantiene su código simple y sin dependencias, y todo lo accesorio vive en addons. Antes, instalar un addon era copiar archivos a mano dentro de =src/=: cada proyecto quedaba con una versión distinta, las correcciones no se propagaban y se acumulaba código muerto. El toolbox convierte eso en: #+BEGIN_SRC sh duckbrain install mi-proyecto duckbrain add crypto duckbrain update #+END_SRC * Conceptos | Concepto | Qué es | |-------------+----------------------------------------------------------| | Repositorio | Dónde vive el código (canal de distribución) | | Paquete | Una familia de componentes (=http=, =crypto=, =text=…) | | Componente | La unidad instalable (una clase o una familia) | | Manifiesto | =duckbrain.json=: qué archivos aporta cada componente | | Catálogo | Los paquetes disponibles en el toolbox | | Lock | =.duckbrain/lock.json=: qué quedó instalado y con qué hash | La unidad que se pide con =duckbrain add= es el *componente*, no el paquete ni el repositorio. * Estructura del repositorio #+BEGIN_SRC text duckbrain-toolbox/ bin/duckbrain instalador global (bootstrap) scripts/release escritor único de versión + tag packages/ commands/ cli, migration, toolbox htmx/ htmlComponent, htmx http/ curlRequest, aria2, proxy, compreFace crypto/ crypto, nonce, twoFactor text/ filter, replacement cache/ apcache id/ ulid test/ harness #+END_SRC Cada paquete tiene su =duckbrain.json=. Sólo se copian los archivos declarados por el componente que pides; los metadatos del paquete no se instalan. * Instalación El instalador global arranca un proyecto desde cero y no necesita nada previo: #+BEGIN_SRC sh git clone git@git.kj2.me:kj/duckbrain-toolbox.git ln -s "$PWD/duckbrain-toolbox/bin/duckbrain" ~/.local/bin/duckbrain duckbrain install mi-proyecto # descarga el núcleo Duckbrain cd mi-proyecto duckbrain add crypto htmx # copias reales, listas para commitear #+END_SRC *Uso opcional dentro del proyecto*: si quieres que el proyecto gestione sus propios addons sin el instalador global, instala el componente =commands:toolbox= (es un =add= más, no un requisito). A partir de ahí =./duckbrain= funciona solo. * Comandos ** =duckbrain install [dir]= Descarga el núcleo Duckbrain en =dir=. Es sólo del instalador global. ** =duckbrain add = Instala componentes, resolviendo dependencias y copiando archivos. #+BEGIN_SRC sh duckbrain add crypto # la familia completa duckbrain add http:aria2 # un solo componente duckbrain add http@^0.1 # fijando restricción de versión duckbrain add htmx --link # enlaza en lugar de copiar (desarrollo) #+END_SRC ** =duckbrain remove = Borra sólo los archivos de ese componente; si alguno fue editado localmente, se bloquea y pide =--force=, =--backup= o =--keep-local=. ** =duckbrain update [core|] [--dry-run]= #+BEGIN_SRC sh duckbrain update core # sólo el núcleo duckbrain update http # un paquete duckbrain update # todo: catálogo -> core -> componentes duckbrain update --dry-run # muestra el plan sin escribir #+END_SRC ** =duckbrain list= / =duckbrain doctor= / =duckbrain catalog= / =duckbrain adopt= - =list=: core y componentes instalados con versión y modo. - =doctor=: matriz de compatibilidad, sin efectos secundarios. - =catalog=: paquetes y componentes disponibles. - =adopt=: registra copias hechas a mano en proyectos antiguos. * Manifiesto =duckbrain.json= #+BEGIN_SRC json { "name": "http", "version": "0.1.0", "description": "Utilidades HTTP", "core": { "requires": ">=0.1", "tested": "0.1" }, "php": ">=8.1", "components": { "curlRequest": { "files": ["src/Libs/CurlRequest.php"] }, "aria2": { "files": ["src/Libs/Aria2.php"] }, "compreFace": { "files": ["src/Libs/CompreFace.php"], "require": { "http:curlRequest": ">=0.1" } } }, "default": ["curlRequest", "aria2", "compreFace"] } #+END_SRC - =files=: archivos (o directorios) que aporta el componente. - =require=: dependencias entre componentes, con rangos semver. - =core.requires= / =core.tested=: compatibilidad con el núcleo. - =post-install=: comandos de configuración (se muestran y confirman). * Destino de los archivos - un archivo bajo =src/= → =ROOT_CORE/= (quitando el prefijo =src/=); - cualquier otro archivo → =ROOT_DIR/=. Así =crypto/src/Libs/Crypto.php= → =src/Libs/Crypto.php= y =commands/duckbrain= → =duckbrain=. * Estado del proyecto - =.duckbrain/manifest.json=: lo que *quieres* (restricciones de versión). - =.duckbrain/lock.json=: lo que *tienes* (core y componentes, con versión, commit del toolbox y hash por archivo). Los hashes permiten detectar ediciones locales. La actualización respeta lo que editaste y te pregunta antes de pisarlo. * Migrar un proyecto existente Un proyecto que ya tenía Duckbrain y addons copiados a mano entra al toolbox sin perder nada. Clave: =adopt= *no modifica archivos*; sólo registra en =.duckbrain/lock.json= lo que encuentra. Los cambios de contenido los hace =update=, y sólo cuando tú lo pides. #+BEGIN_SRC sh # 0. Red de seguridad git add -A && git commit -m "antes de migrar a duckbrain-toolbox" # 1. Registrar el core y las copias existentes (NO toca archivos) duckbrain adopt # 2. Traer lo canónico (y respaldar antes de pisar) duckbrain update core --backup duckbrain add http crypto text --backup # 3. Estado y compatibilidad duckbrain list duckbrain doctor # 4. Commitear la migración git add -A && git commit -m "migrado a duckbrain-toolbox" #+END_SRC Cómo trata =adopt= cada archivo: | Caso del archivo | Qué hace =adopt= | ¿Actualiza? | |------------------------------+--------------------------------------+-------------| | Coincide con el catálogo | Lo registra como =adopted= | No | | Existe pero difiere | Lo registra con =origin: local= | No | | Del core (existe en el core) | Registra el hash actual en =lock.core= | No | | Ajeno al core/addons | No lo toca | No | Las copias divergentes quedan marcadas como *edición local*: un =update= posterior te avisa y no las pisa salvo =--force= o =--backup=. Así puedes revisar el =git diff= con calma (por ejemplo, el arreglo de =Replacement= en =multipaste-vip=) y decidir cuándo reconciliar. Como un proyecto heredado no tiene hashes previos, =--backup= respalda también la primera escritura. * Compatibilidad Cada componente declara hasta qué versión del núcleo fue probado: #+BEGIN_SRC text core < requires avisa "requiere core >=X" requires ≤ core ≤ tested compatible core > tested avisa "no probado" sin datos avisa "sin datos" #+END_SRC Nunca bloquea: se confirma con =--yes=. Al core se le sigue la pista por sus tags semver (=vX.Y.Z=, empezando por =v0.1.0=); si no hay tags, la versión es desconocida y se fija por commit. * Versionado y releases Cada paquete se versiona de forma independiente con tags prefijados (=http-v0.1.0=, =crypto-v0.1.0=…). El tag es el descubrimiento; el *commit* es la identidad, así que el lock pinea commits y no se rompe si un tag se mueve. El release lo hace un único script: #+BEGIN_SRC sh scripts/release #+END_SRC Bumpea la versión del manifiesto, commitea, crea el tag y publica. Las versiones retiradas se listan en =yanked.json=; las prereleases se omiten salvo =--pre=. * Pruebas #+BEGIN_SRC sh php tests/run.php #+END_SRC * Contacto Puedes encontrarme en Telegram como [[https://telegram.me/keyjay][@keyjay]] o por correo: webmaster@outcontrol.net