pre-commit:
  parallel: true
  commands:
    lint:
      glob: "*.{js,jsx,ts,tsx}"
      run: bunx oxlint --no-error-on-unmatched-pattern {staged_files}
    format:
      glob: "*.{js,jsx,ts,tsx,json,md,yaml,yml}"
      # Auto-format and re-stage so the committed snapshot is always formatted.
      # Replaces --check which only reports — that left unformatted files in
      # commits when the hook ran after the amend snapshot was taken.
      run: bunx oxfmt --no-error-on-unmatched-pattern {staged_files} && git add -f {staged_files}
    skills-manifest:
      glob: "skills/**"
      # Regenerate the freshness fingerprint when a skill changes, then re-stage
      # it so skills-manifest.json (repo root) never drifts from skills/ (CI
      # enforces the same via the "Skills: manifest in sync" job). Churn-free:
      # the generator rewrites only when a content hash actually changed.
      run: bun packages/cli/scripts/gen-skills-manifest.ts && git add skills-manifest.json
    typecheck:
      glob: "*.{ts,tsx}"
      run: cd packages/core && bunx tsc --noEmit && cd ../studio && bunx tsc --noEmit
    # Mirrors the CI gate (same `--base origin/main` so the local hook can't
    # pass on a branch CI would fail). Audits the working tree, which means
    # unstaged WIP in `packages/**` is part of the diff — stash before
    # committing if that surprises you. `--gate new-only` (the default) only
    # fails on issues introduced by the branch, not inherited findings.
    fallow:
      glob: "packages/**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"
      # Unset git worktree env vars: fallow creates a temp worktree internally and
      # GIT_DIR/GIT_INDEX_FILE (set by git in worktree hook context) break that.
      # env -u is safe in non-worktree contexts (no-op when var is unset).
      run: env -u GIT_DIR -u GIT_INDEX_FILE -u GIT_WORK_TREE bunx fallow audit --base origin/main --fail-on-issues
    largefiles:
      # Reject large binaries committed straight into the git pack instead of
      # LFS. The script reads the staged set itself (via `git diff --cached`)
      # rather than taking lefthook's `{staged_files}` expansion, which would
      # split paths containing spaces. It skips files under the limit, anything
      # routed through LFS, and registry/ assets. Tune via HF_MAX_NONLFS_KB.
      run: ./scripts/check-large-files.sh
    tracked-artifacts:
      # Keep ignored dependency trees and platform metadata out of commits.
      # `git ls-files` observes the staged index, so staged removals pass and
      # an accidental force-add fails before the commit is created.
      run: bun run check:tracked-artifacts
    filesize:
      # Scoped to packages/studio — the 600 LOC limit is a studio architecture
      # standard enforced as part of the App.tsx decomposition work. Player and
      # other packages enforce size discipline via code review and convention.
      glob: "packages/studio/**/*.{ts,tsx}"
      exclude: "(\\.test\\.(ts|tsx)$|\\.generated\\.)"
      run: |
        for f in {staged_files}; do
          # Skip test and generated files (exclude pattern backup in case lefthook doesn't filter)
          case "$f" in *.test.ts|*.test.tsx|*.generated.*) continue ;; esac
          lines=$(wc -l < "$f")
          if [ "$lines" -gt 600 ]; then
            echo "ERROR: $f has $lines lines (max 600)"
            exit 1
          fi
        done

commit-msg:
  commands:
    commitlint:
      run: bunx commitlint --edit "{1}"
