From 58abcf5c6a8a6c02d17ccb7f86c52ae977bed2ff Mon Sep 17 00:00:00 2001 From: Tara X V01D <1711810+taraxvoid@users.noreply.github.com> Date: Fri, 2 Oct 2026 14:19:30 -0500 Subject: [PATCH 1/3] feat(lefthook): pick bun or pnpm from the lockfile in the shared site hooks Co-Authored-By: Claude Sonnet 5.5 --- README.md | 3 ++- lefthook/site.yml | 33 +++++++++++++++++++-------------- test/lefthook-site.test.ts | 10 ++++++++-- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 9f63a60..092238c 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,8 @@ on the repo. [`lefthook/site.yml`](lefthook/site.yml) is the shared hook set for the site stack, consumed as a lefthook remote. It calls the site's own `package.json` -scripts (`bun run --if-present`, so a missing script is skipped): +scripts (` run --if-present`, so a missing script is skipped; `` is pnpm +when the repo has a `pnpm-lock.yaml`, bun otherwise): - `pre-commit`: dependency guard, `format` (formatted files are re-staged), `lint:actions`, `check`, `test:unit`, and `check:licenses` / `audit` when the diff --git a/lefthook/site.yml b/lefthook/site.yml index b1a9c94..71489ba 100644 --- a/lefthook/site.yml +++ b/lefthook/site.yml @@ -1,11 +1,12 @@ -# Shared git hooks for the Astro/bun site stack. Sites pull this in as a -# lefthook remote and call their own package.json scripts, so a script a site -# does not define is skipped (`bun run --if-present`). +# Shared git hooks for the Astro site stack (bun, or pnpm when the repo has a +# pnpm-lock.yaml). Sites pull this in as a lefthook remote and call their own +# package.json scripts, so a script a site does not define is skipped +# (` run --if-present`). # # # lefthook.yml in the site # remotes: # - git_url: https://github.com/taraxvoid/voidflow -# ref: # pin; bump deliberately +# ref: # a tag or branch (not a SHA); bump deliberately # configs: # - lefthook/site.yml # @@ -14,6 +15,10 @@ # one defined here. Differences go through package.json scripts instead, e.g. # `test:unit:precommit` replaces `test:unit` for the pre-commit unit step. +templates: + # Package manager: pnpm when the repo is a pnpm project, bun otherwise. + pm: "$(if [ -f pnpm-lock.yaml ]; then echo pnpm; else echo bun; fi)" + pre-commit: skip: [merge, rebase] commands: @@ -22,39 +27,39 @@ pre-commit: run: | if [ ! -d node_modules ]; then echo "pre-commit: 'node_modules' is missing, dependencies aren't installed." - echo " Run 'bun install' before committing, then commit again." + echo " Run '{pm} install' before committing, then commit again." exit 1 fi format: priority: 2 - run: bun run --if-present format + run: "{pm} run --if-present format" stage_fixed: true lint-actions: priority: 3 - run: bun run --if-present lint:actions + run: "{pm} run --if-present lint:actions" typecheck: priority: 3 - run: bun run --if-present check + run: "{pm} run --if-present check" unit: priority: 3 # A site that can't run its whole suite pre-commit (e.g. tests that need # a built dist/) defines `test:unit:precommit`; otherwise test:unit runs. run: | if grep -q '"test:unit:precommit"' package.json; then - bun run test:unit:precommit + {pm} run test:unit:precommit else - bun run --if-present test:unit + {pm} run --if-present test:unit fi licenses: priority: 3 glob: "{package.json,bun.lock,pnpm-lock.yaml}" - run: bun run --if-present check:licenses + run: "{pm} run --if-present check:licenses" audit: # Local only: hits a remote vulnerability database and can hang offline, # so it runs when dependencies changed and fails closed. priority: 3 glob: "{package.json,bun.lock,pnpm-lock.yaml}" - run: bun run --if-present audit + run: "{pm} run --if-present audit" commit-msg: commands: @@ -109,8 +114,8 @@ pre-push: if [ ! -d node_modules ]; then echo "pre-push: 'node_modules' is missing, dependencies aren't installed." - echo " Run 'bun install' before pushing, then push again." + echo " Run '{pm} install' before pushing, then push again." exit 1 fi - bun run --if-present test:push + {pm} run --if-present test:push diff --git a/test/lefthook-site.test.ts b/test/lefthook-site.test.ts index 574c31d..ca0d12c 100644 --- a/test/lefthook-site.test.ts +++ b/test/lefthook-site.test.ts @@ -28,7 +28,13 @@ describe('lefthook/site.yml', () => { test('pre-commit unit step prefers test:unit:precommit when a site defines it', async () => { const text = await Bun.file(config).text() expect(text).toContain('grep -q \'"test:unit:precommit"\' package.json') - expect(text).toContain('bun run test:unit:precommit') - expect(text).toContain('bun run --if-present test:unit') + expect(text).toContain('{pm} run test:unit:precommit') + expect(text).toContain('{pm} run --if-present test:unit') + }) + + test('picks the package manager from the lockfile instead of hardcoding bun', async () => { + const text = await Bun.file(config).text() + expect(text).toContain('pnpm-lock.yaml ]; then echo pnpm; else echo bun') + expect(text).not.toMatch(/\bbun run\b/) }) }) From 1ad3cce3ee5c01f375cce4a507aee49e67b9431e Mon Sep 17 00:00:00 2001 From: Tara X V01D <1711810+taraxvoid@users.noreply.github.com> Date: Fri, 2 Oct 2026 14:20:11 -0500 Subject: [PATCH 2/3] fix(lefthook): skip audit step when the site has no audit script Co-Authored-By: Claude Sonnet 5.5 --- lefthook/site.yml | 8 +++++++- test/lefthook-site.test.ts | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lefthook/site.yml b/lefthook/site.yml index 71489ba..3f7c78d 100644 --- a/lefthook/site.yml +++ b/lefthook/site.yml @@ -59,7 +59,13 @@ pre-commit: # so it runs when dependencies changed and fails closed. priority: 3 glob: "{package.json,bun.lock,pnpm-lock.yaml}" - run: "{pm} run --if-present audit" + # Checked by hand: under bun, `run --if-present audit` falls through to + # the system `audit` binary (macOS /usr/sbin/audit) when the site has no + # audit script, and that exits non-zero. + run: | + if grep -q '"audit"' package.json; then + {pm} run audit + fi commit-msg: commands: diff --git a/test/lefthook-site.test.ts b/test/lefthook-site.test.ts index ca0d12c..f44c796 100644 --- a/test/lefthook-site.test.ts +++ b/test/lefthook-site.test.ts @@ -37,4 +37,10 @@ describe('lefthook/site.yml', () => { expect(text).toContain('pnpm-lock.yaml ]; then echo pnpm; else echo bun') expect(text).not.toMatch(/\bbun run\b/) }) + + test('audit step only runs when the site defines an audit script', async () => { + const text = await Bun.file(config).text() + expect(text).toContain('grep -q \'"audit"\' package.json') + expect(text).not.toContain('--if-present audit') + }) }) From e1df7530ee281fc67db72c5f7cf0661b4fb60a9b Mon Sep 17 00:00:00 2001 From: Tara X V01D <1711810+taraxvoid@users.noreply.github.com> Date: Fri, 2 Oct 2026 14:20:20 -0500 Subject: [PATCH 3/3] test(lefthook): keep the audit comment from tripping its own assertion Co-Authored-By: Claude Sonnet 5.5 --- lefthook/site.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lefthook/site.yml b/lefthook/site.yml index 3f7c78d..47dc8e6 100644 --- a/lefthook/site.yml +++ b/lefthook/site.yml @@ -59,7 +59,7 @@ pre-commit: # so it runs when dependencies changed and fails closed. priority: 3 glob: "{package.json,bun.lock,pnpm-lock.yaml}" - # Checked by hand: under bun, `run --if-present audit` falls through to + # Checked by hand: under bun, `--if-present` falls through to # the system `audit` binary (macOS /usr/sbin/audit) when the site has no # audit script, and that exits non-zero. run: |