diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b4718f69b23b4..82e4a6aaf82eb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,6 +107,13 @@ jobs: node-version: 22.x cache: npm + - name: Check for CRLF line endings + run: | + if git grep -Il $'\r'; then + echo "::error::CRLF line endings detected. Configure your editor to use LF line endings (this repo has an .editorconfig file that most editors respect automatically)." + exit 1 + fi + - run: | FILES=$( find src/content \ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000000000..df6b0c4a5dc257 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,32 @@ +#!/bin/sh +# Convert CRLF to LF in all staged files before committing. +# This guards against AI tooling and Windows environments introducing CRLF. + +STAGED=$(git diff --cached --name-only) + +if [ -z "$STAGED" ]; then + exit 0 +fi + +FIXED=0 + +while IFS= read -r file; do + # Skip files that no longer exist on disk (e.g. deleted files) + if [ ! -f "$file" ]; then + continue + fi + + # Check for carriage returns + if grep -qU $'\r' "$file"; then + # perl -pi works cross-platform (macOS BSD and Linux GNU) + perl -pi -e 's/\r\n/\n/g; s/\r/\n/g' "$file" + FIXED=1 + fi +done << EOF +$STAGED +EOF + +if [ "$FIXED" = "1" ]; then + echo "pre-commit: CRLF line endings converted to LF in staged files." + git add --update +fi diff --git a/package-lock.json b/package-lock.json index 5467c582187ce0..05fa72b86e0b6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,6 +62,7 @@ "hast-util-select": "6.0.4", "hastscript": "9.0.1", "he": "1.2.0", + "husky": "9.1.7", "jsonc-parser": "3.3.1", "ldrs": "1.1.7", "lz-string": "1.5.0", @@ -12083,6 +12084,22 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/i18next": { "version": "23.16.8", "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.8.tgz", diff --git a/package.json b/package.json index 5151febf72e40b..df570841140c3b 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "ai-setup:import-from-opencode": "npx rulesync import --targets opencode --features rules,commands,subagents", "ai-setup:claudecode": "npm run ai-setup:import-from-opencode && npx rulesync generate --targets claudecode --features rules,commands,subagents", "ai-setup:cursor": "npm run ai-setup:import-from-opencode && npx rulesync generate --targets cursor --features commands,subagents", - "ai-setup:copilot": "npm run ai-setup:import-from-opencode && npx rulesync generate --targets copilot --features commands,subagents" + "ai-setup:copilot": "npm run ai-setup:import-from-opencode && npx rulesync generate --targets copilot --features commands,subagents", + "prepare": "husky" }, "devDependencies": { "@actions/core": "1.11.1", @@ -86,6 +87,7 @@ "hast-util-select": "6.0.4", "hastscript": "9.0.1", "he": "1.2.0", + "husky": "9.1.7", "jsonc-parser": "3.3.1", "ldrs": "1.1.7", "lz-string": "1.5.0",