mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-10 20:47:14 +01:00
Next to the one-tap "I'm sick" (unchanged: keeps nothing, unlocks), a small secondary link lays sickdays 0.3.0's embeddable KeepPanel over every surface, in-process so it gets input under the lock's grab. Closing the overlay reveals the untouched screen underneath, so no countdown or phone check is restarted or skipped. After the panel's own write + sync: sick with the workout lock standing down -> sick floor, decision, close (shared with the one-tap path, no second mark or push); sick with the workout kept -> sick floor and a note, lock stays; cleared / unchanged / cancel -> the panel just closes. Tests stub KeepPanel and redirect resolve_paths and sync_quietly in every sickdays.* module, sickdays.gui._panel included. The fit check measures the panel on a throwaway pool. Pins bumped to sickdays-v0.3.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PAhbNszs5JKdtnD4uBi3xp
335 lines
14 KiB
YAML
335 lines
14 KiB
YAML
# Pre-commit Configuration for screen-locker
|
|
# Install: pre-commit install && pre-commit install --hook-type pre-push
|
|
# Run: pre-commit run --all-files
|
|
# Update: pre-commit autoupdate
|
|
|
|
default_language_version:
|
|
python: python3
|
|
default_stages: [pre-commit]
|
|
fail_fast: false
|
|
|
|
repos:
|
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
rev: v4.6.0
|
|
hooks:
|
|
- id: trailing-whitespace
|
|
args: [--markdown-linebreak-ext=md]
|
|
- id: end-of-file-fixer
|
|
- id: check-yaml
|
|
# pnpm-lock.yaml is a two-document stream by design.
|
|
exclude: ^web/pnpm-lock\.yaml$
|
|
- id: check-json
|
|
- id: check-toml
|
|
- id: check-added-large-files
|
|
args: [--maxkb=2000]
|
|
- id: check-merge-conflict
|
|
- id: detect-private-key
|
|
- id: debug-statements
|
|
- id: name-tests-test
|
|
args: [--pytest-test-first]
|
|
# Shared, non-test helpers (fixtures, factories) imported by the
|
|
# real test modules — deliberately not collected as tests, hence the
|
|
# leading underscore rather than a test_/*_test name.
|
|
exclude: ^screen_locker/tests/_[a-z][a-z_]*\.py$
|
|
- id: check-ast
|
|
- id: mixed-line-ending
|
|
args: [--fix=lf]
|
|
- id: requirements-txt-fixer
|
|
|
|
- repo: local
|
|
hooks:
|
|
- id: repo-contract
|
|
name: repo contract (CLAUDE.md Commands + test_changed)
|
|
entry: scripts/check_repo_contract.sh
|
|
language: system
|
|
pass_filenames: false
|
|
files: ^(CLAUDE\.md|AGENTS\.md|scripts/test_changed\.sh)$
|
|
- id: no-noqa
|
|
name: Block noqa comments
|
|
entry: '(?i)#\s*(noqa|type:\s*ignore)'
|
|
language: pygrep
|
|
types: [python]
|
|
- id: no-ruff-noqa
|
|
name: Block ruff noqa file-level comments
|
|
entry: '(?i)#\s*ruff:\s*noqa'
|
|
language: pygrep
|
|
types: [python]
|
|
- id: requirements-sync
|
|
name: requirements.txt covers all package imports
|
|
# scripts/ became a real package (it now holds shared helpers), so
|
|
# auto-detection sees two candidates -- name the one that ships.
|
|
entry: python3 scripts/check_requirements_sync.py --package screen_locker
|
|
language: system
|
|
pass_filenames: false
|
|
files: ^(screen_locker/.*\.py|requirements\.txt)$
|
|
|
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
rev: v0.17.1
|
|
hooks:
|
|
- id: ruff
|
|
args: [--fix, --unsafe-fixes, --exit-non-zero-on-fix, --show-fixes]
|
|
types_or: [python, pyi]
|
|
- id: ruff-format
|
|
types_or: [python, pyi]
|
|
|
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
rev: v1.13.0
|
|
hooks:
|
|
- id: mypy
|
|
args:
|
|
- --ignore-missing-imports
|
|
- --no-error-summary
|
|
- --disable-error-code=no-untyped-def
|
|
- --disable-error-code=no-untyped-call
|
|
- --disable-error-code=var-annotated
|
|
- --disable-error-code=no-any-unimported
|
|
- --disable-error-code=type-arg
|
|
- --disable-error-code=no-any-return
|
|
- --disable-error-code=misc
|
|
- --disable-error-code=unused-ignore
|
|
- --disable-error-code=unreachable
|
|
- --disable-error-code=assignment
|
|
- --disable-error-code=no-redef
|
|
- --disable-error-code=attr-defined
|
|
- --disable-error-code=arg-type
|
|
- --disable-error-code=union-attr
|
|
- --disable-error-code=call-overload
|
|
- --disable-error-code=return-value
|
|
- --disable-error-code=redundant-cast
|
|
- --disable-error-code=empty-body
|
|
- --disable-error-code=list-item
|
|
# The hook runs in its own isolated venv, so stubs installed into the
|
|
# project venv are invisible to it. Without this, the Firebase session
|
|
# recovery's `import requests` fails as import-untyped here while
|
|
# type-checking cleanly everywhere else.
|
|
additional_dependencies:
|
|
- types-requests>=2.31.0
|
|
|
|
- repo: https://github.com/pylint-dev/pylint
|
|
rev: v4.0.8
|
|
hooks:
|
|
# Two hooks, because the three checks below are not defects in a test
|
|
# suite -- they are how pytest and unit-testing private mixins work --
|
|
# while in SOURCE they are real findings that must still fail:
|
|
# protected-access tests drive private mixin methods directly; those
|
|
# methods ARE the unit under test (ruff already
|
|
# exempts the same thing via SLF001 for tests).
|
|
# unused-argument pytest fixtures must be REQUESTED in the signature
|
|
# to take effect but are never referenced in the body.
|
|
# duplicate-code near-identical `with patch(...)` preambles; a test
|
|
# should read top-to-bottom without chasing a fixture.
|
|
# Splitting also removes the old failure mode where the score depended on
|
|
# what else happened to be staged alongside. See
|
|
# todo_fix_pylint_10_prompt.md for raising both to a hard 10.00.
|
|
- id: pylint
|
|
name: pylint (source)
|
|
exclude: ^screen_locker/tests/
|
|
args:
|
|
- --rcfile=pyproject.toml
|
|
- --fail-under=8.0
|
|
- --jobs=4
|
|
additional_dependencies:
|
|
- pytest
|
|
# Kept in step with pyproject.toml: pip refuses two different
|
|
# direct URLs for one distribution, so any pin that drifts from
|
|
# the manifest becomes an unresolvable hook environment rather
|
|
# than merely an old one.
|
|
- gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.9.0#subdirectory=gatelock
|
|
- crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.9.2#subdirectory=crdt-sync
|
|
- earned-time @ git+https://github.com/kuhyx/utils@earned-time-v0.11.0#subdirectory=earned_time
|
|
- freedays @ git+https://github.com/kuhyx/utils@freedays-v0.4.0#subdirectory=freedays
|
|
- sickdays @ git+https://github.com/kuhyx/utils@sickdays-v0.3.0#subdirectory=sickdays
|
|
- mcp>=2,<3
|
|
- pydantic
|
|
- id: pylint
|
|
name: pylint (tests)
|
|
alias: pylint-tests
|
|
files: ^screen_locker/tests/
|
|
args:
|
|
- --rcfile=pyproject.toml
|
|
- --fail-under=8.0
|
|
- --jobs=4
|
|
- --disable=protected-access,unused-argument,duplicate-code
|
|
additional_dependencies:
|
|
- pytest
|
|
# Kept in step with pyproject.toml: pip refuses two different
|
|
# direct URLs for one distribution, so any pin that drifts from
|
|
# the manifest becomes an unresolvable hook environment rather
|
|
# than merely an old one.
|
|
- gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.9.0#subdirectory=gatelock
|
|
- crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.9.2#subdirectory=crdt-sync
|
|
- earned-time @ git+https://github.com/kuhyx/utils@earned-time-v0.11.0#subdirectory=earned_time
|
|
- freedays @ git+https://github.com/kuhyx/utils@freedays-v0.4.0#subdirectory=freedays
|
|
- sickdays @ git+https://github.com/kuhyx/utils@sickdays-v0.3.0#subdirectory=sickdays
|
|
- mcp>=2,<3
|
|
- pydantic
|
|
|
|
- repo: https://github.com/PyCQA/bandit
|
|
rev: 1.7.10
|
|
hooks:
|
|
- id: bandit
|
|
args:
|
|
- -c
|
|
- pyproject.toml
|
|
- --severity-level=high
|
|
- --confidence-level=medium
|
|
- --skip=B113
|
|
additional_dependencies: ["bandit[toml]"]
|
|
exclude: ^(tests/|.*test.*\.py$)
|
|
|
|
- repo: local
|
|
hooks:
|
|
- id: ci-mirror
|
|
name: CI mirror (clean-venv pytest + pre-commit --all-files)
|
|
entry: bash scripts/ci_mirror.sh
|
|
language: system
|
|
pass_filenames: false
|
|
always_run: true
|
|
require_serial: true
|
|
stages: [manual]
|
|
|
|
- repo: https://github.com/codespell-project/codespell
|
|
rev: v2.3.0
|
|
hooks:
|
|
- id: codespell
|
|
args:
|
|
- --skip=*.json,*.lock,*pnpm-lock.yaml,.git,__pycache__,.venv
|
|
- --ignore-words-list=als,ans,ect,nd,som,sur,te,nam,numer,lew,sie,wil,postion,clen,ther,folow,derrive,ony,tje,noe,theses,crate,doubleclick,wile,tabel,pary,blok,bloc,proces,serwer,parametr,adres,hart,dout,metod,tekst,synonim,grup,mosty,lokal,skalar,milion,nowe,tre,hel,alph
|
|
|
|
- repo: local
|
|
hooks:
|
|
# Fails a commit that still points crdt_sync at a local path. Local
|
|
# tests would go green against a library CI has never seen, silently.
|
|
- id: crdt-sync-override
|
|
name: no local crdt_sync dependency_override
|
|
entry: bash scripts/check_no_crdt_sync_override.sh stronglift_replacement/workout_app/pubspec.yaml
|
|
language: system
|
|
pass_filenames: false
|
|
always_run: true
|
|
- id: shellcheck
|
|
name: shellcheck
|
|
entry: bash -c 'printf "%s\0" "$@" | xargs -0 -n 40 shellcheck --severity=warning' --
|
|
language: system
|
|
types: [shell]
|
|
- id: max-file-length
|
|
name: Max file length (250 lines)
|
|
entry: python3 scripts/check_file_length.py
|
|
language: system
|
|
# Dart was missing here until 2026-08-15, so the cap had never looked at
|
|
# a single file in workout_app/ — the whole Flutter app was exempt from
|
|
# the gate it was being refactored to satisfy. ts/tsx joined on
|
|
# 2026-08-29 with web/, for exactly the same reason: a language absent
|
|
# from this list is a directory the cap silently does not apply to.
|
|
types_or: [python, shell, dart, ts, tsx]
|
|
exclude: '^web/(node_modules|dist|coverage)/'
|
|
- id: no-silent-failures
|
|
name: Block silent failures (swallowed exceptions and silent sys.exit(0) must say why)
|
|
entry: python3 scripts/check_silent_failures.py
|
|
language: system
|
|
types: [python]
|
|
- id: no-silent-failures-dart
|
|
# The Python hook above is types:[python] and so had never looked at a
|
|
# single Dart file — in the app where a swallowed sync error costs the
|
|
# user a workout with nothing anywhere saying so.
|
|
name: Block silent failures in Dart (swallowed errors must log why)
|
|
entry: python3 scripts/check_silent_failures_dart.py
|
|
language: system
|
|
types: [dart]
|
|
- id: screens-fit
|
|
name: Every lock screen fits 1366x768 (no scrolling required)
|
|
entry: python3 -m scripts.verify_screen_fits
|
|
language: system
|
|
files: '^screen_locker/.*\.py$'
|
|
pass_filenames: false
|
|
require_serial: true
|
|
- id: flutter-analyze
|
|
name: flutter analyze (workout app)
|
|
# env -u GIT_DIR: git exports it to hooks, and flutter shells out to
|
|
# git to identify its own SDK -- with it set, flutter reads THIS repo
|
|
# as the SDK and pub resolves every constraint against 0.0.0-unknown.
|
|
entry: bash -c 'cd stronglift_replacement/workout_app &&
|
|
env -u GIT_DIR -u GIT_WORK_TREE -u GIT_INDEX_FILE flutter analyze'
|
|
language: system
|
|
files: '^stronglift_replacement/workout_app/.*\.(dart|yaml)$'
|
|
pass_filenames: false
|
|
- id: flutter-test-coverage
|
|
name: flutter test --coverage 100% (workout app)
|
|
entry: bash scripts/check_flutter_coverage.sh
|
|
language: system
|
|
files: '^stronglift_replacement/workout_app/.*\.dart$'
|
|
pass_filenames: false
|
|
require_serial: true
|
|
stages: [manual]
|
|
|
|
# web/ gates. steam-backlog-enforcer, which this app was copied from, has
|
|
# only a coverage hook -- its lint and typecheck are unenforced, so both
|
|
# can rot without anything failing. All three run here.
|
|
- id: web-lint
|
|
name: eslint (status web UI)
|
|
entry: pnpm --dir web run lint
|
|
language: system
|
|
files: '^web/(src/.*\.(ts|tsx)|eslint\.config\.js|package\.json)$'
|
|
pass_filenames: false
|
|
require_serial: true
|
|
- id: web-typecheck
|
|
name: tsc --build (status web UI)
|
|
entry: pnpm --dir web run build
|
|
language: system
|
|
files: '^web/(src/.*\.(ts|tsx)|tsconfig.*\.json|vite\.config\.ts)$'
|
|
pass_filenames: false
|
|
require_serial: true
|
|
- id: web-coverage
|
|
name: vitest --coverage 100% (status web UI)
|
|
entry: pnpm --dir web run coverage
|
|
language: system
|
|
files: '^web/src/'
|
|
pass_filenames: false
|
|
require_serial: true
|
|
stages: [manual]
|
|
|
|
# Four markdown namespaces (README / CLAUDE* / DOCS* / TODO*), plus the
|
|
# rule that a TODO carries "REMOVE ME AFTER FINISH" and nothing else may.
|
|
# Shared gate in ~/src/utils owns the namespaces and the exemption list, so
|
|
# one repo's idea of a valid name cannot drift from every other repo's.
|
|
- id: md-naming
|
|
name: markdown naming convention
|
|
entry: scripts/check_md_naming.sh
|
|
language: system
|
|
files: \.(md|markdown)$
|
|
|
|
# Every dependency on its ecosystem's newest STABLE release, exact-pinned
|
|
# so the question is mechanically answerable at all.
|
|
#
|
|
# `files:` is what keeps this cheap: a commit touching only source makes
|
|
# ZERO network requests, and manifest commits mostly hit a 6h disk cache.
|
|
#
|
|
# Runs WITHOUT --strict on purpose. Offline it degrades to the cached
|
|
# answer and passes with a loud banner; `--no-verify` is banned here, so
|
|
# a hook that hard-failed on a flaky connection would leave no way to
|
|
# commit at all. CI, always online, is the strict authority.
|
|
- id: dependency-freshness
|
|
name: dependencies on newest stable
|
|
entry: scripts/check_dependency_freshness.sh
|
|
language: system
|
|
pass_filenames: true
|
|
files: >-
|
|
(pubspec\.(yaml|lock)|pyproject\.toml|requirements.*\.txt|uv\.lock
|
|
|package\.json|package-lock\.json|pnpm-lock\.yaml
|
|
|Cargo\.(toml|lock)|go\.(mod|sum)
|
|
|\.fvmrc|\.nvmrc|\.python-version
|
|
|\.github/workflows/.*\.ya?ml)$
|
|
|
|
- repo: local
|
|
hooks:
|
|
# The only pre-push hook. Everything that used to run here is now
|
|
# `stages: [manual]` -- run on demand with `scripts/check_gate_stamp.sh
|
|
# full`, and by CI on every push. finish_auto.sh stamps HEAD after its
|
|
# gate; a tree without that receipt cannot leave the machine.
|
|
- id: gate-stamp
|
|
name: pushed tree passed the local gate (stamp check)
|
|
entry: scripts/check_gate_stamp.sh check
|
|
language: system
|
|
pass_filenames: false
|
|
always_run: true
|
|
stages: [pre-push]
|