#:schema https://www.schemastore.org/prek.json default_install_hook_types = ["pre-commit", "commit-msg"] # Local hooks default to the pre-commit stage; the commit lint opts into # commit-msg explicitly. default_stages = ["pre-commit"] [[repos]] repo = "builtin" hooks = [ { id = "trailing-whitespace" }, { id = "end-of-file-fixer" }, { id = "check-merge-conflict" }, { id = "check-added-large-files" }, { id = "check-json" }, ] [[repos]] repo = "local" [[repos.hooks]] id = "tsc" name = "typescript type-check" entry = "npm run check" language = "system" files = '\.(ts|tsx)$|tsconfig\.json$' pass_filenames = false # Offline half of the release guard (the --hosted and --dist halves belong to # scripts/deploy-ext.sh). Catches metadata that no longer covers every id the # extension ships under at the commit that causes it, not at the release that # would ship it. [[repos.hooks]] id = "oauth-metadata" name = "oauth client metadata covers every extension id" entry = "node scripts/check-oauth-metadata.mjs" language = "system" files = '^(oauth/.+\.json|public/manifest\.json|src/lib/authflow\.ts|scripts/check-oauth-metadata\.mjs)$' pass_filenames = false [[repos.hooks]] id = "tofu-fmt" name = "opentofu fmt" entry = "tofu fmt -check -diff" language = "system" files = '\.tf$' # Read-only: version bumping happens at release time (npm run bump), not per # commit, so parallel worktrees stop conflicting on the version files. [[repos.hooks]] id = "commit-lint" name = "conventional commit header lint" entry = "node scripts/lint-commit-msg.mjs" language = "system" stages = ["commit-msg"] # Regeneration hooks: when a brand source or its render script changes, the # derived assets are re-rendered in place. A hook that rewrites files fails # the run; stage the regenerated assets and commit again. Editing a derived # asset by hand also triggers its hook, so the render overwrites the edit. [[repos.hooks]] id = "icons" name = "render icon pngs from brand/sticker.svg" entry = "npm run icons" language = "system" files = '^(brand/sticker(-round)?\.svg|scripts/render-icons\.mjs|public/icons/icon\d+\.png|web/public/icons/icon\d+\.png|brand/icon480\.png|brand/icon\d+-round\.png|brand/icons-dev/icon\d+\.png)$' pass_filenames = false [[repos.hooks]] id = "wordmark" name = "render the wordmark from brand sources" entry = "npm run wordmark" language = "system" files = '^(scripts/(render-wordmark|render-icons|rasterize)\.mjs|brand/wordmark\.svg|brand/wordmark/.+\.png)$' pass_filenames = false [[repos.hooks]] id = "cws-tiles" name = "render chrome web store tiles from brand svgs" entry = "npm run cws" language = "system" files = '^(brand/(mark|sticker|wordmark)\.svg|scripts/(render-cws|render-icons|rasterize|compose|shots)\.mjs|brand/cws/.+\.png|docs/img/popup-(publication|labeled)\.png)$' pass_filenames = false # The frontpage gallery serves the popup captures themselves, so a recapture # has to reach web/public/ as well as docs/img/ or the site keeps showing the # old popup. Sizes go into web/src/shots.json, which the page reserves boxes # from; deploys re-run this and verify:dist refuses a stale copy. [[repos.hooks]] id = "site-shots" name = "sync the frontpage screenshots from docs/img" entry = "npm run shots" language = "system" files = '^(docs/img/popup-.+\.png|scripts/(shots|sync-shots|render-icons)\.mjs|web/public/shots/.+\.png|web/src/shots\.json)$' pass_filenames = false # The architecture diagram is Mermaid rendered to SVG ahead of time, because # the site's CSP blocks a client-side one. Same deal as the brand assets: edit # the .mmd, the .svg is re-rendered in place. Needs a local Chrome. [[repos.hooks]] id = "diagram" name = "render the architecture diagram from its mermaid source" entry = "npm --prefix web run diagram" language = "system" files = '^web/(src/diagrams/.+\.(mmd|svg)|scripts/render-diagram\.mjs)$' pass_filenames = false [[repos.hooks]] id = "og-card" name = "render the social card from brand svgs" entry = "npm run og" language = "system" files = '^(brand/(sticker|wordmark)\.svg|scripts/(render-og|render-icons|rasterize|compose)\.mjs|web/public/og\.png)$' pass_filenames = false [[repos.hooks]] id = "favicon" name = "copy brand/sticker.svg to the web favicon" entry = "cp brand/sticker.svg web/public/favicon.svg" language = "system" files = '^(brand/sticker\.svg|web/public/favicon\.svg)$' pass_filenames = false