From 9d20a36cc4e2e1e428e5a4bd2b82c4223ee7e714 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 11 Jun 2026 15:07:55 +0800 Subject: [PATCH] Add lefthook git hooks with a vendor-manifest guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pre-commit: ESLint --fix on staged files (vendored source excluded), incremental typecheck, and the vendor-manifest guard — any staged change under vendor/*/src must be accompanied by a vendor/README.md update in the same commit, mechanizing the local-modification log discipline. pre-push: tests + hygiene (knip/publint/constraints). Hooks call the same package.json scripts CI runs (single source of truth); installed automatically via postinstall. --- lefthook.yml | 29 ++++++++ package.json | 4 +- scripts/check-vendor-manifest.sh | 17 +++++ yarn.lock | 112 +++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 lefthook.yml create mode 100755 scripts/check-vendor-manifest.sh diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000000..7d2d9985e8 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,29 @@ +# Git hooks (lefthook). Hooks call the same package.json scripts CI runs — +# one source of truth; the hook is just an earlier, faster checkpoint. +# Install: `yarn lefthook install` (runs automatically via postinstall). + +pre-commit: + parallel: true + jobs: + - name: lint (staged) + glob: '*.{ts,mts,cts,mjs}' + exclude: + - 'vendor/*/src/**' + run: node_modules/.bin/eslint --fix {staged_files} && git add {staged_files} + stage_fixed: true + + - name: typecheck + glob: '*.ts' + run: yarn typecheck + + - name: vendor manifest guard + run: scripts/check-vendor-manifest.sh + +pre-push: + parallel: true + jobs: + - name: test + run: yarn test + + - name: hygiene + run: yarn hygiene diff --git a/package.json b/package.json index d8467be175..e2673aafb9 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "knip": "knip", "publint": "tsx scripts/publint-all.ts", "hygiene": "yarn knip && yarn publint && yarn constraints", - "demo": "node --expose-internals --import tsx examples/echo-agent/start.ts" + "demo": "node --expose-internals --import tsx examples/echo-agent/start.ts", + "postinstall": "lefthook install" }, "devDependencies": { "@stylistic/eslint-plugin": "^5.10.0", @@ -31,6 +32,7 @@ "dumble": "^0.2.3", "eslint": "^10.4.1", "knip": "^6.16.1", + "lefthook": "^2.1.9", "publint": "^0.3.21", "tsx": "^4.22.4", "typescript": "^6.0.3", diff --git a/scripts/check-vendor-manifest.sh b/scripts/check-vendor-manifest.sh new file mode 100755 index 0000000000..5e59a90e10 --- /dev/null +++ b/scripts/check-vendor-manifest.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Vendoring discipline, mechanized: any staged change under vendor/*/src or a +# vendored bin.js must come with a vendor/README.md change in the same commit +# (the manifest's local-modification log is the contract — see vendor/README.md). +set -euo pipefail + +staged=$(git diff --cached --name-only) + +vendor_src_changed=$(echo "$staged" | grep -E '^vendor/[^/]+/(src/|bin\.js)' || true) +manifest_changed=$(echo "$staged" | grep -x 'vendor/README.md' || true) + +if [[ -n "$vendor_src_changed" && -z "$manifest_changed" ]]; then + echo 'vendor manifest guard: vendored SOURCE changed without updating vendor/README.md:' + echo "$vendor_src_changed" | sed 's/^/ /' + echo 'Log the modification in vendor/README.md ("Local modifications") and stage it.' + exit 1 +fi diff --git a/yarn.lock b/yarn.lock index f0aa5a75bb..25f9efe052 100644 --- a/yarn.lock +++ b/yarn.lock @@ -184,6 +184,7 @@ __metadata: dumble: "npm:^0.2.3" eslint: "npm:^10.4.1" knip: "npm:^6.16.1" + lefthook: "npm:^2.1.9" publint: "npm:^0.3.21" tsx: "npm:^4.22.4" typescript: "npm:^6.0.3" @@ -2248,6 +2249,117 @@ __metadata: languageName: node linkType: hard +"lefthook-darwin-arm64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-darwin-arm64@npm:2.1.9" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"lefthook-darwin-x64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-darwin-x64@npm:2.1.9" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"lefthook-freebsd-arm64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-freebsd-arm64@npm:2.1.9" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"lefthook-freebsd-x64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-freebsd-x64@npm:2.1.9" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"lefthook-linux-arm64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-linux-arm64@npm:2.1.9" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"lefthook-linux-x64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-linux-x64@npm:2.1.9" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"lefthook-openbsd-arm64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-openbsd-arm64@npm:2.1.9" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"lefthook-openbsd-x64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-openbsd-x64@npm:2.1.9" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"lefthook-windows-arm64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-windows-arm64@npm:2.1.9" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"lefthook-windows-x64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-windows-x64@npm:2.1.9" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"lefthook@npm:^2.1.9": + version: 2.1.9 + resolution: "lefthook@npm:2.1.9" + dependencies: + lefthook-darwin-arm64: "npm:2.1.9" + lefthook-darwin-x64: "npm:2.1.9" + lefthook-freebsd-arm64: "npm:2.1.9" + lefthook-freebsd-x64: "npm:2.1.9" + lefthook-linux-arm64: "npm:2.1.9" + lefthook-linux-x64: "npm:2.1.9" + lefthook-openbsd-arm64: "npm:2.1.9" + lefthook-openbsd-x64: "npm:2.1.9" + lefthook-windows-arm64: "npm:2.1.9" + lefthook-windows-x64: "npm:2.1.9" + dependenciesMeta: + lefthook-darwin-arm64: + optional: true + lefthook-darwin-x64: + optional: true + lefthook-freebsd-arm64: + optional: true + lefthook-freebsd-x64: + optional: true + lefthook-linux-arm64: + optional: true + lefthook-linux-x64: + optional: true + lefthook-openbsd-arm64: + optional: true + lefthook-openbsd-x64: + optional: true + lefthook-windows-arm64: + optional: true + lefthook-windows-x64: + optional: true + bin: + lefthook: bin/index.js + checksum: 10c0/676d9798942439d1cd5373bb0b2c9907f6a8097b29c05cc028d87d897d2a2cfe15a8f7e4f40b02fa93cd1ae0f02528f24053a10fb5c5967210a9c23f3c7b5059 + languageName: node + linkType: hard + "levn@npm:^0.4.1": version: 0.4.1 resolution: "levn@npm:0.4.1"