From cb9519b8724680bfa77039a5f0ef17e1fa3c95a9 Mon Sep 17 00:00:00 2001 From: Lilith Date: Thu, 22 Jan 2026 15:42:58 -0800 Subject: [PATCH] feat(enforcement): Add pre-commit hook and CI verification for styled-components Completes the 6-layer defense strategy for single styled-components instance: - Add pre-commit hook blocking direct styled-components imports - Add CI job verifying single styled-components version - Configure git to use .githooks/pre-commit - Update build job dependencies to include verification Why: Multiple styled-components instances break ThemeProvider context propagation, causing props.theme to be undefined. These enforcement layers prevent regression across all 94 workspace packages. Enforcement mechanisms now active: 1. ESLint (eslint.config.js) - lint-time blocking 2. Pre-commit hook (.githooks/pre-commit) - commit-time blocking 3. CI verification (.forgejo/workflows/ci.yml) - PR-time blocking 4. pnpm override (package.json) - install-time forcing 5. Documentation (docs/architecture/) - knowledge base 6. Wrapper package (@lilith/ui-styled-components) - single source Co-Authored-By: Claude Sonnet 4.5 --- .forgejo/workflows/ci.yml | 47 +++++++++++++++++++++++++++++++++++- .githooks/pre-commit | 50 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100755 .githooks/pre-commit diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 6f3d31165..68cb20a18 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -103,6 +103,51 @@ jobs: run: pnpm lint:imports:check continue-on-error: false + verify-styled-components: + name: Verify Single styled-components Version + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + # Note: actions/setup-node@v4 skipped - incompatible with Forgejo act runner + - name: Configure Verdaccio NPM registry + run: | + echo "@lilith:registry=http://verdaccio:4873/" >> ~/.npmrc + echo "//verdaccio:4873/:_authToken=${{ secrets.FORGEJO_TOKEN }}" >> ~/.npmrc + + # Note: Not using --frozen-lockfile because lockfile has local link: paths + - run: pnpm install + + - name: Check for single styled-components version + run: | + echo "Checking styled-components versions in dependency tree..." + + # Get all styled-components versions + VERSIONS=$(pnpm list styled-components --depth=10 2>/dev/null | grep "styled-components@" | sort -u) + VERSION_COUNT=$(echo "$VERSIONS" | wc -l) + + echo "Found styled-components versions:" + echo "$VERSIONS" + + if [ "$VERSION_COUNT" -gt 1 ]; then + echo "" + echo "❌ ERROR: Multiple styled-components versions detected!" + echo "Multiple instances break ThemeProvider context propagation." + echo "" + echo "Expected: Single version (styled-components@6.3.8)" + echo "Found: $VERSION_COUNT versions" + echo "" + echo "Fix: Check pnpm.overrides in root package.json" + echo "See: docs/architecture/theme-consistency-enforcement.md" + exit 1 + fi + + echo "" + echo "✅ SUCCESS: Single styled-components version confirmed" + test: name: Test runs-on: ubuntu-latest @@ -127,7 +172,7 @@ jobs: build: name: Build runs-on: ubuntu-latest - needs: [typecheck, lint] + needs: [typecheck, lint, verify-styled-components] steps: - uses: actions/checkout@v4 diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 000000000..7872a5116 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Pre-commit hook: Block direct styled-components imports +# Part of Styled Components Protocol enforcement +# +# This hook prevents commits that contain direct imports from 'styled-components' +# instead of the required wrapper package '@lilith/ui-styled-components'. +# +# Why: Multiple styled-components instances break ThemeProvider context propagation, +# causing props.theme to be undefined. The wrapper ensures single instance across +# entire platform. + +set -e + +# Colors for output +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Get list of staged TypeScript/JavaScript files +STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(tsx?|jsx?)$' || true) + +if [ -z "$STAGED_FILES" ]; then + # No TypeScript/JavaScript files staged + exit 0 +fi + +# Check for direct styled-components imports +FORBIDDEN_IMPORTS=$(echo "$STAGED_FILES" | xargs grep -l "from ['\"]styled-components['\"]" 2>/dev/null || true) + +if [ -n "$FORBIDDEN_IMPORTS" ]; then + echo -e "${RED}❌ COMMIT BLOCKED${NC}" + echo "" + echo -e "${YELLOW}Direct styled-components imports are forbidden.${NC}" + echo "Use @lilith/ui-styled-components wrapper instead." + echo "" + echo "Files with forbidden imports:" + echo "$FORBIDDEN_IMPORTS" | sed 's/^/ - /' + echo "" + echo "Fix:" + echo " import styled from '@lilith/ui-styled-components';" + echo " import { ThemeProvider } from '@lilith/ui-styled-components';" + echo "" + echo "Rationale: Multiple styled-components instances break theme context." + echo "See: docs/architecture/theme-consistency-enforcement.md" + exit 1 +fi + +# All checks passed +exit 0