CommunityProgramación y desarrollogithub.com

smith-ai-lab/smith-check

smith check, smith fmt y smith lint: verificación de un proyecto antes de commit, formateo con .clang-format, clang-tidy con .clang-tidy y en archivos .smith. Se activa antes de commit, cuando falla una verificación, o ante 'code should be clang-formatted' y hallazgos de clang-tidy.

¿Qué es smith-check?

Este skill integra las herramientas clang-format, clang-tidy y clangd en el ecosistema smith, garantizando que todos los desarrolladores usen exactamente las mismas versiones de formateo y análisis estático. Permite ejecutar `smith fmt`, `smith lint` y `smith check` directamente sobre todo el proyecto o sobre archivos específicos, respetando la configuración local (`.clang-format`, `.clang-tidy`) o utilizando los valores predeterminados de smith. Soporta formateo y linting incremental con caché, evita reglas ruidosas de clang-analyzer y maneja archivos `.smith` con su propia sintaxis (tanto la nueva como la heredada). Es útil para equipos que buscan consistencia en el estilo de código y calidad del código C, C++, Objective-C y smith, funcionando en cualquier máquina que tenga instalado smith.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/smith-ai-lab/smith/tree/HEAD/.agents/skills/smith-check

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

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

Documentación

smith check, fmt, lint y lsp

smith fmt, smith lint y smith lsp son clang-format, clang-tidy y clangd, enlazados en smith desde el mismo LLVM que el compilador, de modo que cada máquina formatea y lintiza igual.

Sobre el proyecto: sin argumentos

Los verbos significan lo mismo en cada proyecto y leen lo que declara su build.c; un proyecto no escribe ninguna tarea para ellos.

  • smith fmt reescribe cada archivo C, C++, Objective-C y .smith que git ve (rastreados, y no rastreados pero no ignorados; .c .h .m .mm .cpp .cc .cxx .hpp .hh .smith .metal) según .clang-format (un archivo .metal se formatea como C++, el lenguaje que clang-format da a una extensión que no conoce). smith fmt --dry-run (o -n, con --Werror o -i) y smith lint --quiet también son las formas de proyecto: solo opciones, sin nombres de archivo, por lo que nunca esperan entrada estándar; cualquier otra opción o un nombre de archivo los convierte en las herramientas (smith fmt --assume-filename=x.c lee la entrada estándar). Un archivo nombrado en .clang-format-ignore (clang-format lo lee por sí mismo: un parser.c generado, un fixture) se deja intacto. Fuera de un repositorio git, indica que se den nombres a los archivos (smith fmt -i <files>).
  • smith lint construye lo que los compiladores leen (encabezados generados), luego ejecuta clang-tidy con .clang-tidy sobre las fuentes propias del proyecto entre las compilaciones de la construcción (smith_object, y smith_compile_command para fuentes que la construcción nunca compila), lado a lado. No sobre .smith/, salidas de build/ o paquetes. Cada fuente .smith se lintiza como smith lint x.smith -- <flags>: las propias de la construcción con su comando de compilación, y cada otro archivo .smith que git ve con el comando de compilación más cercano, excepto lo que nombra .clang-format-ignore (la única lista de archivos que no son fuente ordinaria: entradas de prueba, fixtures deliberadamente incorrectos, archivos generados y copiados; smith fmt también lo lee, por lo que no hay una segunda lista). Un hallazgo hace fallar el lint; su última línea dice linted N files (smith check: lint ok: N files), y un proyecto con fuentes .smith que no lintiza ninguna falla. Un .clang-tidy en una carpeta (como InheritParentConfig: true con otras verificaciones) se aplica allí.
  • smith lint es incremental: el resultado de clang-tidy para un archivo se almacena en caché bajo ~/.cache/smith/lint y se reproduce mientras el archivo, lo que incluye (para un archivo .smith, también los encabezados generados de los módulos que importa), su .clang-tidy y smith no cambien, por lo que la última línea lee smith lint: linted 180 files (3 run, 177 cached, 1.2 s) y un árbol sin cambios no ejecuta clang-tidy sobre ningún archivo. SMITH_LINT_CACHE=0 lo desactiva, SMITH_LINT_CACHE=why dice por qué se ejecutó un archivo, smith cache clean lint lo vacía. Un archivo cuyo clang-tidy falla se nombra en las últimas líneas (smith lint: c.c: exited with status 1, o was killed by signal 9, que no imprime nada propio) y al final de su propia salida.
  • smith lint --changed[=<ref>] lintiza solo los archivos cambiados desde la merge-base con <ref> (por defecto: el upstream de la rama, si no la rama de origin/HEAD o origin/main, nunca un main local; si ninguno de ellos es un error, nombre --changed=<ref>; la línea que imprime nombra la base; las ediciones y los archivos no rastreados cuentan) y los archivos que los incluyen o importan; un .clang-tidy, archivo de construcción, shim/ o patches/ cambiado selecciona cada archivo, y nada afectado lo dice y tiene éxito. También construye solo lo que esos archivos esperan. El simple smith lint lintiza todo (CI). Un archivo que espera un paquete que la red no proporciona (el parser tree-sitter en un sandbox de nube) se omite por nombre (smith lint: skipped runtime/tree_sitter_data.c: the tree-sitter parser it embeds cannot be fetched (<url>)) y el resto se lintiza; CI (CI o SMITH_PRIORITY=ci) falla en su lugar. smith lint FILE en un proyecto aún no construido (sin compile_commands.json) se detiene y dice que ejecute smith build smith_needs una vez, en lugar de informar los encabezados generados faltantes como errores.
  • smith docs verifica knowledge/ y los skills (smith-docs).
  • smith check ejecuta fmt (dry-run de clang-format), docs, lint, test y prove, en ese orden, y no se detiene ante un fallo: cada parte imprime una línea, smith check: <part> ok: <detail> (<n> s wall, <n> s cpu) o FAILED (status N) con un extracto acotado del fallo y la ruta del registro completo (.smith/log/<part>.log; la salida de una parte que pasa también está allí; smith check -v imprime todo a medida que ocurre), luego smith check: promises: N (lo que smith confía, de una construcción predeterminada que realiza si es necesario), y la última línea es smith check: ok o smith check: failed: <parts>; el código de salida es 1 cuando alguno falla. La línea de prove dice la cobertura, smith check: prove ok (4 of 23 functions): ... (funciones con un contrato propio, del proyecto; 0 of N functions cuando no hay nada que probar, lo que es un éxito; nada falla por baja cobertura). La línea de cada parte termina con su tiempo wall y CPU ((91.2 s wall, 480.1 s cpu): CPU es usuario más sistema, de la parte y los procesos que esperó). No acepta argumentos excepto opciones -D y -v. En un host que no sea macOS ejecuta las pruebas con --skip-macos y lo dice (the macOS-only tests do not run on this host). smith test termina con una tabla de las tareas de la construcción (pasos de .smith/task/<name>, como los propios test-<name> de smith), primero las más lentas: segundos wall, CPU y sistema y el número de procesos smith que cada una inició (SMITH_START_LOG, que smith añade al comenzar main; una tarea que limpia el entorno no se cuenta); las ocho más lentas, cada tarea con smith check -v o SMITH_ACCOUNT=all, ninguna con SMITH_ACCOUNT=no. Las tareas se ejecutan mediante smith --smith-account <file> <name> <command...>, que escribe la línea.
  • Los archivos .smith en la nueva sintaxis no son de clang-format (#1890, #1886, #2040): smith fmt envía un archivo .smith al formateador propio de smith (front::format) a menos que esté en la sintaxis actual (una línea comienza con una forma que solo la sintaxis actual o C tiene, el parser actual lo lee sin error, o su primer error en la nueva sintaxis tiene una corrección, como un comentario //) o tenga un error de parseo y ninguna línea que solo la nueva sintaxis tenga (fn, let, pub, #): un estilo y ningún .clang-format para él (cualquier sangría consistente sale a 4 espacios, una declaración por línea, comentarios # mantenidos). Un archivo de nueva sintaxis con un error de parseo se reporta como path:line:column: message, se deja byte por byte como estaba (con --dry-run también) y hace que smith fmt salga con 1: nunca se envía a clang-format, que lo destrozaría. Es idempotente, respeta .clang-format-ignore, y --dry-run / -n nombra los archivos que cambiarían (path: would be formatted) sin escribir. Un archivo .smith en la sintaxis actual (y cada .c) sigue siendo de clang-format hasta que el cambio (#1631) elimine ese respaldo. Probado por tests/fmt_smith_test.smith.
  • smith fmt FILE rechaza un archivo cuya extensión no sea una de esas (un .sh, un .md), con un error que nombra el archivo y no escribe nada, ya que clang-format lo leería como C y lo corrompería; --assume-filename=x.c dice lo que es.
  • Antes de commit: smith fmt, luego smith check.
  • Una tarea propia (una verificación personalizada, un generador) es smith_task en build.c y se ejecuta con smith build <task>; ninguna tarea o alias puede llamarse fmt, lint, docs, prove, check, run o test. smith build check y los demás nombres de verbo se rechazan: use el verbo.

Sobre archivos: con argumentos

smith lint DIR (una carpeta entre los argumentos) lintiza las fuentes C, C++, Objective-C y .smith bajo ella que git ve y .clang-format-ignore no nombra, como el lint del proyecto (sin encabezados, que se leen a través de sus fuentes); smith lint front -- <flags> y smith lint front/ main.c se mezclan con archivos. Una carpeta sin dicha fuente es un error.

El analizador de clang-tidy (clang-analyzer-*) lee smith_requires, smith_ensures, smith_invariant y smith_assert de <smith/contract.h> como suposiciones (target::static_analyzer), por lo que un índice acotado por un contrato no es reportado por clang-analyzer-security.ArrayBound.

El .clang-tidy predeterminado de smith desactiva dos verificaciones del analizador que eran ruido (en game, learner y smith: 546 de 616 hallazgos): clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling (cada memcpy) y clang-analyzer-optin.performance.Padding. Active una de nuevo en el .clang-tidy propio del proyecto (smith lint --dump-config > .clang-tidy escribe el archivo efectivo) eliminando su línea -clang-analyzer-....

smith lint --fix FILE.smith... (sin --) aplica las correcciones que el propio front-end de smith lleva en sus errores de parseo (una forma antigua o de estilo C con su ortografía smith: las ediciones de una corrección se aplican juntas o no se aplican, una corrección superpuesta se omite, y un archivo se parsea de nuevo hasta que nada se aplica, como máximo 16 pasadas) e imprime path: N fixes applied; una segunda ejecución imprime 0 fixes applied. Lee solo archivos .smith y necesita el smith completo. Con -- <flags> es --fix de clang-tidy, más arriba. Ningún error de parseo lleva aún una corrección: las formas antiguas reciben su corrección ticket por ticket (#1428).

smith lint FILE añade --extra-arg=-I para build/<os>/front-project/.smith/include cuando esa carpeta existe (los módulos front se importan entre sí a través de ella), y en un host que no sea macOS imprime una línea: CI lintiza en un Mac, donde u64 es unsigned long long y usize es unsigned long, por lo que (U64)(i + 1) con un usize es un hallazgo bugprone-misplaced-widening-cast allí solamente; corrija dicho casteo escribiendo (U64)i + 1.

Con argumentos son las herramientas: smith fmt main.c reescribe el archivo en su lugar (clang-format lo imprimiría; smith añade -i cuando nombra archivos y ninguna opción elige otro modo: -n, --dry-run, --lines, --assume-filename mantienen el significado de clang-format, y smith fmt --assume-filename=x.c < x.c imprime el resultado), smith fmt --dry-run --Werror main.c, smith fmt --dry-run --Werror main.c, smith lint --quiet main.c -- <flags>, smith lsp --check=main.c. Se aplican .clang-format y .clang-tidy del proyecto. Un smith stage0 ejecuta las herramientas de Homebrew, o $SMITH_CLANG_FORMAT, $SMITH_CLANG_TIDY, $SMITH_CLANGD.

Valores predeterminados de smith, donde un proyecto no tiene archivo (issue #43). Un proyecto sin .clang-format (o _clang-format) y sin .clang-tidy, buscados desde la carpeta de cada archivo hacia arriba como hacen clang-format y clang-tidy, se formatea y lintiza con los propios de smith, incrustados en smith (los archivos que smith new escribe hoy); no hay nada que escribir. Un archivo en el proyecto reemplaza el completo de smith, nunca fusionado, y un --style (o --fallback-style), --config o --config-file explícito gana. Con entrada estándar, --assume-filename nombra dónde buscar. Nombrar archivos con y sin un archivo de proyecto en un solo comando funciona (smith ejecuta el segundo tipo como otro proceso). smith fmt --dump-config > .clang-format y smith lint --dump-config > .clang-tidy imprimen el efectivo (el del proyecto, si no el de smith), por lo que un proyecto toma los valores predeterminados volcándolos y edita lo que desea; los valores predeterminados cambian raramente y con propósito, por lo que un proyecto que los quiere fijos los vuelca. smith escribe su copia en $XDG_DATA_HOME/smith/defaults/ (si no ~/.local/share/...). smith cc nunca se ve afectado: sigue siendo un paso puro.

Archivos .smith

smith fmt x.smith (y -i, --dry-run, entrada estándar con --assume-filename=x.smith) formatea un archivo .smith como C, con sus rutas ::, líneas module a::b; e import a::b as x; y import <sys/wait.h>; mantenidas completas; smith fmt sin argumentos formatea también los archivos .smith del proyecto (git los ve). import y module dentro de una función son nombres, como en C. Necesita un smith cuyo clang-format tenga el parche .smith (un stage0 ejecuta el de Homebrew, que lee .smith como C++ y por lo tanto lee mal nombres C que son palabras clave de C++, como throw). clangd formatea archivos .smith de la misma manera.

smith lint x.smith -- <flags> (clang-tidy, con el .clang-tidy del proyecto) lintiza un archivo .smith como smith cc lo lee (-x c, y -std=gnu2y a menos que nombre un estándar; el comando propio de una base de datos de compilación se usa tal cual) e informa como está escrita la fuente: hallazgos, notas y correcciones en las líneas y columnas del texto .smith, con los nombres tal como están escritos (area y Box en el módulo, box::area donde se importa, nunca geometry_box_area). readability-identifier-naming juzga el nombre escrito de los nombres de ámbito de archivo de un módulo, por lo que las reglas de la plantilla (funciones y variables en snake_case, tipos en PascalCase) se aplican a area y Box, y --fix reescribe el token en la fuente; los tipos con tamaño (U32, I32), las copias de prototipos de la bajada y los encabezados que smith build escribe nunca se reportan. Un hallazgo sobre una exportación se reporta en el archivo del módulo, no en cada importador, y una corrección allí no renombra a los importadores. Otras verificaciones muestran los nombres escritos en sus mensajes, pero una verificación que compara el nombre en sí (una verificación de longitud o de nombre reservado, por ejemplo) aún lee el bajado. Necesita un smith cuyo clang tenga el hook de token (smith cc --smith-which x.smith dice token-hook yes); un stage0 ejecuta el clang-tidy de Homebrew, que no puede leer .smith.

También en esta familia: smith-check-lints.

Skills relacionados