wardcat 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. wardcat-1.0.0/.github/CODEOWNERS +2 -0
  2. wardcat-1.0.0/.github/ISSUE_TEMPLATE/bug_report.yml +44 -0
  3. wardcat-1.0.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. wardcat-1.0.0/.github/ISSUE_TEMPLATE/feature_request.yml +20 -0
  5. wardcat-1.0.0/.github/PULL_REQUEST_TEMPLATE.md +13 -0
  6. wardcat-1.0.0/.github/dependabot.yml +18 -0
  7. wardcat-1.0.0/.github/workflows/ci.yml +109 -0
  8. wardcat-1.0.0/.github/workflows/publish.yml +59 -0
  9. wardcat-1.0.0/.github/workflows/real-model-tests.yml +56 -0
  10. wardcat-1.0.0/.gitignore +22 -0
  11. wardcat-1.0.0/.idea/.gitignore +3 -0
  12. wardcat-1.0.0/.idea/ai-guard.iml +8 -0
  13. wardcat-1.0.0/.idea/inspectionProfiles/profiles_settings.xml +6 -0
  14. wardcat-1.0.0/.idea/material_theme_project_new.xml +12 -0
  15. wardcat-1.0.0/.idea/modules.xml +8 -0
  16. wardcat-1.0.0/.idea/vcs.xml +6 -0
  17. wardcat-1.0.0/.pre-commit-config.yaml +27 -0
  18. wardcat-1.0.0/.python-version +1 -0
  19. wardcat-1.0.0/CHANGELOG.md +348 -0
  20. wardcat-1.0.0/CONTRIBUTING.md +102 -0
  21. wardcat-1.0.0/LICENSE +21 -0
  22. wardcat-1.0.0/PKG-INFO +924 -0
  23. wardcat-1.0.0/README.md +860 -0
  24. wardcat-1.0.0/SECURITY.md +51 -0
  25. wardcat-1.0.0/config/default.yaml +159 -0
  26. wardcat-1.0.0/docs/assets/logo.png +0 -0
  27. wardcat-1.0.0/docs/changelog.md +1 -0
  28. wardcat-1.0.0/docs/guide/configuration.md +74 -0
  29. wardcat-1.0.0/docs/guide/extending.md +42 -0
  30. wardcat-1.0.0/docs/guide/layers.md +199 -0
  31. wardcat-1.0.0/docs/guide/mcp-server.md +83 -0
  32. wardcat-1.0.0/docs/guide/security.md +54 -0
  33. wardcat-1.0.0/docs/index.md +74 -0
  34. wardcat-1.0.0/docs/installation.md +54 -0
  35. wardcat-1.0.0/docs/quickstart.md +79 -0
  36. wardcat-1.0.0/docs/reference/internals.md +27 -0
  37. wardcat-1.0.0/docs/reference/models.md +19 -0
  38. wardcat-1.0.0/docs/reference/wardcat.md +5 -0
  39. wardcat-1.0.0/docs/stylesheets/extra.css +67 -0
  40. wardcat-1.0.0/examples/all_layers.py +97 -0
  41. wardcat-1.0.0/examples/asgi_middleware.py +202 -0
  42. wardcat-1.0.0/examples/batch_and_async.py +47 -0
  43. wardcat-1.0.0/examples/demo.py +57 -0
  44. wardcat-1.0.0/examples/llm_hybrid.py +39 -0
  45. wardcat-1.0.0/mkdocs.yml +88 -0
  46. wardcat-1.0.0/overrides/partials/source.html +31 -0
  47. wardcat-1.0.0/pyproject.toml +132 -0
  48. wardcat-1.0.0/scripts/filter_coverage_test.py +485 -0
  49. wardcat-1.0.0/scripts/live_scan_test.py +497 -0
  50. wardcat-1.0.0/src/wardcat/__init__.py +81 -0
  51. wardcat-1.0.0/src/wardcat/_entity_policy.py +393 -0
  52. wardcat-1.0.0/src/wardcat/config/__init__.py +0 -0
  53. wardcat-1.0.0/src/wardcat/config/default.yaml +152 -0
  54. wardcat-1.0.0/src/wardcat/config/loader.py +313 -0
  55. wardcat-1.0.0/src/wardcat/core/__init__.py +0 -0
  56. wardcat-1.0.0/src/wardcat/core/actions.py +151 -0
  57. wardcat-1.0.0/src/wardcat/core/anonymizer.py +57 -0
  58. wardcat-1.0.0/src/wardcat/core/engine.py +354 -0
  59. wardcat-1.0.0/src/wardcat/core/models.py +222 -0
  60. wardcat-1.0.0/src/wardcat/core/registry.py +49 -0
  61. wardcat-1.0.0/src/wardcat/detectors/__init__.py +0 -0
  62. wardcat-1.0.0/src/wardcat/detectors/base.py +59 -0
  63. wardcat-1.0.0/src/wardcat/detectors/llm_detector.py +351 -0
  64. wardcat-1.0.0/src/wardcat/detectors/ner_detector.py +241 -0
  65. wardcat-1.0.0/src/wardcat/detectors/regex_detector.py +666 -0
  66. wardcat-1.0.0/src/wardcat/entity_groups.py +87 -0
  67. wardcat-1.0.0/src/wardcat/exceptions.py +35 -0
  68. wardcat-1.0.0/src/wardcat/guard.py +735 -0
  69. wardcat-1.0.0/src/wardcat/llm/__init__.py +0 -0
  70. wardcat-1.0.0/src/wardcat/llm/backends/__init__.py +0 -0
  71. wardcat-1.0.0/src/wardcat/llm/backends/base.py +107 -0
  72. wardcat-1.0.0/src/wardcat/llm/backends/ollama.py +192 -0
  73. wardcat-1.0.0/src/wardcat/llm/backends/openai_compat.py +135 -0
  74. wardcat-1.0.0/src/wardcat/llm/backends/registry.py +94 -0
  75. wardcat-1.0.0/src/wardcat/llm/backends/transformers_backend.py +251 -0
  76. wardcat-1.0.0/src/wardcat/llm/backends/vllm.py +107 -0
  77. wardcat-1.0.0/src/wardcat/llm/model_catalog.py +99 -0
  78. wardcat-1.0.0/src/wardcat/llm/model_manager.py +106 -0
  79. wardcat-1.0.0/src/wardcat/llm/prompt.py +522 -0
  80. wardcat-1.0.0/src/wardcat/ner/__init__.py +0 -0
  81. wardcat-1.0.0/src/wardcat/ner/downloader.py +151 -0
  82. wardcat-1.0.0/src/wardcat/ner/spacy_catalog.py +385 -0
  83. wardcat-1.0.0/src/wardcat/py.typed +0 -0
  84. wardcat-1.0.0/src/wardcat/utils/__init__.py +0 -0
  85. wardcat-1.0.0/src/wardcat/utils/hashing.py +7 -0
  86. wardcat-1.0.0/src/wardcat/utils/normalize.py +133 -0
  87. wardcat-1.0.0/src/wardcat/utils/text.py +41 -0
  88. wardcat-1.0.0/tests/__init__.py +0 -0
  89. wardcat-1.0.0/tests/benchmark/__init__.py +0 -0
  90. wardcat-1.0.0/tests/benchmark/eval_harness.py +193 -0
  91. wardcat-1.0.0/tests/benchmark/test_false_positives.py +216 -0
  92. wardcat-1.0.0/tests/benchmark/test_precision_recall.py +32 -0
  93. wardcat-1.0.0/tests/conftest.py +73 -0
  94. wardcat-1.0.0/tests/integration/__init__.py +0 -0
  95. wardcat-1.0.0/tests/integration/test_adversarial.py +253 -0
  96. wardcat-1.0.0/tests/integration/test_complex_scenarios.py +607 -0
  97. wardcat-1.0.0/tests/integration/test_config_edge_cases.py +240 -0
  98. wardcat-1.0.0/tests/integration/test_full_scan.py +57 -0
  99. wardcat-1.0.0/tests/integration/test_llm_integration.py +234 -0
  100. wardcat-1.0.0/tests/integration/test_llm_live.py +132 -0
  101. wardcat-1.0.0/tests/integration/test_model_setup_flow.py +90 -0
  102. wardcat-1.0.0/tests/integration/test_transformers_live.py +58 -0
  103. wardcat-1.0.0/tests/test_examples.py +40 -0
  104. wardcat-1.0.0/tests/unit/__init__.py +0 -0
  105. wardcat-1.0.0/tests/unit/test_action_registry.py +62 -0
  106. wardcat-1.0.0/tests/unit/test_address_detector.py +61 -0
  107. wardcat-1.0.0/tests/unit/test_adjudication.py +187 -0
  108. wardcat-1.0.0/tests/unit/test_async_api.py +133 -0
  109. wardcat-1.0.0/tests/unit/test_backend_registry.py +35 -0
  110. wardcat-1.0.0/tests/unit/test_builtin_redos.py +43 -0
  111. wardcat-1.0.0/tests/unit/test_config_loader.py +230 -0
  112. wardcat-1.0.0/tests/unit/test_configure.py +150 -0
  113. wardcat-1.0.0/tests/unit/test_engine_internals.py +338 -0
  114. wardcat-1.0.0/tests/unit/test_entity_enum.py +453 -0
  115. wardcat-1.0.0/tests/unit/test_entity_groups.py +134 -0
  116. wardcat-1.0.0/tests/unit/test_eu_us_uk_entities.py +318 -0
  117. wardcat-1.0.0/tests/unit/test_exceptions.py +77 -0
  118. wardcat-1.0.0/tests/unit/test_guard.py +404 -0
  119. wardcat-1.0.0/tests/unit/test_hashing.py +21 -0
  120. wardcat-1.0.0/tests/unit/test_is_sensitive.py +206 -0
  121. wardcat-1.0.0/tests/unit/test_layer_warnings.py +157 -0
  122. wardcat-1.0.0/tests/unit/test_llm_backends.py +513 -0
  123. wardcat-1.0.0/tests/unit/test_llm_detector.py +380 -0
  124. wardcat-1.0.0/tests/unit/test_model_catalog.py +73 -0
  125. wardcat-1.0.0/tests/unit/test_model_manager_setup.py +112 -0
  126. wardcat-1.0.0/tests/unit/test_ner_config.py +195 -0
  127. wardcat-1.0.0/tests/unit/test_ner_detector.py +356 -0
  128. wardcat-1.0.0/tests/unit/test_normalize.py +80 -0
  129. wardcat-1.0.0/tests/unit/test_production_hardening.py +373 -0
  130. wardcat-1.0.0/tests/unit/test_propagation.py +120 -0
  131. wardcat-1.0.0/tests/unit/test_regex_detector.py +663 -0
  132. wardcat-1.0.0/tests/unit/test_scan_batch.py +39 -0
  133. wardcat-1.0.0/tests/unit/test_spacy_catalog.py +259 -0
  134. wardcat-1.0.0/tests/unit/test_spacy_downloader.py +143 -0
  135. wardcat-1.0.0/tests/unit/test_special_category.py +105 -0
  136. wardcat-1.0.0/tests/unit/test_transformers_backend.py +369 -0
  137. wardcat-1.0.0/tests/unit/test_vllm_backend.py +159 -0
  138. wardcat-1.0.0/uv.lock +2688 -0
@@ -0,0 +1,2 @@
1
+ # Default owner for everything in the repo.
2
+ * @oguzhantopcu0
@@ -0,0 +1,44 @@
1
+ name: Bug report
2
+ description: Something in wardcat behaves incorrectly
3
+ labels: ["bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ ⚠️ **Do not paste real PII.** Redact or use fake values in your examples.
9
+ For security vulnerabilities, use the [security advisory](../security/advisories/new) flow instead.
10
+ - type: textarea
11
+ id: what-happened
12
+ attributes:
13
+ label: What happened?
14
+ description: What did you expect, and what happened instead?
15
+ validations:
16
+ required: true
17
+ - type: textarea
18
+ id: repro
19
+ attributes:
20
+ label: Minimal reproduction
21
+ description: A short code snippet (with fake data) that reproduces it.
22
+ render: python
23
+ validations:
24
+ required: true
25
+ - type: input
26
+ id: version
27
+ attributes:
28
+ label: wardcat version
29
+ placeholder: "0.5.0"
30
+ validations:
31
+ required: true
32
+ - type: input
33
+ id: python
34
+ attributes:
35
+ label: Python version
36
+ placeholder: "3.12"
37
+ validations:
38
+ required: true
39
+ - type: dropdown
40
+ id: layers
41
+ attributes:
42
+ label: Which detection layer(s)?
43
+ multiple: true
44
+ options: [regex, ner, llm, "not sure"]
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/oguzhantopcu0/wardcat/security/advisories/new
5
+ about: Report security issues privately — never in a public issue.
@@ -0,0 +1,20 @@
1
+ name: Feature request
2
+ description: Suggest an entity type, layer, action, or capability
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem / use case
9
+ description: What are you trying to do that wardcat doesn't support today?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: Proposed solution
16
+ description: What would the API or behaviour look like?
17
+ - type: textarea
18
+ id: alternatives
19
+ attributes:
20
+ label: Alternatives considered
@@ -0,0 +1,13 @@
1
+ <!-- Thanks for contributing to wardcat! -->
2
+
3
+ ## What & why
4
+
5
+ <!-- What does this change and why? Link any related issue. -->
6
+
7
+ ## Checklist
8
+
9
+ - [ ] Tests added/updated and `uv run pytest tests/unit tests/integration` passes
10
+ - [ ] `uv run ruff check .` and `uv run mypy` are clean
11
+ - [ ] Docs updated if behaviour/API changed (`uv run --group docs mkdocs build --strict`)
12
+ - [ ] `CHANGELOG.md` `[Unreleased]` updated for user-facing changes
13
+ - [ ] No raw PII, secrets, or salts committed
@@ -0,0 +1,18 @@
1
+ version: 2
2
+ updates:
3
+ # Python dependencies (pyproject.toml / uv.lock)
4
+ - package-ecosystem: "uv"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ open-pull-requests-limit: 5
9
+ groups:
10
+ python-deps:
11
+ patterns: ["*"]
12
+
13
+ # GitHub Actions used in the workflows
14
+ - package-ecosystem: "github-actions"
15
+ directory: "/"
16
+ schedule:
17
+ interval: "weekly"
18
+ open-pull-requests-limit: 5
@@ -0,0 +1,109 @@
1
+ name: CI
2
+
3
+ on:
4
+ # Post-merge verification on the trunk.
5
+ push:
6
+ branches: ["main"]
7
+ # The gate: run on every pull request (any base branch) so nothing reaches
8
+ # main without a green lint + test + build run.
9
+ pull_request:
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ lint:
17
+ name: Lint & type-check
18
+ runs-on: ubuntu-latest
19
+
20
+ steps:
21
+ - uses: actions/checkout@v7
22
+
23
+ - name: Set up uv
24
+ uses: astral-sh/setup-uv@v7
25
+ with:
26
+ enable-cache: true
27
+
28
+ - name: Install dependencies
29
+ run: uv sync --dev
30
+
31
+ - name: Ruff lint
32
+ run: uv run ruff check .
33
+
34
+ - name: Ruff format check
35
+ run: uv run ruff format --check .
36
+
37
+ - name: Mypy type check
38
+ run: uv run mypy
39
+
40
+ test:
41
+ name: Test (${{ matrix.os }}, Python ${{ matrix.python-version }})
42
+ runs-on: ${{ matrix.os }}
43
+ needs: lint
44
+ strategy:
45
+ fail-fast: false
46
+ matrix:
47
+ os: [ubuntu-latest, macos-latest]
48
+ python-version: ["3.11", "3.12", "3.13"]
49
+
50
+ steps:
51
+ - uses: actions/checkout@v7
52
+
53
+ - name: Set up uv
54
+ uses: astral-sh/setup-uv@v7
55
+ with:
56
+ enable-cache: true
57
+
58
+ - name: Install dependencies
59
+ run: uv sync --python ${{ matrix.python-version }} --dev
60
+
61
+ - name: Run tests
62
+ run: |
63
+ uv run pytest tests/unit/ tests/integration/ tests/benchmark/ \
64
+ --tb=short \
65
+ -q \
66
+ --cov=src/wardcat \
67
+ --cov-report=term-missing \
68
+ --cov-fail-under=80
69
+
70
+ build:
71
+ name: Build & check wheel
72
+ runs-on: ubuntu-latest
73
+ needs: test
74
+
75
+ steps:
76
+ - uses: actions/checkout@v7
77
+
78
+ - name: Set up uv
79
+ uses: astral-sh/setup-uv@v7
80
+ with:
81
+ enable-cache: true
82
+
83
+ - name: Build wheel and sdist
84
+ run: uv build
85
+
86
+ - name: Check distribution
87
+ run: uv run --with twine twine check dist/*
88
+
89
+ - name: Upload artifacts
90
+ uses: actions/upload-artifact@v7
91
+ with:
92
+ name: dist
93
+ path: dist/
94
+ retention-days: 7
95
+
96
+ docs:
97
+ name: Docs build (strict)
98
+ runs-on: ubuntu-latest
99
+
100
+ steps:
101
+ - uses: actions/checkout@v7
102
+
103
+ - name: Set up uv
104
+ uses: astral-sh/setup-uv@v7
105
+ with:
106
+ enable-cache: true
107
+
108
+ - name: Build docs (strict — fails on broken links/refs)
109
+ run: uv run --group docs mkdocs build --strict
@@ -0,0 +1,59 @@
1
+ name: Release
2
+
3
+ # On a `v*` tag: build + validate the distribution, publish to PyPI via Trusted
4
+ # Publishing, and cut a GitHub Release with the wheel/sdist attached.
5
+ #
6
+ # NOTE: before pushing the first release tag, a Trusted Publisher must be
7
+ # configured for `wardcat` on PyPI (Publishing → Add a new pending publisher:
8
+ # owner `oguzhantopcu0`, repository `wardcat`, workflow `publish.yml`,
9
+ # environment `pypi`) — otherwise the publish step will fail.
10
+ on:
11
+ push:
12
+ tags:
13
+ - "v*"
14
+
15
+ jobs:
16
+ release:
17
+ name: Build, publish to PyPI & GitHub Release
18
+ runs-on: ubuntu-latest
19
+ environment: pypi
20
+ permissions:
21
+ id-token: write # PyPI Trusted Publishing (OIDC)
22
+ contents: write # create the GitHub Release
23
+
24
+ steps:
25
+ - uses: actions/checkout@v7
26
+
27
+ - name: Set up uv
28
+ uses: astral-sh/setup-uv@v7
29
+ with:
30
+ enable-cache: true
31
+
32
+ - name: Install dependencies
33
+ run: uv sync --dev
34
+
35
+ - name: Run tests before releasing
36
+ run: |
37
+ uv run pytest tests/unit/ tests/integration/ tests/benchmark/ \
38
+ --tb=short \
39
+ -q \
40
+ --cov=src/wardcat \
41
+ --cov-fail-under=80
42
+
43
+ - name: Build wheel and sdist
44
+ run: uv build
45
+
46
+ - name: Check distribution
47
+ run: uv run --with twine twine check dist/*
48
+
49
+ - name: Publish to PyPI (Trusted Publishing)
50
+ run: uv publish --trusted-publishing always
51
+
52
+ - name: Create GitHub Release
53
+ env:
54
+ GH_TOKEN: ${{ github.token }}
55
+ run: >
56
+ gh release create "${{ github.ref_name }}"
57
+ --title "${{ github.ref_name }}"
58
+ --notes "See [CHANGELOG.md](https://github.com/oguzhantopcu0/wardcat/blob/main/CHANGELOG.md) for release notes."
59
+ dist/*
@@ -0,0 +1,56 @@
1
+ name: Real-model tests
2
+
3
+ # Model-based backends are mock-only in the fast PR suite, so a bug in the real
4
+ # pipeline path (like the dtype/torch_dtype kwarg regression) is invisible there.
5
+ # This job installs the heavy extras and runs the `slow` tests against real
6
+ # models. It runs:
7
+ # • nightly — to catch drift from a new transformers/torch release, and
8
+ # • on PRs/pushes that touch the model backend or its deps — to gate the exact
9
+ # code whose mock-only tests let the dtype bug through.
10
+ # It stays off the default PR path filter, so day-to-day CI stays fast.
11
+ on:
12
+ schedule:
13
+ - cron: "0 6 * * *" # daily 06:00 UTC
14
+ workflow_dispatch:
15
+ pull_request:
16
+ paths:
17
+ - "src/wardcat/llm/backends/transformers_backend.py"
18
+ - "tests/integration/test_transformers_live.py"
19
+ - "pyproject.toml"
20
+ - ".github/workflows/real-model-tests.yml"
21
+ push:
22
+ branches: [main]
23
+ paths:
24
+ - "src/wardcat/llm/backends/transformers_backend.py"
25
+ - "pyproject.toml"
26
+
27
+ # A newer commit on the same ref supersedes an in-flight (slow) run.
28
+ concurrency:
29
+ group: real-model-${{ github.ref }}
30
+ cancel-in-progress: true
31
+
32
+ jobs:
33
+ slow-tests:
34
+ name: Real-model slow tests
35
+ runs-on: ubuntu-latest
36
+
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+
40
+ - name: Set up uv
41
+ uses: astral-sh/setup-uv@v7
42
+ with:
43
+ enable-cache: true
44
+
45
+ - name: Cache HuggingFace models
46
+ uses: actions/cache@v4
47
+ with:
48
+ path: ~/.cache/huggingface
49
+ key: hf-${{ runner.os }}-smollm2-135m
50
+ restore-keys: hf-${{ runner.os }}-
51
+
52
+ - name: Install with the transformers extra
53
+ run: uv sync --extra transformers --dev
54
+
55
+ - name: Run slow tests (real models; auto-skip what's unavailable)
56
+ run: uv run pytest -m slow tests/integration/ --tb=short -q
@@ -0,0 +1,22 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+ .coverage
12
+
13
+ # Generated test/scan outputs (manual harness runs)
14
+ *_results.txt
15
+ filter_coverage_results.txt
16
+ live_test_results.txt
17
+
18
+ # MkDocs build output
19
+ site/
20
+
21
+ # Local Claude Code config / agents (machine-local, not part of the package)
22
+ .claude/
@@ -0,0 +1,3 @@
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="PYTHON_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$" />
5
+ <orderEntry type="inheritedJdk" />
6
+ <orderEntry type="sourceFolder" forTests="false" />
7
+ </component>
8
+ </module>
@@ -0,0 +1,6 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="MaterialThemeProjectNewConfig">
4
+ <option name="metadata">
5
+ <MTProjectMetadataState>
6
+ <option name="migrated" value="true" />
7
+ <option name="pristineConfig" value="false" />
8
+ <option name="userId" value="-4d90f355:198cc5aa17c:-7ffe" />
9
+ </MTProjectMetadataState>
10
+ </option>
11
+ </component>
12
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/wardcat.iml" filepath="$PROJECT_DIR$/.idea/wardcat.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,27 @@
1
+ # Run `pre-commit install` once, then ruff + mypy run automatically on commit.
2
+ # Mirrors the CI "Lint & type-check" job so failures surface locally first.
3
+ repos:
4
+ - repo: https://github.com/astral-sh/ruff-pre-commit
5
+ rev: v0.14.0
6
+ hooks:
7
+ - id: ruff
8
+ args: [--fix]
9
+ - id: ruff-format
10
+
11
+ - repo: https://github.com/pre-commit/pre-commit-hooks
12
+ rev: v5.0.0
13
+ hooks:
14
+ - id: end-of-file-fixer
15
+ - id: trailing-whitespace
16
+ - id: check-yaml
17
+ - id: check-toml
18
+ - id: check-merge-conflict
19
+
20
+ - repo: local
21
+ hooks:
22
+ - id: mypy
23
+ name: mypy
24
+ entry: uv run mypy
25
+ language: system
26
+ pass_filenames: false
27
+ types: [python]
@@ -0,0 +1 @@
1
+ 3.13