--- name: git-preflight description: "Runs the project's configured typecheck, lint, format, security and test checks and offers to fix what fails. Use when the user asks for preflight checks or to check code before committing, and when /git-commit-push-pr --preflight runs it." argument-hint: "[--fix | --check-only | --verbose]" allowed-tools: - Bash - Read - Glob - Grep - AskUserQuestion --- # Preflight Code Quality Checks Discover the quality checks this project has configured (type checking, linting, formatting, security scanning and tests), run them, and fix what can be fixed. ## Arguments - `--fix` - Automatically attempt to fix issues without prompting - `--check-only` - Only report issues, never prompt to fix - `--verbose` - Show detailed output from all commands - No arguments - Interactive mode (default): prompt before fixing The text typed after the command holds the arguments. In Claude Code it is inserted here: `$ARGUMENTS`. In other agents, read it from the user's message, or from the skill that asked you to run this one (`/git-commit-push-pr --preflight` passes `--fix`). It may be empty. Ask questions with the AskUserQuestion tool when it's available, and in plain text otherwise, then wait for the answer. ## Step 1: Discovery Phase First, analyze the project to discover configured quality tools. Check for: ### Package Manager & Config Files - `package.json` - Check for scripts: `lint`, `typecheck`, `type-check`, `tsc`, `test`, `check`, `validate` - `tsconfig.json` / `jsconfig.json` - TypeScript/JavaScript configuration - `.eslintrc*`, `eslint.config.*` - ESLint configuration - `biome.json`, `biome.jsonc` - Biome configuration - `.prettierrc*`, `prettier.config.*` - Prettier configuration - `deno.json` / `deno.jsonc` - Deno configuration - `.stylelintrc*` - Stylelint configuration ### Python Projects - `pyproject.toml` - Check for ruff, mypy, pytest, black, isort configs - `setup.py` / `setup.cfg` - Legacy Python config - `requirements.txt` / `requirements-dev.txt` - Dependencies - `mypy.ini` / `.mypy.ini` - MyPy configuration - `ruff.toml` / `.ruff.toml` - Ruff configuration - `pytest.ini` / `pyproject.toml [tool.pytest]` - Pytest configuration - `tox.ini` - Tox configuration ### .NET Projects - `*.csproj` / `*.fsproj` / `*.vbproj` - .NET project files - `*.sln` - Solution files - `.editorconfig` - Editor configuration with .NET analyzers - `Directory.Build.props` - MSBuild properties ### Go Projects - `go.mod` - Go module - `.golangci.yml` / `.golangci.yaml` - GolangCI-Lint configuration ### Rust Projects - `Cargo.toml` - Check for clippy, rustfmt - `rustfmt.toml` / `.rustfmt.toml` - Rustfmt configuration - `clippy.toml` / `.clippy.toml` - Clippy configuration ### Security Scanning - `pnpm-lock.yaml` / `package-lock.json` / `yarn.lock` - Dependency audit support - `.semgreprc.yml` / `.semgrep.yml` / `semgrep.yml` / `.semgrep/` - Semgrep configuration - `.github/workflows/*.yml` - Check for semgrep CI jobs (extract config flags) - `eslint-plugin-security` in devDependencies - ESLint security rules - `package.json` scripts containing `audit` or `semgrep` - Custom security scripts - `README.md` / `CONTRIBUTING.md` - Check for documented security scanning commands ### Other - `Makefile` / `makefile` - Check for lint/test/check targets - `.pre-commit-config.yaml` - Pre-commit hooks - `justfile` - Just command runner ## Step 2: Report Discovery Present a summary of what was discovered: ``` Preflight Discovery Summary Project Type: [Node.js / Python / .NET / Go / Rust / Multi-language] Type Checking: [tool name] via [config file] Linting: [tool name] via [config file] Testing: [tool name] via [config file] Formatting: [tool name] via [config file] Security Scanning: [tool name(s)] via [config file/method] Not configured: [any missing categories] ``` Then run the checks without waiting for confirmation. ## Step 3: Execute Checks Run the discovered checks in this order: 1. **Type checking** (fastest feedback on type errors) 2. **Linting** (code quality issues) 3. **Formatting check** (style consistency - check only, don't auto-fix yet) 4. **Security scanning** - MANDATORY if any security tools detected: - Dependency audit (npm audit, pnpm audit, etc.) - **Semgrep SAST** - MUST run if detected in CI workflows or config files 5. **Tests** (run last as they take longest) **CRITICAL: If Semgrep was detected in discovery (CI workflows, config files, or README), you MUST run it. Do NOT skip Semgrep and report "All checks passed" without running it.** For each check, report: - Pass - no issues found - Warnings - non-blocking issues - Fail - blocking issues found ### Common Commands by Ecosystem **Node.js/TypeScript:** - TypeScript: `npx tsc --noEmit` or `npm run typecheck` - ESLint: `npx eslint . --max-warnings=0` or `npm run lint` - Biome: `npx biome check .` - Tests: `npm test` or `npx jest` or `npx vitest run` **Python:** - MyPy: `mypy .` or `mypy src/` - Ruff: `ruff check .` - Pytest: `pytest` or `python -m pytest` - Black check: `black --check .` **.NET:** - Build with warnings: `dotnet build --warnaserror` - Format check: `dotnet format --verify-no-changes` - Tests: `dotnet test` **Go:** - Type check: `go build ./...` - Lint: `golangci-lint run` - Tests: `go test ./...` **Rust:** - Check: `cargo check` - Clippy: `cargo clippy -- -D warnings` - Tests: `cargo test` - Format check: `cargo fmt --check` ### Security Scanning Commands **Dependency Audits (run based on detected package manager):** - pnpm: `pnpm audit` or `pnpm audit:check` (if script exists in package.json) - npm: `npm audit` - yarn: `yarn audit` - pip: `pip-audit` (if installed) or `safety check` (if installed) - cargo: `cargo audit` (if installed) **Semgrep (static analysis - MUST run if detected in CI or config):** IMPORTANT: If Semgrep is detected in CI workflows or config files, you MUST run it as part of preflight checks. Do not skip it. Detection order: 1. Check for custom script in package.json (e.g., `pnpm run semgrep` or `npm run semgrep`) 2. Check for semgrep config files: `.semgreprc.yml`, `.semgrep.yml`, `semgrep.yml`, or `.semgrep/` directory 3. Check `.github/workflows/*.yml` for semgrep jobs - extract `--config` flags used in CI 4. **Check `README.md` for documented semgrep commands** - ALWAYS check this before trying generic Docker commands, as projects often document the exact command needed for their setup 5. Check if `semgrep` CLI is available locally: `semgrep --version` 6. Check if Docker is available: `docker --version` 7. If Docker available but no semgrep CLI, use Docker (see platform-specific commands below) **Semgrep execution:** - With config file: `semgrep scan --config .semgreprc.yml` (or detected config) - Without config (auto rules): `semgrep scan --config auto` - With language-specific rules: `semgrep scan --config auto --config p/javascript --config p/typescript` **Docker execution (AUTOMATIC PLATFORM DETECTION):** CRITICAL: You MUST detect the platform and use the correct command automatically. Use the platform your agent reports in its environment details, or run `uname -s`: `MINGW*`, `MSYS*` or `CYGWIN*` means Windows with Git Bash. - **If platform is `win32` (Windows):** ALWAYS use `MSYS_NO_PATHCONV=1` prefix for Docker commands: ```bash MSYS_NO_PATHCONV=1 docker run --rm -v "$(pwd):/src" semgrep/semgrep semgrep scan --config auto /src ``` - **If platform is `darwin` (macOS) or `linux`:** Use standard Docker command: ```bash docker run --rm -v "$(pwd):/src" semgrep/semgrep semgrep scan --config auto /src ``` **Why this matters on Windows:** Git Bash/MSYS2 performs automatic POSIX-to-Windows path conversion. Without `MSYS_NO_PATHCONV=1`, the Docker volume mount `/src` gets incorrectly converted to `C:/Program Files/Git/src`, causing Semgrep to fail with "Invalid scanning root" error. DO NOT try the command without the prefix first on Windows - use the correct platform-specific command immediately. **ESLint Security Plugin:** - If `eslint-plugin-security` is detected in devDependencies, security rules are already included in the linting step - No separate command needed, but note in discovery output that security linting is active ## Step 4: Results Summary Present results in a clear summary: ``` Preflight Results Type Checking Passed Linting 3 errors, 2 warnings Formatting 5 files need formatting Security Audit 2 vulnerabilities found Security SAST Passed (semgrep) Tests 42 passed, 0 failed Overall: Issues found ``` ## Step 5: Fix Prompt (Interactive Mode) If issues were found AND user didn't pass `--check-only`: **If `--fix` was passed:** Proceed directly to fixing without prompting. **Otherwise, ask** (AskUserQuestion when available, or this numbered list in plain text): ``` Would you like me to attempt fixes? [1] Fix all auto-fixable issues (lint --fix, format, etc.) [2] Fix only linting issues [3] Fix only formatting issues [4] Show me the specific issues first [5] Skip fixes - I'll handle it manually Enter choice (1-5): ``` Wait for the user's answer before proceeding. ## Step 6: Apply Fixes (if requested) When fixing: 1. Run auto-fix commands (e.g., `eslint --fix`, `ruff --fix`, `prettier --write`) 2. Re-run the checks to verify fixes 3. Report what was fixed and what still needs manual attention ``` Fix Results Auto-fixed: 3 linting errors resolved 5 files formatted Still needs attention: 1 type error in src/utils.ts:42 Property 'foo' does not exist on type 'Bar' ``` ## Important Guidelines 1. **Never run fix commands without user consent** unless `--fix` was explicitly passed 2. **Preserve user's working state** - don't modify files unexpectedly 3. **Respect existing configuration** - use project's own scripts when available (e.g., `npm run lint` over raw `eslint`) 4. **Handle missing tools gracefully** - if a tool isn't installed, note it and continue 5. **Provide actionable feedback** - include file paths and line numbers for manual fixes 6. **Consider CI alignment** - mention if checks match CI configuration ## Error Handling If a tool fails to run: ``` Could not run [tool]: [error message] Suggestion: [how to install or configure] ``` If no quality tools are configured, say so. With `--fix` or `--check-only`, stop there. Otherwise ask: ``` No quality tools detected in this project. Would you like me to help set up: [1] TypeScript type checking [2] ESLint for linting [3] Prettier for formatting [4] A testing framework [5] Skip setup ``` --- ## Reference by Ecosystem Commands and auto-fix equivalents for discovering and running the checks above. ### Node.js / TypeScript Projects | Check | Command | Auto-fix | |-------|---------|----------| | TypeScript | `npx tsc --noEmit` | N/A (manual) | | ESLint | `npx eslint .` | `npx eslint . --fix` | | Biome | `npx biome check .` | `npx biome check . --write` | | Prettier | `npx prettier --check .` | `npx prettier --write .` | | Jest | `npx jest` | N/A | | Vitest | `npx vitest run` | N/A | **Prefer npm scripts when available:** ```bash # Check package.json scripts first npm run lint # if exists npm run typecheck # if exists npm run test # if exists npm run check # often runs all checks ``` ### Python Projects | Check | Command | Auto-fix | |-------|---------|----------| | MyPy | `mypy .` | N/A (manual) | | Ruff lint | `ruff check .` | `ruff check . --fix` | | Ruff format | `ruff format --check .` | `ruff format .` | | Black | `black --check .` | `black .` | | isort | `isort --check .` | `isort .` | | Pytest | `pytest` | N/A | **With pyproject.toml (modern Python):** ```bash # Check for [tool.X] sections ruff check . && ruff format --check . # Ruff (fast, recommended) mypy src/ # Type checking pytest # Tests ``` ### .NET Projects | Check | Command | Auto-fix | |-------|---------|----------| | Build | `dotnet build` | N/A | | Build strict | `dotnet build --warnaserror` | N/A | | Format check | `dotnet format --verify-no-changes` | `dotnet format` | | Tests | `dotnet test` | N/A | | Analyzers | Configured in `.editorconfig` | N/A | **.NET specific considerations:** - Warnings as errors: Add `true` to `.csproj` - Enable nullable: `enable` for null safety - Analyzers run during build automatically ### Go Projects | Check | Command | Auto-fix | |-------|---------|----------| | Build | `go build ./...` | N/A | | Vet | `go vet ./...` | N/A | | golangci-lint | `golangci-lint run` | `golangci-lint run --fix` | | gofmt | `gofmt -l .` | `gofmt -w .` | | Tests | `go test ./...` | N/A | ### Rust Projects | Check | Command | Auto-fix | |-------|---------|----------| | Check | `cargo check` | N/A | | Clippy | `cargo clippy -- -D warnings` | `cargo clippy --fix` | | Format | `cargo fmt --check` | `cargo fmt` | | Tests | `cargo test` | N/A | ### Security Scanning (Cross-Platform) | Tool | Purpose | Command | |------|---------|---------| | pnpm audit | Dependency CVE scan | `pnpm audit` or `pnpm audit:check` | | npm audit | Dependency CVE scan | `npm audit` | | yarn audit | Dependency CVE scan | `yarn audit` | | eslint-plugin-security | JS/TS security patterns | Runs with ESLint | | Semgrep | SAST scanning | `semgrep scan --config auto` | | Semgrep (Docker) | SAST scanning | See platform-specific commands below | | pip-audit | Python dependency scan | `pip-audit` | | cargo-audit | Rust dependency scan | `cargo audit` | **IMPORTANT: If Semgrep is detected in CI workflows or config files, you MUST run it as part of preflight checks. Do not skip it.** **Semgrep Detection Priority:** 1. Package.json scripts (e.g., `pnpm run semgrep`) 2. Config files: `.semgreprc.yml`, `.semgrep.yml`, `semgrep.yml`, `.semgrep/` 3. CI workflows: `.github/workflows/*.yml` (extract `--config` flags) 4. **README.md documentation** - ALWAYS check this before trying generic Docker commands 5. Local CLI: `semgrep --version` 6. Docker fallback (see platform-specific commands below) **Semgrep Docker Commands (AUTOMATIC PLATFORM DETECTION):** CRITICAL: Detect the platform (as above: your agent's environment details, or `uname -s`) and use the correct command automatically. - **Windows (`win32`):** ALWAYS use `MSYS_NO_PATHCONV=1` prefix: ```bash MSYS_NO_PATHCONV=1 docker run --rm -v "$(pwd):/src" semgrep/semgrep semgrep scan --config auto /src ``` - **macOS (`darwin`) / Linux:** Standard command: ```bash docker run --rm -v "$(pwd):/src" semgrep/semgrep semgrep scan --config auto /src ``` **Why `MSYS_NO_PATHCONV=1` is required on Windows:** Git Bash/MSYS2 auto-converts POSIX paths to Windows paths. Without this prefix, `/src` becomes `C:/Program Files/Git/src`, causing "Invalid scanning root" error. DO NOT try without the prefix first on Windows. ## Discovery Strategy ### Step 1: Identify Project Type(s) Check for presence of key files: ``` # JavaScript/TypeScript package.json, tsconfig.json, deno.json # Python pyproject.toml, setup.py, requirements.txt, Pipfile # .NET *.csproj, *.sln, *.fsproj # Go go.mod # Rust Cargo.toml ``` ### Step 2: Check for Configured Scripts/Tasks **package.json scripts (Node.js):** ```json { "scripts": { "lint": "eslint .", "typecheck": "tsc --noEmit", "test": "vitest", "check": "npm run lint && npm run typecheck && npm run test" } } ``` **pyproject.toml (Python):** ```toml [tool.ruff] line-length = 100 [tool.mypy] strict = true [tool.pytest.ini_options] testpaths = ["tests"] ``` **Makefile targets:** ```makefile lint: ruff check . test: pytest check: lint test ``` ### Step 3: Detect CI Configuration Check for CI files to align local checks with CI: - `.github/workflows/*.yml` - GitHub Actions (also check for semgrep jobs) - `.gitlab-ci.yml` - GitLab CI - `azure-pipelines.yml` - Azure DevOps - `Jenkinsfile` - Jenkins - `.circleci/config.yml` - CircleCI ### Step 4: Detect Security Tools Check for security scanning configuration: - `package.json` devDependencies for `eslint-plugin-security` - `package.json` scripts containing `audit` or `semgrep` - Semgrep config files: `.semgreprc.yml`, `.semgrep.yml`, `semgrep.yml` - CI workflows for semgrep jobs (extract `--config` flags for local replication) - `README.md` for documented security commands (often in Security sections) - Lock files (`pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`) for audit support ## Best Practices ### Execution Order Run checks in the order Step 3 gives, from fastest feedback to slowest: 1. **Type checking** (fast, catches type errors) 2. **Linting** (medium, catches quality issues) 3. **Format check** (fast, catches style issues) 4. **Security scanning** (medium, catches vulnerabilities) 5. **Tests** (slowest, catches logic errors) ### Handling Monorepos For monorepos, check for workspace configuration: - `pnpm-workspace.yaml` - `lerna.json` - `package.json` with `workspaces` field - `Cargo.toml` with `[workspace]` Run checks at workspace root or iterate through packages. ### CI Alignment Ensure local preflight matches CI: ```bash # Good: Use same commands as CI npm run lint # Same as CI step # Avoid: Different commands locally vs CI eslint . --max-warnings=0 # If CI uses npm run lint ``` ### Exit Codes Respect exit codes for CI integration: - `0` - Success, no issues - `1` - Failure, issues found - `2` - Configuration error ### Caching For faster subsequent runs: - ESLint: Uses `.eslintcache` with `--cache` flag - TypeScript: Uses `tsconfig.tsbuildinfo` with `incremental: true` - Pytest: Uses `.pytest_cache` - Rust: Uses `target/` directory ## Error Messages Reference ### TypeScript Common Errors ``` TS2339: Property 'x' does not exist on type 'Y' -> Add property to interface or use type assertion TS2322: Type 'X' is not assignable to type 'Y' -> Check type definitions, may need union type TS7006: Parameter 'x' implicitly has an 'any' type -> Add explicit type annotation ``` ### ESLint Common Errors ``` @typescript-eslint/no-unused-vars -> Remove unused variable or prefix with _ @typescript-eslint/no-explicit-any -> Replace 'any' with specific type import/order -> Auto-fixable: eslint --fix ``` ### Python Common Errors ``` mypy: Incompatible return value type -> Check return type annotation matches actual return ruff: E501 Line too long -> Auto-fixable or configure line-length ruff: F401 Module imported but unused -> Remove unused import ``` ## Integration with Pre-commit Hooks Preflight checks can be configured as pre-commit hooks: **.pre-commit-config.yaml:** ```yaml repos: - repo: local hooks: - id: preflight name: Preflight Checks entry: npm run check language: system pass_filenames: false ``` **Husky (Node.js):** ```bash # .husky/pre-commit npm run lint npm run typecheck ``` ## When to Skip Checks Some scenarios where partial checks are acceptable: - `--no-verify` for emergency fixes (use sparingly) - WIP commits on feature branches - Exploratory/spike work Always run full preflight before: - Opening PRs - Merging to main/master - Deploying to production