code-aide 1.3.0__tar.gz → 1.4.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 (41) hide show
  1. code_aide-1.4.0/.github/workflows/ci.yml +24 -0
  2. {code_aide-1.3.0 → code_aide-1.4.0}/.gitignore +0 -1
  3. code_aide-1.4.0/.gitlab-ci.yml +26 -0
  4. code_aide-1.4.0/.pre-commit-config.yaml +36 -0
  5. {code_aide-1.3.0 → code_aide-1.4.0}/AGENTS.md +3 -1
  6. {code_aide-1.3.0 → code_aide-1.4.0}/PKG-INFO +33 -28
  7. {code_aide-1.3.0 → code_aide-1.4.0}/README.md +32 -27
  8. {code_aide-1.3.0 → code_aide-1.4.0}/pyproject.toml +1 -0
  9. code_aide-1.4.0/specs/pre-commit-uv-setup.md +291 -0
  10. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/__init__.py +1 -1
  11. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/data/tools.json +2 -2
  12. {code_aide-1.3.0 → code_aide-1.4.0}/tests/test_commands_actions.py +1 -4
  13. code_aide-1.4.0/uv.lock +243 -0
  14. code_aide-1.3.0/.github/workflows/ci.yml +0 -13
  15. {code_aide-1.3.0 → code_aide-1.4.0}/.github/workflows/publish.yml +0 -0
  16. {code_aide-1.3.0 → code_aide-1.4.0}/CLAUDE.md +0 -0
  17. {code_aide-1.3.0 → code_aide-1.4.0}/LICENSE +0 -0
  18. {code_aide-1.3.0 → code_aide-1.4.0}/TODO.md +0 -0
  19. {code_aide-1.3.0 → code_aide-1.4.0}/specs/missing-coding-llm-cli-tools.md +0 -0
  20. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/__main__.py +0 -0
  21. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/commands_actions.py +0 -0
  22. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/commands_tools.py +0 -0
  23. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/config.py +0 -0
  24. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/console.py +0 -0
  25. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/constants.py +0 -0
  26. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/detection.py +0 -0
  27. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/entry.py +0 -0
  28. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/install.py +0 -0
  29. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/operations.py +0 -0
  30. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/prereqs.py +0 -0
  31. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/status.py +0 -0
  32. {code_aide-1.3.0 → code_aide-1.4.0}/src/code_aide/versions.py +0 -0
  33. {code_aide-1.3.0 → code_aide-1.4.0}/tests/test_commands_tools.py +0 -0
  34. {code_aide-1.3.0 → code_aide-1.4.0}/tests/test_config.py +0 -0
  35. {code_aide-1.3.0 → code_aide-1.4.0}/tests/test_console.py +0 -0
  36. {code_aide-1.3.0 → code_aide-1.4.0}/tests/test_constants.py +0 -0
  37. {code_aide-1.3.0 → code_aide-1.4.0}/tests/test_detection.py +0 -0
  38. {code_aide-1.3.0 → code_aide-1.4.0}/tests/test_install.py +0 -0
  39. {code_aide-1.3.0 → code_aide-1.4.0}/tests/test_operations.py +0 -0
  40. {code_aide-1.3.0 → code_aide-1.4.0}/tests/test_status.py +0 -0
  41. {code_aide-1.3.0 → code_aide-1.4.0}/tests/test_versions.py +0 -0
@@ -0,0 +1,24 @@
1
+ name: CI
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ runs-on: ${{ matrix.os }}
6
+ strategy:
7
+ matrix:
8
+ os: [ubuntu-latest, macos-latest]
9
+ python-version: ["3.11", "3.12", "3.13"]
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: astral-sh/setup-uv@v5
13
+ with:
14
+ python-version: ${{ matrix.python-version }}
15
+ - name: Verify lockfile is up to date
16
+ run: uv lock --check
17
+ - name: Install dependencies (exact lockfile)
18
+ run: uv sync --locked --python ${{ matrix.python-version }}
19
+ - name: Lint
20
+ run: uv run ruff check .
21
+ - name: Format check
22
+ run: uv run black --check .
23
+ - name: Run tests
24
+ run: uv run pytest tests/ -v
@@ -12,4 +12,3 @@
12
12
  __pycache__/
13
13
  build/
14
14
  dist/
15
- uv.lock
@@ -0,0 +1,26 @@
1
+ # GitLab CI - same checks as GitHub Actions
2
+ # Uses Astral's uv Docker images with UV_LINK_MODE=copy (required for GitLab CI)
3
+
4
+ variables:
5
+ UV_LINK_MODE: copy
6
+
7
+ .check_template: &check_definition
8
+ before_script:
9
+ - uv lock --check
10
+ - uv sync --locked
11
+ script:
12
+ - uv run ruff check .
13
+ - uv run black --check .
14
+ - uv run pytest tests/ -v
15
+
16
+ check:python3.11:
17
+ <<: *check_definition
18
+ image: ghcr.io/astral-sh/uv:python3.11-trixie-slim
19
+
20
+ check:python3.12:
21
+ <<: *check_definition
22
+ image: ghcr.io/astral-sh/uv:python3.12-trixie-slim
23
+
24
+ check:python3.13:
25
+ <<: *check_definition
26
+ image: ghcr.io/astral-sh/uv:python3.13-trixie-slim
@@ -0,0 +1,36 @@
1
+ # .pre-commit-config.yaml
2
+ #
3
+ # Run `pre-commit install` after cloning to enable hooks.
4
+ # Run `pre-commit run --all-files` to check all files manually.
5
+ # Run `pre-commit autoupdate` to update hook versions.
6
+
7
+ repos:
8
+ # --- General file hygiene ---
9
+ - repo: https://github.com/pre-commit/pre-commit-hooks
10
+ rev: v5.0.0
11
+ hooks:
12
+ - id: trailing-whitespace
13
+ - id: end-of-file-fixer
14
+ - id: check-yaml
15
+ - id: check-toml
16
+ - id: check-added-large-files
17
+ - id: check-merge-conflict
18
+
19
+ # --- Python formatting (black) ---
20
+ - repo: https://github.com/psf/black
21
+ rev: 24.10.0
22
+ hooks:
23
+ - id: black
24
+
25
+ # --- Python linting (ruff) ---
26
+ - repo: https://github.com/astral-sh/ruff-pre-commit
27
+ rev: v0.9.10
28
+ hooks:
29
+ - id: ruff
30
+ args: [--fix]
31
+
32
+ # --- Keep uv.lock in sync with pyproject.toml ---
33
+ - repo: https://github.com/astral-sh/uv-pre-commit
34
+ rev: 0.10.6
35
+ hooks:
36
+ - id: uv-lock
@@ -6,7 +6,9 @@
6
6
  - Three-layer version data: bundled definitions, bundled baseline versions,
7
7
  user's local cache (~/.config/code-aide/versions.json)
8
8
  - All tests should pass before committing
9
- - Run `black` formatter on python before commits
9
+ - pre-commit runs black and ruff on commit; run `pre-commit run --all-files` to
10
+ check before committing
11
+ - When changing pyproject.toml dependencies, run `uv lock` and commit uv.lock
10
12
  - Write useful commit messages: start subjects with past-tense action verbs
11
13
  (`Added`, `Changed`, `Fixed`, `Removed`), keep them user-facing, and keep
12
14
  commits focused.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-aide
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: Manage AI coding CLI tools (Claude, Copilot, Cursor, Gemini, Amp, Codex)
5
5
  Project-URL: Homepage, https://github.com/dajobe/code-aide
6
6
  Project-URL: Repository, https://github.com/dajobe/code-aide
@@ -28,8 +28,9 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  An aide for your AI coding tools.
30
30
 
31
- Manages installation, upgrade, removal, and version tracking of AI coding CLI
32
- tools: Claude Code, Copilot, Cursor, Gemini, Amp, Codex, OpenCode, and Kilo.
31
+ Manages installation, upgrade, removal, and version tracking of AI coding
32
+ CLI tools: Claude Code, Copilot, Cursor, Gemini, Amp, Codex, OpenCode, and
33
+ Kilo.
33
34
 
34
35
  ## Installation
35
36
 
@@ -81,33 +82,34 @@ code-aide update-versions -b -y
81
82
  ## Supported Tools
82
83
 
83
84
  | Tool | Command | Install Type | Default |
84
- |--------------------------|------------|--------------------|---------|
85
- | Cursor CLI | `agent` | Direct download | Yes |
86
- | Claude CLI (Claude Code) | `claude` | Self-managed (npm) | Yes |
87
- | Gemini CLI | `gemini` | npm | Yes |
88
- | OpenCode | `opencode`| npm | No |
89
- | Kilo CLI | `kilo` | npm | No |
90
- | Amp (Sourcegraph) | `amp` | Script | No |
91
- | Codex CLI | `codex` | npm | No |
92
- | Copilot CLI | `copilot` | npm | No |
85
+ |--------------------------|-----------|--------------------|---------|
86
+ | Cursor CLI | `agent` | Direct download | Yes |
87
+ | Claude CLI (Claude Code) | `claude` | Self-managed (npm) | Yes |
88
+ | Gemini CLI | `gemini` | npm | Yes |
89
+ | OpenCode | `opencode`| npm | No |
90
+ | Kilo CLI | `kilo` | npm | No |
91
+ | Amp (Sourcegraph) | `amp` | Script | No |
92
+ | Codex CLI | `codex` | npm | No |
93
+ | Copilot CLI | `copilot` | npm | No |
93
94
 
94
95
  ## How Version Data Works
95
96
 
96
97
  code-aide uses a three-layer version data model:
97
98
 
98
- 1. **Tool definitions** (bundled with the package): Install methods, URLs, npm
99
- packages, version args. Updated by releasing new versions of code-aide.
99
+ 1. **Tool definitions** (bundled with the package): Install methods,
100
+ URLs, npm packages, version args. Updated by releasing new versions
101
+ of code-aide.
100
102
 
101
- 2. **Bundled version baseline** (in `data/tools.json`): Latest versions and
102
- SHA256 hashes as known at release time. Acts as a fallback for fresh
103
- installs.
103
+ 2. **Bundled version baseline** (in `data/tools.json`): Latest
104
+ versions and SHA256 hashes as known at release time. Acts as a
105
+ fallback for fresh installs.
104
106
 
105
- 3. **User's local version cache** (`~/.config/code-aide/versions.json`): Written
106
- by `code-aide update-versions`. Takes precedence over bundled data when
107
- present.
107
+ 3. **User's local version cache**
108
+ (`~/.config/code-aide/versions.json`): Written by `code-aide
109
+ update-versions`. Takes precedence over bundled data when present.
108
110
 
109
- Run `code-aide update-versions` to get fresher version data without waiting for
110
- a new code-aide release.
111
+ Run `code-aide update-versions` to get fresher version data without
112
+ waiting for a new code-aide release.
111
113
 
112
114
  ## Features
113
115
 
@@ -126,14 +128,16 @@ a new code-aide release.
126
128
 
127
129
  ## Development
128
130
 
131
+ 1. Install uv: `curl -LsSf https://astral.sh/uv/install.sh | sh`
132
+ 2. Install dependencies: `uv sync`
133
+ 3. Install pre-commit hooks: `uv tool install pre-commit && pre-commit install`
134
+ 4. Run tests: `uv run pytest tests/ -v`
135
+
129
136
  ```bash
130
137
  # Run from development checkout
131
138
  uv run python -m code_aide status
132
139
  uv run python -m code_aide install copilot
133
140
 
134
- # Run tests
135
- uv run pytest tests/ -v
136
-
137
141
  # Run a specific test
138
142
  uv run pytest tests/test_install.py::TestDetectOsArch -v
139
143
  ```
@@ -157,7 +161,8 @@ uv run pytest tests/test_install.py::TestDetectOsArch -v
157
161
  5. Write useful commit messages before tagging:
158
162
  - Start subject lines with an action verb in past tense (`Added`, `Changed`,
159
163
  `Fixed`, `Removed`).
160
- - Keep subjects user-facing so auto-generated release notes are meaningful.
164
+ - Keep subjects user-facing so auto-generated release notes are
165
+ meaningful.
161
166
  - Group related changes into focused commits instead of one broad commit.
162
167
  - Example: `Fixed timeout handling in status command`
163
168
  6. Tag and push:
@@ -166,8 +171,8 @@ uv run pytest tests/test_install.py::TestDetectOsArch -v
166
171
  7. Confirm GitHub Actions:
167
172
  - CI should pass.
168
173
  - Publish workflow should upload to PyPI and create GitHub Release notes.
169
- - Release notes should include generated notes plus a commit summary from the
170
- previous tag to the current tag.
174
+ - Release notes should include generated notes plus a commit summary from
175
+ the previous tag to the current tag.
171
176
 
172
177
  ## License
173
178
 
@@ -2,8 +2,9 @@
2
2
 
3
3
  An aide for your AI coding tools.
4
4
 
5
- Manages installation, upgrade, removal, and version tracking of AI coding CLI
6
- tools: Claude Code, Copilot, Cursor, Gemini, Amp, Codex, OpenCode, and Kilo.
5
+ Manages installation, upgrade, removal, and version tracking of AI coding
6
+ CLI tools: Claude Code, Copilot, Cursor, Gemini, Amp, Codex, OpenCode, and
7
+ Kilo.
7
8
 
8
9
  ## Installation
9
10
 
@@ -55,33 +56,34 @@ code-aide update-versions -b -y
55
56
  ## Supported Tools
56
57
 
57
58
  | Tool | Command | Install Type | Default |
58
- |--------------------------|------------|--------------------|---------|
59
- | Cursor CLI | `agent` | Direct download | Yes |
60
- | Claude CLI (Claude Code) | `claude` | Self-managed (npm) | Yes |
61
- | Gemini CLI | `gemini` | npm | Yes |
62
- | OpenCode | `opencode`| npm | No |
63
- | Kilo CLI | `kilo` | npm | No |
64
- | Amp (Sourcegraph) | `amp` | Script | No |
65
- | Codex CLI | `codex` | npm | No |
66
- | Copilot CLI | `copilot` | npm | No |
59
+ |--------------------------|-----------|--------------------|---------|
60
+ | Cursor CLI | `agent` | Direct download | Yes |
61
+ | Claude CLI (Claude Code) | `claude` | Self-managed (npm) | Yes |
62
+ | Gemini CLI | `gemini` | npm | Yes |
63
+ | OpenCode | `opencode`| npm | No |
64
+ | Kilo CLI | `kilo` | npm | No |
65
+ | Amp (Sourcegraph) | `amp` | Script | No |
66
+ | Codex CLI | `codex` | npm | No |
67
+ | Copilot CLI | `copilot` | npm | No |
67
68
 
68
69
  ## How Version Data Works
69
70
 
70
71
  code-aide uses a three-layer version data model:
71
72
 
72
- 1. **Tool definitions** (bundled with the package): Install methods, URLs, npm
73
- packages, version args. Updated by releasing new versions of code-aide.
73
+ 1. **Tool definitions** (bundled with the package): Install methods,
74
+ URLs, npm packages, version args. Updated by releasing new versions
75
+ of code-aide.
74
76
 
75
- 2. **Bundled version baseline** (in `data/tools.json`): Latest versions and
76
- SHA256 hashes as known at release time. Acts as a fallback for fresh
77
- installs.
77
+ 2. **Bundled version baseline** (in `data/tools.json`): Latest
78
+ versions and SHA256 hashes as known at release time. Acts as a
79
+ fallback for fresh installs.
78
80
 
79
- 3. **User's local version cache** (`~/.config/code-aide/versions.json`): Written
80
- by `code-aide update-versions`. Takes precedence over bundled data when
81
- present.
81
+ 3. **User's local version cache**
82
+ (`~/.config/code-aide/versions.json`): Written by `code-aide
83
+ update-versions`. Takes precedence over bundled data when present.
82
84
 
83
- Run `code-aide update-versions` to get fresher version data without waiting for
84
- a new code-aide release.
85
+ Run `code-aide update-versions` to get fresher version data without
86
+ waiting for a new code-aide release.
85
87
 
86
88
  ## Features
87
89
 
@@ -100,14 +102,16 @@ a new code-aide release.
100
102
 
101
103
  ## Development
102
104
 
105
+ 1. Install uv: `curl -LsSf https://astral.sh/uv/install.sh | sh`
106
+ 2. Install dependencies: `uv sync`
107
+ 3. Install pre-commit hooks: `uv tool install pre-commit && pre-commit install`
108
+ 4. Run tests: `uv run pytest tests/ -v`
109
+
103
110
  ```bash
104
111
  # Run from development checkout
105
112
  uv run python -m code_aide status
106
113
  uv run python -m code_aide install copilot
107
114
 
108
- # Run tests
109
- uv run pytest tests/ -v
110
-
111
115
  # Run a specific test
112
116
  uv run pytest tests/test_install.py::TestDetectOsArch -v
113
117
  ```
@@ -131,7 +135,8 @@ uv run pytest tests/test_install.py::TestDetectOsArch -v
131
135
  5. Write useful commit messages before tagging:
132
136
  - Start subject lines with an action verb in past tense (`Added`, `Changed`,
133
137
  `Fixed`, `Removed`).
134
- - Keep subjects user-facing so auto-generated release notes are meaningful.
138
+ - Keep subjects user-facing so auto-generated release notes are
139
+ meaningful.
135
140
  - Group related changes into focused commits instead of one broad commit.
136
141
  - Example: `Fixed timeout handling in status command`
137
142
  6. Tag and push:
@@ -140,8 +145,8 @@ uv run pytest tests/test_install.py::TestDetectOsArch -v
140
145
  7. Confirm GitHub Actions:
141
146
  - CI should pass.
142
147
  - Publish workflow should upload to PyPI and create GitHub Release notes.
143
- - Release notes should include generated notes plus a commit summary from the
144
- previous tag to the current tag.
148
+ - Release notes should include generated notes plus a commit summary from
149
+ the previous tag to the current tag.
145
150
 
146
151
  ## License
147
152
 
@@ -48,4 +48,5 @@ dev = [
48
48
  "pytest>=8.0",
49
49
  "pytest-xdist>=3.0",
50
50
  "black>=25.1.0",
51
+ "ruff>=0.9.0",
51
52
  ]
@@ -0,0 +1,291 @@
1
+ # Setting Up pre-commit with uv for Python 3 Projects
2
+
3
+ ## Overview
4
+
5
+ This document describes how to set up the **pre-commit** framework with
6
+ **uv** (the Python package/project manager from Astral) in a Python 3
7
+ project. It covers what pre-commit is, why to use it, and provides exact
8
+ steps to deploy it.
9
+
10
+ ## What is pre-commit?
11
+
12
+ **pre-commit** is a tool that manages git pre-commit hooks declaratively.
13
+ Instead of manually writing scripts in `.git/hooks/`, you declare hooks in a
14
+ `.pre-commit-config.yaml` file that is committed to the repo. The framework
15
+ handles downloading, caching, and running hooks in isolated environments.
16
+
17
+ Key benefits:
18
+
19
+ - Hooks are version-controlled and shared across the team
20
+ - Each hook runs in its own isolated environment (no dependency conflicts)
21
+ - Hooks are sourced from external repos and pinned to specific versions
22
+ - Runs automatically on every `git commit`
23
+
24
+ **Website:** <https://pre-commit.com/>
25
+
26
+ ## What is uv.lock and why commit it?
27
+
28
+ `uv.lock` is a cross-platform lockfile generated by uv that pins exact
29
+ dependency versions. The official uv documentation states it should be
30
+ committed to version control for reproducible builds. The lockfile ensures
31
+ all developers and CI get identical dependency trees.
32
+
33
+ - **Applications/services (deployed code):** Always commit `uv.lock`.
34
+ - **Libraries (published to PyPI):** Commit `uv.lock` for reproducible dev
35
+ environments. Also test without `--locked` in CI to verify declared
36
+ version ranges work.
37
+
38
+ ## Prerequisites
39
+
40
+ - Python 3.8+
41
+ - uv installed (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
42
+ - git initialized in the project
43
+ - A `pyproject.toml` managed by uv
44
+
45
+ ## Installation Steps
46
+
47
+ ### 1. Install pre-commit
48
+
49
+ Using uv as a tool (recommended — keeps it out of project dependencies):
50
+
51
+ ```bash
52
+ uv tool install pre-commit
53
+ ```
54
+
55
+ Alternatively, with pip:
56
+
57
+ ```bash
58
+ pip install pre-commit
59
+ ```
60
+
61
+ Verify installation:
62
+
63
+ ```bash
64
+ pre-commit --version
65
+ ```
66
+
67
+ ### 2. Create `.pre-commit-config.yaml`
68
+
69
+ Create this file in the project root (same directory as `pyproject.toml`).
70
+
71
+ **This project uses black for formatting and ruff for linting only:**
72
+
73
+ ```yaml
74
+ # .pre-commit-config.yaml
75
+ #
76
+ # Run `pre-commit install` after cloning to enable hooks.
77
+ # Run `pre-commit run --all-files` to check all files manually.
78
+ # Run `pre-commit autoupdate` to update hook versions.
79
+
80
+ repos:
81
+ # --- General file hygiene ---
82
+ - repo: https://github.com/pre-commit/pre-commit-hooks
83
+ rev: v5.0.0
84
+ hooks:
85
+ - id: trailing-whitespace
86
+ - id: end-of-file-fixer
87
+ - id: check-yaml
88
+ - id: check-toml
89
+ - id: check-added-large-files
90
+ - id: check-merge-conflict
91
+
92
+ # --- Python formatting (black) ---
93
+ - repo: https://github.com/psf/black
94
+ rev: 24.10.0
95
+ hooks:
96
+ - id: black
97
+
98
+ # --- Python linting (ruff) ---
99
+ - repo: https://github.com/astral-sh/ruff-pre-commit
100
+ rev: v0.9.10
101
+ hooks:
102
+ - id: ruff
103
+ args: [--fix]
104
+
105
+ # --- Keep uv.lock in sync with pyproject.toml ---
106
+ - repo: https://github.com/astral-sh/uv-pre-commit
107
+ rev: 0.10.6
108
+ hooks:
109
+ - id: uv-lock
110
+ ```
111
+
112
+ **Note on `rev` values:** These are current as of early 2026. Run
113
+ `pre-commit autoupdate` to fetch the latest versions.
114
+
115
+ ### 3. Install the git hooks
116
+
117
+ From the project root:
118
+
119
+ ```bash
120
+ pre-commit install
121
+ ```
122
+
123
+ This writes a script to `.git/hooks/pre-commit` that invokes the framework.
124
+ This step must be run once per clone (it modifies `.git/` which is not
125
+ version-controlled).
126
+
127
+ ### 4. (Optional) Run against all existing files
128
+
129
+ To retroactively check all files in the repo:
130
+
131
+ ```bash
132
+ pre-commit run --all-files
133
+ ```
134
+
135
+ ### 5. Commit the configuration
136
+
137
+ ```bash
138
+ git add .pre-commit-config.yaml
139
+ git commit -m "Add pre-commit configuration"
140
+ ```
141
+
142
+ ## How It Works at Commit Time
143
+
144
+ When a developer runs `git commit`:
145
+
146
+ 1. Git triggers the pre-commit hook installed in `.git/hooks/`
147
+ 2. The pre-commit framework reads `.pre-commit-config.yaml`
148
+ 3. Each hook runs against the staged files (only files being committed)
149
+ 4. If any hook fails, the commit is blocked and the developer sees the error
150
+ 5. Some hooks auto-fix files (e.g., `trailing-whitespace`, `ruff --fix`).
151
+ The developer reviews the fixes, re-stages, and commits again.
152
+
153
+ The `uv-lock` hook specifically checks if `pyproject.toml` has changed and,
154
+ if so, runs `uv lock` to regenerate `uv.lock` and stages the updated
155
+ lockfile.
156
+
157
+ ## CI Complement: GitHub Actions
158
+
159
+ pre-commit runs locally to catch issues early. CI should enforce
160
+ correctness. Here is a minimal GitHub Actions workflow that complements the
161
+ local hooks:
162
+
163
+ ```yaml
164
+ # .github/workflows/ci.yml
165
+ name: CI
166
+
167
+ on:
168
+ push:
169
+ branches: [main]
170
+ pull_request:
171
+
172
+ jobs:
173
+ check:
174
+ runs-on: ubuntu-latest
175
+ steps:
176
+ - uses: actions/checkout@v4
177
+
178
+ - name: Install uv
179
+ uses: astral-sh/setup-uv@v5
180
+
181
+ - name: Verify lockfile is up to date
182
+ run: uv lock --check
183
+
184
+ - name: Install dependencies (exact lockfile)
185
+ run: uv sync --locked
186
+
187
+ - name: Lint
188
+ run: uv run ruff check .
189
+
190
+ - name: Format check
191
+ run: uv run black --check .
192
+
193
+ - name: Run tests
194
+ run: uv run pytest
195
+ ```
196
+
197
+ Key CI commands:
198
+
199
+ - `uv lock --check` — Fails if `uv.lock` is out of sync with
200
+ `pyproject.toml`. Does not modify files.
201
+ - `uv sync --locked` — Installs exactly what's in `uv.lock`. Fails if
202
+ lockfile is missing or stale.
203
+
204
+ ## CI Complement: GitLab CI
205
+
206
+ GitLab CI runs the same checks as GitHub Actions. Use Astral's uv Docker
207
+ image with `UV_LINK_MODE: copy` (required for GitLab CI build directories):
208
+
209
+ ```yaml
210
+ # .gitlab-ci.yml
211
+ variables:
212
+ UV_VERSION: "0.10.7"
213
+ UV_LINK_MODE: copy
214
+
215
+ .check_template: &check_definition
216
+ image: ghcr.io/astral-sh/uv:${UV_VERSION}-python${PYTHON_VERSION}-trixie-slim
217
+ variables:
218
+ UV_LINK_MODE: copy
219
+ before_script:
220
+ - uv lock --check
221
+ - uv sync --locked
222
+ script:
223
+ - uv run ruff check .
224
+ - uv run black --check .
225
+ - uv run pytest tests/ -v
226
+
227
+ check:python3.11:
228
+ <<: *check_definition
229
+ variables:
230
+ PYTHON_VERSION: "3.11"
231
+
232
+ check:python3.12:
233
+ <<: *check_definition
234
+ variables:
235
+ PYTHON_VERSION: "3.12"
236
+
237
+ check:python3.13:
238
+ <<: *check_definition
239
+ variables:
240
+ PYTHON_VERSION: "3.13"
241
+ ```
242
+
243
+ Optional: add caching keyed on `uv.lock` for faster runs, with `uv cache
244
+ prune --ci` at the end of the job.
245
+
246
+ ## Files to Commit to Git
247
+
248
+ | File | Commit? | Notes |
249
+ |------|---------|-------|
250
+ | `pyproject.toml` | Yes | Project metadata and dependency declarations |
251
+ | `uv.lock` | Yes | Pinned dependency versions for reproducibility |
252
+ | `.pre-commit-config.yaml` | Yes | Hook configuration shared across team |
253
+ | `.venv/` | No | Auto-excluded by uv's internal `.gitignore` |
254
+ | `.git/hooks/` | No | Generated locally by `pre-commit install` |
255
+
256
+ ## Common Commands Reference
257
+
258
+ | Command | Purpose |
259
+ |---------|---------|
260
+ | `pre-commit install` | Wire up git hooks (run once per clone) |
261
+ | `pre-commit run --all-files` | Run all hooks on all files |
262
+ | `pre-commit run ruff --all-files` | Run a specific hook on all files |
263
+ | `pre-commit autoupdate` | Update all hook `rev` values to latest |
264
+ | `pre-commit clean` | Clear the hook cache |
265
+ | `git commit --no-verify` | Skip hooks for this commit (escape hatch) |
266
+
267
+ ## Onboarding New Contributors
268
+
269
+ Add this to your README or CONTRIBUTING.md:
270
+
271
+ ```markdown
272
+ ## Development Setup
273
+
274
+ 1. Install uv: `curl -LsSf https://astral.sh/uv/install.sh | sh`
275
+ 2. Install dependencies: `uv sync`
276
+ 3. Install pre-commit hooks: `uv tool install pre-commit && pre-commit install`
277
+ 4. Run tests: `uv run pytest tests/ -v`
278
+ ```
279
+
280
+ ## Customization Notes
281
+
282
+ - **Adding mypy:** Use `https://github.com/pre-commit/mirrors-mypy` as a
283
+ hook repo. Note that mypy hooks need access to your project's
284
+ dependencies, which can require additional configuration.
285
+ - **Adding pytest as a hook:** Generally not recommended — tests are slow
286
+ and better suited for CI. Keep pre-commit hooks fast (<5 seconds total).
287
+ - **Skipping hooks for specific files:** Use the `exclude` key on a hook
288
+ definition (regex pattern against file paths).
289
+ - **Hook stages:** By default hooks run on `pre-commit`. You can configure
290
+ hooks to run on `pre-push` instead by setting `stages: [pre-push]` on the
291
+ hook.
@@ -1,3 +1,3 @@
1
1
  """code-aide - Manage AI coding CLI tools."""
2
2
 
3
- __version__ = "1.3.0"
3
+ __version__ = "1.4.0"
@@ -80,8 +80,8 @@
80
80
  ],
81
81
  "docs_url": "https://ampcode.com/manual",
82
82
  "default_install": false,
83
- "latest_version": "0.0.1772308894-g06c525",
84
- "latest_date": "2026-02-28"
83
+ "latest_version": "0.0.1772339780-g24a24e",
84
+ "latest_date": "2026-03-01"
85
85
  },
86
86
  "codex": {
87
87
  "name": "Codex CLI",
@@ -124,7 +124,6 @@ class TestCmdUpdateVersions(unittest.TestCase):
124
124
  self.assertIn("No upstream config changes detected.", buf.getvalue())
125
125
  mock_save.assert_not_called()
126
126
 
127
-
128
127
  def test_bundled_flag_skips_cache_and_saves_to_bundled(self):
129
128
  args = type(
130
129
  "Args",
@@ -156,9 +155,7 @@ class TestCmdUpdateVersions(unittest.TestCase):
156
155
  mock.patch.object(
157
156
  commands_actions, "load_versions_cache", return_value={}
158
157
  ) as mock_cache,
159
- mock.patch.object(
160
- commands_actions, "merge_cached_versions"
161
- ) as mock_merge,
158
+ mock.patch.object(commands_actions, "merge_cached_versions") as mock_merge,
162
159
  mock.patch.object(
163
160
  commands_actions,
164
161
  "check_npm_tool",
@@ -0,0 +1,243 @@
1
+ version = 1
2
+ revision = 3
3
+ requires-python = ">=3.11"
4
+
5
+ [[package]]
6
+ name = "black"
7
+ version = "26.1.0"
8
+ source = { registry = "https://pypi.org/simple" }
9
+ dependencies = [
10
+ { name = "click" },
11
+ { name = "mypy-extensions" },
12
+ { name = "packaging" },
13
+ { name = "pathspec" },
14
+ { name = "platformdirs" },
15
+ { name = "pytokens" },
16
+ ]
17
+ sdist = { url = "https://files.pythonhosted.org/packages/13/88/560b11e521c522440af991d46848a2bde64b5f7202ec14e1f46f9509d328/black-26.1.0.tar.gz", hash = "sha256:d294ac3340eef9c9eb5d29288e96dc719ff269a88e27b396340459dd85da4c58", size = 658785, upload-time = "2026-01-18T04:50:11.993Z" }
18
+ wheels = [
19
+ { url = "https://files.pythonhosted.org/packages/30/83/f05f22ff13756e1a8ce7891db517dbc06200796a16326258268f4658a745/black-26.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3cee1487a9e4c640dc7467aaa543d6c0097c391dc8ac74eb313f2fbf9d7a7cb5", size = 1831956, upload-time = "2026-01-18T04:59:21.38Z" },
20
+ { url = "https://files.pythonhosted.org/packages/7d/f2/b2c570550e39bedc157715e43927360312d6dd677eed2cc149a802577491/black-26.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d62d14ca31c92adf561ebb2e5f2741bf8dea28aef6deb400d49cca011d186c68", size = 1672499, upload-time = "2026-01-18T04:59:23.257Z" },
21
+ { url = "https://files.pythonhosted.org/packages/7a/d7/990d6a94dc9e169f61374b1c3d4f4dd3037e93c2cc12b6f3b12bc663aa7b/black-26.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb1dafbbaa3b1ee8b4550a84425aac8874e5f390200f5502cf3aee4a2acb2f14", size = 1735431, upload-time = "2026-01-18T04:59:24.729Z" },
22
+ { url = "https://files.pythonhosted.org/packages/36/1c/cbd7bae7dd3cb315dfe6eeca802bb56662cc92b89af272e014d98c1f2286/black-26.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:101540cb2a77c680f4f80e628ae98bd2bd8812fb9d72ade4f8995c5ff019e82c", size = 1400468, upload-time = "2026-01-18T04:59:27.381Z" },
23
+ { url = "https://files.pythonhosted.org/packages/59/b1/9fe6132bb2d0d1f7094613320b56297a108ae19ecf3041d9678aec381b37/black-26.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:6f3977a16e347f1b115662be07daa93137259c711e526402aa444d7a88fdc9d4", size = 1207332, upload-time = "2026-01-18T04:59:28.711Z" },
24
+ { url = "https://files.pythonhosted.org/packages/f5/13/710298938a61f0f54cdb4d1c0baeb672c01ff0358712eddaf29f76d32a0b/black-26.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6eeca41e70b5f5c84f2f913af857cf2ce17410847e1d54642e658e078da6544f", size = 1878189, upload-time = "2026-01-18T04:59:30.682Z" },
25
+ { url = "https://files.pythonhosted.org/packages/79/a6/5179beaa57e5dbd2ec9f1c64016214057b4265647c62125aa6aeffb05392/black-26.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dd39eef053e58e60204f2cdf059e2442e2eb08f15989eefe259870f89614c8b6", size = 1700178, upload-time = "2026-01-18T04:59:32.387Z" },
26
+ { url = "https://files.pythonhosted.org/packages/8c/04/c96f79d7b93e8f09d9298b333ca0d31cd9b2ee6c46c274fd0f531de9dc61/black-26.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9459ad0d6cd483eacad4c6566b0f8e42af5e8b583cee917d90ffaa3778420a0a", size = 1777029, upload-time = "2026-01-18T04:59:33.767Z" },
27
+ { url = "https://files.pythonhosted.org/packages/49/f9/71c161c4c7aa18bdda3776b66ac2dc07aed62053c7c0ff8bbda8c2624fe2/black-26.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a19915ec61f3a8746e8b10adbac4a577c6ba9851fa4a9e9fbfbcf319887a5791", size = 1406466, upload-time = "2026-01-18T04:59:35.177Z" },
28
+ { url = "https://files.pythonhosted.org/packages/4a/8b/a7b0f974e473b159d0ac1b6bcefffeb6bec465898a516ee5cc989503cbc7/black-26.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:643d27fb5facc167c0b1b59d0315f2674a6e950341aed0fc05cf307d22bf4954", size = 1216393, upload-time = "2026-01-18T04:59:37.18Z" },
29
+ { url = "https://files.pythonhosted.org/packages/79/04/fa2f4784f7237279332aa735cdfd5ae2e7730db0072fb2041dadda9ae551/black-26.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ba1d768fbfb6930fc93b0ecc32a43d8861ded16f47a40f14afa9bb04ab93d304", size = 1877781, upload-time = "2026-01-18T04:59:39.054Z" },
30
+ { url = "https://files.pythonhosted.org/packages/cf/ad/5a131b01acc0e5336740a039628c0ab69d60cf09a2c87a4ec49f5826acda/black-26.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b807c240b64609cb0e80d2200a35b23c7df82259f80bef1b2c96eb422b4aac9", size = 1699670, upload-time = "2026-01-18T04:59:41.005Z" },
31
+ { url = "https://files.pythonhosted.org/packages/da/7c/b05f22964316a52ab6b4265bcd52c0ad2c30d7ca6bd3d0637e438fc32d6e/black-26.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1de0f7d01cc894066a1153b738145b194414cc6eeaad8ef4397ac9abacf40f6b", size = 1775212, upload-time = "2026-01-18T04:59:42.545Z" },
32
+ { url = "https://files.pythonhosted.org/packages/a6/a3/e8d1526bea0446e040193185353920a9506eab60a7d8beb062029129c7d2/black-26.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:91a68ae46bf07868963671e4d05611b179c2313301bd756a89ad4e3b3db2325b", size = 1409953, upload-time = "2026-01-18T04:59:44.357Z" },
33
+ { url = "https://files.pythonhosted.org/packages/c7/5a/d62ebf4d8f5e3a1daa54adaab94c107b57be1b1a2f115a0249b41931e188/black-26.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:be5e2fe860b9bd9edbf676d5b60a9282994c03fbbd40fe8f5e75d194f96064ca", size = 1217707, upload-time = "2026-01-18T04:59:45.719Z" },
34
+ { url = "https://files.pythonhosted.org/packages/6a/83/be35a175aacfce4b05584ac415fd317dd6c24e93a0af2dcedce0f686f5d8/black-26.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9dc8c71656a79ca49b8d3e2ce8103210c9481c57798b48deeb3a8bb02db5f115", size = 1871864, upload-time = "2026-01-18T04:59:47.586Z" },
35
+ { url = "https://files.pythonhosted.org/packages/a5/f5/d33696c099450b1274d925a42b7a030cd3ea1f56d72e5ca8bbed5f52759c/black-26.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b22b3810451abe359a964cc88121d57f7bce482b53a066de0f1584988ca36e79", size = 1701009, upload-time = "2026-01-18T04:59:49.443Z" },
36
+ { url = "https://files.pythonhosted.org/packages/1b/87/670dd888c537acb53a863bc15abbd85b22b429237d9de1b77c0ed6b79c42/black-26.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53c62883b3f999f14e5d30b5a79bd437236658ad45b2f853906c7cbe79de00af", size = 1767806, upload-time = "2026-01-18T04:59:50.769Z" },
37
+ { url = "https://files.pythonhosted.org/packages/fe/9c/cd3deb79bfec5bcf30f9d2100ffeec63eecce826eb63e3961708b9431ff1/black-26.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:f016baaadc423dc960cdddf9acae679e71ee02c4c341f78f3179d7e4819c095f", size = 1433217, upload-time = "2026-01-18T04:59:52.218Z" },
38
+ { url = "https://files.pythonhosted.org/packages/4e/29/f3be41a1cf502a283506f40f5d27203249d181f7a1a2abce1c6ce188035a/black-26.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:66912475200b67ef5a0ab665011964bf924745103f51977a78b4fb92a9fc1bf0", size = 1245773, upload-time = "2026-01-18T04:59:54.457Z" },
39
+ { url = "https://files.pythonhosted.org/packages/e4/3d/51bdb3ecbfadfaf825ec0c75e1de6077422b4afa2091c6c9ba34fbfc0c2d/black-26.1.0-py3-none-any.whl", hash = "sha256:1054e8e47ebd686e078c0bb0eaf31e6ce69c966058d122f2c0c950311f9f3ede", size = 204010, upload-time = "2026-01-18T04:50:09.978Z" },
40
+ ]
41
+
42
+ [[package]]
43
+ name = "click"
44
+ version = "8.3.1"
45
+ source = { registry = "https://pypi.org/simple" }
46
+ dependencies = [
47
+ { name = "colorama", marker = "sys_platform == 'win32'" },
48
+ ]
49
+ sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
50
+ wheels = [
51
+ { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
52
+ ]
53
+
54
+ [[package]]
55
+ name = "code-aide"
56
+ source = { editable = "." }
57
+
58
+ [package.dev-dependencies]
59
+ dev = [
60
+ { name = "black" },
61
+ { name = "pytest" },
62
+ { name = "pytest-xdist" },
63
+ { name = "ruff" },
64
+ ]
65
+
66
+ [package.metadata]
67
+
68
+ [package.metadata.requires-dev]
69
+ dev = [
70
+ { name = "black", specifier = ">=25.1.0" },
71
+ { name = "pytest", specifier = ">=8.0" },
72
+ { name = "pytest-xdist", specifier = ">=3.0" },
73
+ { name = "ruff", specifier = ">=0.9.0" },
74
+ ]
75
+
76
+ [[package]]
77
+ name = "colorama"
78
+ version = "0.4.6"
79
+ source = { registry = "https://pypi.org/simple" }
80
+ sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
81
+ wheels = [
82
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
83
+ ]
84
+
85
+ [[package]]
86
+ name = "execnet"
87
+ version = "2.1.2"
88
+ source = { registry = "https://pypi.org/simple" }
89
+ sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" }
90
+ wheels = [
91
+ { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" },
92
+ ]
93
+
94
+ [[package]]
95
+ name = "iniconfig"
96
+ version = "2.3.0"
97
+ source = { registry = "https://pypi.org/simple" }
98
+ sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
99
+ wheels = [
100
+ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
101
+ ]
102
+
103
+ [[package]]
104
+ name = "mypy-extensions"
105
+ version = "1.1.0"
106
+ source = { registry = "https://pypi.org/simple" }
107
+ sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
108
+ wheels = [
109
+ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
110
+ ]
111
+
112
+ [[package]]
113
+ name = "packaging"
114
+ version = "26.0"
115
+ source = { registry = "https://pypi.org/simple" }
116
+ sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
117
+ wheels = [
118
+ { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
119
+ ]
120
+
121
+ [[package]]
122
+ name = "pathspec"
123
+ version = "1.0.4"
124
+ source = { registry = "https://pypi.org/simple" }
125
+ sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" }
126
+ wheels = [
127
+ { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" },
128
+ ]
129
+
130
+ [[package]]
131
+ name = "platformdirs"
132
+ version = "4.9.2"
133
+ source = { registry = "https://pypi.org/simple" }
134
+ sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394, upload-time = "2026-02-16T03:56:10.574Z" }
135
+ wheels = [
136
+ { url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168, upload-time = "2026-02-16T03:56:08.891Z" },
137
+ ]
138
+
139
+ [[package]]
140
+ name = "pluggy"
141
+ version = "1.6.0"
142
+ source = { registry = "https://pypi.org/simple" }
143
+ sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
144
+ wheels = [
145
+ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
146
+ ]
147
+
148
+ [[package]]
149
+ name = "pygments"
150
+ version = "2.19.2"
151
+ source = { registry = "https://pypi.org/simple" }
152
+ sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
153
+ wheels = [
154
+ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
155
+ ]
156
+
157
+ [[package]]
158
+ name = "pytest"
159
+ version = "9.0.2"
160
+ source = { registry = "https://pypi.org/simple" }
161
+ dependencies = [
162
+ { name = "colorama", marker = "sys_platform == 'win32'" },
163
+ { name = "iniconfig" },
164
+ { name = "packaging" },
165
+ { name = "pluggy" },
166
+ { name = "pygments" },
167
+ ]
168
+ sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
169
+ wheels = [
170
+ { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
171
+ ]
172
+
173
+ [[package]]
174
+ name = "pytest-xdist"
175
+ version = "3.8.0"
176
+ source = { registry = "https://pypi.org/simple" }
177
+ dependencies = [
178
+ { name = "execnet" },
179
+ { name = "pytest" },
180
+ ]
181
+ sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" }
182
+ wheels = [
183
+ { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" },
184
+ ]
185
+
186
+ [[package]]
187
+ name = "pytokens"
188
+ version = "0.4.1"
189
+ source = { registry = "https://pypi.org/simple" }
190
+ sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" }
191
+ wheels = [
192
+ { url = "https://files.pythonhosted.org/packages/3d/92/790ebe03f07b57e53b10884c329b9a1a308648fc083a6d4a39a10a28c8fc/pytokens-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d70e77c55ae8380c91c0c18dea05951482e263982911fc7410b1ffd1dadd3440", size = 160864, upload-time = "2026-01-30T01:02:57.882Z" },
193
+ { url = "https://files.pythonhosted.org/packages/13/25/a4f555281d975bfdd1eba731450e2fe3a95870274da73fb12c40aeae7625/pytokens-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a58d057208cb9075c144950d789511220b07636dd2e4708d5645d24de666bdc", size = 248565, upload-time = "2026-01-30T01:02:59.912Z" },
194
+ { url = "https://files.pythonhosted.org/packages/17/50/bc0394b4ad5b1601be22fa43652173d47e4c9efbf0044c62e9a59b747c56/pytokens-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b49750419d300e2b5a3813cf229d4e5a4c728dae470bcc89867a9ad6f25a722d", size = 260824, upload-time = "2026-01-30T01:03:01.471Z" },
195
+ { url = "https://files.pythonhosted.org/packages/4e/54/3e04f9d92a4be4fc6c80016bc396b923d2a6933ae94b5f557c939c460ee0/pytokens-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9907d61f15bf7261d7e775bd5d7ee4d2930e04424bab1972591918497623a16", size = 264075, upload-time = "2026-01-30T01:03:04.143Z" },
196
+ { url = "https://files.pythonhosted.org/packages/d1/1b/44b0326cb5470a4375f37988aea5d61b5cc52407143303015ebee94abfd6/pytokens-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee44d0f85b803321710f9239f335aafe16553b39106384cef8e6de40cb4ef2f6", size = 103323, upload-time = "2026-01-30T01:03:05.412Z" },
197
+ { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" },
198
+ { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" },
199
+ { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" },
200
+ { url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", size = 268076, upload-time = "2026-01-30T01:03:10.957Z" },
201
+ { url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", size = 103552, upload-time = "2026-01-30T01:03:12.066Z" },
202
+ { url = "https://files.pythonhosted.org/packages/cb/dc/08b1a080372afda3cceb4f3c0a7ba2bde9d6a5241f1edb02a22a019ee147/pytokens-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8bdb9d0ce90cbf99c525e75a2fa415144fd570a1ba987380190e8b786bc6ef9b", size = 160720, upload-time = "2026-01-30T01:03:13.843Z" },
203
+ { url = "https://files.pythonhosted.org/packages/64/0c/41ea22205da480837a700e395507e6a24425151dfb7ead73343d6e2d7ffe/pytokens-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5502408cab1cb18e128570f8d598981c68a50d0cbd7c61312a90507cd3a1276f", size = 254204, upload-time = "2026-01-30T01:03:14.886Z" },
204
+ { url = "https://files.pythonhosted.org/packages/e0/d2/afe5c7f8607018beb99971489dbb846508f1b8f351fcefc225fcf4b2adc0/pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1", size = 268423, upload-time = "2026-01-30T01:03:15.936Z" },
205
+ { url = "https://files.pythonhosted.org/packages/68/d4/00ffdbd370410c04e9591da9220a68dc1693ef7499173eb3e30d06e05ed1/pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4", size = 266859, upload-time = "2026-01-30T01:03:17.458Z" },
206
+ { url = "https://files.pythonhosted.org/packages/a7/c9/c3161313b4ca0c601eeefabd3d3b576edaa9afdefd32da97210700e47652/pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78", size = 103520, upload-time = "2026-01-30T01:03:18.652Z" },
207
+ { url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload-time = "2026-01-30T01:03:19.684Z" },
208
+ { url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload-time = "2026-01-30T01:03:20.834Z" },
209
+ { url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload-time = "2026-01-30T01:03:21.888Z" },
210
+ { url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload-time = "2026-01-30T01:03:23.633Z" },
211
+ { url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload-time = "2026-01-30T01:03:24.788Z" },
212
+ { url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload-time = "2026-01-30T01:03:26.428Z" },
213
+ { url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload-time = "2026-01-30T01:03:27.415Z" },
214
+ { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" },
215
+ { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" },
216
+ { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" },
217
+ { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" },
218
+ ]
219
+
220
+ [[package]]
221
+ name = "ruff"
222
+ version = "0.15.4"
223
+ source = { registry = "https://pypi.org/simple" }
224
+ sdist = { url = "https://files.pythonhosted.org/packages/da/31/d6e536cdebb6568ae75a7f00e4b4819ae0ad2640c3604c305a0428680b0c/ruff-0.15.4.tar.gz", hash = "sha256:3412195319e42d634470cc97aa9803d07e9d5c9223b99bcb1518f0c725f26ae1", size = 4569550, upload-time = "2026-02-26T20:04:14.959Z" }
225
+ wheels = [
226
+ { url = "https://files.pythonhosted.org/packages/f2/82/c11a03cfec3a4d26a0ea1e571f0f44be5993b923f905eeddfc397c13d360/ruff-0.15.4-py3-none-linux_armv6l.whl", hash = "sha256:a1810931c41606c686bae8b5b9a8072adac2f611bb433c0ba476acba17a332e0", size = 10453333, upload-time = "2026-02-26T20:04:20.093Z" },
227
+ { url = "https://files.pythonhosted.org/packages/ce/5d/6a1f271f6e31dffb31855996493641edc3eef8077b883eaf007a2f1c2976/ruff-0.15.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5a1632c66672b8b4d3e1d1782859e98d6e0b4e70829530666644286600a33992", size = 10853356, upload-time = "2026-02-26T20:04:05.808Z" },
228
+ { url = "https://files.pythonhosted.org/packages/b1/d8/0fab9f8842b83b1a9c2bf81b85063f65e93fb512e60effa95b0be49bfc54/ruff-0.15.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a4386ba2cd6c0f4ff75252845906acc7c7c8e1ac567b7bc3d373686ac8c222ba", size = 10187434, upload-time = "2026-02-26T20:03:54.656Z" },
229
+ { url = "https://files.pythonhosted.org/packages/85/cc/cc220fd9394eff5db8d94dec199eec56dd6c9f3651d8869d024867a91030/ruff-0.15.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2496488bdfd3732747558b6f95ae427ff066d1fcd054daf75f5a50674411e75", size = 10535456, upload-time = "2026-02-26T20:03:52.738Z" },
230
+ { url = "https://files.pythonhosted.org/packages/fa/0f/bced38fa5cf24373ec767713c8e4cadc90247f3863605fb030e597878661/ruff-0.15.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f1c4893841ff2d54cbda1b2860fa3260173df5ddd7b95d370186f8a5e66a4ac", size = 10287772, upload-time = "2026-02-26T20:04:08.138Z" },
231
+ { url = "https://files.pythonhosted.org/packages/2b/90/58a1802d84fed15f8f281925b21ab3cecd813bde52a8ca033a4de8ab0e7a/ruff-0.15.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:820b8766bd65503b6c30aaa6331e8ef3a6e564f7999c844e9a547c40179e440a", size = 11049051, upload-time = "2026-02-26T20:04:03.53Z" },
232
+ { url = "https://files.pythonhosted.org/packages/d2/ac/b7ad36703c35f3866584564dc15f12f91cb1a26a897dc2fd13d7cb3ae1af/ruff-0.15.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9fb74bab47139c1751f900f857fa503987253c3ef89129b24ed375e72873e85", size = 11890494, upload-time = "2026-02-26T20:04:10.497Z" },
233
+ { url = "https://files.pythonhosted.org/packages/93/3d/3eb2f47a39a8b0da99faf9c54d3eb24720add1e886a5309d4d1be73a6380/ruff-0.15.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80c98765949c518142b3a50a5db89343aa90f2c2bf7799de9986498ae6176db", size = 11326221, upload-time = "2026-02-26T20:04:12.84Z" },
234
+ { url = "https://files.pythonhosted.org/packages/ff/90/bf134f4c1e5243e62690e09d63c55df948a74084c8ac3e48a88468314da6/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451a2e224151729b3b6c9ffb36aed9091b2996fe4bdbd11f47e27d8f2e8888ec", size = 11168459, upload-time = "2026-02-26T20:04:00.969Z" },
235
+ { url = "https://files.pythonhosted.org/packages/b5/e5/a64d27688789b06b5d55162aafc32059bb8c989c61a5139a36e1368285eb/ruff-0.15.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a8f157f2e583c513c4f5f896163a93198297371f34c04220daf40d133fdd4f7f", size = 11104366, upload-time = "2026-02-26T20:03:48.099Z" },
236
+ { url = "https://files.pythonhosted.org/packages/f1/f6/32d1dcb66a2559763fc3027bdd65836cad9eb09d90f2ed6a63d8e9252b02/ruff-0.15.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:917cc68503357021f541e69b35361c99387cdbbf99bd0ea4aa6f28ca99ff5338", size = 10510887, upload-time = "2026-02-26T20:03:45.771Z" },
237
+ { url = "https://files.pythonhosted.org/packages/ff/92/22d1ced50971c5b6433aed166fcef8c9343f567a94cf2b9d9089f6aa80fe/ruff-0.15.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e9737c8161da79fd7cfec19f1e35620375bd8b2a50c3e77fa3d2c16f574105cc", size = 10285939, upload-time = "2026-02-26T20:04:22.42Z" },
238
+ { url = "https://files.pythonhosted.org/packages/e6/f4/7c20aec3143837641a02509a4668fb146a642fd1211846634edc17eb5563/ruff-0.15.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:291258c917539e18f6ba40482fe31d6f5ac023994ee11d7bdafd716f2aab8a68", size = 10765471, upload-time = "2026-02-26T20:03:58.924Z" },
239
+ { url = "https://files.pythonhosted.org/packages/d0/09/6d2f7586f09a16120aebdff8f64d962d7c4348313c77ebb29c566cefc357/ruff-0.15.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3f83c45911da6f2cd5936c436cf86b9f09f09165f033a99dcf7477e34041cbc3", size = 11263382, upload-time = "2026-02-26T20:04:24.424Z" },
240
+ { url = "https://files.pythonhosted.org/packages/1b/fa/2ef715a1cd329ef47c1a050e10dee91a9054b7ce2fcfdd6a06d139afb7ec/ruff-0.15.4-py3-none-win32.whl", hash = "sha256:65594a2d557d4ee9f02834fcdf0a28daa8b3b9f6cb2cb93846025a36db47ef22", size = 10506664, upload-time = "2026-02-26T20:03:50.56Z" },
241
+ { url = "https://files.pythonhosted.org/packages/d0/a8/c688ef7e29983976820d18710f955751d9f4d4eb69df658af3d006e2ba3e/ruff-0.15.4-py3-none-win_amd64.whl", hash = "sha256:04196ad44f0df220c2ece5b0e959c2f37c777375ec744397d21d15b50a75264f", size = 11651048, upload-time = "2026-02-26T20:04:17.191Z" },
242
+ { url = "https://files.pythonhosted.org/packages/3e/0a/9e1be9035b37448ce2e68c978f0591da94389ade5a5abafa4cf99985d1b2/ruff-0.15.4-py3-none-win_arm64.whl", hash = "sha256:60d5177e8cfc70e51b9c5fad936c634872a74209f934c1e79107d11787ad5453", size = 10966776, upload-time = "2026-02-26T20:03:56.908Z" },
243
+ ]
@@ -1,13 +0,0 @@
1
- name: CI
2
- on: [push, pull_request]
3
- jobs:
4
- test:
5
- runs-on: ${{ matrix.os }}
6
- strategy:
7
- matrix:
8
- os: [ubuntu-latest, macos-latest]
9
- python-version: ["3.11", "3.12", "3.13"]
10
- steps:
11
- - uses: actions/checkout@v4
12
- - uses: astral-sh/setup-uv@v5
13
- - run: uv run --python ${{ matrix.python-version }} pytest tests/ -v
File without changes
File without changes
File without changes