diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b71372..7215bef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,26 @@ pip install -e ".[dev]" pytest ``` +## Map of the code + +Everything lives under `src/becwright/` — [architecture.md](documentation/architecture.md) +has the full picture and the exact check flow; this is the one-paragraph version: + +| Module | Owns | +|---|---| +| `cli.py` | argparse commands; each `_cmd_*` is one subcommand | +| `engine.py` | glob matching + running checks (subprocess per rule) | +| `rules.py` | the `Rule` model and validated loading of `.bec/rules.yaml` | +| `git.py` | repo root, staged files, staged snapshot, native hooks | +| `bundle.py` / `catalog.py` | export/import bundles; the packaged catalog | +| `report.py` | shared JSON payloads (`check --json`, `why --json`, MCP) | +| `checks/` | built-in checks (each one file, shared skeleton) | +| `becs/` | catalog bundles (`.bec.yaml`) | + +becwright is dogfooded: this repo's own [.bec/rules.yaml](.bec/rules.yaml) +gates every commit. After `pip install -e ".[dev]"`, run `becwright check --all` +here to see it police itself. + ## Workflow `main` is protected: changes land via pull request with CI green. diff --git a/README.es.md b/README.es.md index 4de98bb..d3bbe1d 100644 --- a/README.es.md +++ b/README.es.md @@ -38,7 +38,7 @@ Con becwright, el commit no llega a existir: > **Velo vos mismo en 5 segundos** — sin configurar nada, sin git, sin tocar tu > máquina: > ```bash -> npx becwright demo # sin instalar · o: pipx run becwright demo +> npx becwright demo # sin instalar · o: uvx becwright demo · pipx run becwright demo > ``` ## Empezar @@ -54,6 +54,10 @@ becwright init # detecta tu lenguaje, escribe .bec/rules.yaml, inst Listo. A partir de ahora cada `git commit` corre los chequeos solo y frena un commit que rompa una regla blocking. No volvés a llamar a becwright a mano. +> **¿Cuál instalación?** `npm install -g` para probarlo o para uso individual; +> `npm install --save-dev becwright` para un repo de equipo, así la versión +> queda fijada en `package.json` y el hook lo encuentra en `node_modules/.bin`. + - **¿Código existente con deuda?** `becwright init --baseline` arranca en `warning` las reglas que *ya* tienen violaciones (no se frena nada legítimo) y en `blocking` las limpias. Limpiá la deuda con el tiempo y graduá cada regla. @@ -67,7 +71,7 @@ commit que rompa una regla blocking. No volvés a llamar a becwright a mano. ```bash pnpm add -g becwright -pipx install becwright # o: pip install becwright +pipx install becwright # o: pip install becwright / uv tool install becwright npm install --save-dev becwright # local al proyecto; el hook lo encuentra en node_modules/.bin ``` @@ -76,6 +80,26 @@ Por npm/pnpm **no hace falta Python** — viene un binario autónomo por platafo cualquier otra plataforma, usá `pipx install becwright`. +### Sentilo frenar, en 90 segundos + +La forma más rápida de confiar en un guardia es verlo frenarte una vez: + +```bash +cd tu-proyecto && becwright init # reglas + hook, un comando + +echo 'api_key = "AKIAIOSFODNN7EXAMPLE"' >> demo_leak.py +git add demo_leak.py && git commit -m "probar el guardia" +# BLOCK no-hardcoded-secrets (blocking) +# Why it matters: un secreto en el repo queda en la historia de git para siempre... +# >>> Commit BLOCKED: a blocking rule was broken. + +git reset demo_leak.py && rm demo_leak.py # deshacer el experimento +git commit -m "..." # los commits normales pasan sin más +``` + +Ese ciclo — violar, ser frenado *con el porqué*, arreglar, commitear — es todo +lo que becwright hace, para siempre, automáticamente. + ## Por qué un guardia, no un cartel Un agente de IA escribe un módulo y deja una nota: *"esto nunca debe loguear @@ -264,7 +288,29 @@ Cada check es un módulo que se invoca desde el campo `check`. Funcionan buscando texto en tus archivos con un patrón — simples y predecibles a propósito; el verdadero valor está en atar cada regla a su *por qué*. Para análisis más profundo, apuntá una regla a cualquier herramienta que ya uses -(gitleaks, ruff, semgrep) como su check. +como su check — la regla lleva el *por qué*, la herramienta hace la detección: + +```yaml + - id: no-secrets-gitleaks + intent: > + Ningún secreto puede commitearse, según el ruleset completo de gitleaks. + why_it_matters: > + Una credencial filtrada en la historia de git queda expuesta para siempre, + incluso después de un revert. + paths: ["**/*"] + check: "gitleaks detect --no-git --redact --exit-code 1" + severity: blocking + + - id: python-passes-ruff + intent: "El código Python debe pasar el ruleset de ruff del equipo antes del commit." + why_it_matters: "Un lint consistente mantiene el review enfocado en la lógica, no en el estilo." + paths: ["**/*.py"] + check: "xargs ruff check --force-exclude" + severity: warning +``` + +Más patrones listos (semgrep, eslint, rutas congeladas, límites de +arquitectura, CI): **[recetas](documentation/recipes.es.md)**. | Check | Qué detecta | Lenguaje | Severidad sugerida | |---|---|---|---| @@ -351,6 +397,8 @@ La documentación completa vive en [`documentation/`](documentation/README.es.md - **Recién empezás:** [uso](documentation/usage.es.md) — instalación, los comandos, códigos de salida y cómo escribir una regla. +- **Reglas para copiar y pegar** (gitleaks/ruff/semgrep como checks, rutas + congeladas, límites de arquitectura, CI): [recetas](documentation/recipes.es.md). - **Querés agregar tu propia regla:** [escribir checks](documentation/writing-checks.es.md). - **Compartir reglas entre proyectos:** [portabilidad](documentation/portability.es.md). - **Curiosidad por cómo funciona adentro:** [arquitectura y flujo](documentation/architecture.es.md). @@ -404,8 +452,12 @@ de pre-commit — ver más arriba. **¿Necesito Python?** No. `npm i -g becwright` instala un binario autónomo; `pipx install becwright` también funciona. -**¿Funciona en Windows?** Sí, vía Git Bash (el hook es un script `sh`, que Git -para Windows provee). La CLI `becwright` en sí es multiplataforma. +**¿Funciona en Windows?** En beta. La CLI y el hook corren bajo Git Bash (que +Git para Windows provee), pero Windows todavía no se ejercita en CI — los +huecos conocidos están en +[#31](https://github.com/DataDave-Dev/becwright/issues/31) y el soporte de +primera clase es el milestone v1.3. Hasta entonces, tratá Windows como +best-effort. **¿Cómo ignoro una línea?** Poné un comentario `becwright: ignore` en ella. diff --git a/README.md b/README.md index bc7d160..294ab9b 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ With becwright, the commit never happens: > **See it yourself in 5 seconds** — no setup, no git, nothing on your machine is > touched: > ```bash -> npx becwright demo # zero-install · or: pipx run becwright demo +> npx becwright demo # zero-install · or: uvx becwright demo · pipx run becwright demo > ``` ## Get started @@ -53,6 +53,10 @@ becwright init # detects your language, writes .bec/rules.yaml, ins That's it. From now on every `git commit` runs the checks by itself and stops a commit that breaks a blocking rule. You never call becwright by hand again. +> **Which install?** `npm install -g` to try it out or for solo use; +> `npm install --save-dev becwright` for a team repo, so the version is pinned +> in `package.json` and the hook finds it in `node_modules/.bin`. + - **Existing codebase with debt?** `becwright init --baseline` starts already-violated rules as `warning` (nothing legitimate is blocked) and clean rules as `blocking`. Fix the debt over time, then graduate each rule. @@ -66,7 +70,7 @@ commit that breaks a blocking rule. You never call becwright by hand again. ```bash pnpm add -g becwright -pipx install becwright # or: pip install becwright +pipx install becwright # or: pip install becwright / uv tool install becwright npm install --save-dev becwright # project-local; the hook finds it in node_modules/.bin ``` @@ -75,6 +79,26 @@ platform (`linux-x64`, `linux-arm64`, `darwin-x64`, `darwin-arm64`, `win32-x64`) On any other platform, use `pipx install becwright`. +### Feel it block, in 90 seconds + +The fastest way to trust a guard is to watch it stop you once: + +```bash +cd your-project && becwright init # rules + hook, one command + +echo 'api_key = "AKIAIOSFODNN7EXAMPLE"' >> demo_leak.py +git add demo_leak.py && git commit -m "test the guard" +# BLOCK no-hardcoded-secrets (blocking) +# Why it matters: a secret in the repo stays in git history forever... +# >>> Commit BLOCKED: a blocking rule was broken. + +git reset demo_leak.py && rm demo_leak.py # undo the experiment +git commit -m "..." # normal commits just pass +``` + +That loop — violate, get blocked *with the why*, fix, commit — is everything +becwright does, forever, automatically. + ## Why a guard, not a sign An AI agent writes a module and notes *"this must never log session tokens."* @@ -256,7 +280,29 @@ constraint, not the whole style guide re-read into context. Each check is a module invoked from the `check` field. They work by searching the text of your files for a pattern — simple and predictable on purpose; the real value is in tying each rule to its *why*. For deeper analysis, point a -rule at any tool you already trust (gitleaks, ruff, semgrep) as its check. +rule at any tool you already trust as its check — the rule carries the *why*, +the tool does the detection: + +```yaml + - id: no-secrets-gitleaks + intent: > + No secret may ever be committed, as judged by gitleaks' full ruleset. + why_it_matters: > + A leaked credential in git history is exposed forever, even after a revert. + paths: ["**/*"] + check: "gitleaks detect --no-git --redact --exit-code 1" + severity: blocking + + - id: python-passes-ruff + intent: "Python code must pass the team's ruff ruleset before commit." + why_it_matters: "Consistent lint keeps review focused on logic, not style." + paths: ["**/*.py"] + check: "xargs ruff check --force-exclude" + severity: warning +``` + +More ready-made patterns (semgrep, eslint, frozen paths, architecture +boundaries, CI): **[recipes](documentation/recipes.md)**. | Check | What it detects | Language | Suggested severity | |---|---|---|---| @@ -342,6 +388,8 @@ Full docs live in [`documentation/`](documentation/): - **Just getting started:** [usage](documentation/usage.md) — install, the commands, exit codes, and how to write a rule. +- **Copy-paste rules for common jobs** (gitleaks/ruff/semgrep as checks, frozen + paths, architecture boundaries, CI): [recipes](documentation/recipes.md). - **Want to add your own rule:** [writing checks](documentation/writing-checks.md). - **Sharing rules between projects:** [portability](documentation/portability.md). - **Curious how it works inside:** [architecture & flow](documentation/architecture.md). @@ -393,8 +441,11 @@ rule that carries its *why* and travels between repos. You can even run becwrigh **Do I need Python?** No. `npm i -g becwright` installs a self-contained binary; `pipx install becwright` also works. -**Does it work on Windows?** Yes, via Git Bash (the git hook is a `sh` script, -which Git for Windows provides). The `becwright` CLI itself is cross-platform. +**Does it work on Windows?** In beta. The CLI and hook run under Git Bash +(which Git for Windows provides), but Windows is not yet exercised in CI — +known gaps are tracked in +[#31](https://github.com/DataDave-Dev/becwright/issues/31) and first-class +support is the v1.3 milestone. Until then, treat Windows as best-effort. **How do I ignore a single line?** Add a `becwright: ignore` comment on it. diff --git a/documentation/README.es.md b/documentation/README.es.md index 7c049a8..a4ff973 100644 --- a/documentation/README.es.md +++ b/documentation/README.es.md @@ -10,6 +10,7 @@ lenguaje simple y después profundiza, así que podés parar donde deje de serte **Empezá acá** - [Uso](usage.es.md) — instalación, comandos y cómo escribir una regla. Leé esto primero. +- [Recetas](recipes.es.md) — reglas para copiar y pegar: gitleaks/ruff/semgrep como checks, rutas congeladas, límites de arquitectura, CI, Husky. - [Escribir checks](writing-checks.es.md) — el atajo sin código `forbid` y luego checks propios en cualquier lenguaje. - [Portabilidad](portability.es.md) — compartir una regla entre proyectos con export/import. diff --git a/documentation/README.md b/documentation/README.md index 2d98fe7..66fe0f3 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -10,6 +10,7 @@ prior background assumed. **Start here** - [Usage](usage.md) — install, the commands, and how to write a rule. Read this first. +- [Recipes](recipes.md) — copy-paste rules for common jobs: gitleaks/ruff/semgrep as checks, frozen paths, architecture boundaries, CI, Husky. - [Writing checks](writing-checks.md) — the no-code `forbid` shortcut, then custom checks in any language. - [Portability](portability.md) — share a rule between projects with export/import. diff --git a/documentation/recipes.es.md b/documentation/recipes.es.md new file mode 100644 index 0000000..cb110e2 --- /dev/null +++ b/documentation/recipes.es.md @@ -0,0 +1,216 @@ +> [English](recipes.md) · **Español** + +# Recetas + +Reglas y configs para copiar y pegar, para los casos más comunes. Cada regla +va bajo `rules:` en tu `.bec/rules.yaml`; cada archivo de config está completo. + +**Cómo recibe su entrada un check:** becwright le pasa la lista de archivos +matcheados por **stdin**, una ruta por línea, con la raíz del repo como +directorio de trabajo. Así, `xargs ` sirve de puente a cualquier +herramienta que reciba archivos como argumentos, y las que escanean el +directorio funcionan directo. + +> **Una salvedad para herramientas externas:** en un commit normal, los checks +> corren dentro de un snapshot temporal del contenido *staged* (así juzgan +> exactamente lo que el commit va a registrar). Ese snapshot no es un +> repositorio git — usá el modo de escaneo de directorio o de archivos de la +> herramienta (`gitleaks detect --no-git`, `ruff check`, `semgrep scan`), no un +> modo que necesite `.git` (`gitleaks protect`). + +## Bloquear secretos (incluido, sin instalar nada) + +```yaml + - id: no-hardcoded-secrets + intent: > + Ningún secreto (clave, token, password) puede estar hardcodeado en el + código. + why_it_matters: > + Un secreto en el repo queda en la historia de git para siempre y es + visible para cualquiera con acceso al código. + paths: ["**/*"] + check: "becwright run hardcoded_secrets" + severity: blocking +``` + +## Correr gitleaks como check + +El check incluido es una red rápida de regex. Si ya confiás en +[gitleaks](https://github.com/gitleaks/gitleaks), apuntá la regla a él — la +regla conserva el *por qué*, gitleaks hace la detección profunda: + +```yaml + - id: no-secrets-gitleaks + intent: > + Ningún secreto puede commitearse, según el ruleset completo de gitleaks. + why_it_matters: > + Una credencial filtrada en la historia de git queda expuesta para + siempre, incluso después de un revert. + paths: ["**/*"] + check: "gitleaks detect --no-git --redact --exit-code 1" + severity: blocking +``` + +## Correr ruff como check + +```yaml + - id: python-passes-ruff + intent: > + El código Python debe pasar el ruleset de ruff del equipo antes de + commitearse. + why_it_matters: > + Un lint consistente mantiene los diffs limpios y el review enfocado en la + lógica, no en el estilo. + paths: ["**/*.py"] + check: "xargs ruff check --force-exclude" + severity: warning +``` + +## Correr semgrep como check + +```yaml + - id: semgrep-ci-rules + intent: > + Los archivos cambiados deben pasar la política semgrep del equipo. + why_it_matters: > + Las reglas AST de semgrep atrapan patrones de inyección y de lógica que + un regex no puede. + paths: ["**/*.py", "**/*.js", "**/*.ts"] + check: "xargs semgrep scan --error --quiet --config p/ci" + severity: blocking +``` + +La misma forma sirve para cualquier herramienta con código de salida: eslint +(`xargs eslint --no-warn-ignored`), shellcheck (`xargs shellcheck`), hadolint, +tsc, mypy… + +## Sin `console.log` / `debugger` (JS/TS) + +```yaml + - id: no-debugger-js + intent: "No dejar 'debugger;' en el código JavaScript/TypeScript." + why_it_matters: "Un 'debugger' olvidado detiene la ejecución en producción." + paths: ["**/*.js", "**/*.ts"] + check: "becwright run forbid --pattern '\\bdebugger\\b'" + severity: blocking + + - id: no-console-log-js + intent: "Evitar 'console.log(...)' fuera del módulo de logging." + why_it_matters: "Los console.log de debug ensucian la salida en producción." + paths: ["**/*.js", "**/*.ts"] + exclude: ["src/lib/logger.ts"] + check: "becwright run forbid --pattern 'console\\.log\\s*\\('" + severity: warning +``` + +## Congelar rutas críticas (p. ej. migraciones aplicadas) + +`filename --forbid '.*'` falla ante *cualquier* archivo staged que matchee los +`paths` de la regla — o sea, la regla se lee como "cambiar estos archivos frena +el commit". Ideal para archivos que un agente de IA no debe tocar jamás: + +```yaml + - id: frozen-migrations + intent: > + Las migraciones de base de datos ya aplicadas son inmutables; escribí una + migración nueva en su lugar. + why_it_matters: > + Editar una migración aplicada desincroniza todas las bases que ya la + corrieron. + paths: ["migrations/**"] + check: "becwright run filename --forbid '.*'" + severity: blocking +``` + +## Forzar un límite de arquitectura + +```yaml + - id: domain-does-not-import-infra + intent: > + La capa de dominio no debe importar de la capa de infraestructura. + why_it_matters: > + Un dominio que llega a infra ya no puede testearse ni reutilizarse + aislado; la dependencia debe apuntar hacia adentro. + paths: ["src/domain/**/*.py"] + check: "becwright run forbid --pattern 'from app\\.infra|import app\\.infra'" + severity: blocking +``` + +## Mensajes de commit convencionales + +```yaml + - id: conventional-commits + target: commit-msg + intent: "Los mensajes de commit siguen el formato Conventional Commits." + why_it_matters: "Un formato consistente mantiene la historia legible y habilita changelogs automáticos." + check: |- + becwright run require --pattern '^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(.+\))?!?: ' + severity: blocking +``` + +## CI: GitHub Actions + +`.github/workflows/becwright.yml` — chequea solo los archivos que cambió el +PR, así la deuda preexistente nunca rompe el build: + +```yaml +name: becwright +on: pull_request + +jobs: + becwright: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: DataDave-Dev/becwright@v1.0.0 +``` + +Marcalo como check *required* en la protección de rama y las reglas ya no se +pueden saltar con `git commit --no-verify`. + +## Framework pre-commit + +`.pre-commit-config.yaml`: + +```yaml +repos: + - repo: https://github.com/DataDave-Dev/becwright + rev: v1.0.0 + hooks: + - id: becwright +``` + +## Husky + +`.husky/pre-commit`: + +```sh +npx becwright check +``` + +## Scripts de package.json + +```json +{ + "scripts": { + "bec": "becwright check", + "bec:all": "becwright check --all" + }, + "devDependencies": { + "becwright": "^1.0.0" + } +} +``` + +## Claude Code y MCP + +```text +/plugin marketplace add DataDave-Dev/becwright +/plugin install becwright@becwright +``` + +Para cualquier agente con MCP, `becwright mcp` (se instala con +`pipx install "becwright[mcp]"`) expone las reglas como herramientas. Detalles: +[mcp.es.md](mcp.es.md). diff --git a/documentation/recipes.md b/documentation/recipes.md new file mode 100644 index 0000000..ae4d513 --- /dev/null +++ b/documentation/recipes.md @@ -0,0 +1,209 @@ +> **English** · [Español](recipes.es.md) + +# Recipes + +Copy-paste rules and configs for the most common jobs. Every rule below goes +under `rules:` in your `.bec/rules.yaml`; every config file is complete. + +**How a check gets its input:** becwright feeds the matched file list to the +check on **stdin**, one path per line, with the repo root as working directory. +So `xargs ` bridges to any tool that takes file arguments, and tools that +scan the working directory just work. + +> **One caveat for external tools:** on a normal commit, checks run inside a +> temporary snapshot of the *staged* content (so they judge exactly what the +> commit will record). That snapshot is not a git repository — use a tool's +> directory- or file-scanning mode (`gitleaks detect --no-git`, `ruff check`, +> `semgrep scan`), not a mode that needs `.git` (`gitleaks protect`). + +## Block secrets (built-in, zero install) + +```yaml + - id: no-hardcoded-secrets + intent: > + No secret (key, token, password) may be hardcoded in the code. + why_it_matters: > + A secret in the repo stays in git history forever and is visible to + anyone with access to the code. + paths: ["**/*"] + check: "becwright run hardcoded_secrets" + severity: blocking +``` + +## Run gitleaks as the check + +The built-in check is a fast regex net. If you already trust +[gitleaks](https://github.com/gitleaks/gitleaks), point the rule at it — the +rule keeps the *why*, gitleaks does the deep detection: + +```yaml + - id: no-secrets-gitleaks + intent: > + No secret may ever be committed, as judged by gitleaks' full ruleset. + why_it_matters: > + A leaked credential in git history is exposed forever, even after a + revert. + paths: ["**/*"] + check: "gitleaks detect --no-git --redact --exit-code 1" + severity: blocking +``` + +## Run ruff as the check + +```yaml + - id: python-passes-ruff + intent: > + Python code must pass the team's ruff ruleset before it is committed. + why_it_matters: > + Consistent lint keeps diffs clean and review focused on logic, not style. + paths: ["**/*.py"] + check: "xargs ruff check --force-exclude" + severity: warning +``` + +## Run semgrep as the check + +```yaml + - id: semgrep-ci-rules + intent: > + Changed files must pass the team's semgrep policy. + why_it_matters: > + Semgrep's AST rules catch injection and logic patterns a regex cannot. + paths: ["**/*.py", "**/*.js", "**/*.ts"] + check: "xargs semgrep scan --error --quiet --config p/ci" + severity: blocking +``` + +The same shape works for any tool with an exit code: eslint +(`xargs eslint --no-warn-ignored`), shellcheck (`xargs shellcheck`), +hadolint, tsc, mypy… + +## No `console.log` / `debugger` (JS/TS) + +```yaml + - id: no-debugger-js + intent: "Do not leave 'debugger;' in JavaScript/TypeScript code." + why_it_matters: "A forgotten 'debugger' halts execution in production." + paths: ["**/*.js", "**/*.ts"] + check: "becwright run forbid --pattern '\\bdebugger\\b'" + severity: blocking + + - id: no-console-log-js + intent: "Avoid 'console.log(...)' outside the logger module." + why_it_matters: "Debug console.log statements clutter production output." + paths: ["**/*.js", "**/*.ts"] + exclude: ["src/lib/logger.ts"] + check: "becwright run forbid --pattern 'console\\.log\\s*\\('" + severity: warning +``` + +## Freeze critical paths (e.g. applied migrations) + +`filename --forbid '.*'` fails on *any* staged file the rule's `paths` match — +so the rule reads as "changing these files blocks the commit". Ideal for files +an AI agent must never touch: + +```yaml + - id: frozen-migrations + intent: > + Applied database migrations are immutable; write a new migration instead. + why_it_matters: > + Editing an applied migration desynchronizes every database that already + ran it. + paths: ["migrations/**"] + check: "becwright run filename --forbid '.*'" + severity: blocking +``` + +## Enforce an architecture boundary + +```yaml + - id: domain-does-not-import-infra + intent: > + The domain layer must not import from the infrastructure layer. + why_it_matters: > + Domain code that reaches into infra can no longer be tested or reused in + isolation; the dependency must point inward. + paths: ["src/domain/**/*.py"] + check: "becwright run forbid --pattern 'from app\\.infra|import app\\.infra'" + severity: blocking +``` + +## Conventional commit messages + +```yaml + - id: conventional-commits + target: commit-msg + intent: "Commit messages follow the Conventional Commits format." + why_it_matters: "A consistent format keeps history readable and enables automated changelogs." + check: |- + becwright run require --pattern '^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(.+\))?!?: ' + severity: blocking +``` + +## CI: GitHub Actions + +`.github/workflows/becwright.yml` — checks only the files the PR changed, so +pre-existing debt never fails the build: + +```yaml +name: becwright +on: pull_request + +jobs: + becwright: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: DataDave-Dev/becwright@v1.0.0 +``` + +Make it a *required* check in branch protection and the rules can no longer be +skipped with `git commit --no-verify`. + +## pre-commit framework + +`.pre-commit-config.yaml`: + +```yaml +repos: + - repo: https://github.com/DataDave-Dev/becwright + rev: v1.0.0 + hooks: + - id: becwright +``` + +## Husky + +`.husky/pre-commit`: + +```sh +npx becwright check +``` + +## package.json scripts + +```json +{ + "scripts": { + "bec": "becwright check", + "bec:all": "becwright check --all" + }, + "devDependencies": { + "becwright": "^1.0.0" + } +} +``` + +## Claude Code and MCP + +```text +/plugin marketplace add DataDave-Dev/becwright +/plugin install becwright@becwright +``` + +For any MCP-capable agent, `becwright mcp` (install with +`pipx install "becwright[mcp]"`) exposes the rules as tools. Details: +[mcp.md](mcp.md). diff --git a/documentation/stability.es.md b/documentation/stability.es.md index 7080cd8..3ae3f68 100644 --- a/documentation/stability.es.md +++ b/documentation/stability.es.md @@ -21,6 +21,14 @@ Estable desde `1.0.0`, cambia solo con un bump mayor: Todo lo demás (el texto de los mensajes, el contenido del catálogo, los módulos internos) puede cambiar en cualquier momento. +## Soporte de plataformas + +Linux y macOS tienen soporte completo y se ejercitan en CI. **Windows está en +beta**: la CLI y el hook corren bajo Git Bash (que Git para Windows provee), +pero Windows todavía no es parte de la matriz de CI y hay huecos conocidos +([#31](https://github.com/DataDave-Dev/becwright/issues/31)). El soporte de +primera clase es el milestone v1.3. + Antes de `1.0.0` la base fue: los dos formatos en disco versionados para que un archivo más nuevo falle fuerte (`schema_version` / `becwright_bec`), el conjunto de campos de `rules.yaml` congelado y fijado por tests, los códigos de salida y diff --git a/documentation/stability.md b/documentation/stability.md index 857ddb6..f9e4327 100644 --- a/documentation/stability.md +++ b/documentation/stability.md @@ -20,6 +20,14 @@ Stable as of `1.0.0`, changed only on a major bump: Everything else (message wording, catalog contents, internal modules) can change at any time. +## Platform support + +Linux and macOS are fully supported and exercised in CI. **Windows is beta**: +the CLI and the hook run under Git Bash (which Git for Windows provides), but +Windows is not yet part of the CI matrix and known gaps exist +([#31](https://github.com/DataDave-Dev/becwright/issues/31)). First-class +Windows support is the v1.3 milestone. + Before `1.0.0` the groundwork was: both on-disk formats versioned so a newer file fails loudly (`schema_version` / `becwright_bec`), the `rules.yaml` field set frozen and test-locked, exit codes and `check --json` documented and test-locked, diff --git a/documentation/usage.es.md b/documentation/usage.es.md index 5e2e9ae..1d4dd2c 100644 --- a/documentation/usage.es.md +++ b/documentation/usage.es.md @@ -10,9 +10,12 @@ Ese es todo el ciclo — el resto de esta página es el detalle. ## Instalación ```bash -pipx install becwright # o: pip install becwright +pipx install becwright # o: pip install becwright / uv tool install becwright ``` +(O sin Python: `npm install -g becwright` trae un binario autónomo por +plataforma.) + ## Configurar un repo ```bash @@ -222,3 +225,26 @@ paquete — instalás desde él con un comando, sin URL y sin conexión: becwright search # lista el catálogo becwright add no-debugger-js # instalá una ``` + +## Rendimiento y límites + +Notas honestas sobre cómo corre el motor, para que puedas predecir su +comportamiento: + +- **Un proceso por regla.** El `check` de cada regla corre como su propio + subproceso sobre los archivos matcheados. En el camino normal del commit (un + puñado de archivos staged) es instantáneo. `becwright check --all` en un repo + muy grande con muchas reglas paga un arranque de proceso por regla — rápido + en la práctica, pero no está diseñado como escáner de monorepos completos. + En CI, preferí `check --diff `, que solo mira lo que cambió el PR. +- **Un check colgado no puede congelar tu commit.** Cada check tiene un tope de + 30 segundos; se ajusta con la variable de entorno `BECWRIGHT_CHECK_TIMEOUT` + (segundos; `0` desactiva el tope) para corridas lentas sobre todo el repo. +- **Un solo `.bec/rules.yaml` por repositorio**, en la raíz. Todavía no hay + archivo de reglas por paquete para monorepos — delimitá reglas por paquete + con globs en `paths`/`exclude` (p. ej. `paths: ["packages/api/**/*.ts"]`). +- **Los checks juzgan el contenido staged.** Al commitear, los checks corren + sobre un snapshot de lo que el commit va a registrar — no sobre tu working + tree, que puede tener ediciones sin stagear. Mirá la nota en + [recetas](recipes.es.md) si un check envuelve una herramienta externa que + espera un repositorio git. diff --git a/documentation/usage.md b/documentation/usage.md index c70a39c..6d68e88 100644 --- a/documentation/usage.md +++ b/documentation/usage.md @@ -10,9 +10,12 @@ whole loop — the rest of this page is the detail. ## Install ```bash -pipx install becwright # or: pip install becwright +pipx install becwright # or: pip install becwright / uv tool install becwright ``` +(Or without Python at all: `npm install -g becwright` ships a self-contained +binary per platform.) + ## Set up a repo ```bash @@ -220,3 +223,24 @@ the package — install from it with one command, no URL, works offline: becwright search # list the catalog becwright add no-debugger-js # install one ``` + +## Performance and limits + +Honest notes on how the engine runs, so you can predict its behavior: + +- **One process per rule.** Each rule's `check` runs as its own subprocess over + the matched files. On the normal commit path (a handful of staged files) this + is instantaneous. `becwright check --all` on a very large repo with many + rules pays one process start per rule — fast in practice, but not designed as + a whole-monorepo scanner. In CI, prefer `check --diff `, which only + looks at what the PR changed. +- **A hung check cannot freeze your commit.** Every check is capped at 30 + seconds; override with the `BECWRIGHT_CHECK_TIMEOUT` environment variable + (seconds; `0` disables the cap) for slow whole-repo runs. +- **One `.bec/rules.yaml` per repository**, at the root. There is no + per-package rules file for monorepos yet — scope rules to packages with + `paths`/`exclude` globs instead (e.g. `paths: ["packages/api/**/*.ts"]`). +- **Checks judge the staged content.** On commit, checks run against a snapshot + of what the commit will actually record — not your working tree, which may + hold unstaged edits. See the note in [recipes](recipes.md) if a check wraps + an external tool that expects a git repository.