diff --git a/.github/actions/build-binaries/linux/action.yaml b/.github/actions/build-binaries/linux/action.yaml
index a5ee3ff33..4298d5116 100644
--- a/.github/actions/build-binaries/linux/action.yaml
+++ b/.github/actions/build-binaries/linux/action.yaml
@@ -16,7 +16,7 @@ runs:
- name: Build binary
shell: bash
run: |
- poetry run poe package_unix
+ uv run poe package_unix
- name: Package binary artifact
shell: bash
@@ -27,7 +27,7 @@ runs:
cd ../..
- name: Upload binary artifact
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: ${{ inputs.package_name }}-snap
path: ${{ inputs.artifacts_dir }}/${{ inputs.package_name }}-snap.tar.gz
diff --git a/.github/actions/build-binaries/macos/action.yaml b/.github/actions/build-binaries/macos/action.yaml
index d1fcc4ca4..6c2ebe859 100644
--- a/.github/actions/build-binaries/macos/action.yaml
+++ b/.github/actions/build-binaries/macos/action.yaml
@@ -36,7 +36,7 @@ runs:
run: |
export APPLE_CERT_ID="${{ inputs.with_codesign == 'true' && inputs.apple_cert_id || '' }}"
export APPLE_BUNDLE_ID="${{ inputs.with_codesign == 'true' && inputs.apple_bundle_id || format('beta.{0}', inputs.apple_bundle_id) }}"
- poetry run poe package_mac
+ uv run poe package_mac
env:
APPLE_CERT_ID: ${{ inputs.with_codesign == 'true' && inputs.apple_cert_id || '' }}
APPLE_BUNDLE_ID: ${{ inputs.with_codesign == 'true' && inputs.apple_bundle_id || format('beta.{0}', inputs.apple_bundle_id) }}
@@ -73,7 +73,7 @@ runs:
cd ../..
- name: Upload binary artifact
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: ${{ inputs.package_name }}
path: ${{ inputs.artifacts_dir }}/${{ inputs.package_name }}-brew.tar.gz
diff --git a/.github/actions/build-binaries/windows/action.yaml b/.github/actions/build-binaries/windows/action.yaml
index f0b5fe50f..5f7e534e2 100644
--- a/.github/actions/build-binaries/windows/action.yaml
+++ b/.github/actions/build-binaries/windows/action.yaml
@@ -82,7 +82,7 @@ runs:
- name: Build binary
shell: bash
run: |
- poetry run poe package_windows
+ uv run poe package_windows
- name: Add metadata to binary
shell: bash
@@ -130,7 +130,7 @@ runs:
timestamp-digest: SHA256
- name: Upload winget artifact
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: ${{ inputs.package_name }}-winget
path: ${{ env.WINGET_INSTALLER }}
diff --git a/.github/actions/build-docs/action.yml b/.github/actions/build-docs/action.yml
new file mode 100644
index 000000000..0af248b28
--- /dev/null
+++ b/.github/actions/build-docs/action.yml
@@ -0,0 +1,31 @@
+name: "Build Documentation"
+description: "Generate CLI reference via sphinx-click and build Starlight site"
+
+runs:
+ using: "composite"
+ steps:
+ - name: Setup Python environment
+ uses: algorandfoundation/algokit-shared-config/.github/actions/setup-algokit-python@main
+ with:
+ install-algokit: "false"
+
+ - name: Set up Node.js 22
+ uses: actions/setup-node@v4
+ with:
+ node-version: "22"
+
+ - uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
+ - name: Install docs dependencies
+ shell: bash
+ run: cd docs && pnpm install --frozen-lockfile
+
+ - name: Generate CLI reference
+ shell: bash
+ run: uv run poe docs-cli
+
+ - name: Build Starlight site
+ shell: bash
+ run: cd docs && pnpm run build
\ No newline at end of file
diff --git a/.github/actions/setup-poetry/action.yaml b/.github/actions/setup-poetry/action.yaml
deleted file mode 100644
index e74b2eefc..000000000
--- a/.github/actions/setup-poetry/action.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-name: "Python Poetry Action"
-description: "An action to setup Poetry"
-runs:
- using: "composite"
- steps:
- # A workaround for pipx isn't installed on M1 runner.
- # We should remove it after this issue is resolved.
- # https://github.com/actions/runner-images/issues/9256
- - if: ${{ runner.os == 'macOS' && runner.arch == 'ARM64' }}
- run: |
- pip install poetry
- pip install poetry-plugin-export
- shell: bash
-
- - if: ${{ runner.os != 'macOS' || runner.arch != 'ARM64' }}
- run: |
- pip install --user pipx
- pipx ensurepath
- pipx install poetry ${{ runner.os == 'macOS' && '--python "$Python_ROOT_DIR/bin/python"' || '' }}
- pipx inject poetry poetry-plugin-export
- shell: bash
-
- - name: Get full Python version
- id: full-python-version
- shell: bash
- run: echo "full_version=$(python -c 'import sys; print(".".join(map(str, sys.version_info[:3])))')" >> $GITHUB_OUTPUT
-
- - name: Setup poetry cache
- uses: actions/cache@v4
- with:
- path: ./.venv
- key: venv-${{ hashFiles('poetry.lock') }}-${{ runner.os }}-${{ runner.arch }}-${{ steps.full-python-version.outputs.full_version }}
diff --git a/.github/actions/setup-uv/action.yaml b/.github/actions/setup-uv/action.yaml
new file mode 100644
index 000000000..0c7cd48bc
--- /dev/null
+++ b/.github/actions/setup-uv/action.yaml
@@ -0,0 +1,20 @@
+name: "Setup uv"
+description: "Install uv and sync project dependencies"
+inputs:
+ extra-sync-args:
+ description: "Additional arguments to pass to uv sync (e.g. --group docs)"
+ required: false
+ default: ""
+runs:
+ using: "composite"
+ steps:
+ - name: Install uv
+ uses: astral-sh/setup-uv@v7
+ with:
+ version: "0.10.x"
+ enable-cache: true
+ cache-dependency-glob: "uv.lock"
+
+ - name: Sync dependencies
+ run: uv sync --frozen ${{ inputs.extra-sync-args }}
+ shell: bash
diff --git a/.github/assets/banner.svg b/.github/assets/banner.svg
new file mode 100644
index 000000000..04624edee
--- /dev/null
+++ b/.github/assets/banner.svg
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [algokit-cli]
+
+
+
+
+
+
+
+
+
+ $ uv tool install algokit
+
+
+
+
+
+
+
+
+
+
+
+ Extensive CLI
+
+
+
+ for Algorand
+
+
+
+ blockchain projects
+
+
+
diff --git a/.github/workflows/build-binaries.yaml b/.github/workflows/build-binaries.yaml
index 9a85f3a93..f1216c3ad 100644
--- a/.github/workflows/build-binaries.yaml
+++ b/.github/workflows/build-binaries.yaml
@@ -40,20 +40,18 @@ jobs:
shell: bash
- name: Checkout source code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
ref: ${{ inputs.release_version != '' && format('v{0}', inputs.release_version) || '' }}
- name: Set up Python
- uses: actions/setup-python@v5
+ uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python_version }}
- - name: Set up Poetry
- uses: ./.github/actions/setup-poetry
+ - name: Set up uv
+ uses: ./.github/actions/setup-uv
- - name: Install dependencies
- run: poetry install --no-interaction
- name: Configure build environment
shell: bash
@@ -116,14 +114,14 @@ jobs:
if: ${{ runner.os == 'Windows' }}
run: |
git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
- poetry run pytest tests/ -m pyinstaller_binary_tests --log-cli-level=INFO
+ uv run pytest tests/ -m pyinstaller_binary_tests --log-cli-level=INFO
shell: cmd
- name: Run portability tests
if: ${{ runner.os != 'Windows' }}
run: |
git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
- poetry run pytest tests/ -m pyinstaller_binary_tests --log-cli-level=INFO
+ uv run pytest tests/ -m pyinstaller_binary_tests --log-cli-level=INFO
shell: bash
# softprops/action-gh-release doesn't support the \ character in paths
@@ -136,7 +134,7 @@ jobs:
- name: Append artifacts to release
if: ${{ inputs.production_release == 'true' }}
- uses: softprops/action-gh-release@v1
+ uses: softprops/action-gh-release@v2
with:
fail_on_unmatched_files: true
files: |
diff --git a/.github/workflows/build-python.yaml b/.github/workflows/build-python.yaml
index efdfc1f62..feff62236 100644
--- a/.github/workflows/build-python.yaml
+++ b/.github/workflows/build-python.yaml
@@ -12,29 +12,29 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Set up Python
- uses: actions/setup-python@v5
+ uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
- name: Set up Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: 20
- - name: Set up Poetry
- uses: ./.github/actions/setup-poetry
+ - name: Set up uv
+ uses: ./.github/actions/setup-uv
- - name: Install dependencies
- # TODO: remove fixed pipx dependency once 3.12 compatibility is addressed
+ - name: Install tealer
+ # TODO: remove fixed tealer dependency once 3.12 compatibility is addressed
# track here -> https://github.com/crytic/tealer/pull/209
- run: poetry install --no-interaction --without docs && pipx install tealer==0.1.2
+ run: uv tool install tealer==0.1.2
- name: Install PuyaPy
if: ${{ matrix.python == '3.12' }}
- run: pipx install puyapy
+ run: uv tool install puyapy
- name: pytest
shell: bash
@@ -43,7 +43,7 @@ jobs:
run: |
set -o pipefail
git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
- poetry run pytest -n auto
+ uv run pytest -n auto
id: pytest
- name: pytest + coverage
@@ -55,12 +55,12 @@ jobs:
run: |
set -o pipefail
git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
- poetry run pytest -n auto --junitxml=pytest-junit.xml --cov-report=term-missing:skip-covered --cov=src | tee pytest-coverage.txt
+ uv run pytest -n auto --junitxml=pytest-junit.xml --cov-report=term-missing:skip-covered --cov=src | tee pytest-coverage.txt
id: pytest-cov
- name: Upload received snapshots (in case of failure)
if: failure() && (steps.pytest.outcome == 'failure' || steps.pytest-cov.outcome == 'failure')
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: test-artifacts-${{ matrix.os }}-python${{ matrix.python }}
path: tests/**/*.received.txt
@@ -74,4 +74,4 @@ jobs:
junitxml-path: ./pytest-junit.xml
- name: Build Wheel
- run: poetry build --format wheel
+ run: uv build --wheel
diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml
index 92c8dd240..cc1891977 100644
--- a/.github/workflows/cd.yaml
+++ b/.github/workflows/cd.yaml
@@ -52,22 +52,19 @@ jobs:
app-id: ${{ secrets.BOT_ID }}
private-key: ${{ secrets.BOT_SK }}
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
with:
# Fetch entire repository history so we can determine version number from it
fetch-depth: 0
token: ${{ steps.app_token.outputs.token }}
- name: Set up Python
- uses: actions/setup-python@v5
+ uses: actions/setup-python@v6
with:
- python-version: "3.10"
+ python-version: "3.12"
- - name: Set up Poetry
- uses: ./.github/actions/setup-poetry
-
- - name: Install dependencies
- run: poetry install --no-interaction --no-root
+ - name: Set up uv
+ uses: ./.github/actions/setup-uv
- name: Get branch name
shell: bash
@@ -80,7 +77,7 @@ jobs:
- name: Create Continuous Deployment - Feature Branch
if: steps.get_branch.outputs.branch != 'main' && inputs.production_release != 'true'
run: |
- poetry run semantic-release \
+ uv run semantic-release \
-v DEBUG \
--prerelease \
--patch \
@@ -98,12 +95,12 @@ jobs:
- name: Create Continuous Deployment - Beta (non-prod)
if: steps.get_branch.outputs.branch == 'main' && inputs.production_release != 'true'
run: |
- poetry run semantic-release \
+ uv run semantic-release \
-v DEBUG \
--prerelease \
--define=branch=main \
publish
- release_version="$(poetry run semantic-release print-version --current)"
+ release_version="$(uv run semantic-release print-version --current)"
gh release edit --prerelease "v$release_version"
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
env:
@@ -114,14 +111,14 @@ jobs:
- name: Create Continuous Deployment - Production
if: steps.get_branch.outputs.branch == 'main' && inputs.production_release == 'true'
run: |
- poetry run semantic-release \
+ uv run semantic-release \
-v DEBUG \
--define=version_source="commit" \
--define=patch_without_tag=true \
--define=upload_to_repository=true \
--define=branch=main \
publish
- release_version="$(poetry run semantic-release print-version --current)"
+ release_version="$(uv run semantic-release print-version --current)"
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
env:
GH_TOKEN: ${{ steps.app_token.outputs.token }}
@@ -134,7 +131,7 @@ jobs:
id: get_release_version
- name: Upload artifact
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: algokit-cli
path: dist/algokit*-py3-none-any.whl
@@ -162,3 +159,34 @@ jobs:
artifactName: algokit-cli
release_version: ${{ needs.release.outputs.release_version }}
secrets: inherit
+
+ deploy-docs:
+ name: Deploy Documentation
+ needs: release
+ runs-on: ubuntu-latest
+ if: github.ref == 'refs/heads/main'
+ concurrency:
+ group: deploy-docs
+ cancel-in-progress: true
+ permissions:
+ contents: read
+ pages: write
+ id-token: write
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Build documentation
+ uses: ./.github/actions/build-docs
+
+ - name: Upload to GitHub Pages
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: docs/dist
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/check-docs.yaml b/.github/workflows/check-docs.yaml
new file mode 100644
index 000000000..2269877bb
--- /dev/null
+++ b/.github/workflows/check-docs.yaml
@@ -0,0 +1,14 @@
+name: Check Documentation
+
+on:
+ workflow_call:
+
+jobs:
+ check-docs:
+ runs-on: "ubuntu-latest"
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Build documentation
+ uses: ./.github/actions/build-docs
\ No newline at end of file
diff --git a/.github/workflows/check-python.yaml b/.github/workflows/check-python.yaml
index e98d78eed..a88ce90e8 100644
--- a/.github/workflows/check-python.yaml
+++ b/.github/workflows/check-python.yaml
@@ -8,40 +8,35 @@ jobs:
runs-on: "ubuntu-latest"
steps:
- name: Checkout source code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Set up Python 3.12
- uses: actions/setup-python@v5
+ uses: actions/setup-python@v6
with:
python-version: "3.12"
- - name: Set up Poetry
- uses: ./.github/actions/setup-poetry
-
- - name: Install dependencies
- run: poetry install --no-interaction --with docs
+ - name: Set up uv
+ uses: ./.github/actions/setup-uv
+ with:
+ extra-sync-args: "--group docs"
- name: Audit with pip-audit
run: |
- poetry export --without=dev --without=docs -o requirements.txt
- poetry run pip-audit -r requirements.txt
- # If a vulnerability is found in a dependency without an available fix,
- # it can be temporarily ignored by adding --ignore-vuln e.g. poetry run pip-audit -r requirements.txt --ignore-vuln 'GHSA-xxxxx'
+ set -o pipefail
+ uv export --no-dev --no-group docs --no-emit-project -o requirements.txt
+ uv run pip-audit -r requirements.txt
- name: Check formatting with Ruff
- run: |
- # stop the build if there are files that don't meet formatting requirements
- poetry run ruff format --check .
+ run: uv run ruff format --check .
- name: Check linting with Ruff
- run: |
- # stop the build if there are Python syntax errors or undefined names
- poetry run ruff check .
+ run: uv run ruff check .
- name: Check types with mypy
- run: poetry run mypy
+ run: uv run mypy
- name: Check docs are up to date
run: |
- poetry run poe docs
+ set -o pipefail
+ uv run poe docs-cli
[ $(git status --porcelain docs/ | wc -l) -eq "0" ]
diff --git a/.github/workflows/clear-caches.yaml b/.github/workflows/clear-caches.yaml
index c2050ce84..11b8e947f 100644
--- a/.github/workflows/clear-caches.yaml
+++ b/.github/workflows/clear-caches.yaml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Clear all repository caches
env:
diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml
index 5be8dec68..24cd4c7c4 100644
--- a/.github/workflows/pr.yaml
+++ b/.github/workflows/pr.yaml
@@ -17,6 +17,10 @@ jobs:
name: Check Python
uses: ./.github/workflows/check-python.yaml
+ pr-docs:
+ name: Check Docs
+ uses: ./.github/workflows/check-docs.yaml
+
pr-build:
name: Build & Test Python
needs: pr-check
diff --git a/.github/workflows/publish-release-packages.yaml b/.github/workflows/publish-release-packages.yaml
index 6026710ca..9629bffff 100644
--- a/.github/workflows/publish-release-packages.yaml
+++ b/.github/workflows/publish-release-packages.yaml
@@ -66,7 +66,7 @@ jobs:
owner: algorandfoundation
- name: Checkout source code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Download wheel from release
run: gh release download v${{ inputs.release_version }} --pattern "*.whl" --dir dist
@@ -91,7 +91,7 @@ jobs:
if: ${{ inputs.do_winget }}
steps:
- name: Checkout source code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Publish to winget
shell: pwsh
@@ -108,7 +108,7 @@ jobs:
steps:
- name: Checkout source code
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Download binary artifact from release
run: |
@@ -123,7 +123,7 @@ jobs:
./scripts/snap/create-snapcraft-yaml.sh ${{ github.workspace }} ${{ inputs.release_version }} ${{ env.BINARY_PATH }} "stable"
- name: Upload snapcraft.yaml as reference artifact
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: snapcraft-yaml
path: ${{ github.workspace }}/snap/snapcraft.yaml
diff --git a/.gitignore b/.gitignore
index 744552e9e..02417d5f4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -172,7 +172,6 @@ cython_debug/
#Sphinx
.doctrees/
-docs/cli/temp.md
# Miscellaneous
ci_token.txt
@@ -180,3 +179,5 @@ ci_token.txt
.algokit/
temp/
+
+mise.toml
diff --git a/.idea/runConfigurations/Run_AlgoKit_CLI.xml b/.idea/runConfigurations/Run_AlgoKit_CLI.xml
deleted file mode 100644
index c8e1763e0..000000000
--- a/.idea/runConfigurations/Run_AlgoKit_CLI.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index a6f846afb..3f9e3a7ab 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -4,7 +4,7 @@ repos:
- id: ruff-format
name: ruff-format
description: "Run 'ruff format' for extremely fast Python formatting"
- entry: poetry run ruff format
+ entry: uv run ruff format
language: system
types: [python]
args: [--no-cache]
@@ -13,7 +13,7 @@ repos:
- id: ruff
name: ruff
description: "Run 'ruff' for extremely fast Python linting"
- entry: poetry run ruff check
+ entry: uv run ruff check
language: system
"types": [python]
args: [--fix, --no-cache]
@@ -23,7 +23,7 @@ repos:
- id: mypy
name: mypy
description: "`mypy` will check Python types for correctness"
- entry: poetry run mypy
+ entry: uv run mypy
language: system
types_or: [python, pyi]
require_serial: true
diff --git a/.python-version b/.python-version
new file mode 100644
index 000000000..e4fba2183
--- /dev/null
+++ b/.python-version
@@ -0,0 +1 @@
+3.12
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 32ca79171..9b271dae3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -15,18 +15,16 @@ AlgoKit development is done within the [AlgoKit Guiding Principles](./docs/algok
1. Clone this repository: `git clone https://github.com/algorandfoundation/algokit-cli`
2. Install pre-requisites:
- - Manually:
- - Install `Python` - [Link](https://www.python.org/downloads/): The minimum required version is `3.10`, but `3.11` is recommended.)
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`.
- - If you're not using PyCharm, then run `poetry install` in the repository root directory (this should set up `.venv` and install all Python dependencies - PyCharm will do this for you on startup)
- - Via AlgoKit CLI:
-
- - [Install AlgoKit CLI](./README.md#install) and run `algokit project bootstrap poetry` in the root directory
- - Install `tealer` - by running `pipx install tealer==0.1.2`. This is a prerequisite to running `pytest`, tealer is a third party tool for static analysis of TEAL code, algokit uses it in `task analyse` command. AlgoKit uses `pytest-xdist` to speed up the test suite execution by running tests in parallel, this requires `tealer` to be installed globally to avoid race conditions.
+ - Install [uv](https://docs.astral.sh/uv/) - the project's package manager:
+ ```shell
+ curl -LsSf https://astral.sh/uv/install.sh | sh
+ ```
+ - Run `uv sync` in the repository root directory (this sets up `.venv` and installs all Python dependencies)
+ - Install `tealer` - by running `uv tool install tealer==0.1.2`. This is a prerequisite to running `pytest`, tealer is a third party tool for static analysis of TEAL code, algokit uses it in `task analyse` command. AlgoKit uses `pytest-xdist` to speed up the test suite execution by running tests in parallel, this requires `tealer` to be installed globally to avoid race conditions.
3. Install pre-commit hooks (optional but recommended):
- [pre-commit](https://pre-commit.com/) is configured in this repository. To enable it, make sure that `poetry install` has been run and the virtual-env is activated by running `poetry shell`. Then execute `pre-commit install` to install the git hook scripts.
+ [pre-commit](https://pre-commit.com/) is configured in this repository. To enable it, make sure that `uv sync` has been run. Then execute `uv run pre-commit install` to install the git hook scripts.
Once it is done, git will ensure formatting, linting, and static typing (via `mypy`) is correct when you perform a commit.
@@ -46,7 +44,7 @@ AlgoKit development is done within the [AlgoKit Guiding Principles](./docs/algok
2. Hit Shift+F9 (or whatever you have debug mapped to) and it should start running with breakpoint debugging
- Other
1. Open the repository root in your text editor of choice
- 2. In a terminal run `poetry shell`
+ 2. In a terminal run `uv run python` or activate the venv with `source .venv/bin/activate`
3. Run `./debug.py` through your debugger of choice
- In each of the above cases, an `args.in` file will be created in the source root.
Each line will be executed in order, with the arguments passed to the cli.
@@ -62,7 +60,7 @@ AlgoKit development is done within the [AlgoKit Guiding Principles](./docs/algok
### Subsequently
-1. If you update to the latest source code and there are new dependencies you will need to run `poetry install` again
+1. If you update to the latest source code and there are new dependencies you will need to run `uv sync` again
2. Follow step 3 above
### Documentation
@@ -71,8 +69,8 @@ Markdown documentation can be found within the docs directory of the repo, there
To autogenerate the CLI documentation from the click source:
-1. Install the docs dependencies: `poetry install --with docs`
-2. Run the docs generation: `poetry run poe docs`
+1. Install the docs dependencies: `uv sync --group docs`
+2. Run the docs generation: `uv run poe docs`
Note: this command won't work on Windows.
@@ -82,11 +80,9 @@ The CLI docs are generated using Sphinx, and its configuration can be found in `
AlgoKit uses Python as a main language and many Python libraries and tools. This section lists all of them with a tiny brief.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.
-- [pipx](https://github.com/pypa/pipx): Install and Run Python Applications in Isolated Environments
+- [uv](https://docs.astral.sh/uv/): Python packaging, dependency management, and tool installation.
- [Click](https://palletsprojects.com/p/click/): A Python package for creating beautiful command line interfaces.
-- [Black](https://github.com/psf/black): A Python code formatter.
-- [Tox](https://tox.wiki/en/latest/): Automate and standardize testing in Python.
+- [Ruff](https://docs.astral.sh/ruff/): An extremely fast Python linter and formatter.
## Architecture decisions
diff --git a/README.md b/README.md
index d2a5079f4..0fd4f5987 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
@@ -85,46 +85,65 @@ This is an open source project managed by the Algorand Foundation. See the [cont
## Prerequisites
-The installation pre-requisites change depending on the method you use to install. Please refer to [Installation Methods](#installation-methods).
+No prerequisites are required to install AlgoKit itself. The install script handles everything.
Depending on the features you choose to leverage from the AlgoKit CLI, additional dependencies may be required.
The AlgoKit CLI will tell you if you are missing one for a given command. These optional dependencies are:
- **Git**: Essential for creating and updating projects from templates. Installation guide available at [Git Installation](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git).
- **Docker**: Necessary for running the AlgoKit LocalNet environment. Docker Compose version 2.5.0 or higher is required. See [Docker Installation](https://docs.docker.com/get-docker/).
-- **Python**: For those installing the AlgoKit CLI via `pipx` or building contracts using Algorand Python. **Minimum required version is Python 3.12+ when working with Algorand Python**. See [Python Installation](https://www.python.org/downloads/).
- **Node.js**: For those working on frontend templates or building contracts using Algorand TypeScript or TEALScript. **Minimum required versions are Node.js `v22` and npm `v10`**. See [Node.js Installation](https://nodejs.org/en/download/).
-> **Note**
-> If you have previously installed AlgoKit using `pipx` and would like to switch to a different installation method, please ensure that
-> you first uninstall the existing version by running `pipx uninstall algokit`. Once uninstalled, you can follow the installation instructions for your preferred platform.
+## Quick Install (Recommended)
+
+AlgoKit is installed via [uv](https://docs.astral.sh/uv/), which handles Python and dependency management automatically.
+
+### macOS / Linux
+
+```shell
+curl -fsSL https://raw.githubusercontent.com/algorandfoundation/algokit-cli/decoupling/scripts/install/install.sh | bash
+```
+
+### Windows (PowerShell)
+
+```powershell
+irm https://raw.githubusercontent.com/algorandfoundation/algokit-cli/decoupling/scripts/install/install.ps1 | iex
+```
+
+### What the installer does
+
+1. Installs [uv](https://docs.astral.sh/uv/) if not already present
+2. Installs Python 3.12 via uv if not already available
+3. Installs AlgoKit via `uv tool install algokit`
+
+### Maintenance
-## Cross-platform installation
+- To update AlgoKit: `uv tool upgrade algokit`
+- To remove AlgoKit: `uv tool uninstall algokit`
-AlgoKit can be installed using OS specific package managers, or using the python tool [pipx](https://pypa.github.io/pipx/).
-See below for specific installation instructions.
+## Alternative: Install with uv directly
-### Installation Methods
+If you already have [uv](https://docs.astral.sh/uv/) installed:
-- [Windows](#install-algokit-on-windows)
-- [Mac](#install-algokit-on-mac)
-- [Linux](#install-algokit-on-linux)
-- [Universal via pipx](#install-algokit-with-pipx-on-any-os)
+```shell
+uv tool install algokit
+```
-## Install AlgoKit on Windows
+## Legacy Installation Methods
> **Note**
-> AlgoKit is supported on Windows 10 1709 (build 16299) and later.
-> We only publish an x64 binary, however it also runs on ARM devices by default using the built in x64 emulation feature.
+> The following installation methods are being phased out in favor of the uv-based installation above.
+> They will continue to work for existing installations but are no longer the recommended approach.
-1. Ensure prerequisites are installed
+
+Click to expand legacy installation methods
+
+### Install AlgoKit on Windows (winget)
+1. Ensure prerequisites are installed
- [WinGet](https://learn.microsoft.com/en-us/windows/package-manager/winget/) (should be installed by default on recent Windows 10 or later)
- [Git](https://github.com/git-guides/install-git#install-git-on-windows) (or `winget install git.git`)
- [Docker](https://docs.docker.com/desktop/install/windows-install/) (or `winget install docker.dockerdesktop`)
- > **Note**
- > See [our LocalNet documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/localnet.md#prerequisites) for more tips on installing Docker on Windows
- - [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
2. Install using winget
@@ -132,27 +151,12 @@ See below for specific installation instructions.
winget install algokit
```
-3. [Verify installation](#verify-installation)
-
-### Maintenance
-
-Some useful commands for updating or removing AlgoKit in the future.
-
-- To update AlgoKit: `winget upgrade algokit`
-- To remove AlgoKit: `winget uninstall algokit`
-
-## Install AlgoKit on Mac
-
-> **Note**
-> AlgoKit is supported on macOS Big Sur (11) and later for both x64 and ARM (Apple Silicon)
+### Install AlgoKit on Mac (Homebrew)
1. Ensure prerequisites are installed
-
- [Homebrew](https://docs.brew.sh/Installation)
- [Git](https://github.com/git-guides/install-git#install-git-on-mac) (should already be available if `brew` is installed)
- [Docker](https://docs.docker.com/desktop/install/mac-install/), (or `brew install --cask docker`)
- > **Note**
- > Docker requires MacOS 11+
2. Install using Homebrew
@@ -160,24 +164,10 @@ Some useful commands for updating or removing AlgoKit in the future.
brew install algorandfoundation/tap/algokit
```
-3. Restart the terminal to ensure AlgoKit is available on the path
-4. [Verify installation](#verify-installation)
-
-### Maintenance
-
-Some useful commands for updating or removing AlgoKit in the future.
-
-- To update AlgoKit: `brew upgrade algokit`
-- To remove AlgoKit: `brew uninstall algokit`
-
-## Install AlgoKit on Linux
-
-> **Note**
-> AlgoKit is compatible with Ubuntu 16.04 and later, Debian, RedHat, and any distribution that supports [Snap](https://snapcraft.io/docs/installing-snapd), but it is only supported on x64 architecture; ARM is not supported.
+### Install AlgoKit on Linux (snap)
1. Ensure prerequisites are installed
-
- - [Snap](https://snapcraft.io/docs/installing-snapd) (should be installed by default on Ubuntu 16.04.4 LTS (Xenial Xerus) or later)
+ - [Snap](https://snapcraft.io/docs/installing-snapd)
- [Git](https://github.com/git-guides/install-git#install-git-on-linux)
- [Docker](https://docs.docker.com/desktop/install/linux-install/)
@@ -187,21 +177,9 @@ Some useful commands for updating or removing AlgoKit in the future.
sudo snap install algokit --classic
```
- > For detailed guidelines per each supported linux distro, refer to [Snap Store](https://snapcraft.io/algokit).
-
-3. [Verify installation](#verify-installation)
-
-### Maintenance
-
-Some useful commands for updating or removing AlgoKit in the future.
-
-- To update AlgoKit: `snap refresh algokit`
-- To remove AlgoKit: `snap remove --purge algokit`
-
-## Install AlgoKit with pipx on any OS
+### Install AlgoKit with pipx on any OS
1. Ensure desired prerequisites are installed
-
- [Python 3.10 - 3.14](https://www.python.org/downloads/)
- [pipx](https://pypa.github.io/pipx/installation/)
- [Git](https://github.com/git-guides/install-git)
@@ -213,62 +191,30 @@ Some useful commands for updating or removing AlgoKit in the future.
pipx install algokit
```
-3. Restart the terminal to ensure AlgoKit is available on the path
-4. [Verify installation](#verify-installation)
-
-### Maintenance
-
-Some useful commands for updating or removing AlgoKit in the future.
-
-- To update AlgoKit: `pipx upgrade algokit`
-- To remove AlgoKit: `pipx uninstall algokit`
+
## Verify installation
Verify AlgoKit is installed correctly by running `algokit --version` and you should see output similar to:
```
-algokit, version 1.0.1
+algokit, version 2.10.2
```
> **Note**
-> If you get receive one of the following errors:
+> If you receive one of the following errors:
>
> - `command not found: algokit` (bash/zsh)
> - `The term 'algokit' is not recognized as the name of a cmdlet, function, script file, or operable program.` (PowerShell)
>
-> Then ensure that `algokit` is available on the PATH by running `pipx ensurepath` and restarting the terminal.
-
-It is also recommended that you run `algokit doctor` to verify there are no issues in your local environment and to diagnose any problems if you do have difficulties running AlgoKit. The output of this command will look similar to:
-
-```
-timestamp: 2023-03-27T01:23:45+00:00
-AlgoKit: 1.0.1
-AlgoKit Python: 3.11.1 (main, Dec 23 2022, 09:28:24) [Clang 14.0.0 (clang-1400.0.29.202)] (location: /Users/algokit/.local/pipx/venvs/algokit)
-OS: macOS-13.1-arm64-arm-64bit
-docker: 20.10.21
-docker compose: 2.13.0
-git: 2.37.1
-python: 3.10.9 (location: /opt/homebrew/bin/python)
-python3: 3.10.9 (location: /opt/homebrew/bin/python3)
-pipx: 1.1.0
-poetry: 1.3.2
-node: 18.12.1
-npm: 8.19.2
-brew: 3.6.18
-
-If you are experiencing a problem with AlgoKit, feel free to submit an issue via:
-https://github.com/algorandfoundation/algokit-cli/issues/new
-Please include this output, if you want to populate this message in your clipboard, run `algokit doctor -c`
-```
+> Ensure that `~/.local/bin` is on your PATH and restart the terminal.
-Per the above output, the doctor command output is a helpful tool if you need to ask for support or [raise an issue](https://github.com/algorandfoundation/algokit-cli/issues/new).
+It is also recommended that you run `algokit doctor` to verify there are no issues in your local environment and to diagnose any problems if you do have difficulties running AlgoKit.
## Troubleshooting
This section addresses specific edge cases and issues that some users might encounter when interacting with the CLI. The following table provides solutions to known edge cases:
-| Issue Description | OS(s) with observed behaviour | Steps to mitigate | References |
-| --------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
-| This scenario may arise if installed `python` was build without `--with-ssl` flag enabled, causing pip to fail when trying to install dependencies. | Debian 12 | Run `sudo apt-get install -y libssl-dev` to install the required openssl dependency. Afterwards, ensure to reinstall python with `--with-ssl` flag enabled. This includes options like [building python from source code](https://medium.com/@enahwe/how-to-06bc8a042345) or using tools like [pyenv](https://github.com/pyenv/pyenv). | |
-| `poetry install` invoked directly or via `algokit project bootstrap all` fails on `Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)`. | `MacOS` >=14 using `python` 3.13 installed via `homebrew` | Install dependencies deprecated in `3.13` and latest MacOS versions via `brew install pkg-config`, delete the virtual environment folder and retry the `poetry install` command invocation. | N/A |
+| Issue Description | OS(s) with observed behaviour | Steps to mitigate | References |
+| --------------------------------------------------------------- | ----------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
+| Python was built without `--with-ssl` flag, causing pip to fail | Debian 12 | Run `sudo apt-get install -y libssl-dev` and reinstall python with `--with-ssl` flag enabled | [setup-python#93](https://github.com/actions/setup-python/issues/93) |
diff --git a/debug.py b/debug.py
index c9ae7f171..8036f537b 100644
--- a/debug.py
+++ b/debug.py
@@ -12,7 +12,7 @@
import click
except ImportError:
print( # noqa: T201
- "ERROR: Couldn't import click, make sure you've run 'poetry install' and activated the virtual environment.\n"
+ "ERROR: Couldn't import click, make sure you've run 'uv sync' and activated the virtual environment.\n"
"For tips on getting started with developing AlgoKit CLI itself see CONTRIBUTING.md.\n",
file=sys.stderr,
)
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 000000000..9d60680c9
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,23 @@
+# build output
+dist/
+# generated types
+.astro/
+
+# dependencies
+node_modules/
+
+# auto-generated CLI reference docs (built by sphinx-click)
+src/content/docs/cli/
+
+# logs
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# environment variables
+.env
+.env.production
+
+# macOS-specific files
+.DS_Store
\ No newline at end of file
diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs
new file mode 100644
index 000000000..124edae4a
--- /dev/null
+++ b/docs/astro.config.mjs
@@ -0,0 +1,108 @@
+// @ts-check
+import starlight from "@astrojs/starlight";
+import { defineConfig } from "astro/config";
+import remarkGithubAlerts from "remark-github-alerts";
+
+export default defineConfig({
+ site: "https://algorandfoundation.github.io",
+ base: "/algokit-cli/",
+ trailingSlash: "always",
+ markdown: {
+ remarkPlugins: [remarkGithubAlerts],
+ },
+ integrations: [
+ starlight({
+ title: "AlgoKit CLI",
+ tableOfContents: { minHeadingLevel: 2, maxHeadingLevel: 4 },
+ customCss: [
+ "./src/styles/cli-reference.css",
+ "remark-github-alerts/styles/github-colors-light.css",
+ "remark-github-alerts/styles/github-colors-dark-media.css",
+ "remark-github-alerts/styles/github-base.css",
+ ],
+ social: [
+ {
+ icon: "github",
+ label: "GitHub",
+ href: "https://github.com/algorandfoundation/algokit-cli",
+ },
+ {
+ icon: "discord",
+ label: "Discord",
+ href: "https://discord.gg/algorand",
+ },
+ ],
+ sidebar: [
+ { label: "Home", link: "/" },
+ {
+ label: "Getting Started",
+ items: [
+ { slug: "tutorials/intro" },
+ { slug: "tutorials/smart-contracts" },
+ { slug: "tutorials/algokit-template" },
+ ],
+ },
+ {
+ label: "Features",
+ items: [
+ { slug: "features/overview" },
+ { slug: "features/init" },
+ { slug: "features/localnet" },
+ { slug: "features/compile" },
+ { slug: "features/generate" },
+ { slug: "features/config" },
+ { slug: "features/doctor" },
+ { slug: "features/explore" },
+ { slug: "features/dispenser" },
+ { slug: "features/goal" },
+ { slug: "features/completions" },
+ { slug: "features/vibe" },
+ {
+ label: "AlgoKit Project",
+ collapsed: true,
+ items: [
+ { slug: "features/project" },
+ { slug: "features/project/bootstrap" },
+ { slug: "features/project/deploy" },
+ { slug: "features/project/link" },
+ { slug: "features/project/list" },
+ { slug: "features/project/run" },
+ ],
+ },
+ {
+ label: "AlgoKit Task",
+ collapsed: true,
+ items: [
+ { slug: "features/tasks" },
+ { slug: "features/tasks/analyze" },
+ { slug: "features/tasks/ipfs" },
+ { slug: "features/tasks/mint" },
+ { slug: "features/tasks/nfd" },
+ { slug: "features/tasks/opt" },
+ { slug: "features/tasks/send" },
+ { slug: "features/tasks/sign" },
+ { slug: "features/tasks/transfer" },
+ { slug: "features/tasks/vanity_address" },
+ { slug: "features/tasks/wallet" },
+ ],
+ },
+ ],
+ },
+ {
+ label: "Concepts",
+ items: [{ slug: "concepts/output-stability" }],
+ },
+ {
+ label: "Architecture Decisions",
+ collapsed: true,
+ autogenerate: { directory: "architecture-decisions" },
+ },
+ {
+ label: "CLI Reference",
+ collapsed: true,
+ items: [{ slug: "cli", label: "AlgoKit CLI" }],
+ },
+ ],
+ }),
+ ],
+});
diff --git a/docs/cli/index.md b/docs/cli/index.md
deleted file mode 100644
index dd63c6e58..000000000
--- a/docs/cli/index.md
+++ /dev/null
@@ -1,1669 +0,0 @@
-# AlgoKit CLI Reference Documentation
-
-
-- [algokit](#algokit)
- - [Options](#options)
- - [--version](#--version)
- - [-v, --verbose](#-v---verbose)
- - [--color, --no-color](#--color---no-color)
- - [--skip-version-check](#--skip-version-check)
- - [compile](#compile)
- - [Options](#options-1)
- - [-v, --version ](#-v---version-)
- - [py](#py)
- - [Arguments](#arguments)
- - [PUYAPY_ARGS](#puyapy_args)
- - [python](#python)
- - [Arguments](#arguments-1)
- - [PUYAPY_ARGS](#puyapy_args-1)
- - [ts](#ts)
- - [Arguments](#arguments-2)
- - [PUYATS_ARGS](#puyats_args)
- - [typescript](#typescript)
- - [Arguments](#arguments-3)
- - [PUYATS_ARGS](#puyats_args-1)
- - [completions](#completions)
- - [install](#install)
- - [Options](#options-2)
- - [--shell ](#--shell-)
- - [uninstall](#uninstall)
- - [Options](#options-3)
- - [--shell ](#--shell--1)
- - [config](#config)
- - [container-engine](#container-engine)
- - [Options](#options-4)
- - [-f, --force](#-f---force)
- - [Arguments](#arguments-4)
- - [ENGINE](#engine)
- - [js-package-manager](#js-package-manager)
- - [Arguments](#arguments-5)
- - [PACKAGE_MANAGER](#package_manager)
- - [py-package-manager](#py-package-manager)
- - [Arguments](#arguments-6)
- - [PACKAGE_MANAGER](#package_manager-1)
- - [version-prompt](#version-prompt)
- - [Arguments](#arguments-7)
- - [ENABLE](#enable)
- - [dispenser](#dispenser)
- - [fund](#fund)
- - [Options](#options-5)
- - [-r, --receiver ](#-r---receiver-)
- - [-a, --amount ](#-a---amount-)
- - [--whole-units](#--whole-units)
- - [limit](#limit)
- - [Options](#options-6)
- - [--whole-units](#--whole-units-1)
- - [login](#login)
- - [Options](#options-7)
- - [--ci](#--ci)
- - [-o, --output ](#-o---output-)
- - [-f, --file ](#-f---file-)
- - [logout](#logout)
- - [refund](#refund)
- - [Options](#options-8)
- - [-t, --txID ](#-t---txid-)
- - [doctor](#doctor)
- - [Options](#options-9)
- - [-c, --copy-to-clipboard](#-c---copy-to-clipboard)
- - [explore](#explore)
- - [Arguments](#arguments-8)
- - [NETWORK](#network)
- - [generate](#generate)
- - [client](#client)
- - [Options](#options-10)
- - [-o, --output ](#-o---output--1)
- - [-l, --language ](#-l---language-)
- - [-v, --version ](#-v---version--1)
- - [Arguments](#arguments-9)
- - [APP_SPEC_PATH_OR_DIR](#app_spec_path_or_dir)
- - [ARGS](#args)
- - [goal](#goal)
- - [Options](#options-11)
- - [--console](#--console)
- - [--interactive](#--interactive)
- - [Arguments](#arguments-10)
- - [GOAL_ARGS](#goal_args)
- - [init](#init)
- - [Options](#options-12)
- - [-n, --name ](#-n---name-)
- - [-t, --template ](#-t---template-)
- - [--template-url ](#--template-url-)
- - [--template-url-ref ](#--template-url-ref-)
- - [--UNSAFE-SECURITY-accept-template-url](#--unsafe-security-accept-template-url)
- - [--git, --no-git](#--git---no-git)
- - [--defaults](#--defaults)
- - [--bootstrap, --no-bootstrap](#--bootstrap---no-bootstrap)
- - [--ide, --no-ide](#--ide---no-ide)
- - [--workspace, --no-workspace](#--workspace---no-workspace)
- - [-a, --answer ](#-a---answer--)
- - [example](#example)
- - [Options](#options-13)
- - [-l, --list](#-l---list)
- - [Arguments](#arguments-11)
- - [EXAMPLE_ID](#example_id)
- - [localnet](#localnet)
- - [codespace](#codespace)
- - [Options](#options-14)
- - [-m, --machine ](#-m---machine-)
- - [-a, --algod-port ](#-a---algod-port-)
- - [-i, --indexer-port ](#-i---indexer-port-)
- - [-k, --kmd-port ](#-k---kmd-port-)
- - [-n, --codespace-name ](#-n---codespace-name-)
- - [-r, --repo-url ](#-r---repo-url-)
- - [-t, --timeout ](#-t---timeout-)
- - [-f, --force](#-f---force-1)
- - [config](#config-1)
- - [Options](#options-15)
- - [-f, --force](#-f---force-2)
- - [Arguments](#arguments-12)
- - [ENGINE](#engine-1)
- - [console](#console)
- - [explore](#explore-1)
- - [logs](#logs)
- - [Options](#options-16)
- - [--follow, -f](#--follow--f)
- - [--tail ](#--tail-)
- - [reset](#reset)
- - [Options](#options-17)
- - [--update, --no-update](#--update---no-update)
- - [-P, --config-dir ](#-p---config-dir-)
- - [--check](#--check)
- - [start](#start)
- - [Options](#options-18)
- - [-n, --name ](#-n---name--1)
- - [-P, --config-dir ](#-p---config-dir--1)
- - [-d, --dev, --no-dev](#-d---dev---no-dev)
- - [--force](#--force)
- - [--check](#--check-1)
- - [status](#status)
- - [Options](#options-19)
- - [--check](#--check-2)
- - [stop](#stop)
- - [project](#project)
- - [bootstrap](#bootstrap)
- - [Options](#options-20)
- - [--force](#--force-1)
- - [Options](#options-21)
- - [--interactive, --no-ci, --non-interactive, --ci](#--interactive---no-ci---non-interactive---ci)
- - [-p, --project-name ](#-p---project-name-)
- - [-t, --type ](#-t---type-)
- - [Options](#options-22)
- - [--interactive, --non-interactive, --ci](#--interactive---non-interactive---ci)
- - [Options](#options-23)
- - [--ci, --no-ci](#--ci---no-ci)
- - [Options](#options-24)
- - [--ci, --no-ci](#--ci---no-ci-1)
- - [deploy](#deploy)
- - [Options](#options-25)
- - [-C, -c, --command ](#-c--c---command-)
- - [--interactive, --non-interactive, --ci](#--interactive---non-interactive---ci-1)
- - [-P, --path ](#-p---path-)
- - [--deployer ](#--deployer-)
- - [--dispenser ](#--dispenser-)
- - [-p, --project-name ](#-p---project-name--1)
- - [Arguments](#arguments-13)
- - [ENVIRONMENT_NAME](#environment_name)
- - [EXTRA_ARGS](#extra_args)
- - [link](#link)
- - [Options](#options-26)
- - [-p, --project-name ](#-p---project-name--2)
- - [-l, --language ](#-l---language--1)
- - [-a, --all](#-a---all)
- - [-f, --fail-fast](#-f---fail-fast)
- - [-v, --version ](#-v---version--2)
- - [list](#list)
- - [Arguments](#arguments-14)
- - [WORKSPACE_PATH](#workspace_path)
- - [run](#run)
- - [task](#task)
- - [analyze](#analyze)
- - [Options](#options-27)
- - [-r, --recursive](#-r---recursive)
- - [--force](#--force-2)
- - [--diff](#--diff)
- - [-o, --output ](#-o---output--2)
- - [-e, --exclude ](#-e---exclude-)
- - [Arguments](#arguments-15)
- - [INPUT_PATHS](#input_paths)
- - [ipfs](#ipfs)
- - [Options](#options-28)
- - [-f, --file ](#-f---file--1)
- - [-n, --name ](#-n---name--2)
- - [mint](#mint)
- - [Options](#options-29)
- - [--creator ](#--creator-)
- - [--name ](#--name-)
- - [-u, --unit ](#-u---unit-)
- - [-t, --total ](#-t---total-)
- - [-d, --decimals ](#-d---decimals-)
- - [--nft, --ft](#--nft---ft)
- - [-i, --image ](#-i---image-)
- - [-m, --metadata ](#-m---metadata-)
- - [--mutable, --immutable](#--mutable---immutable)
- - [-n, --network ](#-n---network-)
- - [nfd-lookup](#nfd-lookup)
- - [Options](#options-30)
- - [-o, --output ](#-o---output--3)
- - [Arguments](#arguments-16)
- - [VALUE](#value)
- - [opt-in](#opt-in)
- - [Options](#options-31)
- - [-a, --account ](#-a---account-)
- - [-n, --network ](#-n---network--1)
- - [Arguments](#arguments-17)
- - [ASSET_IDS](#asset_ids)
- - [opt-out](#opt-out)
- - [Options](#options-32)
- - [-a, --account ](#-a---account--1)
- - [--all](#--all)
- - [-n, --network ](#-n---network--2)
- - [Arguments](#arguments-18)
- - [ASSET_IDS](#asset_ids-1)
- - [send](#send)
- - [Options](#options-33)
- - [-f, --file ](#-f---file--2)
- - [-t, --transaction ](#-t---transaction-)
- - [-n, --network ](#-n---network--3)
- - [sign](#sign)
- - [Options](#options-34)
- - [-a, --account ](#-a---account--2)
- - [-f, --file ](#-f---file--3)
- - [-t, --transaction ](#-t---transaction--1)
- - [-o, --output ](#-o---output--4)
- - [--force](#--force-3)
- - [transfer](#transfer)
- - [Options](#options-35)
- - [-s, --sender ](#-s---sender-)
- - [-r, --receiver ](#-r---receiver--1)
- - [--asset, --id ](#--asset---id-)
- - [-a, --amount ](#-a---amount--1)
- - [--whole-units](#--whole-units-2)
- - [-n, --network ](#-n---network--4)
- - [vanity-address](#vanity-address)
- - [Options](#options-36)
- - [-m, --match ](#-m---match-)
- - [-o, --output ](#-o---output--5)
- - [-a, --alias ](#-a---alias-)
- - [--file-path ](#--file-path-)
- - [-f, --force](#-f---force-3)
- - [Arguments](#arguments-19)
- - [KEYWORD](#keyword)
- - [wallet](#wallet)
- - [Options](#options-37)
- - [-a, --address ](#-a---address-)
- - [-m, --mnemonic](#-m---mnemonic)
- - [-f, --force](#-f---force-4)
- - [Arguments](#arguments-20)
- - [ALIAS_NAME](#alias_name)
- - [Arguments](#arguments-21)
- - [ALIAS](#alias)
- - [Options](#options-38)
- - [-f, --force](#-f---force-5)
- - [Arguments](#arguments-22)
- - [ALIAS](#alias-1)
- - [Options](#options-39)
- - [-f, --force](#-f---force-6)
-
-# algokit
-
-AlgoKit is your one-stop shop to develop applications on the Algorand blockchain.
-
-If you are getting started, please see the quick start tutorial: [https://dev.algorand.co/getting-started/algokit-quick-start/](https://dev.algorand.co/getting-started/algokit-quick-start/).
-
-```shell
-algokit [OPTIONS] COMMAND [ARGS]...
-```
-
-### Options
-
-
-### --version
-Show the version and exit.
-
-
-### -v, --verbose
-Enable logging of DEBUG messages to the console.
-
-
-### --color, --no-color
-Force enable or disable of console output styling.
-
-
-### --skip-version-check
-Skip version checking and prompting.
-
-## compile
-
-Compile smart contracts and smart signatures written in a supported high-level language
-to a format deployable on the Algorand Virtual Machine (AVM).
-
-```shell
-algokit compile [OPTIONS] COMMAND [ARGS]...
-```
-
-### Options
-
-
-### -v, --version
-The compiler version to pin to, for example, 1.0.0. If no version is specified, AlgoKit checks if the compiler is installed and runs the installed version. If the compiler is not installed, AlgoKit runs the latest version. If a version is specified, AlgoKit checks if an installed version matches and runs the installed version. Otherwise, AlgoKit runs the specified version.
-
-### py
-
-Compile Algorand Python contract(s) using the PuyaPy compiler.
-
-```shell
-algokit compile py [OPTIONS] [PUYAPY_ARGS]...
-```
-
-### Arguments
-
-
-### PUYAPY_ARGS
-Optional argument(s)
-
-### python
-
-Compile Algorand Python contract(s) using the PuyaPy compiler.
-
-```shell
-algokit compile python [OPTIONS] [PUYAPY_ARGS]...
-```
-
-### Arguments
-
-
-### PUYAPY_ARGS
-Optional argument(s)
-
-### ts
-
-Compile Algorand TypeScript contract(s) using the PuyaTs compiler.
-
-```shell
-algokit compile ts [OPTIONS] [PUYATS_ARGS]...
-```
-
-### Arguments
-
-
-### PUYATS_ARGS
-Optional argument(s)
-
-### typescript
-
-Compile Algorand TypeScript contract(s) using the PuyaTs compiler.
-
-```shell
-algokit compile typescript [OPTIONS] [PUYATS_ARGS]...
-```
-
-### Arguments
-
-
-### PUYATS_ARGS
-Optional argument(s)
-
-## completions
-
-Install and Uninstall AlgoKit shell integrations.
-
-```shell
-algokit completions [OPTIONS] COMMAND [ARGS]...
-```
-
-### install
-
-Install shell completions, this command will attempt to update the interactive profile script
-for the current shell to support algokit completions. To specify a specific shell use --shell.
-
-```shell
-algokit completions install [OPTIONS]
-```
-
-### Options
-
-
-### --shell
-Specify shell to install algokit completions for.
-
-
-* **Options**
-
- bash | zsh
-
-
-### uninstall
-
-Uninstall shell completions, this command will attempt to update the interactive profile script
-for the current shell to remove any algokit completions that have been added.
-To specify a specific shell use --shell.
-
-```shell
-algokit completions uninstall [OPTIONS]
-```
-
-### Options
-
-
-### --shell
-Specify shell to install algokit completions for.
-
-
-* **Options**
-
- bash | zsh
-
-
-## config
-
-Configure settings used by AlgoKit
-
-```shell
-algokit config [OPTIONS] COMMAND [ARGS]...
-```
-
-### container-engine
-
-Set the default container engine for use by AlgoKit CLI to run LocalNet images.
-
-```shell
-algokit config container-engine [OPTIONS] [[docker|podman]]
-```
-
-### Options
-
-
-### -f, --force
-Skip confirmation prompts. Defaults to 'yes' to all prompts.
-
-### Arguments
-
-
-### ENGINE
-Optional argument
-
-### js-package-manager
-
-Set the default JavaScript package manager for use by AlgoKit CLI.
-
-```shell
-algokit config js-package-manager [OPTIONS] [[npm|pnpm]]
-```
-
-### Arguments
-
-
-### PACKAGE_MANAGER
-Optional argument
-
-### py-package-manager
-
-Set the default Python package manager for use by AlgoKit CLI.
-
-```shell
-algokit config py-package-manager [OPTIONS] [[poetry|uv]]
-```
-
-### Arguments
-
-
-### PACKAGE_MANAGER
-Optional argument
-
-### version-prompt
-
-Controls whether AlgoKit checks and prompts for new versions.
-Set to [disable] to prevent AlgoKit performing this check permanently, or [enable] to resume checking.
-If no argument is provided then outputs current setting.
-
-Also see --skip-version-check which can be used to disable check for a single command.
-
-```shell
-algokit config version-prompt [OPTIONS] [[enable|disable]]
-```
-
-### Arguments
-
-
-### ENABLE
-Optional argument
-
-## dispenser
-
-Interact with the AlgoKit TestNet Dispenser.
-
-```shell
-algokit dispenser [OPTIONS] COMMAND [ARGS]...
-```
-
-### fund
-
-Fund your wallet address with TestNet ALGOs.
-
-```shell
-algokit dispenser fund [OPTIONS]
-```
-
-### Options
-
-
-### -r, --receiver
-**Required** Address or alias of the receiver to fund with TestNet ALGOs.
-
-
-### -a, --amount
-**Required** Amount to fund. Defaults to microAlgos.
-
-
-### --whole-units
-Use whole units (Algos) instead of smallest divisible units (microAlgos). Disabled by default.
-
-### limit
-
-Get information about current fund limit on your account. Resets daily.
-
-```shell
-algokit dispenser limit [OPTIONS]
-```
-
-### Options
-
-
-### --whole-units
-Use whole units (Algos) instead of smallest divisible units (microAlgos). Disabled by default.
-
-### login
-
-Login to your Dispenser API account.
-
-```shell
-algokit dispenser login [OPTIONS]
-```
-
-### Options
-
-
-### --ci
-Generate an access token for CI. Issued for 30 days.
-
-
-### -o, --output
-Choose the output method for the access token. Defaults to stdout. Only applicable when --ci flag is set.
-
-
-* **Options**
-
- stdout | file
-
-
-
-### -f, --file
-Output filename where you want to store the generated access token.Defaults to algokit_ci_token.txt. Only applicable when --ci flag is set and --output mode is file.
-
-### logout
-
-Logout of your Dispenser API account.
-
-```shell
-algokit dispenser logout [OPTIONS]
-```
-
-### refund
-
-Refund ALGOs back to the dispenser wallet address.
-
-```shell
-algokit dispenser refund [OPTIONS]
-```
-
-### Options
-
-
-### -t, --txID
-**Required** Transaction ID of your refund operation.
-
-## doctor
-
-Diagnose potential environment issues that may affect AlgoKit.
-
-Will search the system for AlgoKit dependencies and show their versions, as well as identifying any
-potential issues.
-
-```shell
-algokit doctor [OPTIONS]
-```
-
-### Options
-
-
-### -c, --copy-to-clipboard
-Copy the contents of the doctor message (in Markdown format) in your clipboard.
-
-## explore
-
-Explore the specified network using lora.
-
-```shell
-algokit explore [OPTIONS] [[localnet|testnet|mainnet]]
-```
-
-### Arguments
-
-
-### NETWORK
-Optional argument
-
-## generate
-
-Generate code for an Algorand project.
-
-```shell
-algokit generate [OPTIONS] COMMAND [ARGS]...
-```
-
-### client
-
-Create a typed ApplicationClient from an ARC-32/56 application.json
-
-Supply the path to an application specification file or a directory to recursively search
-for "application.json" files
-
-```shell
-algokit generate client [OPTIONS] [APP_SPEC_PATH_OR_DIR] [ARGS]...
-```
-
-### Options
-
-
-### -o, --output
-Path to the output file. The following tokens can be used to substitute into the output path: {contract_name}, {app_spec_dir}
-
-
-### -l, --language
-Programming language of the generated client code
-
-
-* **Options**
-
- python | typescript
-
-
-
-### -v, --version
-The client generator version to pin to, for example, 1.0.0. If no version is specified, AlgoKit checks if the client generator is installed and runs the installed version. If the client generator is not installed, AlgoKit runs the latest version. If a version is specified, AlgoKit checks if an installed version matches and runs the installed version. Otherwise, AlgoKit runs the specified version.
-
-### Arguments
-
-
-### APP_SPEC_PATH_OR_DIR
-Optional argument
-
-
-### ARGS
-Optional argument(s)
-
-## goal
-
-Run the Algorand goal CLI against the AlgoKit LocalNet.
-
-Look at [https://dev.algorand.co/algokit/algokit-cli/goal](https://dev.algorand.co/algokit/algokit-cli/goal) for more information.
-
-```shell
-algokit goal [OPTIONS] [GOAL_ARGS]...
-```
-
-### Options
-
-
-### --console
-Open a Bash console so you can execute multiple goal commands and/or interact with a filesystem.
-
-
-### --interactive
-Force running the goal command in interactive mode.
-
-### Arguments
-
-
-### GOAL_ARGS
-Optional argument(s)
-
-## init
-
-Initializes a new project from a template, including prompting
-for template specific questions to be used in template rendering.
-
-Templates can be default templates shipped with AlgoKit, or custom
-templates in public Git repositories.
-
-Includes ability to initialise Git repository, run algokit project bootstrap and
-automatically open Visual Studio Code.
-
-This should be run in the parent directory that you want the project folder
-created in.
-
-By default, the --workspace flag creates projects within a workspace structure or integrates them into an existing
-one, promoting organized management of multiple projects. Alternatively,
-to disable this behavior use the --no-workspace flag, which ensures
-the new project is created in a standalone target directory. This is
-suitable for isolated projects or when workspace integration is unnecessary.
-
-```shell
-algokit init [OPTIONS] COMMAND [ARGS]...
-```
-
-### Options
-
-
-### -n, --name
-Name of the project / directory / repository to create.
-
-
-### -t, --template
-Name of an official template to use. To choose interactively, run this command with no arguments.
-
-
-* **Options**
-
- tealscript | typescript | python | react | fullstack | base
-
-
-
-### --template-url
-URL to a git repo with a custom project template.
-
-
-### --template-url-ref
-Specific tag, branch or commit to use on git repo specified with --template-url. Defaults to latest.
-
-
-### --UNSAFE-SECURITY-accept-template-url
-Accept the specified template URL, acknowledging the security implications of arbitrary code execution trusting an unofficial template.
-
-
-### --git, --no-git
-Initialise git repository in directory after creation.
-
-
-### --defaults
-Automatically choose default answers without asking when creating this template.
-
-
-### --bootstrap, --no-bootstrap
-Whether to run algokit project bootstrap to install and configure the new project's dependencies locally.
-
-
-### --ide, --no-ide
-Whether to open an IDE for you if the IDE and IDE config are detected. Supported IDEs: VS Code.
-
-
-### --workspace, --no-workspace
-Whether to prefer structuring standalone projects as part of a workspace. An AlgoKit workspace is a conventional project structure that allows managing multiple standalone projects in a monorepo.
-
-
-### -a, --answer
-Answers key/value pairs to pass to the template.
-
-### example
-
-Initialize a new project from an example template.
-
-Allows you to quickly create a new project by copying one of the official AlgoKit example templates.
-If no example ID is provided, launches an interactive selector to choose from available examples.
-The example will be copied to a new directory in your current location.
-
-```shell
-algokit init example [OPTIONS] [EXAMPLE_ID]
-```
-
-### Options
-
-
-### -l, --list
-List all available examples
-
-### Arguments
-
-
-### EXAMPLE_ID
-Optional argument
-
-## localnet
-
-Manage the AlgoKit LocalNet.
-
-```shell
-algokit localnet [OPTIONS] COMMAND [ARGS]...
-```
-
-### codespace
-
-Manage the AlgoKit LocalNet in GitHub Codespaces.
-
-```shell
-algokit localnet codespace [OPTIONS]
-```
-
-### Options
-
-
-### -m, --machine
-The GitHub Codespace machine type to use. Defaults to base tier.
-
-
-* **Options**
-
- basicLinux32gb | standardLinux32gb | premiumLinux | largePremiumLinux
-
-
-
-### -a, --algod-port
-The port for the Algorand daemon. Defaults to 4001.
-
-
-### -i, --indexer-port
-The port for the Algorand indexer. Defaults to 8980.
-
-
-### -k, --kmd-port
-The port for the Algorand kmd. Defaults to 4002.
-
-
-### -n, --codespace-name
-The name of the codespace. Defaults to 'algokit-localnet_timestamp'.
-
-
-### -r, --repo-url
-The URL of the repository. Defaults to algokit base template repo.
-
-
-### -t, --timeout
-Default max runtime timeout in minutes. Upon hitting the timeout a codespace will be shutdown to prevent accidental spending over GitHub Codespaces quota. Defaults to 4 hours.
-
-
-### -f, --force
-Force delete previously used codespaces with {CODESPACE_NAME_PREFIX}\* name prefix and skip prompts. Defaults to explicitly prompting for confirmation.
-
-### config
-
-Set the default container engine for use by AlgoKit CLI to run LocalNet images.
-
-```shell
-algokit localnet config [OPTIONS] [[docker|podman]]
-```
-
-### Options
-
-
-### -f, --force
-Skip confirmation prompts. Defaults to 'yes' to all prompts.
-
-### Arguments
-
-
-### ENGINE
-Optional argument
-
-### console
-
-Run the Algorand goal CLI against the AlgoKit LocalNet via a Bash console so you can execute multiple goal commands and/or interact with a filesystem.
-
-```shell
-algokit localnet console [OPTIONS]
-```
-
-### explore
-
-Explore the AlgoKit LocalNet using lora.
-
-```shell
-algokit localnet explore [OPTIONS]
-```
-
-### logs
-
-See the output of the Docker containers.
-
-```shell
-algokit localnet logs [OPTIONS]
-```
-
-### Options
-
-
-### --follow, -f
-Follow log output.
-
-
-### --tail
-Number of lines to show from the end of the logs for each container.
-
-
-* **Default**
-
- `all`
-
-
-### reset
-
-Reset the AlgoKit LocalNet.
-
-```shell
-algokit localnet reset [OPTIONS]
-```
-
-### Options
-
-
-### --update, --no-update
-Enable or disable updating to the latest available LocalNet version, default: don't update
-
-
-### -P, --config-dir
-Specify the custom localnet configuration directory.
-
-
-### --check
-Force check the Docker registry for new LocalNet image versions, ignoring the version check cache.
-
-### start
-
-Start the AlgoKit LocalNet.
-
-```shell
-algokit localnet start [OPTIONS]
-```
-
-### Options
-
-
-### -n, --name
-Specify a name for a custom LocalNet instance. AlgoKit will not manage the configuration of named LocalNet instances, allowing developers to configure it in any way they need. Defaults to 'sandbox'.
-
-
-### -P, --config-dir
-Specify the custom localnet configuration directory. Defaults to '~/.config' on UNIX and 'C:\\Users\\USERNAME\\AppData\\Roaming' on Windows.
-
-
-### -d, --dev, --no-dev
-Control whether to launch 'algod' in developer mode or not. Defaults to 'yes'.
-
-
-### --force
-Ignore the prompt to stop the LocalNet if it's already running.
-
-
-### --check
-Force check the Docker registry for new LocalNet image versions, ignoring the version check cache.
-
-### status
-
-Check the status of the AlgoKit LocalNet.
-
-```shell
-algokit localnet status [OPTIONS]
-```
-
-### Options
-
-
-### --check
-Force check the Docker registry for new LocalNet image versions, ignoring the version check cache.
-
-### stop
-
-Stop the AlgoKit LocalNet.
-
-```shell
-algokit localnet stop [OPTIONS]
-```
-
-## project
-
-Provides a suite of commands for managing your AlgoKit project.
-This includes initializing project dependencies, deploying smart contracts,
-and executing predefined or custom commands within your project environment.
-
-```shell
-algokit project [OPTIONS] COMMAND [ARGS]...
-```
-
-### bootstrap
-
-Expedited initial setup for any developer by installing and configuring dependencies and other
-key development environment setup activities.
-
-```shell
-algokit project bootstrap [OPTIONS] COMMAND [ARGS]...
-```
-
-### Options
-
-
-### --force
-Continue even if minimum AlgoKit version is not met
-
-#### all
-
-Runs all bootstrap sub-commands in the current directory and immediate sub directories.
-
-```shell
-algokit project bootstrap all [OPTIONS]
-```
-
-### Options
-
-
-### --interactive, --no-ci, --non-interactive, --ci
-Enable/disable interactive prompts. If the CI environment variable is set, defaults to non-interactive
-
-
-### -p, --project-name
-(Optional) Projects to execute the command on. Defaults to all projects found in the current directory.
-
-
-### -t, --type
-(Optional) Limit execution to specific project types if executing from workspace.
-
-
-* **Options**
-
- ProjectType.FRONTEND | ProjectType.CONTRACT | ProjectType.BACKEND
-
-
-#### env
-
-Copies .env.template file to .env in the current working directory and prompts for any unspecified values.
-
-```shell
-algokit project bootstrap env [OPTIONS]
-```
-
-### Options
-
-
-### --interactive, --non-interactive, --ci
-Enable/disable interactive prompts. If the CI environment variable is set, defaults to non-interactive
-
-#### npm
-
-Runs npm install in the current working directory to install Node.js dependencies.
-
-```shell
-algokit project bootstrap npm [OPTIONS]
-```
-
-### Options
-
-
-### --ci, --no-ci
-Run 'npm ci' instead of 'npm install' in CI mode (clean install).
-
-#### pnpm
-
-Runs pnpm install in the current working directory to install Node.js dependencies.
-
-```shell
-algokit project bootstrap pnpm [OPTIONS]
-```
-
-### Options
-
-
-### --ci, --no-ci
-Run 'pnpm install --frozen-lockfile' instead of 'pnpm install' in CI mode (clean install with frozen lockfile).
-
-#### poetry
-
-Installs Python Poetry (if not present) and runs poetry install in the current working directory to install Python dependencies.
-
-```shell
-algokit project bootstrap poetry [OPTIONS]
-```
-
-#### uv
-
-Installs UV (if not present) and runs uv sync in the current working directory to install Python dependencies.
-
-```shell
-algokit project bootstrap uv [OPTIONS]
-```
-
-### deploy
-
-Deploy smart contracts from AlgoKit compliant repository.
-
-```shell
-algokit project deploy [OPTIONS] [ENVIRONMENT_NAME] [EXTRA_ARGS]...
-```
-
-### Options
-
-
-### -C, -c, --command
-Custom deploy command. If not provided, will load the deploy command from .algokit.toml file.
-
-
-### --interactive, --non-interactive, --ci
-Enable/disable interactive prompts. Defaults to non-interactive if the CI environment variable is set. Interactive MainNet deployments prompt for confirmation.
-
-
-### -P, --path
-Specify the project directory. If not provided, current working directory will be used.
-
-
-### --deployer
-(Optional) Alias of the deployer account. Otherwise, will prompt the deployer mnemonic if specified in .algokit.toml file.
-
-
-### --dispenser
-(Optional) Alias of the dispenser account. Otherwise, will prompt the dispenser mnemonic if specified in .algokit.toml file.
-
-
-### -p, --project-name
-(Optional) Projects to execute the command on. Defaults to all projects found in the current directory. Option is mutually exclusive with command.
-
-### Arguments
-
-
-### ENVIRONMENT_NAME
-Optional argument
-
-
-### EXTRA_ARGS
-Optional argument(s)
-
-### link
-
-Automatically invoke 'algokit generate client' on contract projects available in the workspace.
-Must be invoked from the root of a standalone 'frontend' typed project.
-
-```shell
-algokit project link [OPTIONS]
-```
-
-### Options
-
-
-### -p, --project-name
-Specify contract projects for the command. Defaults to all in the current workspace.
-
-
-### -l, --language
-Programming language of the generated client code
-
-
-* **Options**
-
- python | typescript
-
-
-
-### -a, --all
-Link all contract projects with the frontend project Option is mutually exclusive with project_name.
-
-
-### -f, --fail-fast
-Exit immediately if at least one client generation process fails
-
-
-### -v, --version
-The client generator version to pin to, for example, 1.0.0. If no version is specified, AlgoKit checks if the client generator is installed and runs the installed version. If the client generator is not installed, AlgoKit runs the latest version. If a version is specified, AlgoKit checks if an installed version matches and runs the installed version. Otherwise, AlgoKit runs the specified version.
-
-### list
-
-List all projects in the workspace
-
-```shell
-algokit project list [OPTIONS] [WORKSPACE_PATH]
-```
-
-### Arguments
-
-
-### WORKSPACE_PATH
-Optional argument
-
-### run
-
-Define custom commands and manage their execution in you projects.
-
-```shell
-algokit project run [OPTIONS] COMMAND [ARGS]...
-```
-
-## task
-
-Collection of useful tasks to help you develop on Algorand.
-
-```shell
-algokit task [OPTIONS] COMMAND [ARGS]...
-```
-
-### analyze
-
-Analyze TEAL programs for common vulnerabilities using Tealer. This task uses a third party tool to suggest improvements for your TEAL programs, but remember to always test your smart contracts code, follow modern software engineering practices and use the guidelines for smart contract development. This should not be used as a substitute for an actual audit. For full list of available detectors, please refer to [https://github.com/crytic/tealer?tab=readme-ov-file#detectors](https://github.com/crytic/tealer?tab=readme-ov-file#detectors)
-
-```shell
-algokit task analyze [OPTIONS] INPUT_PATHS...
-```
-
-### Options
-
-
-### -r, --recursive
-Recursively search for all TEAL files within the provided directory.
-
-
-### --force
-Force verification without the disclaimer confirmation prompt.
-
-
-### --diff
-Exit with a non-zero code if differences are found between current and last reports. Reports are generated each run, but with this flag execution fails if the current report doesn't match the last report. Reports are stored in the .algokit/static-analysis/snapshots folder by default. Use --output for a custom path.
-
-
-### -o, --output
-Directory path where to store the results of the static analysis. Defaults to .algokit/static-analysis/snapshots.
-
-
-### -e, --exclude
-Exclude specific vulnerabilities from the analysis. Supports multiple exclusions in a single run.
-
-### Arguments
-
-
-### INPUT_PATHS
-Required argument(s)
-
-### ipfs
-
-Upload files to IPFS using Pinata provider.
-
-```shell
-algokit task ipfs [OPTIONS] COMMAND [ARGS]...
-```
-
-#### login
-
-Login to Pinata ipfs provider. You will be prompted for your JWT.
-
-```shell
-algokit task ipfs login [OPTIONS]
-```
-
-#### logout
-
-Logout of Pinata ipfs provider.
-
-```shell
-algokit task ipfs logout [OPTIONS]
-```
-
-#### upload
-
-Upload a file to Pinata ipfs provider. Please note, max file size is 100MB.
-
-```shell
-algokit task ipfs upload [OPTIONS]
-```
-
-### Options
-
-
-### -f, --file
-**Required** Path to the file to upload.
-
-
-### -n, --name
-Human readable name for this upload, for use in file listings.
-
-### mint
-
-Mint new fungible or non-fungible assets on Algorand.
-
-```shell
-algokit task mint [OPTIONS]
-```
-
-### Options
-
-
-### --creator
-**Required** Address or alias of the asset creator.
-
-
-### --name
-Asset name.
-
-
-### -u, --unit
-**Required** Unit name of the asset.
-
-
-### -t, --total
-Total supply of the asset. Defaults to 1.
-
-
-### -d, --decimals
-Number of decimals. Defaults to 0.
-
-
-### --nft, --ft
-Whether the asset should be validated as NFT or FT. Refers to NFT by default and validates canonical
-definitions of pure or fractional NFTs as per ARC3 standard.
-
-
-### -i, --image
-**Required** Path to the asset image file to be uploaded to IPFS.
-
-
-### -m, --metadata
-Path to the ARC19 compliant asset metadata file to be uploaded to IPFS. If not provided,
-a default metadata object will be generated automatically based on asset-name, decimals and image.
-For more details refer to [https://arc.algorand.foundation/ARCs/arc-0003#json-metadata-file-schema](https://arc.algorand.foundation/ARCs/arc-0003#json-metadata-file-schema).
-
-
-### --mutable, --immutable
-Whether the asset should be mutable or immutable. Refers to ARC19 by default.
-
-
-### -n, --network
-Network to use. Refers to localnet by default.
-
-
-* **Options**
-
- localnet | testnet | mainnet
-
-
-### nfd-lookup
-
-Perform a lookup via NFD domain or address, returning the associated address or domain respectively.
-
-```shell
-algokit task nfd-lookup [OPTIONS] VALUE
-```
-
-### Options
-
-
-### -o, --output
-Output format for NFD API response. Defaults to address|domain resolved.
-
-
-* **Options**
-
- full | tiny | address
-
-
-### Arguments
-
-
-### VALUE
-Required argument
-
-### opt-in
-
-Opt-in to an asset(s). This is required before you can receive an asset. Use -n to specify localnet, testnet, or mainnet. To supply multiple asset IDs, separate them with a whitespace.
-
-```shell
-algokit task opt-in [OPTIONS] ASSET_IDS...
-```
-
-### Options
-
-
-### -a, --account
-**Required** Address or alias of the signer account.
-
-
-### -n, --network
-Network to use. Refers to localnet by default.
-
-
-* **Options**
-
- localnet | testnet | mainnet
-
-
-### Arguments
-
-
-### ASSET_IDS
-Required argument(s)
-
-### opt-out
-
-opt-out of an asset(s). You can only opt out of an asset with a zero balance. Use -n to specify localnet, testnet, or mainnet. To supply multiple asset IDs, separate them with a whitespace.
-
-```shell
-algokit task opt-out [OPTIONS] [ASSET_IDS]...
-```
-
-### Options
-
-
-### -a, --account
-**Required** Address or alias of the signer account.
-
-
-### --all
-Opt-out of all assets with zero balance.
-
-
-### -n, --network
-Network to use. Refers to localnet by default.
-
-
-* **Options**
-
- localnet | testnet | mainnet
-
-
-### Arguments
-
-
-### ASSET_IDS
-Optional argument(s)
-
-### send
-
-Send a signed transaction to the given network.
-
-```shell
-algokit task send [OPTIONS]
-```
-
-### Options
-
-
-### -f, --file
-Single or multiple message pack encoded signed transactions from binary file to send. Option is mutually exclusive with transaction.
-
-
-### -t, --transaction
-Base64 encoded signed transaction to send. Option is mutually exclusive with file.
-
-
-### -n, --network
-Network to use. Refers to localnet by default.
-
-
-* **Options**
-
- localnet | testnet | mainnet
-
-
-### sign
-
-Sign goal clerk compatible Algorand transaction(s).
-
-```shell
-algokit task sign [OPTIONS]
-```
-
-### Options
-
-
-### -a, --account
-**Required** Address or alias of the signer account.
-
-
-### -f, --file
-Single or multiple message pack encoded transactions from binary file to sign. Option is mutually exclusive with transaction.
-
-
-### -t, --transaction
-Single base64 encoded transaction object to sign. Option is mutually exclusive with file.
-
-
-### -o, --output
-The output file path to store signed transaction(s).
-
-
-### --force
-Force signing without confirmation.
-
-### transfer
-
-Transfer algos or assets from one account to another.
-
-```shell
-algokit task transfer [OPTIONS]
-```
-
-### Options
-
-
-### -s, --sender
-**Required** Address or alias of the sender account.
-
-
-### -r, --receiver
-**Required** Address or alias to an account that will receive the asset(s).
-
-
-### --asset, --id
-Asset ID to transfer. Defaults to 0 (Algo).
-
-
-### -a, --amount
-**Required** Amount to transfer.
-
-
-### --whole-units
-Use whole units (Algos | ASAs) instead of smallest divisible units (for example, microAlgos). Disabled by default.
-
-
-### -n, --network
-Network to use. Refers to localnet by default.
-
-
-* **Options**
-
- localnet | testnet | mainnet
-
-
-### vanity-address
-
-Generate a vanity Algorand address. Your KEYWORD can only include letters A - Z and numbers 2 - 7.
-Keeping your KEYWORD under 5 characters will usually result in faster generation.
-Note: The longer the KEYWORD, the longer it may take to generate a matching address.
-Please be patient if you choose a long keyword.
-
-```shell
-algokit task vanity-address [OPTIONS] KEYWORD
-```
-
-### Options
-
-
-### -m, --match
-Location where the keyword will be included. Default is start.
-
-
-* **Options**
-
- start | anywhere | end
-
-
-
-### -o, --output
-How the output will be presented.
-
-
-* **Options**
-
- stdout | alias | file
-
-
-
-### -a, --alias
-Alias for the address. Required if output is "alias".
-
-
-### --file-path
-File path where to dump the output. Required if output is "file".
-
-
-### -f, --force
-Allow overwriting an aliases without confirmation, if output option is 'alias'.
-
-### Arguments
-
-
-### KEYWORD
-Required argument
-
-### wallet
-
-Create short aliases for your addresses and accounts on AlgoKit CLI.
-
-```shell
-algokit task wallet [OPTIONS] COMMAND [ARGS]...
-```
-
-#### add
-
-Add an address or account to be stored against a named alias (at most 50 aliases).
-
-```shell
-algokit task wallet add [OPTIONS] ALIAS_NAME
-```
-
-### Options
-
-
-### -a, --address
-**Required** The address of the account.
-
-
-### -m, --mnemonic
-If specified then prompt the user for a mnemonic phrase interactively using masked input.
-
-
-### -f, --force
-Allow overwriting an existing alias.
-
-### Arguments
-
-
-### ALIAS_NAME
-Required argument
-
-#### get
-
-Get an address or account stored against a named alias.
-
-```shell
-algokit task wallet get [OPTIONS] ALIAS
-```
-
-### Arguments
-
-
-### ALIAS
-Required argument
-
-#### list
-
-List all addresses and accounts stored against a named alias.
-
-```shell
-algokit task wallet list [OPTIONS]
-```
-
-#### remove
-
-Remove an address or account stored against a named alias.
-
-```shell
-algokit task wallet remove [OPTIONS] ALIAS
-```
-
-### Options
-
-
-### -f, --force
-Allow removing an alias without confirmation.
-
-### Arguments
-
-
-### ALIAS
-Required argument
-
-#### reset
-
-Remove all aliases.
-
-```shell
-algokit task wallet reset [OPTIONS]
-```
-
-### Options
-
-
-### -f, --force
-Allow removing all aliases without confirmation.
diff --git a/docs/cli_build.py b/docs/cli_build.py
new file mode 100644
index 000000000..155497a52
--- /dev/null
+++ b/docs/cli_build.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+"""Generate CLI reference markdown from Click source using Sphinx + sphinx-click,
+then post-process the output for Starlight consumption.
+
+Run via: uv run poe docs-cli
+Or directly: uv run --group docs python docs/cli_build.py
+"""
+
+from __future__ import annotations
+
+import re
+import shutil
+import subprocess
+import sys
+from pathlib import Path
+
+DOCS_DIR = Path(__file__).resolve().parent
+REPO_ROOT = DOCS_DIR.parent
+CLI_OUT = DOCS_DIR / "src" / "content" / "docs" / "cli"
+
+
+def _clean_cli_output() -> None:
+ """Remove previous CLI reference output."""
+ print("==> Cleaning previous CLI output...")
+ if CLI_OUT.exists():
+ shutil.rmtree(CLI_OUT)
+ CLI_OUT.mkdir(parents=True, exist_ok=True)
+
+
+def _run_sphinx_build() -> None:
+ """Run Sphinx markdown build to generate CLI reference docs."""
+ print("==> Running Sphinx + sphinx-click build...")
+ result = subprocess.run(
+ [
+ "uv",
+ "run",
+ "--group",
+ "docs",
+ "sphinx-build",
+ "-b",
+ "markdown",
+ "-E", # force fresh build (don't reuse cached environment)
+ "-q", # quiet
+ "docs/sphinx",
+ str(CLI_OUT),
+ ],
+ check=False,
+ cwd=str(REPO_ROOT),
+ capture_output=True,
+ text=True,
+ )
+ if result.returncode != 0:
+ print(f"ERROR: Sphinx build failed (exit code {result.returncode})", file=sys.stderr)
+ if result.stderr:
+ print(result.stderr, file=sys.stderr)
+ if result.stdout:
+ print(result.stdout, file=sys.stderr)
+ sys.exit(1)
+
+
+def _remove_sphinx_artifacts() -> None:
+ """Remove Sphinx build artifacts not needed by Starlight."""
+ print("==> Removing Sphinx artifacts...")
+ for name in [".buildinfo"]:
+ p = CLI_OUT / name
+ if p.exists():
+ p.unlink()
+ doctrees = CLI_OUT / ".doctrees"
+ if doctrees.exists():
+ shutil.rmtree(doctrees)
+
+
+def _inject_frontmatter() -> None:
+ """Inject Starlight frontmatter into the generated CLI reference page."""
+ print("==> Injecting Starlight frontmatter...")
+ index_md = CLI_OUT / "index.md"
+ if not index_md.exists():
+ print("ERROR: Expected index.md not found after Sphinx build.", file=sys.stderr)
+ sys.exit(1)
+
+ content = index_md.read_text(encoding="utf-8")
+
+ # Extract title from H1 if present, otherwise use a default
+ title = "AlgoKit CLI Reference"
+ h1_match = re.match(r"^#\s+(.+)$", content, re.MULTILINE)
+ if h1_match:
+ title = h1_match.group(1).strip()
+ # Strip the H1 line — Starlight renders frontmatter title as H1
+ content = re.sub(r"^#\s+[^\n]+\n(\n)?", "", content, count=1)
+
+ escaped_title = title.replace('"', '\\"')
+ index_md.write_text(
+ f'---\ntitle: "{escaped_title}"\n---\n\n{content}',
+ encoding="utf-8",
+ )
+
+
+def main() -> None:
+ """Run the full CLI docs build pipeline."""
+ _clean_cli_output()
+ _run_sphinx_build()
+ _remove_sphinx_artifacts()
+ _inject_frontmatter()
+
+ file_count = sum(1 for _ in CLI_OUT.rglob("*.md"))
+ print(f"==> CLI reference generated at: {CLI_OUT}")
+ print(f" {file_count} markdown file(s)")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/docs/features/compile.md b/docs/features/compile.md
index e339a7cb5..90b3a5c49 100644
--- a/docs/features/compile.md
+++ b/docs/features/compile.md
@@ -83,7 +83,7 @@ Any errors detected by PuyaPy during the compilation process will be printed to
PuyaPy requires Python 3.12+, so please ensure your Python version satisfies this requirement.
-This command will attempt to resolve a matching installed PuyaPy compiler, either globally installed in the system or locally installed in your project (via [Poetry](https://python-poetry.org/)). If no appropriate match is found, the PuyaPy compiler will be dynamically run using [pipx](https://pipx.pypa.io/stable/). In this case pipx is also required.
+This command will attempt to resolve a matching installed PuyaPy compiler, either globally installed in the system or locally installed in your project (via [uv](https://docs.astral.sh/uv/) or [Poetry](https://python-poetry.org/)). If no appropriate match is found, the PuyaPy compiler will be dynamically run using [uv](https://docs.astral.sh/uv/) (or [pipx](https://pipx.pypa.io/stable/) as a fallback).
#### Examples
diff --git a/docs/features/doctor.md b/docs/features/doctor.md
index da4dfb241..bd002ea64 100644
--- a/docs/features/doctor.md
+++ b/docs/features/doctor.md
@@ -8,7 +8,7 @@ The AlgoKit Doctor allows you to make sure that your system has the correct depe
Please run this command to if you are facing an issue running AlgoKit. It is recommended to run it before [submitting an issue to AlgoKit](https://github.com/algorandfoundation/algokit-cli/issues/new). You can copy the contents of the Doctor command message (in Markdown format) to your clipboard by providing the `-c` flag to the command as follows `algokit doctor -c`.
-> NOTE: You can also use the `--verbose` or `-v` flag to show additional information including package dependencies of the AlgoKit CLI: `algokit -v doctor`. This only works when `algokit` is installed as a Python package (e.g., via `pipx install algokit`).
+> NOTE: You can also use the `--verbose` or `-v` flag to show additional information including package dependencies of the AlgoKit CLI: `algokit -v doctor`. This only works when `algokit` is installed as a Python package (e.g., via `uv tool install algokit`).
# Examples
@@ -17,19 +17,17 @@ For example, running `algokit doctor` with all prerequisites installed will resu
```
$ ~ algokit doctor
timestamp: 2023-03-29T03:58:05+00:00
-AlgoKit: 0.6.0
-AlgoKit Python: 3.11.2 (main, Mar 24 2023, 00:16:47) [Clang 14.0.0 (clang-1400.0.29.202)] (location: /Users/algokit/.local/pipx/venvs/algokit)
-OS: macOS-13.2.1-arm64-arm-64bit
-docker: 20.10.22
-docker compose: 2.15.1
-git: 2.39.1
-python: 3.10.9 (location: /Users/algokit/.asdf/shims/python)
-python3: 3.10.9 (location: /Users/algokit/.asdf/shims/python3)
-pipx: 1.2.0
-poetry: 1.3.2
-node: 18.12.1
-npm: 8.19.2
-brew: 4.0.10-34-gb753315
+AlgoKit: 2.10.2
+AlgoKit Python: 3.12.11 (location: ~/.local/share/uv/tools/algokit)
+OS: macOS-15.0-arm64-arm-64bit
+docker: 27.5.1
+docker compose: 2.32.4
+git: 2.47.0
+python: 3.12.11 (location: ~/.local/share/uv/python/cpython-3.12.11)
+python3: 3.12.11 (location: ~/.local/share/uv/python/cpython-3.12.11)
+uv: 0.10.7
+node: 22.14.0
+npm: 10.9.2
If you are experiencing a problem with AlgoKit, feel free to submit an issue via:
https://github.com/algorandfoundation/algokit-cli/issues/new
diff --git a/docs/features/generate.md b/docs/features/generate.md
index aba6ff883..0a94f97d0 100644
--- a/docs/features/generate.md
+++ b/docs/features/generate.md
@@ -8,7 +8,7 @@ The `algokit generate client` [command](../cli/index.md#client) can be used to g
### Prerequisites
-To generate Python clients an installation of pip and pipx is required.
+To generate Python clients an installation of Python and uv (or pipx) is required.
To generate TypeScript clients an installation of Node.js and npx is also required.
Each generated client will also have a dependency on `algokit-utils` libraries for the target language.
@@ -33,7 +33,7 @@ If you want to ensure typed client output stability across different environment
To make use of this feature, pass `-v`, `--version`, for example `algokit generate client --version 1.2.3 path/to/application.json`.
-Alternatively, you can achieve output stability by installing the underlying [Python](https://github.com/algorandfoundation/algokit-client-generator-py) or [TypeScript](https://github.com/algorandfoundation/algokit-client-generator-ts) client generator package either locally in your project (via `poetry` or `npm` respectively) or globally on your system (via `pipx` or `npm` respectively). AlgoKit will search for a matching installed version before dynamically resolving.
+Alternatively, you can achieve output stability by installing the underlying [Python](https://github.com/algorandfoundation/algokit-client-generator-py) or [TypeScript](https://github.com/algorandfoundation/algokit-client-generator-ts) client generator package either locally in your project (via `uv` or `npm` respectively) or globally on your system (via `uv tool` or `npm` respectively). AlgoKit will search for a matching installed version before dynamically resolving.
### Usage
diff --git a/docs/features/tasks.md b/docs/features/tasks.md
deleted file mode 100644
index 9e4c286b6..000000000
--- a/docs/features/tasks.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# AlgoKit Tasks
-
-AlgoKit Tasks are a collection of handy tasks that can be used to perform various operations on Algorand blockchain.
-
-## Features
-
-- [Wallet Aliasing](./tasks/wallet.md) - Manage your Algorand addresses and accounts effortlessly with the AlgoKit Wallet feature. This feature allows you to create short aliases for your addresses and accounts on AlgoKit CLI.
-- [Vanity Address Generation](./tasks/vanity_address.md) - Generate vanity addresses for your Algorand accounts with the AlgoKit Vanity feature. This feature allows you to generate Algorand addresses which contains a specific keyword of your choice.
-- [Transfer Assets or Algos](./tasks/transfer.md) - Transfer Algos or Assets from one account to another with the AlgoKit Transfer feature. This feature allows you to transfer Algos or Assets from one account to another on Algorand blockchain.
-- [Opt-(in|out) Assets](./tasks/opt.md) - Opt-in or opt-out of Algorand Asset(s). Supports single or multiple assets.
-- [Signing transactions](./tasks/sign.md) - Sign goal clerk compatible Algorand transactions.
-- [Sending transactions](./tasks/send.md) - Send signed goal clerk compatible Algorand transactions.
-- [NFD lookups](./tasks/nfd.md) - Perform a lookup via NFD domain or address, returning the associated address or domain respectively using the AlgoKit CLI.
-- [IPFS uploads](./tasks/ipfs.md) - Upload files to IPFS.
-- [Asset minting](./tasks/mint.md) - Mint new fungible or non-fungible assets on Algorand.
-- [Analyze TEAL code](./tasks/analyze.md) - Analyze TEAL code using [`tealer`](https://github.com/crytic/tealer) integration for common vulnerabilities.
diff --git a/docs/package.json b/docs/package.json
new file mode 100644
index 000000000..aaf1c26ed
--- /dev/null
+++ b/docs/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "docs",
+ "type": "module",
+ "version": "0.0.1",
+ "scripts": {
+ "dev": "astro dev",
+ "start": "astro dev",
+ "build": "astro build",
+ "preview": "astro preview",
+ "astro": "astro"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "dependencies": {
+ "@astrojs/starlight": "^0.37.6",
+ "astro": "^5.6.1",
+ "remark-github-alerts": "^0.1.1",
+ "sharp": "^0.34.2"
+ }
+}
diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml
new file mode 100644
index 000000000..4baff2b3b
--- /dev/null
+++ b/docs/pnpm-lock.yaml
@@ -0,0 +1,4409 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ '@astrojs/starlight':
+ specifier: ^0.37.6
+ version: 0.37.7(astro@5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3))
+ astro:
+ specifier: ^5.6.1
+ version: 5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3)
+ remark-github-alerts:
+ specifier: ^0.1.1
+ version: 0.1.1(@types/mdast@4.0.4)(unified@11.0.5)
+ sharp:
+ specifier: ^0.34.2
+ version: 0.34.5
+
+packages:
+
+ '@astrojs/compiler@2.13.1':
+ resolution: {integrity: sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==}
+
+ '@astrojs/internal-helpers@0.7.6':
+ resolution: {integrity: sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==}
+
+ '@astrojs/markdown-remark@6.3.11':
+ resolution: {integrity: sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ==}
+
+ '@astrojs/mdx@4.3.14':
+ resolution: {integrity: sha512-FBrqJQORVm+rkRa2TS5CjU9PBA6hkhrwLVBSS9A77gN2+iehvjq1w6yya/d0YKC7osiVorKkr3Qd9wNbl0ZkGA==}
+ engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
+ peerDependencies:
+ astro: ^5.0.0
+
+ '@astrojs/prism@3.3.0':
+ resolution: {integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==}
+ engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
+
+ '@astrojs/sitemap@3.7.1':
+ resolution: {integrity: sha512-IzQqdTeskaMX+QDZCzMuJIp8A8C1vgzMBp/NmHNnadepHYNHcxQdGLQZYfkbd2EbRXUfOS+UDIKx8sKg0oWVdw==}
+
+ '@astrojs/starlight@0.37.7':
+ resolution: {integrity: sha512-KyBnou8aKIlPJUSNx6a1SN7XyH22oj/VAvTGC+Edld4Bnei1A//pmCRTBvSrSeoGrdUjK0ErFUfaEhhO1bPfDg==}
+ peerDependencies:
+ astro: ^5.5.0
+
+ '@astrojs/telemetry@3.3.0':
+ resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==}
+ engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.28.5':
+ resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.29.0':
+ resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/runtime@7.28.6':
+ resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.29.0':
+ resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
+ engines: {node: '>=6.9.0'}
+
+ '@capsizecss/unpack@4.0.0':
+ resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==}
+ engines: {node: '>=18'}
+
+ '@ctrl/tinycolor@4.2.0':
+ resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==}
+ engines: {node: '>=14'}
+
+ '@emnapi/runtime@1.8.1':
+ resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==}
+
+ '@esbuild/aix-ppc64@0.25.12':
+ resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/aix-ppc64@0.27.3':
+ resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.25.12':
+ resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm64@0.27.3':
+ resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.25.12':
+ resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-arm@0.27.3':
+ resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.25.12':
+ resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/android-x64@0.27.3':
+ resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.25.12':
+ resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-arm64@0.27.3':
+ resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.25.12':
+ resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.27.3':
+ resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.25.12':
+ resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-arm64@0.27.3':
+ resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.25.12':
+ resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.27.3':
+ resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.25.12':
+ resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm64@0.27.3':
+ resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.25.12':
+ resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.27.3':
+ resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.25.12':
+ resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.27.3':
+ resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.25.12':
+ resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.27.3':
+ resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.25.12':
+ resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.27.3':
+ resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.25.12':
+ resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.27.3':
+ resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.25.12':
+ resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.27.3':
+ resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.25.12':
+ resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.27.3':
+ resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.25.12':
+ resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.27.3':
+ resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-arm64@0.25.12':
+ resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-arm64@0.27.3':
+ resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.25.12':
+ resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.27.3':
+ resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.25.12':
+ resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-arm64@0.27.3':
+ resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.25.12':
+ resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.27.3':
+ resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/openharmony-arm64@0.25.12':
+ resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@esbuild/openharmony-arm64@0.27.3':
+ resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@esbuild/sunos-x64@0.25.12':
+ resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/sunos-x64@0.27.3':
+ resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.25.12':
+ resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-arm64@0.27.3':
+ resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.25.12':
+ resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.27.3':
+ resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.25.12':
+ resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.27.3':
+ resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
+ '@expressive-code/core@0.41.7':
+ resolution: {integrity: sha512-ck92uZYZ9Wba2zxkiZLsZGi9N54pMSAVdrI9uW3Oo9AtLglD5RmrdTwbYPCT2S/jC36JGB2i+pnQtBm/Ib2+dg==}
+
+ '@expressive-code/plugin-frames@0.41.7':
+ resolution: {integrity: sha512-diKtxjQw/979cTglRFaMCY/sR6hWF0kSMg8jsKLXaZBSfGS0I/Hoe7Qds3vVEgeoW+GHHQzMcwvgx/MOIXhrTA==}
+
+ '@expressive-code/plugin-shiki@0.41.7':
+ resolution: {integrity: sha512-DL605bLrUOgqTdZ0Ot5MlTaWzppRkzzqzeGEu7ODnHF39IkEBbFdsC7pbl3LbUQ1DFtnfx6rD54k/cdofbW6KQ==}
+
+ '@expressive-code/plugin-text-markers@0.41.7':
+ resolution: {integrity: sha512-Ewpwuc5t6eFdZmWlFyeuy3e1PTQC0jFvw2Q+2bpcWXbOZhPLsT7+h8lsSIJxb5mS7wZko7cKyQ2RLYDyK6Fpmw==}
+
+ '@img/colour@1.1.0':
+ resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
+ engines: {node: '>=18'}
+
+ '@img/sharp-darwin-arm64@0.34.5':
+ resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-darwin-x64@0.34.5':
+ resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-arm64@1.2.4':
+ resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-x64@1.2.4':
+ resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-linux-arm64@1.2.4':
+ resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linux-arm@1.2.4':
+ resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linux-ppc64@1.2.4':
+ resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linux-riscv64@1.2.4':
+ resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linux-s390x@1.2.4':
+ resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linux-x64@1.2.4':
+ resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.2.4':
+ resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@img/sharp-libvips-linuxmusl-x64@1.2.4':
+ resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@img/sharp-linux-arm64@0.34.5':
+ resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linux-arm@0.34.5':
+ resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linux-ppc64@0.34.5':
+ resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linux-riscv64@0.34.5':
+ resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linux-s390x@0.34.5':
+ resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linux-x64@0.34.5':
+ resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linuxmusl-arm64@0.34.5':
+ resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@img/sharp-linuxmusl-x64@0.34.5':
+ resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@img/sharp-wasm32@0.34.5':
+ resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [wasm32]
+
+ '@img/sharp-win32-arm64@0.34.5':
+ resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@img/sharp-win32-ia32@0.34.5':
+ resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@img/sharp-win32-x64@0.34.5':
+ resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@mdx-js/mdx@3.1.1':
+ resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==}
+
+ '@oslojs/encoding@1.1.0':
+ resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
+
+ '@pagefind/darwin-arm64@1.4.0':
+ resolution: {integrity: sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@pagefind/darwin-x64@1.4.0':
+ resolution: {integrity: sha512-e7JPIS6L9/cJfow+/IAqknsGqEPjJnVXGjpGm25bnq+NPdoD3c/7fAwr1OXkG4Ocjx6ZGSCijXEV4ryMcH2E3A==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@pagefind/default-ui@1.4.0':
+ resolution: {integrity: sha512-wie82VWn3cnGEdIjh4YwNESyS1G6vRHwL6cNjy9CFgNnWW/PGRjsLq300xjVH5sfPFK3iK36UxvIBymtQIEiSQ==}
+
+ '@pagefind/freebsd-x64@1.4.0':
+ resolution: {integrity: sha512-WcJVypXSZ+9HpiqZjFXMUobfFfZZ6NzIYtkhQ9eOhZrQpeY5uQFqNWLCk7w9RkMUwBv1HAMDW3YJQl/8OqsV0Q==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@pagefind/linux-arm64@1.4.0':
+ resolution: {integrity: sha512-PIt8dkqt4W06KGmQjONw7EZbhDF+uXI7i0XtRLN1vjCUxM9vGPdtJc2mUyVPevjomrGz5M86M8bqTr6cgDp1Uw==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@pagefind/linux-x64@1.4.0':
+ resolution: {integrity: sha512-z4oddcWwQ0UHrTHR8psLnVlz6USGJ/eOlDPTDYZ4cI8TK8PgwRUPQZp9D2iJPNIPcS6Qx/E4TebjuGJOyK8Mmg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@pagefind/windows-x64@1.4.0':
+ resolution: {integrity: sha512-NkT+YAdgS2FPCn8mIA9bQhiBs+xmniMGq1LFPDhcFn0+2yIUEiIG06t7bsZlhdjknEQRTSdT7YitP6fC5qwP0g==}
+ cpu: [x64]
+ os: [win32]
+
+ '@rollup/pluginutils@5.3.0':
+ resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
+ '@rollup/rollup-android-arm-eabi@4.59.0':
+ resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.59.0':
+ resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.59.0':
+ resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.59.0':
+ resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.59.0':
+ resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.59.0':
+ resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.59.0':
+ resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.59.0':
+ resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==}
+ cpu: [arm]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-arm64-gnu@4.59.0':
+ resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-arm64-musl@4.59.0':
+ resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-loong64-gnu@4.59.0':
+ resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==}
+ cpu: [loong64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-loong64-musl@4.59.0':
+ resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==}
+ cpu: [loong64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.59.0':
+ resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-ppc64-musl@4.59.0':
+ resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.59.0':
+ resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-riscv64-musl@4.59.0':
+ resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-s390x-gnu@4.59.0':
+ resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-x64-gnu@4.59.0':
+ resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-x64-musl@4.59.0':
+ resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-openbsd-x64@4.59.0':
+ resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@rollup/rollup-openharmony-arm64@4.59.0':
+ resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rollup/rollup-win32-arm64-msvc@4.59.0':
+ resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.59.0':
+ resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-gnu@4.59.0':
+ resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.59.0':
+ resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@shikijs/core@3.23.0':
+ resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==}
+
+ '@shikijs/engine-javascript@3.23.0':
+ resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==}
+
+ '@shikijs/engine-oniguruma@3.23.0':
+ resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==}
+
+ '@shikijs/langs@3.23.0':
+ resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==}
+
+ '@shikijs/themes@3.23.0':
+ resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==}
+
+ '@shikijs/types@3.23.0':
+ resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==}
+
+ '@shikijs/vscode-textmate@10.0.2':
+ resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
+
+ '@types/debug@4.1.12':
+ resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
+
+ '@types/estree-jsx@1.0.5':
+ resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
+
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+ '@types/hast@3.0.4':
+ resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
+
+ '@types/js-yaml@4.0.9':
+ resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==}
+
+ '@types/mdast@4.0.4':
+ resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
+
+ '@types/mdx@2.0.13':
+ resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==}
+
+ '@types/ms@2.1.0':
+ resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
+
+ '@types/nlcst@2.0.3':
+ resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==}
+
+ '@types/node@24.12.0':
+ resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==}
+
+ '@types/sax@1.2.7':
+ resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
+
+ '@types/unist@2.0.11':
+ resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
+
+ '@types/unist@3.0.3':
+ resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+
+ '@ungap/structured-clone@1.3.0':
+ resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
+
+ acorn-jsx@5.3.2:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ acorn@8.16.0:
+ resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ ansi-align@3.0.1:
+ resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
+
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ ansi-regex@6.2.2:
+ resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==}
+ engines: {node: '>=12'}
+
+ ansi-styles@6.2.3:
+ resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
+ engines: {node: '>=12'}
+
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+
+ arg@5.0.2:
+ resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ aria-query@5.3.2:
+ resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
+ engines: {node: '>= 0.4'}
+
+ array-iterate@2.0.1:
+ resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==}
+
+ astring@1.9.0:
+ resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==}
+ hasBin: true
+
+ astro-expressive-code@0.41.7:
+ resolution: {integrity: sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ==}
+ peerDependencies:
+ astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta
+
+ astro@5.18.1:
+ resolution: {integrity: sha512-m4VWilWZ+Xt6NPoYzC4CgGZim/zQUO7WFL0RHCH0AiEavF1153iC3+me2atDvXpf/yX4PyGUeD8wZLq1cirT3g==}
+ engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'}
+ hasBin: true
+
+ axobject-query@4.1.0:
+ resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
+ engines: {node: '>= 0.4'}
+
+ bail@2.0.2:
+ resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
+
+ base-64@1.0.0:
+ resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==}
+
+ bcp-47-match@2.0.3:
+ resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==}
+
+ bcp-47@2.1.0:
+ resolution: {integrity: sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==}
+
+ boolbase@1.0.0:
+ resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+
+ boxen@8.0.1:
+ resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==}
+ engines: {node: '>=18'}
+
+ camelcase@8.0.0:
+ resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==}
+ engines: {node: '>=16'}
+
+ ccount@2.0.1:
+ resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
+
+ chalk@5.6.2:
+ resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==}
+ engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+
+ character-entities-html4@2.1.0:
+ resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
+
+ character-entities-legacy@3.0.0:
+ resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
+
+ character-entities@2.0.2:
+ resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
+
+ character-reference-invalid@2.0.1:
+ resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
+
+ chokidar@5.0.0:
+ resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
+ engines: {node: '>= 20.19.0'}
+
+ ci-info@4.4.0:
+ resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==}
+ engines: {node: '>=8'}
+
+ cli-boxes@3.0.0:
+ resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
+ engines: {node: '>=10'}
+
+ clsx@2.1.1:
+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
+ engines: {node: '>=6'}
+
+ collapse-white-space@2.1.0:
+ resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==}
+
+ comma-separated-tokens@2.0.3:
+ resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
+
+ commander@11.1.0:
+ resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
+ engines: {node: '>=16'}
+
+ common-ancestor-path@1.0.1:
+ resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==}
+
+ cookie-es@1.2.2:
+ resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==}
+
+ cookie@1.1.1:
+ resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
+ engines: {node: '>=18'}
+
+ crossws@0.3.5:
+ resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==}
+
+ css-select@5.2.2:
+ resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
+
+ css-selector-parser@3.3.0:
+ resolution: {integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==}
+
+ css-tree@2.2.1:
+ resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+
+ css-tree@3.2.1:
+ resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
+ css-what@6.2.2:
+ resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
+ engines: {node: '>= 6'}
+
+ cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ csso@5.0.5:
+ resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ decode-named-character-reference@1.3.0:
+ resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==}
+
+ defu@6.1.4:
+ resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
+
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
+ destr@2.0.5:
+ resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
+
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
+ deterministic-object-hash@2.0.2:
+ resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==}
+ engines: {node: '>=18'}
+
+ devalue@5.6.3:
+ resolution: {integrity: sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==}
+
+ devlop@1.1.0:
+ resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
+
+ diff@8.0.3:
+ resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==}
+ engines: {node: '>=0.3.1'}
+
+ direction@2.0.1:
+ resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==}
+ hasBin: true
+
+ dlv@1.1.3:
+ resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
+
+ dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+ domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+ domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+
+ domutils@3.2.2:
+ resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
+
+ dset@3.1.4:
+ resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
+ engines: {node: '>=4'}
+
+ emoji-regex@10.6.0:
+ resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
+
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
+ entities@6.0.1:
+ resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
+ engines: {node: '>=0.12'}
+
+ es-module-lexer@1.7.0:
+ resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
+
+ esast-util-from-estree@2.0.0:
+ resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==}
+
+ esast-util-from-js@2.0.1:
+ resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==}
+
+ esbuild@0.25.12:
+ resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ esbuild@0.27.3:
+ resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ escape-string-regexp@5.0.0:
+ resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
+ engines: {node: '>=12'}
+
+ estree-util-attach-comments@3.0.0:
+ resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==}
+
+ estree-util-build-jsx@3.0.1:
+ resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==}
+
+ estree-util-is-identifier-name@3.0.0:
+ resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==}
+
+ estree-util-scope@1.0.0:
+ resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==}
+
+ estree-util-to-js@2.0.0:
+ resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==}
+
+ estree-util-visit@2.0.0:
+ resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==}
+
+ estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+ estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
+ eventemitter3@5.0.4:
+ resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
+
+ expressive-code@0.41.7:
+ resolution: {integrity: sha512-2wZjC8OQ3TaVEMcBtYY4Va3lo6J+Ai9jf3d4dbhURMJcU4Pbqe6EcHe424MIZI0VHUA1bR6xdpoHYi3yxokWqA==}
+
+ extend@3.0.2:
+ resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ flattie@1.1.1:
+ resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==}
+ engines: {node: '>=8'}
+
+ fontace@0.4.1:
+ resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==}
+
+ fontkitten@1.0.3:
+ resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==}
+ engines: {node: '>=20'}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ get-east-asian-width@1.5.0:
+ resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==}
+ engines: {node: '>=18'}
+
+ github-slugger@2.0.0:
+ resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
+
+ h3@1.15.6:
+ resolution: {integrity: sha512-oi15ESLW5LRthZ+qPCi5GNasY/gvynSKUQxgiovrY63bPAtG59wtM+LSrlcwvOHAXzGrXVLnI97brbkdPF9WoQ==}
+
+ hast-util-embedded@3.0.0:
+ resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==}
+
+ hast-util-format@1.1.0:
+ resolution: {integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==}
+
+ hast-util-from-html@2.0.3:
+ resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==}
+
+ hast-util-from-parse5@8.0.3:
+ resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==}
+
+ hast-util-has-property@3.0.0:
+ resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==}
+
+ hast-util-is-body-ok-link@3.0.1:
+ resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==}
+
+ hast-util-is-element@3.0.0:
+ resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==}
+
+ hast-util-minify-whitespace@1.0.1:
+ resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==}
+
+ hast-util-parse-selector@4.0.0:
+ resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
+
+ hast-util-phrasing@3.0.1:
+ resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==}
+
+ hast-util-raw@9.1.0:
+ resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==}
+
+ hast-util-select@6.0.4:
+ resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==}
+
+ hast-util-to-estree@3.1.3:
+ resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==}
+
+ hast-util-to-html@9.0.5:
+ resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
+
+ hast-util-to-jsx-runtime@2.3.6:
+ resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==}
+
+ hast-util-to-parse5@8.0.1:
+ resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==}
+
+ hast-util-to-string@3.0.1:
+ resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==}
+
+ hast-util-to-text@4.0.2:
+ resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==}
+
+ hast-util-whitespace@3.0.0:
+ resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
+
+ hastscript@9.0.1:
+ resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==}
+
+ html-escaper@3.0.3:
+ resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==}
+
+ html-void-elements@3.0.0:
+ resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
+
+ html-whitespace-sensitive-tag-names@3.0.1:
+ resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==}
+
+ http-cache-semantics@4.2.0:
+ resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==}
+
+ i18next@23.16.8:
+ resolution: {integrity: sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==}
+
+ import-meta-resolve@4.2.0:
+ resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==}
+
+ inline-style-parser@0.2.7:
+ resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
+
+ iron-webcrypto@1.2.1:
+ resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
+
+ is-alphabetical@2.0.1:
+ resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==}
+
+ is-alphanumerical@2.0.1:
+ resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==}
+
+ is-decimal@2.0.1:
+ resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
+
+ is-docker@3.0.0:
+ resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ hasBin: true
+
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ is-hexadecimal@2.0.1:
+ resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==}
+
+ is-inside-container@1.0.0:
+ resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
+ engines: {node: '>=14.16'}
+ hasBin: true
+
+ is-plain-obj@4.1.0:
+ resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
+ engines: {node: '>=12'}
+
+ is-wsl@3.1.1:
+ resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==}
+ engines: {node: '>=16'}
+
+ js-yaml@4.1.1:
+ resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
+ hasBin: true
+
+ kleur@3.0.3:
+ resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
+ engines: {node: '>=6'}
+
+ klona@2.0.6:
+ resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==}
+ engines: {node: '>= 8'}
+
+ longest-streak@3.1.0:
+ resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
+
+ lru-cache@11.2.6:
+ resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==}
+ engines: {node: 20 || >=22}
+
+ magic-string@0.30.21:
+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+
+ magicast@0.5.2:
+ resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==}
+
+ markdown-extensions@2.0.0:
+ resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==}
+ engines: {node: '>=16'}
+
+ markdown-table@3.0.4:
+ resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
+
+ mdast-util-definitions@6.0.0:
+ resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==}
+
+ mdast-util-directive@3.1.0:
+ resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==}
+
+ mdast-util-find-and-replace@3.0.2:
+ resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==}
+
+ mdast-util-from-markdown@2.0.3:
+ resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==}
+
+ mdast-util-gfm-autolink-literal@2.0.1:
+ resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==}
+
+ mdast-util-gfm-footnote@2.1.0:
+ resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==}
+
+ mdast-util-gfm-strikethrough@2.0.0:
+ resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==}
+
+ mdast-util-gfm-table@2.0.0:
+ resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==}
+
+ mdast-util-gfm-task-list-item@2.0.0:
+ resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==}
+
+ mdast-util-gfm@3.1.0:
+ resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==}
+
+ mdast-util-mdx-expression@2.0.1:
+ resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==}
+
+ mdast-util-mdx-jsx@3.2.0:
+ resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==}
+
+ mdast-util-mdx@3.0.0:
+ resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==}
+
+ mdast-util-mdxjs-esm@2.0.1:
+ resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==}
+
+ mdast-util-phrasing@4.1.0:
+ resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
+
+ mdast-util-to-hast@13.2.1:
+ resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==}
+
+ mdast-util-to-markdown@2.1.2:
+ resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==}
+
+ mdast-util-to-string@4.0.0:
+ resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
+
+ mdn-data@2.0.28:
+ resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
+
+ mdn-data@2.27.1:
+ resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
+
+ micromark-core-commonmark@2.0.3:
+ resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
+
+ micromark-extension-directive@3.0.2:
+ resolution: {integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==}
+
+ micromark-extension-gfm-autolink-literal@2.1.0:
+ resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==}
+
+ micromark-extension-gfm-footnote@2.1.0:
+ resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==}
+
+ micromark-extension-gfm-strikethrough@2.1.0:
+ resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==}
+
+ micromark-extension-gfm-table@2.1.1:
+ resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==}
+
+ micromark-extension-gfm-tagfilter@2.0.0:
+ resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==}
+
+ micromark-extension-gfm-task-list-item@2.1.0:
+ resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==}
+
+ micromark-extension-gfm@3.0.0:
+ resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==}
+
+ micromark-extension-mdx-expression@3.0.1:
+ resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==}
+
+ micromark-extension-mdx-jsx@3.0.2:
+ resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==}
+
+ micromark-extension-mdx-md@2.0.0:
+ resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==}
+
+ micromark-extension-mdxjs-esm@3.0.0:
+ resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==}
+
+ micromark-extension-mdxjs@3.0.0:
+ resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==}
+
+ micromark-factory-destination@2.0.1:
+ resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
+
+ micromark-factory-label@2.0.1:
+ resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==}
+
+ micromark-factory-mdx-expression@2.0.3:
+ resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==}
+
+ micromark-factory-space@2.0.1:
+ resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==}
+
+ micromark-factory-title@2.0.1:
+ resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==}
+
+ micromark-factory-whitespace@2.0.1:
+ resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==}
+
+ micromark-util-character@2.1.1:
+ resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==}
+
+ micromark-util-chunked@2.0.1:
+ resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==}
+
+ micromark-util-classify-character@2.0.1:
+ resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==}
+
+ micromark-util-combine-extensions@2.0.1:
+ resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==}
+
+ micromark-util-decode-numeric-character-reference@2.0.2:
+ resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==}
+
+ micromark-util-decode-string@2.0.1:
+ resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==}
+
+ micromark-util-encode@2.0.1:
+ resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==}
+
+ micromark-util-events-to-acorn@2.0.3:
+ resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==}
+
+ micromark-util-html-tag-name@2.0.1:
+ resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==}
+
+ micromark-util-normalize-identifier@2.0.1:
+ resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==}
+
+ micromark-util-resolve-all@2.0.1:
+ resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==}
+
+ micromark-util-sanitize-uri@2.0.1:
+ resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==}
+
+ micromark-util-subtokenize@2.1.0:
+ resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==}
+
+ micromark-util-symbol@2.0.1:
+ resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==}
+
+ micromark-util-types@2.0.2:
+ resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==}
+
+ micromark@4.0.2:
+ resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==}
+
+ mrmime@2.0.1:
+ resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
+ engines: {node: '>=10'}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ neotraverse@0.6.18:
+ resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==}
+ engines: {node: '>= 10'}
+
+ nlcst-to-string@4.0.0:
+ resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==}
+
+ node-fetch-native@1.6.7:
+ resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
+
+ node-mock-http@1.0.4:
+ resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==}
+
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ nth-check@2.1.1:
+ resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
+ ofetch@1.5.1:
+ resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
+
+ ohash@2.0.11:
+ resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
+
+ oniguruma-parser@0.12.1:
+ resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==}
+
+ oniguruma-to-es@4.3.4:
+ resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==}
+
+ p-limit@6.2.0:
+ resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==}
+ engines: {node: '>=18'}
+
+ p-queue@8.1.1:
+ resolution: {integrity: sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==}
+ engines: {node: '>=18'}
+
+ p-timeout@6.1.4:
+ resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==}
+ engines: {node: '>=14.16'}
+
+ package-manager-detector@1.6.0:
+ resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==}
+
+ pagefind@1.4.0:
+ resolution: {integrity: sha512-z2kY1mQlL4J8q5EIsQkLzQjilovKzfNVhX8De6oyE6uHpfFtyBaqUpcl/XzJC/4fjD8vBDyh1zolimIcVrCn9g==}
+ hasBin: true
+
+ parse-entities@4.0.2:
+ resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
+
+ parse-latin@7.0.0:
+ resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==}
+
+ parse5@7.3.0:
+ resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
+
+ piccolore@0.1.3:
+ resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ picomatch@4.0.3:
+ resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ engines: {node: '>=12'}
+
+ postcss-nested@6.2.0:
+ resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==}
+ engines: {node: '>=12.0'}
+ peerDependencies:
+ postcss: ^8.2.14
+
+ postcss-selector-parser@6.1.2:
+ resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
+ engines: {node: '>=4'}
+
+ postcss@8.5.8:
+ resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ prismjs@1.30.0:
+ resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
+ engines: {node: '>=6'}
+
+ prompts@2.4.2:
+ resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
+ engines: {node: '>= 6'}
+
+ property-information@7.1.0:
+ resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
+
+ radix3@1.1.2:
+ resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
+
+ readdirp@5.0.0:
+ resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
+ engines: {node: '>= 20.19.0'}
+
+ recma-build-jsx@1.0.0:
+ resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==}
+
+ recma-jsx@1.0.1:
+ resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ recma-parse@1.0.0:
+ resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==}
+
+ recma-stringify@1.0.0:
+ resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==}
+
+ regex-recursion@6.0.2:
+ resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==}
+
+ regex-utilities@2.3.0:
+ resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==}
+
+ regex@6.1.0:
+ resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==}
+
+ rehype-expressive-code@0.41.7:
+ resolution: {integrity: sha512-25f8ZMSF1d9CMscX7Cft0TSQIqdwjce2gDOvQ+d/w0FovsMwrSt3ODP4P3Z7wO1jsIJ4eYyaDRnIR/27bd/EMQ==}
+
+ rehype-format@5.0.1:
+ resolution: {integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==}
+
+ rehype-parse@9.0.1:
+ resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==}
+
+ rehype-raw@7.0.0:
+ resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==}
+
+ rehype-recma@1.0.0:
+ resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==}
+
+ rehype-stringify@10.0.1:
+ resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==}
+
+ rehype@13.0.2:
+ resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==}
+
+ remark-directive@3.0.1:
+ resolution: {integrity: sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==}
+
+ remark-gfm@4.0.1:
+ resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==}
+
+ remark-github-alerts@0.1.1:
+ resolution: {integrity: sha512-A0NLfeAuu76ymiGIoEoBcHmqlPcdLFq+FoCGiWlzu8vkyhscyDv+pAkMA9paGr+OHpzpFflZKnsqOCvMESG/Uw==}
+ peerDependencies:
+ '@types/mdast': ^4.0.0
+ unified: ^11.0.0
+
+ remark-mdx@3.1.1:
+ resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==}
+
+ remark-parse@11.0.0:
+ resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
+
+ remark-rehype@11.1.2:
+ resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==}
+
+ remark-smartypants@3.0.2:
+ resolution: {integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==}
+ engines: {node: '>=16.0.0'}
+
+ remark-stringify@11.0.0:
+ resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
+
+ retext-latin@4.0.0:
+ resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==}
+
+ retext-smartypants@6.2.0:
+ resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==}
+
+ retext-stringify@4.0.0:
+ resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==}
+
+ retext@9.0.0:
+ resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==}
+
+ rollup@4.59.0:
+ resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ sax@1.5.0:
+ resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==}
+ engines: {node: '>=11.0.0'}
+
+ semver@7.7.4:
+ resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ sharp@0.34.5:
+ resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+
+ shiki@3.23.0:
+ resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==}
+
+ sisteransi@1.0.5:
+ resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+
+ sitemap@9.0.1:
+ resolution: {integrity: sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==}
+ engines: {node: '>=20.19.5', npm: '>=10.8.2'}
+ hasBin: true
+
+ smol-toml@1.6.0:
+ resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==}
+ engines: {node: '>= 18'}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ source-map@0.7.6:
+ resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
+ engines: {node: '>= 12'}
+
+ space-separated-tokens@2.0.2:
+ resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
+
+ stream-replace-string@2.0.0:
+ resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==}
+
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
+ string-width@7.2.0:
+ resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
+ engines: {node: '>=18'}
+
+ stringify-entities@4.0.4:
+ resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
+
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
+ strip-ansi@7.2.0:
+ resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==}
+ engines: {node: '>=12'}
+
+ style-to-js@1.1.21:
+ resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==}
+
+ style-to-object@1.0.14:
+ resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==}
+
+ svgo@4.0.1:
+ resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==}
+ engines: {node: '>=16'}
+ hasBin: true
+
+ tiny-inflate@1.0.3:
+ resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
+
+ tinyexec@1.0.2:
+ resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
+ engines: {node: '>=18'}
+
+ tinyglobby@0.2.15:
+ resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
+ engines: {node: '>=12.0.0'}
+
+ trim-lines@3.0.1:
+ resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
+
+ trough@2.2.0:
+ resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
+
+ tsconfck@3.1.6:
+ resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
+ engines: {node: ^18 || >=20}
+ hasBin: true
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ type-fest@4.41.0:
+ resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
+ engines: {node: '>=16'}
+
+ typescript@5.9.3:
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ ufo@1.6.3:
+ resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
+
+ ultrahtml@1.6.0:
+ resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==}
+
+ uncrypto@0.1.3:
+ resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
+
+ undici-types@7.16.0:
+ resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
+
+ unified@11.0.5:
+ resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
+
+ unifont@0.7.4:
+ resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==}
+
+ unist-util-find-after@5.0.0:
+ resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==}
+
+ unist-util-is@6.0.1:
+ resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==}
+
+ unist-util-modify-children@4.0.0:
+ resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==}
+
+ unist-util-position-from-estree@2.0.0:
+ resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==}
+
+ unist-util-position@5.0.0:
+ resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
+
+ unist-util-remove-position@5.0.0:
+ resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==}
+
+ unist-util-stringify-position@4.0.0:
+ resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
+
+ unist-util-visit-children@3.0.0:
+ resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==}
+
+ unist-util-visit-parents@6.0.2:
+ resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==}
+
+ unist-util-visit@5.1.0:
+ resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==}
+
+ unstorage@1.17.4:
+ resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==}
+ peerDependencies:
+ '@azure/app-configuration': ^1.8.0
+ '@azure/cosmos': ^4.2.0
+ '@azure/data-tables': ^13.3.0
+ '@azure/identity': ^4.6.0
+ '@azure/keyvault-secrets': ^4.9.0
+ '@azure/storage-blob': ^12.26.0
+ '@capacitor/preferences': ^6 || ^7 || ^8
+ '@deno/kv': '>=0.9.0'
+ '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
+ '@planetscale/database': ^1.19.0
+ '@upstash/redis': ^1.34.3
+ '@vercel/blob': '>=0.27.1'
+ '@vercel/functions': ^2.2.12 || ^3.0.0
+ '@vercel/kv': ^1 || ^2 || ^3
+ aws4fetch: ^1.0.20
+ db0: '>=0.2.1'
+ idb-keyval: ^6.2.1
+ ioredis: ^5.4.2
+ uploadthing: ^7.4.4
+ peerDependenciesMeta:
+ '@azure/app-configuration':
+ optional: true
+ '@azure/cosmos':
+ optional: true
+ '@azure/data-tables':
+ optional: true
+ '@azure/identity':
+ optional: true
+ '@azure/keyvault-secrets':
+ optional: true
+ '@azure/storage-blob':
+ optional: true
+ '@capacitor/preferences':
+ optional: true
+ '@deno/kv':
+ optional: true
+ '@netlify/blobs':
+ optional: true
+ '@planetscale/database':
+ optional: true
+ '@upstash/redis':
+ optional: true
+ '@vercel/blob':
+ optional: true
+ '@vercel/functions':
+ optional: true
+ '@vercel/kv':
+ optional: true
+ aws4fetch:
+ optional: true
+ db0:
+ optional: true
+ idb-keyval:
+ optional: true
+ ioredis:
+ optional: true
+ uploadthing:
+ optional: true
+
+ util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+ vfile-location@5.0.3:
+ resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
+
+ vfile-message@4.0.3:
+ resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==}
+
+ vfile@6.0.3:
+ resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
+
+ vite@6.4.1:
+ resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ jiti: '>=1.21.0'
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ vitefu@1.1.2:
+ resolution: {integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==}
+ peerDependencies:
+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0
+ peerDependenciesMeta:
+ vite:
+ optional: true
+
+ web-namespaces@2.0.1:
+ resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
+
+ which-pm-runs@1.1.0:
+ resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==}
+ engines: {node: '>=4'}
+
+ widest-line@5.0.0:
+ resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==}
+ engines: {node: '>=18'}
+
+ wrap-ansi@9.0.2:
+ resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==}
+ engines: {node: '>=18'}
+
+ xxhash-wasm@1.1.0:
+ resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==}
+
+ yargs-parser@21.1.1:
+ resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
+ engines: {node: '>=12'}
+
+ yocto-queue@1.2.2:
+ resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==}
+ engines: {node: '>=12.20'}
+
+ yocto-spinner@0.2.3:
+ resolution: {integrity: sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==}
+ engines: {node: '>=18.19'}
+
+ yoctocolors@2.1.2:
+ resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==}
+ engines: {node: '>=18'}
+
+ zod-to-json-schema@3.25.1:
+ resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==}
+ peerDependencies:
+ zod: ^3.25 || ^4
+
+ zod-to-ts@1.2.0:
+ resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==}
+ peerDependencies:
+ typescript: ^4.9.4 || ^5.0.2
+ zod: ^3
+
+ zod@3.25.76:
+ resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
+
+ zod@4.3.6:
+ resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
+
+ zwitch@2.0.4:
+ resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
+
+snapshots:
+
+ '@astrojs/compiler@2.13.1': {}
+
+ '@astrojs/internal-helpers@0.7.6': {}
+
+ '@astrojs/markdown-remark@6.3.11':
+ dependencies:
+ '@astrojs/internal-helpers': 0.7.6
+ '@astrojs/prism': 3.3.0
+ github-slugger: 2.0.0
+ hast-util-from-html: 2.0.3
+ hast-util-to-text: 4.0.2
+ import-meta-resolve: 4.2.0
+ js-yaml: 4.1.1
+ mdast-util-definitions: 6.0.0
+ rehype-raw: 7.0.0
+ rehype-stringify: 10.0.1
+ remark-gfm: 4.0.1
+ remark-parse: 11.0.0
+ remark-rehype: 11.1.2
+ remark-smartypants: 3.0.2
+ shiki: 3.23.0
+ smol-toml: 1.6.0
+ unified: 11.0.5
+ unist-util-remove-position: 5.0.0
+ unist-util-visit: 5.1.0
+ unist-util-visit-parents: 6.0.2
+ vfile: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@astrojs/mdx@4.3.14(astro@5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3))':
+ dependencies:
+ '@astrojs/markdown-remark': 6.3.11
+ '@mdx-js/mdx': 3.1.1
+ acorn: 8.16.0
+ astro: 5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3)
+ es-module-lexer: 1.7.0
+ estree-util-visit: 2.0.0
+ hast-util-to-html: 9.0.5
+ piccolore: 0.1.3
+ rehype-raw: 7.0.0
+ remark-gfm: 4.0.1
+ remark-smartypants: 3.0.2
+ source-map: 0.7.6
+ unist-util-visit: 5.1.0
+ vfile: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@astrojs/prism@3.3.0':
+ dependencies:
+ prismjs: 1.30.0
+
+ '@astrojs/sitemap@3.7.1':
+ dependencies:
+ sitemap: 9.0.1
+ stream-replace-string: 2.0.0
+ zod: 4.3.6
+
+ '@astrojs/starlight@0.37.7(astro@5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3))':
+ dependencies:
+ '@astrojs/markdown-remark': 6.3.11
+ '@astrojs/mdx': 4.3.14(astro@5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3))
+ '@astrojs/sitemap': 3.7.1
+ '@pagefind/default-ui': 1.4.0
+ '@types/hast': 3.0.4
+ '@types/js-yaml': 4.0.9
+ '@types/mdast': 4.0.4
+ astro: 5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3)
+ astro-expressive-code: 0.41.7(astro@5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3))
+ bcp-47: 2.1.0
+ hast-util-from-html: 2.0.3
+ hast-util-select: 6.0.4
+ hast-util-to-string: 3.0.1
+ hastscript: 9.0.1
+ i18next: 23.16.8
+ js-yaml: 4.1.1
+ klona: 2.0.6
+ magic-string: 0.30.21
+ mdast-util-directive: 3.1.0
+ mdast-util-to-markdown: 2.1.2
+ mdast-util-to-string: 4.0.0
+ pagefind: 1.4.0
+ rehype: 13.0.2
+ rehype-format: 5.0.1
+ remark-directive: 3.0.1
+ ultrahtml: 1.6.0
+ unified: 11.0.5
+ unist-util-visit: 5.1.0
+ vfile: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@astrojs/telemetry@3.3.0':
+ dependencies:
+ ci-info: 4.4.0
+ debug: 4.4.3
+ dlv: 1.1.3
+ dset: 3.1.4
+ is-docker: 3.0.0
+ is-wsl: 3.1.1
+ which-pm-runs: 1.1.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.28.5': {}
+
+ '@babel/parser@7.29.0':
+ dependencies:
+ '@babel/types': 7.29.0
+
+ '@babel/runtime@7.28.6': {}
+
+ '@babel/types@7.29.0':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
+
+ '@capsizecss/unpack@4.0.0':
+ dependencies:
+ fontkitten: 1.0.3
+
+ '@ctrl/tinycolor@4.2.0': {}
+
+ '@emnapi/runtime@1.8.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@esbuild/aix-ppc64@0.25.12':
+ optional: true
+
+ '@esbuild/aix-ppc64@0.27.3':
+ optional: true
+
+ '@esbuild/android-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/android-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/android-arm@0.25.12':
+ optional: true
+
+ '@esbuild/android-arm@0.27.3':
+ optional: true
+
+ '@esbuild/android-x64@0.25.12':
+ optional: true
+
+ '@esbuild/android-x64@0.27.3':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/darwin-x64@0.25.12':
+ optional: true
+
+ '@esbuild/darwin-x64@0.27.3':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.25.12':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.27.3':
+ optional: true
+
+ '@esbuild/linux-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/linux-arm@0.25.12':
+ optional: true
+
+ '@esbuild/linux-arm@0.27.3':
+ optional: true
+
+ '@esbuild/linux-ia32@0.25.12':
+ optional: true
+
+ '@esbuild/linux-ia32@0.27.3':
+ optional: true
+
+ '@esbuild/linux-loong64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-loong64@0.27.3':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.25.12':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.27.3':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.27.3':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.27.3':
+ optional: true
+
+ '@esbuild/linux-s390x@0.25.12':
+ optional: true
+
+ '@esbuild/linux-s390x@0.27.3':
+ optional: true
+
+ '@esbuild/linux-x64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-x64@0.27.3':
+ optional: true
+
+ '@esbuild/netbsd-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/netbsd-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.25.12':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.27.3':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.25.12':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.27.3':
+ optional: true
+
+ '@esbuild/openharmony-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/openharmony-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/sunos-x64@0.25.12':
+ optional: true
+
+ '@esbuild/sunos-x64@0.27.3':
+ optional: true
+
+ '@esbuild/win32-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/win32-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/win32-ia32@0.25.12':
+ optional: true
+
+ '@esbuild/win32-ia32@0.27.3':
+ optional: true
+
+ '@esbuild/win32-x64@0.25.12':
+ optional: true
+
+ '@esbuild/win32-x64@0.27.3':
+ optional: true
+
+ '@expressive-code/core@0.41.7':
+ dependencies:
+ '@ctrl/tinycolor': 4.2.0
+ hast-util-select: 6.0.4
+ hast-util-to-html: 9.0.5
+ hast-util-to-text: 4.0.2
+ hastscript: 9.0.1
+ postcss: 8.5.8
+ postcss-nested: 6.2.0(postcss@8.5.8)
+ unist-util-visit: 5.1.0
+ unist-util-visit-parents: 6.0.2
+
+ '@expressive-code/plugin-frames@0.41.7':
+ dependencies:
+ '@expressive-code/core': 0.41.7
+
+ '@expressive-code/plugin-shiki@0.41.7':
+ dependencies:
+ '@expressive-code/core': 0.41.7
+ shiki: 3.23.0
+
+ '@expressive-code/plugin-text-markers@0.41.7':
+ dependencies:
+ '@expressive-code/core': 0.41.7
+
+ '@img/colour@1.1.0': {}
+
+ '@img/sharp-darwin-arm64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-arm64': 1.2.4
+ optional: true
+
+ '@img/sharp-darwin-x64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-x64': 1.2.4
+ optional: true
+
+ '@img/sharp-libvips-darwin-arm64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-darwin-x64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-ppc64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-riscv64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-s390x@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-x64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-x64@1.2.4':
+ optional: true
+
+ '@img/sharp-linux-arm64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm64': 1.2.4
+ optional: true
+
+ '@img/sharp-linux-arm@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm': 1.2.4
+ optional: true
+
+ '@img/sharp-linux-ppc64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-ppc64': 1.2.4
+ optional: true
+
+ '@img/sharp-linux-riscv64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-riscv64': 1.2.4
+ optional: true
+
+ '@img/sharp-linux-s390x@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-s390x': 1.2.4
+ optional: true
+
+ '@img/sharp-linux-x64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-x64': 1.2.4
+ optional: true
+
+ '@img/sharp-linuxmusl-arm64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-arm64': 1.2.4
+ optional: true
+
+ '@img/sharp-linuxmusl-x64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-x64': 1.2.4
+ optional: true
+
+ '@img/sharp-wasm32@0.34.5':
+ dependencies:
+ '@emnapi/runtime': 1.8.1
+ optional: true
+
+ '@img/sharp-win32-arm64@0.34.5':
+ optional: true
+
+ '@img/sharp-win32-ia32@0.34.5':
+ optional: true
+
+ '@img/sharp-win32-x64@0.34.5':
+ optional: true
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@mdx-js/mdx@3.1.1':
+ dependencies:
+ '@types/estree': 1.0.8
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ '@types/mdx': 2.0.13
+ acorn: 8.16.0
+ collapse-white-space: 2.1.0
+ devlop: 1.1.0
+ estree-util-is-identifier-name: 3.0.0
+ estree-util-scope: 1.0.0
+ estree-walker: 3.0.3
+ hast-util-to-jsx-runtime: 2.3.6
+ markdown-extensions: 2.0.0
+ recma-build-jsx: 1.0.0
+ recma-jsx: 1.0.1(acorn@8.16.0)
+ recma-stringify: 1.0.0
+ rehype-recma: 1.0.0
+ remark-mdx: 3.1.1
+ remark-parse: 11.0.0
+ remark-rehype: 11.1.2
+ source-map: 0.7.6
+ unified: 11.0.5
+ unist-util-position-from-estree: 2.0.0
+ unist-util-stringify-position: 4.0.0
+ unist-util-visit: 5.1.0
+ vfile: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@oslojs/encoding@1.1.0': {}
+
+ '@pagefind/darwin-arm64@1.4.0':
+ optional: true
+
+ '@pagefind/darwin-x64@1.4.0':
+ optional: true
+
+ '@pagefind/default-ui@1.4.0': {}
+
+ '@pagefind/freebsd-x64@1.4.0':
+ optional: true
+
+ '@pagefind/linux-arm64@1.4.0':
+ optional: true
+
+ '@pagefind/linux-x64@1.4.0':
+ optional: true
+
+ '@pagefind/windows-x64@1.4.0':
+ optional: true
+
+ '@rollup/pluginutils@5.3.0(rollup@4.59.0)':
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-walker: 2.0.2
+ picomatch: 4.0.3
+ optionalDependencies:
+ rollup: 4.59.0
+
+ '@rollup/rollup-android-arm-eabi@4.59.0':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.59.0':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.59.0':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.59.0':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.59.0':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-gnu@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-musl@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-gnu@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-musl@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.59.0':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.59.0':
+ optional: true
+
+ '@rollup/rollup-openbsd-x64@4.59.0':
+ optional: true
+
+ '@rollup/rollup-openharmony-arm64@4.59.0':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.59.0':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.59.0':
+ optional: true
+
+ '@rollup/rollup-win32-x64-gnu@4.59.0':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.59.0':
+ optional: true
+
+ '@shikijs/core@3.23.0':
+ dependencies:
+ '@shikijs/types': 3.23.0
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+ hast-util-to-html: 9.0.5
+
+ '@shikijs/engine-javascript@3.23.0':
+ dependencies:
+ '@shikijs/types': 3.23.0
+ '@shikijs/vscode-textmate': 10.0.2
+ oniguruma-to-es: 4.3.4
+
+ '@shikijs/engine-oniguruma@3.23.0':
+ dependencies:
+ '@shikijs/types': 3.23.0
+ '@shikijs/vscode-textmate': 10.0.2
+
+ '@shikijs/langs@3.23.0':
+ dependencies:
+ '@shikijs/types': 3.23.0
+
+ '@shikijs/themes@3.23.0':
+ dependencies:
+ '@shikijs/types': 3.23.0
+
+ '@shikijs/types@3.23.0':
+ dependencies:
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+
+ '@shikijs/vscode-textmate@10.0.2': {}
+
+ '@types/debug@4.1.12':
+ dependencies:
+ '@types/ms': 2.1.0
+
+ '@types/estree-jsx@1.0.5':
+ dependencies:
+ '@types/estree': 1.0.8
+
+ '@types/estree@1.0.8': {}
+
+ '@types/hast@3.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
+ '@types/js-yaml@4.0.9': {}
+
+ '@types/mdast@4.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
+ '@types/mdx@2.0.13': {}
+
+ '@types/ms@2.1.0': {}
+
+ '@types/nlcst@2.0.3':
+ dependencies:
+ '@types/unist': 3.0.3
+
+ '@types/node@24.12.0':
+ dependencies:
+ undici-types: 7.16.0
+
+ '@types/sax@1.2.7':
+ dependencies:
+ '@types/node': 24.12.0
+
+ '@types/unist@2.0.11': {}
+
+ '@types/unist@3.0.3': {}
+
+ '@ungap/structured-clone@1.3.0': {}
+
+ acorn-jsx@5.3.2(acorn@8.16.0):
+ dependencies:
+ acorn: 8.16.0
+
+ acorn@8.16.0: {}
+
+ ansi-align@3.0.1:
+ dependencies:
+ string-width: 4.2.3
+
+ ansi-regex@5.0.1: {}
+
+ ansi-regex@6.2.2: {}
+
+ ansi-styles@6.2.3: {}
+
+ anymatch@3.1.3:
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+
+ arg@5.0.2: {}
+
+ argparse@2.0.1: {}
+
+ aria-query@5.3.2: {}
+
+ array-iterate@2.0.1: {}
+
+ astring@1.9.0: {}
+
+ astro-expressive-code@0.41.7(astro@5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3)):
+ dependencies:
+ astro: 5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3)
+ rehype-expressive-code: 0.41.7
+
+ astro@5.18.1(@types/node@24.12.0)(rollup@4.59.0)(typescript@5.9.3):
+ dependencies:
+ '@astrojs/compiler': 2.13.1
+ '@astrojs/internal-helpers': 0.7.6
+ '@astrojs/markdown-remark': 6.3.11
+ '@astrojs/telemetry': 3.3.0
+ '@capsizecss/unpack': 4.0.0
+ '@oslojs/encoding': 1.1.0
+ '@rollup/pluginutils': 5.3.0(rollup@4.59.0)
+ acorn: 8.16.0
+ aria-query: 5.3.2
+ axobject-query: 4.1.0
+ boxen: 8.0.1
+ ci-info: 4.4.0
+ clsx: 2.1.1
+ common-ancestor-path: 1.0.1
+ cookie: 1.1.1
+ cssesc: 3.0.0
+ debug: 4.4.3
+ deterministic-object-hash: 2.0.2
+ devalue: 5.6.3
+ diff: 8.0.3
+ dlv: 1.1.3
+ dset: 3.1.4
+ es-module-lexer: 1.7.0
+ esbuild: 0.27.3
+ estree-walker: 3.0.3
+ flattie: 1.1.1
+ fontace: 0.4.1
+ github-slugger: 2.0.0
+ html-escaper: 3.0.3
+ http-cache-semantics: 4.2.0
+ import-meta-resolve: 4.2.0
+ js-yaml: 4.1.1
+ magic-string: 0.30.21
+ magicast: 0.5.2
+ mrmime: 2.0.1
+ neotraverse: 0.6.18
+ p-limit: 6.2.0
+ p-queue: 8.1.1
+ package-manager-detector: 1.6.0
+ piccolore: 0.1.3
+ picomatch: 4.0.3
+ prompts: 2.4.2
+ rehype: 13.0.2
+ semver: 7.7.4
+ shiki: 3.23.0
+ smol-toml: 1.6.0
+ svgo: 4.0.1
+ tinyexec: 1.0.2
+ tinyglobby: 0.2.15
+ tsconfck: 3.1.6(typescript@5.9.3)
+ ultrahtml: 1.6.0
+ unifont: 0.7.4
+ unist-util-visit: 5.1.0
+ unstorage: 1.17.4
+ vfile: 6.0.3
+ vite: 6.4.1(@types/node@24.12.0)
+ vitefu: 1.1.2(vite@6.4.1(@types/node@24.12.0))
+ xxhash-wasm: 1.1.0
+ yargs-parser: 21.1.1
+ yocto-spinner: 0.2.3
+ zod: 3.25.76
+ zod-to-json-schema: 3.25.1(zod@3.25.76)
+ zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76)
+ optionalDependencies:
+ sharp: 0.34.5
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@types/node'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - db0
+ - idb-keyval
+ - ioredis
+ - jiti
+ - less
+ - lightningcss
+ - rollup
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - tsx
+ - typescript
+ - uploadthing
+ - yaml
+
+ axobject-query@4.1.0: {}
+
+ bail@2.0.2: {}
+
+ base-64@1.0.0: {}
+
+ bcp-47-match@2.0.3: {}
+
+ bcp-47@2.1.0:
+ dependencies:
+ is-alphabetical: 2.0.1
+ is-alphanumerical: 2.0.1
+ is-decimal: 2.0.1
+
+ boolbase@1.0.0: {}
+
+ boxen@8.0.1:
+ dependencies:
+ ansi-align: 3.0.1
+ camelcase: 8.0.0
+ chalk: 5.6.2
+ cli-boxes: 3.0.0
+ string-width: 7.2.0
+ type-fest: 4.41.0
+ widest-line: 5.0.0
+ wrap-ansi: 9.0.2
+
+ camelcase@8.0.0: {}
+
+ ccount@2.0.1: {}
+
+ chalk@5.6.2: {}
+
+ character-entities-html4@2.1.0: {}
+
+ character-entities-legacy@3.0.0: {}
+
+ character-entities@2.0.2: {}
+
+ character-reference-invalid@2.0.1: {}
+
+ chokidar@5.0.0:
+ dependencies:
+ readdirp: 5.0.0
+
+ ci-info@4.4.0: {}
+
+ cli-boxes@3.0.0: {}
+
+ clsx@2.1.1: {}
+
+ collapse-white-space@2.1.0: {}
+
+ comma-separated-tokens@2.0.3: {}
+
+ commander@11.1.0: {}
+
+ common-ancestor-path@1.0.1: {}
+
+ cookie-es@1.2.2: {}
+
+ cookie@1.1.1: {}
+
+ crossws@0.3.5:
+ dependencies:
+ uncrypto: 0.1.3
+
+ css-select@5.2.2:
+ dependencies:
+ boolbase: 1.0.0
+ css-what: 6.2.2
+ domhandler: 5.0.3
+ domutils: 3.2.2
+ nth-check: 2.1.1
+
+ css-selector-parser@3.3.0: {}
+
+ css-tree@2.2.1:
+ dependencies:
+ mdn-data: 2.0.28
+ source-map-js: 1.2.1
+
+ css-tree@3.2.1:
+ dependencies:
+ mdn-data: 2.27.1
+ source-map-js: 1.2.1
+
+ css-what@6.2.2: {}
+
+ cssesc@3.0.0: {}
+
+ csso@5.0.5:
+ dependencies:
+ css-tree: 2.2.1
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ decode-named-character-reference@1.3.0:
+ dependencies:
+ character-entities: 2.0.2
+
+ defu@6.1.4: {}
+
+ dequal@2.0.3: {}
+
+ destr@2.0.5: {}
+
+ detect-libc@2.1.2: {}
+
+ deterministic-object-hash@2.0.2:
+ dependencies:
+ base-64: 1.0.0
+
+ devalue@5.6.3: {}
+
+ devlop@1.1.0:
+ dependencies:
+ dequal: 2.0.3
+
+ diff@8.0.3: {}
+
+ direction@2.0.1: {}
+
+ dlv@1.1.3: {}
+
+ dom-serializer@2.0.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
+
+ domhandler@5.0.3:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domutils@3.2.2:
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+
+ dset@3.1.4: {}
+
+ emoji-regex@10.6.0: {}
+
+ emoji-regex@8.0.0: {}
+
+ entities@4.5.0: {}
+
+ entities@6.0.1: {}
+
+ es-module-lexer@1.7.0: {}
+
+ esast-util-from-estree@2.0.0:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ devlop: 1.1.0
+ estree-util-visit: 2.0.0
+ unist-util-position-from-estree: 2.0.0
+
+ esast-util-from-js@2.0.1:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ acorn: 8.16.0
+ esast-util-from-estree: 2.0.0
+ vfile-message: 4.0.3
+
+ esbuild@0.25.12:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.25.12
+ '@esbuild/android-arm': 0.25.12
+ '@esbuild/android-arm64': 0.25.12
+ '@esbuild/android-x64': 0.25.12
+ '@esbuild/darwin-arm64': 0.25.12
+ '@esbuild/darwin-x64': 0.25.12
+ '@esbuild/freebsd-arm64': 0.25.12
+ '@esbuild/freebsd-x64': 0.25.12
+ '@esbuild/linux-arm': 0.25.12
+ '@esbuild/linux-arm64': 0.25.12
+ '@esbuild/linux-ia32': 0.25.12
+ '@esbuild/linux-loong64': 0.25.12
+ '@esbuild/linux-mips64el': 0.25.12
+ '@esbuild/linux-ppc64': 0.25.12
+ '@esbuild/linux-riscv64': 0.25.12
+ '@esbuild/linux-s390x': 0.25.12
+ '@esbuild/linux-x64': 0.25.12
+ '@esbuild/netbsd-arm64': 0.25.12
+ '@esbuild/netbsd-x64': 0.25.12
+ '@esbuild/openbsd-arm64': 0.25.12
+ '@esbuild/openbsd-x64': 0.25.12
+ '@esbuild/openharmony-arm64': 0.25.12
+ '@esbuild/sunos-x64': 0.25.12
+ '@esbuild/win32-arm64': 0.25.12
+ '@esbuild/win32-ia32': 0.25.12
+ '@esbuild/win32-x64': 0.25.12
+
+ esbuild@0.27.3:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.27.3
+ '@esbuild/android-arm': 0.27.3
+ '@esbuild/android-arm64': 0.27.3
+ '@esbuild/android-x64': 0.27.3
+ '@esbuild/darwin-arm64': 0.27.3
+ '@esbuild/darwin-x64': 0.27.3
+ '@esbuild/freebsd-arm64': 0.27.3
+ '@esbuild/freebsd-x64': 0.27.3
+ '@esbuild/linux-arm': 0.27.3
+ '@esbuild/linux-arm64': 0.27.3
+ '@esbuild/linux-ia32': 0.27.3
+ '@esbuild/linux-loong64': 0.27.3
+ '@esbuild/linux-mips64el': 0.27.3
+ '@esbuild/linux-ppc64': 0.27.3
+ '@esbuild/linux-riscv64': 0.27.3
+ '@esbuild/linux-s390x': 0.27.3
+ '@esbuild/linux-x64': 0.27.3
+ '@esbuild/netbsd-arm64': 0.27.3
+ '@esbuild/netbsd-x64': 0.27.3
+ '@esbuild/openbsd-arm64': 0.27.3
+ '@esbuild/openbsd-x64': 0.27.3
+ '@esbuild/openharmony-arm64': 0.27.3
+ '@esbuild/sunos-x64': 0.27.3
+ '@esbuild/win32-arm64': 0.27.3
+ '@esbuild/win32-ia32': 0.27.3
+ '@esbuild/win32-x64': 0.27.3
+
+ escape-string-regexp@5.0.0: {}
+
+ estree-util-attach-comments@3.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+
+ estree-util-build-jsx@3.0.1:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ devlop: 1.1.0
+ estree-util-is-identifier-name: 3.0.0
+ estree-walker: 3.0.3
+
+ estree-util-is-identifier-name@3.0.0: {}
+
+ estree-util-scope@1.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ devlop: 1.1.0
+
+ estree-util-to-js@2.0.0:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ astring: 1.9.0
+ source-map: 0.7.6
+
+ estree-util-visit@2.0.0:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ '@types/unist': 3.0.3
+
+ estree-walker@2.0.2: {}
+
+ estree-walker@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+
+ eventemitter3@5.0.4: {}
+
+ expressive-code@0.41.7:
+ dependencies:
+ '@expressive-code/core': 0.41.7
+ '@expressive-code/plugin-frames': 0.41.7
+ '@expressive-code/plugin-shiki': 0.41.7
+ '@expressive-code/plugin-text-markers': 0.41.7
+
+ extend@3.0.2: {}
+
+ fdir@6.5.0(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
+
+ flattie@1.1.1: {}
+
+ fontace@0.4.1:
+ dependencies:
+ fontkitten: 1.0.3
+
+ fontkitten@1.0.3:
+ dependencies:
+ tiny-inflate: 1.0.3
+
+ fsevents@2.3.3:
+ optional: true
+
+ get-east-asian-width@1.5.0: {}
+
+ github-slugger@2.0.0: {}
+
+ h3@1.15.6:
+ dependencies:
+ cookie-es: 1.2.2
+ crossws: 0.3.5
+ defu: 6.1.4
+ destr: 2.0.5
+ iron-webcrypto: 1.2.1
+ node-mock-http: 1.0.4
+ radix3: 1.1.2
+ ufo: 1.6.3
+ uncrypto: 0.1.3
+
+ hast-util-embedded@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-is-element: 3.0.0
+
+ hast-util-format@1.1.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-embedded: 3.0.0
+ hast-util-minify-whitespace: 1.0.1
+ hast-util-phrasing: 3.0.1
+ hast-util-whitespace: 3.0.0
+ html-whitespace-sensitive-tag-names: 3.0.1
+ unist-util-visit-parents: 6.0.2
+
+ hast-util-from-html@2.0.3:
+ dependencies:
+ '@types/hast': 3.0.4
+ devlop: 1.1.0
+ hast-util-from-parse5: 8.0.3
+ parse5: 7.3.0
+ vfile: 6.0.3
+ vfile-message: 4.0.3
+
+ hast-util-from-parse5@8.0.3:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ devlop: 1.1.0
+ hastscript: 9.0.1
+ property-information: 7.1.0
+ vfile: 6.0.3
+ vfile-location: 5.0.3
+ web-namespaces: 2.0.1
+
+ hast-util-has-property@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hast-util-is-body-ok-link@3.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hast-util-is-element@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hast-util-minify-whitespace@1.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-embedded: 3.0.0
+ hast-util-is-element: 3.0.0
+ hast-util-whitespace: 3.0.0
+ unist-util-is: 6.0.1
+
+ hast-util-parse-selector@4.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hast-util-phrasing@3.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-embedded: 3.0.0
+ hast-util-has-property: 3.0.0
+ hast-util-is-body-ok-link: 3.0.1
+ hast-util-is-element: 3.0.0
+
+ hast-util-raw@9.1.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ '@ungap/structured-clone': 1.3.0
+ hast-util-from-parse5: 8.0.3
+ hast-util-to-parse5: 8.0.1
+ html-void-elements: 3.0.0
+ mdast-util-to-hast: 13.2.1
+ parse5: 7.3.0
+ unist-util-position: 5.0.0
+ unist-util-visit: 5.1.0
+ vfile: 6.0.3
+ web-namespaces: 2.0.1
+ zwitch: 2.0.4
+
+ hast-util-select@6.0.4:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ bcp-47-match: 2.0.3
+ comma-separated-tokens: 2.0.3
+ css-selector-parser: 3.3.0
+ devlop: 1.1.0
+ direction: 2.0.1
+ hast-util-has-property: 3.0.0
+ hast-util-to-string: 3.0.1
+ hast-util-whitespace: 3.0.0
+ nth-check: 2.1.1
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+ unist-util-visit: 5.1.0
+ zwitch: 2.0.4
+
+ hast-util-to-estree@3.1.3:
+ dependencies:
+ '@types/estree': 1.0.8
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ comma-separated-tokens: 2.0.3
+ devlop: 1.1.0
+ estree-util-attach-comments: 3.0.0
+ estree-util-is-identifier-name: 3.0.0
+ hast-util-whitespace: 3.0.0
+ mdast-util-mdx-expression: 2.0.1
+ mdast-util-mdx-jsx: 3.2.0
+ mdast-util-mdxjs-esm: 2.0.1
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+ style-to-js: 1.1.21
+ unist-util-position: 5.0.0
+ zwitch: 2.0.4
+ transitivePeerDependencies:
+ - supports-color
+
+ hast-util-to-html@9.0.5:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ ccount: 2.0.1
+ comma-separated-tokens: 2.0.3
+ hast-util-whitespace: 3.0.0
+ html-void-elements: 3.0.0
+ mdast-util-to-hast: 13.2.1
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+ stringify-entities: 4.0.4
+ zwitch: 2.0.4
+
+ hast-util-to-jsx-runtime@2.3.6:
+ dependencies:
+ '@types/estree': 1.0.8
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ comma-separated-tokens: 2.0.3
+ devlop: 1.1.0
+ estree-util-is-identifier-name: 3.0.0
+ hast-util-whitespace: 3.0.0
+ mdast-util-mdx-expression: 2.0.1
+ mdast-util-mdx-jsx: 3.2.0
+ mdast-util-mdxjs-esm: 2.0.1
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+ style-to-js: 1.1.21
+ unist-util-position: 5.0.0
+ vfile-message: 4.0.3
+ transitivePeerDependencies:
+ - supports-color
+
+ hast-util-to-parse5@8.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ comma-separated-tokens: 2.0.3
+ devlop: 1.1.0
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+ web-namespaces: 2.0.1
+ zwitch: 2.0.4
+
+ hast-util-to-string@3.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hast-util-to-text@4.0.2:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ hast-util-is-element: 3.0.0
+ unist-util-find-after: 5.0.0
+
+ hast-util-whitespace@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hastscript@9.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ comma-separated-tokens: 2.0.3
+ hast-util-parse-selector: 4.0.0
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+
+ html-escaper@3.0.3: {}
+
+ html-void-elements@3.0.0: {}
+
+ html-whitespace-sensitive-tag-names@3.0.1: {}
+
+ http-cache-semantics@4.2.0: {}
+
+ i18next@23.16.8:
+ dependencies:
+ '@babel/runtime': 7.28.6
+
+ import-meta-resolve@4.2.0: {}
+
+ inline-style-parser@0.2.7: {}
+
+ iron-webcrypto@1.2.1: {}
+
+ is-alphabetical@2.0.1: {}
+
+ is-alphanumerical@2.0.1:
+ dependencies:
+ is-alphabetical: 2.0.1
+ is-decimal: 2.0.1
+
+ is-decimal@2.0.1: {}
+
+ is-docker@3.0.0: {}
+
+ is-fullwidth-code-point@3.0.0: {}
+
+ is-hexadecimal@2.0.1: {}
+
+ is-inside-container@1.0.0:
+ dependencies:
+ is-docker: 3.0.0
+
+ is-plain-obj@4.1.0: {}
+
+ is-wsl@3.1.1:
+ dependencies:
+ is-inside-container: 1.0.0
+
+ js-yaml@4.1.1:
+ dependencies:
+ argparse: 2.0.1
+
+ kleur@3.0.3: {}
+
+ klona@2.0.6: {}
+
+ longest-streak@3.1.0: {}
+
+ lru-cache@11.2.6: {}
+
+ magic-string@0.30.21:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ magicast@0.5.2:
+ dependencies:
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+ source-map-js: 1.2.1
+
+ markdown-extensions@2.0.0: {}
+
+ markdown-table@3.0.4: {}
+
+ mdast-util-definitions@6.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ unist-util-visit: 5.1.0
+
+ mdast-util-directive@3.1.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ ccount: 2.0.1
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ parse-entities: 4.0.2
+ stringify-entities: 4.0.4
+ unist-util-visit-parents: 6.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-find-and-replace@3.0.2:
+ dependencies:
+ '@types/mdast': 4.0.4
+ escape-string-regexp: 5.0.0
+ unist-util-is: 6.0.1
+ unist-util-visit-parents: 6.0.2
+
+ mdast-util-from-markdown@2.0.3:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ decode-named-character-reference: 1.3.0
+ devlop: 1.1.0
+ mdast-util-to-string: 4.0.0
+ micromark: 4.0.2
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-decode-string: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ unist-util-stringify-position: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-autolink-literal@2.0.1:
+ dependencies:
+ '@types/mdast': 4.0.4
+ ccount: 2.0.1
+ devlop: 1.1.0
+ mdast-util-find-and-replace: 3.0.2
+ micromark-util-character: 2.1.1
+
+ mdast-util-gfm-footnote@2.1.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ micromark-util-normalize-identifier: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-strikethrough@2.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-table@2.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ markdown-table: 3.0.4
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-task-list-item@2.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm@3.1.0:
+ dependencies:
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-gfm-autolink-literal: 2.0.1
+ mdast-util-gfm-footnote: 2.1.0
+ mdast-util-gfm-strikethrough: 2.0.0
+ mdast-util-gfm-table: 2.0.0
+ mdast-util-gfm-task-list-item: 2.0.0
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-mdx-expression@2.0.1:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-mdx-jsx@3.2.0:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ ccount: 2.0.1
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ parse-entities: 4.0.2
+ stringify-entities: 4.0.4
+ unist-util-stringify-position: 4.0.0
+ vfile-message: 4.0.3
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-mdx@3.0.0:
+ dependencies:
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-mdx-expression: 2.0.1
+ mdast-util-mdx-jsx: 3.2.0
+ mdast-util-mdxjs-esm: 2.0.1
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-mdxjs-esm@2.0.1:
+ dependencies:
+ '@types/estree-jsx': 1.0.5
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-phrasing@4.1.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ unist-util-is: 6.0.1
+
+ mdast-util-to-hast@13.2.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ '@ungap/structured-clone': 1.3.0
+ devlop: 1.1.0
+ micromark-util-sanitize-uri: 2.0.1
+ trim-lines: 3.0.1
+ unist-util-position: 5.0.0
+ unist-util-visit: 5.1.0
+ vfile: 6.0.3
+
+ mdast-util-to-markdown@2.1.2:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ longest-streak: 3.1.0
+ mdast-util-phrasing: 4.1.0
+ mdast-util-to-string: 4.0.0
+ micromark-util-classify-character: 2.0.1
+ micromark-util-decode-string: 2.0.1
+ unist-util-visit: 5.1.0
+ zwitch: 2.0.4
+
+ mdast-util-to-string@4.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+
+ mdn-data@2.0.28: {}
+
+ mdn-data@2.27.1: {}
+
+ micromark-core-commonmark@2.0.3:
+ dependencies:
+ decode-named-character-reference: 1.3.0
+ devlop: 1.1.0
+ micromark-factory-destination: 2.0.1
+ micromark-factory-label: 2.0.1
+ micromark-factory-space: 2.0.1
+ micromark-factory-title: 2.0.1
+ micromark-factory-whitespace: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-chunked: 2.0.1
+ micromark-util-classify-character: 2.0.1
+ micromark-util-html-tag-name: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-subtokenize: 2.1.0
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-directive@3.0.2:
+ dependencies:
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-factory-whitespace: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ parse-entities: 4.0.2
+
+ micromark-extension-gfm-autolink-literal@2.1.0:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-footnote@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-strikethrough@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-chunked: 2.0.1
+ micromark-util-classify-character: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-table@2.1.1:
+ dependencies:
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-tagfilter@2.0.0:
+ dependencies:
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-task-list-item@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm@3.0.0:
+ dependencies:
+ micromark-extension-gfm-autolink-literal: 2.1.0
+ micromark-extension-gfm-footnote: 2.1.0
+ micromark-extension-gfm-strikethrough: 2.1.0
+ micromark-extension-gfm-table: 2.1.1
+ micromark-extension-gfm-tagfilter: 2.0.0
+ micromark-extension-gfm-task-list-item: 2.1.0
+ micromark-util-combine-extensions: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-mdx-expression@3.0.1:
+ dependencies:
+ '@types/estree': 1.0.8
+ devlop: 1.1.0
+ micromark-factory-mdx-expression: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-events-to-acorn: 2.0.3
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-mdx-jsx@3.0.2:
+ dependencies:
+ '@types/estree': 1.0.8
+ devlop: 1.1.0
+ estree-util-is-identifier-name: 3.0.0
+ micromark-factory-mdx-expression: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-events-to-acorn: 2.0.3
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ vfile-message: 4.0.3
+
+ micromark-extension-mdx-md@2.0.0:
+ dependencies:
+ micromark-util-types: 2.0.2
+
+ micromark-extension-mdxjs-esm@3.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.3
+ micromark-util-character: 2.1.1
+ micromark-util-events-to-acorn: 2.0.3
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ unist-util-position-from-estree: 2.0.0
+ vfile-message: 4.0.3
+
+ micromark-extension-mdxjs@3.0.0:
+ dependencies:
+ acorn: 8.16.0
+ acorn-jsx: 5.3.2(acorn@8.16.0)
+ micromark-extension-mdx-expression: 3.0.1
+ micromark-extension-mdx-jsx: 3.0.2
+ micromark-extension-mdx-md: 2.0.0
+ micromark-extension-mdxjs-esm: 3.0.0
+ micromark-util-combine-extensions: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-destination@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-label@2.0.1:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-mdx-expression@2.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-events-to-acorn: 2.0.3
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ unist-util-position-from-estree: 2.0.0
+ vfile-message: 4.0.3
+
+ micromark-factory-space@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-title@2.0.1:
+ dependencies:
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-whitespace@2.0.1:
+ dependencies:
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-character@2.1.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-chunked@2.0.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-classify-character@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-combine-extensions@2.0.1:
+ dependencies:
+ micromark-util-chunked: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-decode-numeric-character-reference@2.0.2:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-decode-string@2.0.1:
+ dependencies:
+ decode-named-character-reference: 1.3.0
+ micromark-util-character: 2.1.1
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-encode@2.0.1: {}
+
+ micromark-util-events-to-acorn@2.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+ '@types/unist': 3.0.3
+ devlop: 1.1.0
+ estree-util-visit: 2.0.0
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ vfile-message: 4.0.3
+
+ micromark-util-html-tag-name@2.0.1: {}
+
+ micromark-util-normalize-identifier@2.0.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-resolve-all@2.0.1:
+ dependencies:
+ micromark-util-types: 2.0.2
+
+ micromark-util-sanitize-uri@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-encode: 2.0.1
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-subtokenize@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-chunked: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-symbol@2.0.1: {}
+
+ micromark-util-types@2.0.2: {}
+
+ micromark@4.0.2:
+ dependencies:
+ '@types/debug': 4.1.12
+ debug: 4.4.3
+ decode-named-character-reference: 1.3.0
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-chunked: 2.0.1
+ micromark-util-combine-extensions: 2.0.1
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-encode: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-subtokenize: 2.1.0
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mrmime@2.0.1: {}
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ neotraverse@0.6.18: {}
+
+ nlcst-to-string@4.0.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+
+ node-fetch-native@1.6.7: {}
+
+ node-mock-http@1.0.4: {}
+
+ normalize-path@3.0.0: {}
+
+ nth-check@2.1.1:
+ dependencies:
+ boolbase: 1.0.0
+
+ ofetch@1.5.1:
+ dependencies:
+ destr: 2.0.5
+ node-fetch-native: 1.6.7
+ ufo: 1.6.3
+
+ ohash@2.0.11: {}
+
+ oniguruma-parser@0.12.1: {}
+
+ oniguruma-to-es@4.3.4:
+ dependencies:
+ oniguruma-parser: 0.12.1
+ regex: 6.1.0
+ regex-recursion: 6.0.2
+
+ p-limit@6.2.0:
+ dependencies:
+ yocto-queue: 1.2.2
+
+ p-queue@8.1.1:
+ dependencies:
+ eventemitter3: 5.0.4
+ p-timeout: 6.1.4
+
+ p-timeout@6.1.4: {}
+
+ package-manager-detector@1.6.0: {}
+
+ pagefind@1.4.0:
+ optionalDependencies:
+ '@pagefind/darwin-arm64': 1.4.0
+ '@pagefind/darwin-x64': 1.4.0
+ '@pagefind/freebsd-x64': 1.4.0
+ '@pagefind/linux-arm64': 1.4.0
+ '@pagefind/linux-x64': 1.4.0
+ '@pagefind/windows-x64': 1.4.0
+
+ parse-entities@4.0.2:
+ dependencies:
+ '@types/unist': 2.0.11
+ character-entities-legacy: 3.0.0
+ character-reference-invalid: 2.0.1
+ decode-named-character-reference: 1.3.0
+ is-alphanumerical: 2.0.1
+ is-decimal: 2.0.1
+ is-hexadecimal: 2.0.1
+
+ parse-latin@7.0.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+ '@types/unist': 3.0.3
+ nlcst-to-string: 4.0.0
+ unist-util-modify-children: 4.0.0
+ unist-util-visit-children: 3.0.0
+ vfile: 6.0.3
+
+ parse5@7.3.0:
+ dependencies:
+ entities: 6.0.1
+
+ piccolore@0.1.3: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ picomatch@4.0.3: {}
+
+ postcss-nested@6.2.0(postcss@8.5.8):
+ dependencies:
+ postcss: 8.5.8
+ postcss-selector-parser: 6.1.2
+
+ postcss-selector-parser@6.1.2:
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+
+ postcss@8.5.8:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ prismjs@1.30.0: {}
+
+ prompts@2.4.2:
+ dependencies:
+ kleur: 3.0.3
+ sisteransi: 1.0.5
+
+ property-information@7.1.0: {}
+
+ radix3@1.1.2: {}
+
+ readdirp@5.0.0: {}
+
+ recma-build-jsx@1.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-util-build-jsx: 3.0.1
+ vfile: 6.0.3
+
+ recma-jsx@1.0.1(acorn@8.16.0):
+ dependencies:
+ acorn: 8.16.0
+ acorn-jsx: 5.3.2(acorn@8.16.0)
+ estree-util-to-js: 2.0.0
+ recma-parse: 1.0.0
+ recma-stringify: 1.0.0
+ unified: 11.0.5
+
+ recma-parse@1.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ esast-util-from-js: 2.0.1
+ unified: 11.0.5
+ vfile: 6.0.3
+
+ recma-stringify@1.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-util-to-js: 2.0.0
+ unified: 11.0.5
+ vfile: 6.0.3
+
+ regex-recursion@6.0.2:
+ dependencies:
+ regex-utilities: 2.3.0
+
+ regex-utilities@2.3.0: {}
+
+ regex@6.1.0:
+ dependencies:
+ regex-utilities: 2.3.0
+
+ rehype-expressive-code@0.41.7:
+ dependencies:
+ expressive-code: 0.41.7
+
+ rehype-format@5.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-format: 1.1.0
+
+ rehype-parse@9.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-from-html: 2.0.3
+ unified: 11.0.5
+
+ rehype-raw@7.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-raw: 9.1.0
+ vfile: 6.0.3
+
+ rehype-recma@1.0.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ '@types/hast': 3.0.4
+ hast-util-to-estree: 3.1.3
+ transitivePeerDependencies:
+ - supports-color
+
+ rehype-stringify@10.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-to-html: 9.0.5
+ unified: 11.0.5
+
+ rehype@13.0.2:
+ dependencies:
+ '@types/hast': 3.0.4
+ rehype-parse: 9.0.1
+ rehype-stringify: 10.0.1
+ unified: 11.0.5
+
+ remark-directive@3.0.1:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-directive: 3.1.0
+ micromark-extension-directive: 3.0.2
+ unified: 11.0.5
+ transitivePeerDependencies:
+ - supports-color
+
+ remark-gfm@4.0.1:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-gfm: 3.1.0
+ micromark-extension-gfm: 3.0.0
+ remark-parse: 11.0.0
+ remark-stringify: 11.0.0
+ unified: 11.0.5
+ transitivePeerDependencies:
+ - supports-color
+
+ remark-github-alerts@0.1.1(@types/mdast@4.0.4)(unified@11.0.5):
+ dependencies:
+ '@types/mdast': 4.0.4
+ unified: 11.0.5
+ unist-util-visit: 5.1.0
+
+ remark-mdx@3.1.1:
+ dependencies:
+ mdast-util-mdx: 3.0.0
+ micromark-extension-mdxjs: 3.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ remark-parse@11.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-from-markdown: 2.0.3
+ micromark-util-types: 2.0.2
+ unified: 11.0.5
+ transitivePeerDependencies:
+ - supports-color
+
+ remark-rehype@11.1.2:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ mdast-util-to-hast: 13.2.1
+ unified: 11.0.5
+ vfile: 6.0.3
+
+ remark-smartypants@3.0.2:
+ dependencies:
+ retext: 9.0.0
+ retext-smartypants: 6.2.0
+ unified: 11.0.5
+ unist-util-visit: 5.1.0
+
+ remark-stringify@11.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-to-markdown: 2.1.2
+ unified: 11.0.5
+
+ retext-latin@4.0.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+ parse-latin: 7.0.0
+ unified: 11.0.5
+
+ retext-smartypants@6.2.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+ nlcst-to-string: 4.0.0
+ unist-util-visit: 5.1.0
+
+ retext-stringify@4.0.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+ nlcst-to-string: 4.0.0
+ unified: 11.0.5
+
+ retext@9.0.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+ retext-latin: 4.0.0
+ retext-stringify: 4.0.0
+ unified: 11.0.5
+
+ rollup@4.59.0:
+ dependencies:
+ '@types/estree': 1.0.8
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.59.0
+ '@rollup/rollup-android-arm64': 4.59.0
+ '@rollup/rollup-darwin-arm64': 4.59.0
+ '@rollup/rollup-darwin-x64': 4.59.0
+ '@rollup/rollup-freebsd-arm64': 4.59.0
+ '@rollup/rollup-freebsd-x64': 4.59.0
+ '@rollup/rollup-linux-arm-gnueabihf': 4.59.0
+ '@rollup/rollup-linux-arm-musleabihf': 4.59.0
+ '@rollup/rollup-linux-arm64-gnu': 4.59.0
+ '@rollup/rollup-linux-arm64-musl': 4.59.0
+ '@rollup/rollup-linux-loong64-gnu': 4.59.0
+ '@rollup/rollup-linux-loong64-musl': 4.59.0
+ '@rollup/rollup-linux-ppc64-gnu': 4.59.0
+ '@rollup/rollup-linux-ppc64-musl': 4.59.0
+ '@rollup/rollup-linux-riscv64-gnu': 4.59.0
+ '@rollup/rollup-linux-riscv64-musl': 4.59.0
+ '@rollup/rollup-linux-s390x-gnu': 4.59.0
+ '@rollup/rollup-linux-x64-gnu': 4.59.0
+ '@rollup/rollup-linux-x64-musl': 4.59.0
+ '@rollup/rollup-openbsd-x64': 4.59.0
+ '@rollup/rollup-openharmony-arm64': 4.59.0
+ '@rollup/rollup-win32-arm64-msvc': 4.59.0
+ '@rollup/rollup-win32-ia32-msvc': 4.59.0
+ '@rollup/rollup-win32-x64-gnu': 4.59.0
+ '@rollup/rollup-win32-x64-msvc': 4.59.0
+ fsevents: 2.3.3
+
+ sax@1.5.0: {}
+
+ semver@7.7.4: {}
+
+ sharp@0.34.5:
+ dependencies:
+ '@img/colour': 1.1.0
+ detect-libc: 2.1.2
+ semver: 7.7.4
+ optionalDependencies:
+ '@img/sharp-darwin-arm64': 0.34.5
+ '@img/sharp-darwin-x64': 0.34.5
+ '@img/sharp-libvips-darwin-arm64': 1.2.4
+ '@img/sharp-libvips-darwin-x64': 1.2.4
+ '@img/sharp-libvips-linux-arm': 1.2.4
+ '@img/sharp-libvips-linux-arm64': 1.2.4
+ '@img/sharp-libvips-linux-ppc64': 1.2.4
+ '@img/sharp-libvips-linux-riscv64': 1.2.4
+ '@img/sharp-libvips-linux-s390x': 1.2.4
+ '@img/sharp-libvips-linux-x64': 1.2.4
+ '@img/sharp-libvips-linuxmusl-arm64': 1.2.4
+ '@img/sharp-libvips-linuxmusl-x64': 1.2.4
+ '@img/sharp-linux-arm': 0.34.5
+ '@img/sharp-linux-arm64': 0.34.5
+ '@img/sharp-linux-ppc64': 0.34.5
+ '@img/sharp-linux-riscv64': 0.34.5
+ '@img/sharp-linux-s390x': 0.34.5
+ '@img/sharp-linux-x64': 0.34.5
+ '@img/sharp-linuxmusl-arm64': 0.34.5
+ '@img/sharp-linuxmusl-x64': 0.34.5
+ '@img/sharp-wasm32': 0.34.5
+ '@img/sharp-win32-arm64': 0.34.5
+ '@img/sharp-win32-ia32': 0.34.5
+ '@img/sharp-win32-x64': 0.34.5
+
+ shiki@3.23.0:
+ dependencies:
+ '@shikijs/core': 3.23.0
+ '@shikijs/engine-javascript': 3.23.0
+ '@shikijs/engine-oniguruma': 3.23.0
+ '@shikijs/langs': 3.23.0
+ '@shikijs/themes': 3.23.0
+ '@shikijs/types': 3.23.0
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+
+ sisteransi@1.0.5: {}
+
+ sitemap@9.0.1:
+ dependencies:
+ '@types/node': 24.12.0
+ '@types/sax': 1.2.7
+ arg: 5.0.2
+ sax: 1.5.0
+
+ smol-toml@1.6.0: {}
+
+ source-map-js@1.2.1: {}
+
+ source-map@0.7.6: {}
+
+ space-separated-tokens@2.0.2: {}
+
+ stream-replace-string@2.0.0: {}
+
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ string-width@7.2.0:
+ dependencies:
+ emoji-regex: 10.6.0
+ get-east-asian-width: 1.5.0
+ strip-ansi: 7.2.0
+
+ stringify-entities@4.0.4:
+ dependencies:
+ character-entities-html4: 2.1.0
+ character-entities-legacy: 3.0.0
+
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
+ strip-ansi@7.2.0:
+ dependencies:
+ ansi-regex: 6.2.2
+
+ style-to-js@1.1.21:
+ dependencies:
+ style-to-object: 1.0.14
+
+ style-to-object@1.0.14:
+ dependencies:
+ inline-style-parser: 0.2.7
+
+ svgo@4.0.1:
+ dependencies:
+ commander: 11.1.0
+ css-select: 5.2.2
+ css-tree: 3.2.1
+ css-what: 6.2.2
+ csso: 5.0.5
+ picocolors: 1.1.1
+ sax: 1.5.0
+
+ tiny-inflate@1.0.3: {}
+
+ tinyexec@1.0.2: {}
+
+ tinyglobby@0.2.15:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+
+ trim-lines@3.0.1: {}
+
+ trough@2.2.0: {}
+
+ tsconfck@3.1.6(typescript@5.9.3):
+ optionalDependencies:
+ typescript: 5.9.3
+
+ tslib@2.8.1:
+ optional: true
+
+ type-fest@4.41.0: {}
+
+ typescript@5.9.3: {}
+
+ ufo@1.6.3: {}
+
+ ultrahtml@1.6.0: {}
+
+ uncrypto@0.1.3: {}
+
+ undici-types@7.16.0: {}
+
+ unified@11.0.5:
+ dependencies:
+ '@types/unist': 3.0.3
+ bail: 2.0.2
+ devlop: 1.1.0
+ extend: 3.0.2
+ is-plain-obj: 4.1.0
+ trough: 2.2.0
+ vfile: 6.0.3
+
+ unifont@0.7.4:
+ dependencies:
+ css-tree: 3.2.1
+ ofetch: 1.5.1
+ ohash: 2.0.11
+
+ unist-util-find-after@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.1
+
+ unist-util-is@6.0.1:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-modify-children@4.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ array-iterate: 2.0.1
+
+ unist-util-position-from-estree@2.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-position@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-remove-position@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-visit: 5.1.0
+
+ unist-util-stringify-position@4.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-visit-children@3.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-visit-parents@6.0.2:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.1
+
+ unist-util-visit@5.1.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.1
+ unist-util-visit-parents: 6.0.2
+
+ unstorage@1.17.4:
+ dependencies:
+ anymatch: 3.1.3
+ chokidar: 5.0.0
+ destr: 2.0.5
+ h3: 1.15.6
+ lru-cache: 11.2.6
+ node-fetch-native: 1.6.7
+ ofetch: 1.5.1
+ ufo: 1.6.3
+
+ util-deprecate@1.0.2: {}
+
+ vfile-location@5.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ vfile: 6.0.3
+
+ vfile-message@4.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-stringify-position: 4.0.0
+
+ vfile@6.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ vfile-message: 4.0.3
+
+ vite@6.4.1(@types/node@24.12.0):
+ dependencies:
+ esbuild: 0.25.12
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+ postcss: 8.5.8
+ rollup: 4.59.0
+ tinyglobby: 0.2.15
+ optionalDependencies:
+ '@types/node': 24.12.0
+ fsevents: 2.3.3
+
+ vitefu@1.1.2(vite@6.4.1(@types/node@24.12.0)):
+ optionalDependencies:
+ vite: 6.4.1(@types/node@24.12.0)
+
+ web-namespaces@2.0.1: {}
+
+ which-pm-runs@1.1.0: {}
+
+ widest-line@5.0.0:
+ dependencies:
+ string-width: 7.2.0
+
+ wrap-ansi@9.0.2:
+ dependencies:
+ ansi-styles: 6.2.3
+ string-width: 7.2.0
+ strip-ansi: 7.2.0
+
+ xxhash-wasm@1.1.0: {}
+
+ yargs-parser@21.1.1: {}
+
+ yocto-queue@1.2.2: {}
+
+ yocto-spinner@0.2.3:
+ dependencies:
+ yoctocolors: 2.1.2
+
+ yoctocolors@2.1.2: {}
+
+ zod-to-json-schema@3.25.1(zod@3.25.76):
+ dependencies:
+ zod: 3.25.76
+
+ zod-to-ts@1.2.0(typescript@5.9.3)(zod@3.25.76):
+ dependencies:
+ typescript: 5.9.3
+ zod: 3.25.76
+
+ zod@3.25.76: {}
+
+ zod@4.3.6: {}
+
+ zwitch@2.0.4: {}
diff --git a/docs/public/favicon.svg b/docs/public/favicon.svg
new file mode 100644
index 000000000..9e3b41ffa
--- /dev/null
+++ b/docs/public/favicon.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/architecture-decisions/assets/2023-06-06_frontend-templates/modular_templates.jpg b/docs/public/images/2023-06-06_frontend-templates/modular_templates.jpg
similarity index 100%
rename from docs/architecture-decisions/assets/2023-06-06_frontend-templates/modular_templates.jpg
rename to docs/public/images/2023-06-06_frontend-templates/modular_templates.jpg
diff --git a/docs/architecture-decisions/assets/2023-06-06_frontend-templates/scenario_1.jpg b/docs/public/images/2023-06-06_frontend-templates/scenario_1.jpg
similarity index 100%
rename from docs/architecture-decisions/assets/2023-06-06_frontend-templates/scenario_1.jpg
rename to docs/public/images/2023-06-06_frontend-templates/scenario_1.jpg
diff --git a/docs/architecture-decisions/assets/2023-06-06_frontend-templates/scenario_2.jpg b/docs/public/images/2023-06-06_frontend-templates/scenario_2.jpg
similarity index 100%
rename from docs/architecture-decisions/assets/2023-06-06_frontend-templates/scenario_2.jpg
rename to docs/public/images/2023-06-06_frontend-templates/scenario_2.jpg
diff --git a/docs/architecture-decisions/assets/2024-01-13_native_binaries/image_1.png b/docs/public/images/2024-01-13_native_binaries/image_1.png
similarity index 100%
rename from docs/architecture-decisions/assets/2024-01-13_native_binaries/image_1.png
rename to docs/public/images/2024-01-13_native_binaries/image_1.png
diff --git a/docs/architecture-decisions/assets/2024-01-13_native_binaries/image_2.png b/docs/public/images/2024-01-13_native_binaries/image_2.png
similarity index 100%
rename from docs/architecture-decisions/assets/2024-01-13_native_binaries/image_2.png
rename to docs/public/images/2024-01-13_native_binaries/image_2.png
diff --git a/docs/imgs/algokit-intro-video-thumbnail.jpg b/docs/public/images/algokit-intro-video-thumbnail.jpg
similarity index 100%
rename from docs/imgs/algokit-intro-video-thumbnail.jpg
rename to docs/public/images/algokit-intro-video-thumbnail.jpg
diff --git a/docs/imgs/algokit-map.png b/docs/public/images/algokit-map.png
similarity index 100%
rename from docs/imgs/algokit-map.png
rename to docs/public/images/algokit-map.png
diff --git a/docs/imgs/algokitartifacts.png b/docs/public/images/algokitartifacts.png
similarity index 100%
rename from docs/imgs/algokitartifacts.png
rename to docs/public/images/algokitartifacts.png
diff --git a/docs/imgs/algokitcodetour.png b/docs/public/images/algokitcodetour.png
similarity index 100%
rename from docs/imgs/algokitcodetour.png
rename to docs/public/images/algokitcodetour.png
diff --git a/docs/imgs/algokitplayground.png b/docs/public/images/algokitplayground.png
similarity index 100%
rename from docs/imgs/algokitplayground.png
rename to docs/public/images/algokitplayground.png
diff --git a/docs/imgs/banner.png b/docs/public/images/banner.png
similarity index 100%
rename from docs/imgs/banner.png
rename to docs/public/images/banner.png
diff --git a/docs/architecture-decisions/lifecycle.jpg b/docs/public/images/lifecycle.jpg
similarity index 100%
rename from docs/architecture-decisions/lifecycle.jpg
rename to docs/public/images/lifecycle.jpg
diff --git a/docs/imgs/localnet.png b/docs/public/images/localnet.png
similarity index 100%
rename from docs/imgs/localnet.png
rename to docs/public/images/localnet.png
diff --git a/docs/src/content.config.ts b/docs/src/content.config.ts
new file mode 100644
index 000000000..d9ee8c9d1
--- /dev/null
+++ b/docs/src/content.config.ts
@@ -0,0 +1,7 @@
+import { defineCollection } from 'astro:content';
+import { docsLoader } from '@astrojs/starlight/loaders';
+import { docsSchema } from '@astrojs/starlight/schema';
+
+export const collections = {
+ docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
+};
diff --git a/docs/architecture-decisions/2022-11-14_sandbox-approach.md b/docs/src/content/docs/architecture-decisions/2022-11-14_sandbox-approach.md
similarity index 95%
rename from docs/architecture-decisions/2022-11-14_sandbox-approach.md
rename to docs/src/content/docs/architecture-decisions/2022-11-14_sandbox-approach.md
index 0658720dc..236a6c350 100644
--- a/docs/architecture-decisions/2022-11-14_sandbox-approach.md
+++ b/docs/src/content/docs/architecture-decisions/2022-11-14_sandbox-approach.md
@@ -1,4 +1,6 @@
-# AlgoKit sandbox approach
+---
+title: "AlgoKit sandbox approach"
+---
- **Status**: Approved
- **Owner:** Rob Moore
@@ -23,7 +25,7 @@ In order for AlgoKit to facilitate a productive development experience it needs
## Principles
-- **[AlgoKit Guiding Principles](../../docs/algokit.md#Guiding-Principles)** - specifically Seamless onramp, Leverage existing ecosystem, Meet devs where they are
+- **[AlgoKit Guiding Principles](/algokit-cli/features/overview/#Guiding-Principles)** - specifically Seamless onramp, Leverage existing ecosystem, Meet devs where they are
- **Lightweight** - the solution should have as low an impact as possible on resources on the developers machine
- **Fast** - the solution should start quickly, which makes for a nicer experience locally and also allows it to be used for continuous integration automation testing
diff --git a/docs/architecture-decisions/2022-11-22_beaker-testing-strategy.md b/docs/src/content/docs/architecture-decisions/2022-11-22_beaker-testing-strategy.md
similarity index 99%
rename from docs/architecture-decisions/2022-11-22_beaker-testing-strategy.md
rename to docs/src/content/docs/architecture-decisions/2022-11-22_beaker-testing-strategy.md
index 57597c919..fe808c1ca 100644
--- a/docs/architecture-decisions/2022-11-22_beaker-testing-strategy.md
+++ b/docs/src/content/docs/architecture-decisions/2022-11-22_beaker-testing-strategy.md
@@ -1,4 +1,6 @@
-# Beaker testing strategy
+---
+title: "Beaker testing strategy"
+---
- **Status**: Draft
- **Owner:** Rob Moore
diff --git a/docs/architecture-decisions/2023-01-11_beaker_productionisation_review.md b/docs/src/content/docs/architecture-decisions/2023-01-11_beaker_productionisation_review.md
similarity index 99%
rename from docs/architecture-decisions/2023-01-11_beaker_productionisation_review.md
rename to docs/src/content/docs/architecture-decisions/2023-01-11_beaker_productionisation_review.md
index 7039d9554..8bc852826 100644
--- a/docs/architecture-decisions/2023-01-11_beaker_productionisation_review.md
+++ b/docs/src/content/docs/architecture-decisions/2023-01-11_beaker_productionisation_review.md
@@ -1,4 +1,6 @@
-# Beaker productionisation review
+---
+title: "Beaker productionisation review"
+---
- **Status**: Approved
- **Owners:** Rob Moore, Adam Chidlow
@@ -226,7 +228,7 @@ The deferment of the `compile()` call is actually a necessary part of recommenda
The immediate `compile()` has issues such as requiring implementors (i.e. subclasses) to call `super().__init__()` as a **final** step in their own `__init__` method - any code that runs after the super init call will have no effect on the application produced!
-Immediate compilation also reduces the control the user has over the output. Although currently the only parameter that `compile` takes is a `client`, it might be useful to add (optional) parameters here to control the compilation. For example, if you can pass in the list of optimisations that should be applied, that allows you to have [output stability](../articles/output_stability.md) of your smart contract code if new optimisations are added in the future.
+Immediate compilation also reduces the control the user has over the output. Although currently the only parameter that `compile` takes is a `client`, it might be useful to add (optional) parameters here to control the compilation. For example, if you can pass in the list of optimisations that should be applied, that allows you to have [output stability](/algokit-cli/concepts/output-stability/) of your smart contract code if new optimisations are added in the future.
The separation of compiled state outside of `Application` simplifies the design, and can be done mostly transparently to end-users.
diff --git a/docs/architecture-decisions/2023-01-11_brew_install.md b/docs/src/content/docs/architecture-decisions/2023-01-11_brew_install.md
similarity index 99%
rename from docs/architecture-decisions/2023-01-11_brew_install.md
rename to docs/src/content/docs/architecture-decisions/2023-01-11_brew_install.md
index 552d4a077..c1f02aac1 100644
--- a/docs/architecture-decisions/2023-01-11_brew_install.md
+++ b/docs/src/content/docs/architecture-decisions/2023-01-11_brew_install.md
@@ -1,4 +1,6 @@
-# HomeBrew install strategy
+---
+title: "HomeBrew install strategy"
+---
- **Status**: Approved
- **Owner:** Daniel McGregor
diff --git a/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md b/docs/src/content/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md
similarity index 97%
rename from docs/architecture-decisions/2023-01-12_smart-contract-deployment.md
rename to docs/src/content/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md
index 9eb56b385..f7bbebf85 100644
--- a/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md
+++ b/docs/src/content/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md
@@ -1,4 +1,6 @@
-# Smart Contract Deployment
+---
+title: "Smart Contract Deployment"
+---
- **Status**: Approved
- **Owner:** Rob Moore
@@ -14,7 +16,7 @@ AlgoKit will provide an end-to-end development and deployment experience that in
1. Development
1. **Write** smart contracts
2. **Transpile** smart contracts with development-time parameters to TEAL Templates
- 3. **Verify** the TEAL Templates maintain [output stability](../articles/output_stability.md) and any other static code quality checks
+ 3. **Verify** the TEAL Templates maintain [output stability](/algokit-cli/concepts/output-stability/) and any other static code quality checks
2. Deployment
1. **Substitute** deploy-time parameters into TEAL Templates to create final TEAL code
2. **Compile** the TEAL to create byte code using algod
@@ -23,7 +25,7 @@ AlgoKit will provide an end-to-end development and deployment experience that in
1. **Validate** the deployed app via automated testing of the smart contracts to provide confidence in their correctness
2. **Call** deployed smart contract with runtime parameters to utilise it
-
+
The default Development experience that AlgoKit exposes will be via Beaker, however AlgoKit is modular and extensible so other tooling can also be used.
@@ -41,7 +43,7 @@ This decision record covers the different options and high level design for how
## Principles
-- [AlgoKit Guiding Principles](../../docs/algokit.md#Guiding-Principles) - specifically:
+- [AlgoKit Guiding Principles](/algokit-cli/features/overview/#Guiding-Principles) - specifically:
- **Cohesive developer tool suite**
- **Seamless onramp**
- **Secure by default**
@@ -74,7 +76,7 @@ There are two key considerations to help answer this question:
1. Should development and deployment be decoupled from each other (i.e. happen at a separate time)?
- If we couple development and deployment together then it necessitates that at deploy time you have the same programming environment running that's needed for the smart contract development. So, if you (for instance) were building a smart contract in Python using PyTEAL or Beaker, but deploying the smart contract using TypeScript that means you need a deployment environment that supports both Node.js _and_ Python. This makes it harder to follow the Modular components principle.
- If development and deployment are coupled together it rules out using Continuous Delivery since it forces you to build the deployment artifact at the same time as you are deploying it. This means you miss out on the confidence and risk benefit of knowing that when you are deploying to (say) MainNet you are deploying the same artifact that was successfully deployed and tested on (say) TestNet and AlgoKit LocalNet (let alone passes any other checks you decide to run as part of Continuous Integration like automated tests, static code analysis, etc.).
- - If development and deployment are coupled together it means we aren't perform an [output stability](../articles/output_stability.md) test so we don't get notified if we make a change that results in a different smart contract (which may then affect things like hashes for smart contract auditing review comparison, unintended introduction of security vulnerabilities, etc.).
+ - If development and deployment are coupled together it means we aren't perform an [output stability](/algokit-cli/concepts/output-stability/) test so we don't get notified if we make a change that results in a different smart contract (which may then affect things like hashes for smart contract auditing review comparison, unintended introduction of security vulnerabilities, etc.).
- Based on all of this, decoupling development and deployment is a very helpful thing for a smart contract and aligns with all of the above-stated principles more closely.
2. Do we need to provide deploy-time parameters?
- When deploying a smart contract to a network (say MainNet), there are likely to be certain parameters that will be different from deploying to a different network (say TestNet), e.g.:
@@ -281,7 +283,7 @@ The proposed AlgoKit implementation for v1 that provides a balance of flexibilit
### Output stability testing
-Ensuring [output stability](../articles/output_stability.md) is useful for smart contract development. It helps ensure that you can refactor code without making an inadvertent change to the smart contract, ensure that a smart contract output isn't changed from any output that is audited, and ensure that there is a clear mechanism to manually review the smart contract output before it's (re-)deployed.
+Ensuring [output stability](/algokit-cli/concepts/output-stability/) is useful for smart contract development. It helps ensure that you can refactor code without making an inadvertent change to the smart contract, ensure that a smart contract output isn't changed from any output that is audited, and ensure that there is a clear mechanism to manually review the smart contract output before it's (re-)deployed.
There are three broad approaches that could be taken by AlgoKit to help facilitate output stability testing:
diff --git a/docs/architecture-decisions/2023-06-06_frontend-templates.md b/docs/src/content/docs/architecture-decisions/2023-06-06_frontend-templates.md
similarity index 97%
rename from docs/architecture-decisions/2023-06-06_frontend-templates.md
rename to docs/src/content/docs/architecture-decisions/2023-06-06_frontend-templates.md
index dbe6560fd..b81f9d7b7 100644
--- a/docs/architecture-decisions/2023-06-06_frontend-templates.md
+++ b/docs/src/content/docs/architecture-decisions/2023-06-06_frontend-templates.md
@@ -1,4 +1,6 @@
-# Frontend Templates
+---
+title: "Frontend Templates"
+---
- **Status**: Approved
- **Owner:** Altynbek Orumbayev
@@ -34,7 +36,7 @@ AlgoKit v2 aims provide an end-to-end development and deployment experience that
- **Maintainability**: The dApp templating feature should be easy to maintain and extend. This implies that the feature should be implemented in a way that allows for easy addition of new templates and/or modification of existing ones as the complexity and variety of templates scale.
- **Seamless onramp**: The dApp templating feature should provide a seamless onramp for developers to get started with dApp development. This implies that the feature should provide a simple and intuitive way to get started with dApp development and deployment. Providing developers a choice on whether they want more flexibility or rely on default recommended practices.
-All of the aforementioned requirements should be met in a way that is consistent with the guiding principles of AlgoKit or attempt to find a balanced trade of between the principles that satisfies the requirements. Refer to [AlgoKit Guiding Principles](../../docs/algokit.md#Guiding-Principles) for detailed reference on the principles.
+All of the aforementioned requirements should be met in a way that is consistent with the guiding principles of AlgoKit or attempt to find a balanced trade of between the principles that satisfies the requirements. Refer to [AlgoKit Guiding Principles](/algokit-cli/features/overview/#Guiding-Principles) for detailed reference on the principles.
## Explored options
@@ -78,7 +80,7 @@ b) Expand on AlgoKit principles of modularity, maintainability and flexibility b
The official standalone frontend templates can be build by reusing already established best practices and templates from official backend repositories and by continuing reliance on `copier` for template automation. Another important consideration to keep in mind is that with the introduction of frontend templates we need to establish a clear separation of concerns between the backend and frontend templates to ensure modularity.
-
+
As demonstrated on the diagram above, the only glue connecting the backend and frontend is the generated typed client. Neither backend or frontend templates should be concerned with the other but instead provide modular interfaces that clearly indicate to developers on how to integrate the two. From a perspective of a backend template, the typed client shall be seen as a static asset that can be reused by any frontend template. Frontend templates on the other hand are mostly standard web projects with an additional layer of utilities that optionally allow them to be integrated with typed clients produced by backend templates.
@@ -86,7 +88,7 @@ As demonstrated on the diagram above, the only glue connecting the backend and f
The main scenario to support for this part is to allow developers to use official starter templates to bootstrap end to end dApp projects.
-
+
As demonstrated above the dev experience will consist of executing an `algokit init` command for the preferred backends and frontends.
@@ -102,7 +104,7 @@ It gives user a choice and responsibility to then decide how to integrate the tw
The main scenario to support for this part is to allow developers to use official starter templates to bootstrap end to end dApp projects.
-
+
As demonstrated above the user experience will consist of a single execution of `algokit init` command pointed at official full-stack template repository. The full stack templates are responsible for bundling both backend and frontend templates together and providing a seamless onramp for developers to get started with dApp development. The way repositories are bundled should be easy to maintain and should not duplicate individual backend and frontend repositories to avoid redundant maintenance, instead it should expand on metatemplating capabilities of `copier` to allow for efficient reuse of existing standalone backend/frontend templates.
diff --git a/docs/architecture-decisions/2023-07-19_advanced_generate_command.md b/docs/src/content/docs/architecture-decisions/2023-07-19_advanced_generate_command.md
similarity index 93%
rename from docs/architecture-decisions/2023-07-19_advanced_generate_command.md
rename to docs/src/content/docs/architecture-decisions/2023-07-19_advanced_generate_command.md
index 1eb9d03be..b2810cb54 100644
--- a/docs/architecture-decisions/2023-07-19_advanced_generate_command.md
+++ b/docs/src/content/docs/architecture-decisions/2023-07-19_advanced_generate_command.md
@@ -1,4 +1,6 @@
-# Advanced `algokit generate` command
+---
+title: "Advanced `algokit generate` command"
+---
- **Status**: Approved
- **Owner:** Altynbek Orumbayev, Inaie Ignacio
@@ -9,7 +11,7 @@
## Context
-The [Frontend Templates ADR](./2023-06-06_frontend-templates.md) introduced and expanded on AlgoKit's principles of Modularity and Maintainability by introducing a new set of official templates for quickly bootstrapping standalone `react` and `fullstack` projects showcasing best practices and patterns for building frontend and fullstack applications with Algorand. As a logical next step, we want to enable developers to extend existing projects instantiated from official templates with new files and features.
+The [Frontend Templates ADR](/algokit-cli/architecture-decisions/2023-06-06_frontend-templates/) introduced and expanded on AlgoKit's principles of Modularity and Maintainability by introducing a new set of official templates for quickly bootstrapping standalone `react` and `fullstack` projects showcasing best practices and patterns for building frontend and fullstack applications with Algorand. As a logical next step, we want to enable developers to extend existing projects instantiated from official templates with new files and features.
## Requirements
@@ -36,7 +38,7 @@ This implies extension of existing starter guidelines available for template bui
- **Maintainability**: The `advanced algokit generate` capabilities on `algokit-cli` and related artifacts on respective official templates should be easy to maintain and extend.
- **Seamless onramp**: Great developer experience for template builders to create their own `generators` and user experience to use them via `advanced algokit generate` command should be a priority.
-All of the aforementioned requirements should be met in a way that is consistent with the guiding principles of AlgoKit or attempt to find a balanced trade of between the principles that satisfies the requirements. Refer to [AlgoKit Guiding Principles](../../docs/algokit.md#Guiding-Principles) for detailed reference on the principles.
+All of the aforementioned requirements should be met in a way that is consistent with the guiding principles of AlgoKit or attempt to find a balanced trade of between the principles that satisfies the requirements. Refer to [AlgoKit Guiding Principles](/algokit-cli/features/overview/#Guiding-Principles) for detailed reference on the principles.
## Considered Options
@@ -181,7 +183,7 @@ The only distinction between this option and option 1 is that generators are hos
- Developing and maintaining generators is significantly more complex due to the need to maintain separate repositories and versioning.
- Official maintainers and community template builders need to be put extra effort at keeping generators generic enough to be reused by other templates. Given that templates can vastly differ in type, structure, conventions and patterns, this can be a challenge.
-- Given that copier is being considered as a backbone for generators feature, drawbacks outlined for hosting templates on monorepos in the [previous adr](2023-06-06_frontend-templates.md#option-1-monolithic-template) apply here as well.
+- Given that copier is being considered as a backbone for generators feature, drawbacks outlined for hosting templates on monorepos in the [previous adr](/algokit-cli/architecture-decisions/2023-06-06_frontend-templates/#option-1-monolithic-template) apply here as well.
## Open questions for reviewers
diff --git a/docs/architecture-decisions/2024-01-13_native_binaries.md b/docs/src/content/docs/architecture-decisions/2024-01-13_native_binaries.md
similarity index 98%
rename from docs/architecture-decisions/2024-01-13_native_binaries.md
rename to docs/src/content/docs/architecture-decisions/2024-01-13_native_binaries.md
index 7d3316468..a1f35d8cb 100644
--- a/docs/architecture-decisions/2024-01-13_native_binaries.md
+++ b/docs/src/content/docs/architecture-decisions/2024-01-13_native_binaries.md
@@ -1,4 +1,6 @@
-# AlgoKit CLI native binaries
+---
+title: "AlgoKit CLI native binaries"
+---
- **Status**: Approved
- **Owner:** Altynbek Orumbayev (MakerX), Negar Abbasi (MakerX)
@@ -114,7 +116,7 @@ The benchmarking was performed on a MacBook M2 running macOS 14.2.1 and an ARM b
| pyinstaller_onefile | 3.031 | 1.466 | 1.875 |
| algokit | 0.3126 | 0.6111 | 0.7579 |
-
+
_Figure: Benchmarking results comparing the performance of Nuitka (onefile, onedir modes), PyInstaller (onefile, onedir modes), and pipx installed Algokit CLI on macOS M2, Windows 11 ARM VM, Ubuntu 20 ARM VM._
| Method | Windows (MB) | Ubuntu (MB) | macOS (MB) |
@@ -124,7 +126,7 @@ _Figure: Benchmarking results comparing the performance of Nuitka (onefile, oned
| pyinstaller_onedir | 46.07 | 52 | 113 |
| pyinstaller_onefile | 26.47 | 25 | 45 |
-
+
_Figure: Bundle sizes of folders with executables build with Nuitka (onefile, onedir modes), PyInstaller (onefile, onedir modes)._
#### Preliminary Observations
diff --git a/docs/architecture-decisions/2024-01-23_init-wizard-v2.md b/docs/src/content/docs/architecture-decisions/2024-01-23_init-wizard-v2.md
similarity index 97%
rename from docs/architecture-decisions/2024-01-23_init-wizard-v2.md
rename to docs/src/content/docs/architecture-decisions/2024-01-23_init-wizard-v2.md
index 82d88bf0a..1b6f21d1e 100644
--- a/docs/architecture-decisions/2024-01-23_init-wizard-v2.md
+++ b/docs/src/content/docs/architecture-decisions/2024-01-23_init-wizard-v2.md
@@ -1,4 +1,6 @@
-# AlgoKit Init Wizard Version 2 and Template Enhancements
+---
+title: "AlgoKit Init Wizard Version 2 and Template Enhancements"
+---
- **Status:** Proposed (Revision 2)
- **Owner:** Altynbek Orumbayev
@@ -14,7 +16,7 @@
## Background
-This ADR emerges from various discussions aimed at enhancing the `init` wizard version 2 user experience and aligning it with emerging smart contract languages/frameworks to make it more user-friendly and accessible to beginners. It builds upon prior decisions from the [Advanced algokit generate command](./2023-07-19_advanced_generate_command.md) and [Frontend Templates](./2023-06-06_frontend-templates.md) ADRs, integrating feedback from the Algorand Foundation and DevRel team.
+This ADR emerges from various discussions aimed at enhancing the `init` wizard version 2 user experience and aligning it with emerging smart contract languages/frameworks to make it more user-friendly and accessible to beginners. It builds upon prior decisions from the [Advanced algokit generate command](/algokit-cli/architecture-decisions/2023-07-19_advanced_generate_command/) and [Frontend Templates](/algokit-cli/architecture-decisions/2023-06-06_frontend-templates/) ADRs, integrating feedback from the Algorand Foundation and DevRel team.
### Main Areas for Improvement
diff --git a/docs/architecture-decisions/2024-01-31_binary_distribution.md b/docs/src/content/docs/architecture-decisions/2024-01-31_binary_distribution.md
similarity index 97%
rename from docs/architecture-decisions/2024-01-31_binary_distribution.md
rename to docs/src/content/docs/architecture-decisions/2024-01-31_binary_distribution.md
index 9547128e2..9d479896a 100644
--- a/docs/architecture-decisions/2024-01-31_binary_distribution.md
+++ b/docs/src/content/docs/architecture-decisions/2024-01-31_binary_distribution.md
@@ -1,4 +1,6 @@
-# AlgoKit CLI binary distribution
+---
+title: "AlgoKit CLI binary distribution"
+---
- **Status**: Approved
- **Owner:** Altynbek Orumbayev (MakerX)
@@ -9,7 +11,7 @@
## Context
-The following ADR is a continuation of [native binaries](./2024-01-13_native_binaries.md) ADR. With initial workflows implemented, the goal is to determine the best way to distribute the native binaries to the end users.
+The following ADR is a continuation of [native binaries](/algokit-cli/architecture-decisions/2024-01-13_native_binaries/) ADR. With initial workflows implemented, the goal is to determine the best way to distribute the native binaries to the end users.
## Requirements
@@ -19,7 +21,7 @@ The following ADR is a continuation of [native binaries](./2024-01-13_native_bin
## Technical Constraints
- ~~Pyinstaller binaries are dependend on the architecture and the OS. Github Actions mainly support `x86-64` architectures. This means that we need a self hosted runner to build binaries for `arm64` architectures OR use an alternative CI provider which has access to `arm64` and other architectures inside runners.~~ Based on recent announcement made at the date of submission of initial draft of this ADR, GitHub now supports mac os ARM runners on all OSS plans. This means we can target arm64 macos binaries using the default macos runners and potentially reuse them to build arm64 linux binaries using QEMU and/or buildx from Docker. Hence this is no longer a constraint - see [post](https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/).
-- Codesigning is a recommended practice for secure distribution and would need to be implemented on top of the initial workflows introduced as part of the implementation of the [native binaries](./2024-01-13_native_binaries.md) ADR.
+- Codesigning is a recommended practice for secure distribution and would need to be implemented on top of the initial workflows introduced as part of the implementation of the [native binaries](/algokit-cli/architecture-decisions/2024-01-13_native_binaries/) ADR.
## Options
diff --git a/docs/architecture-decisions/2024-03-06_local_dev_ui_packaging.md b/docs/src/content/docs/architecture-decisions/2024-03-06_local_dev_ui_packaging.md
similarity index 99%
rename from docs/architecture-decisions/2024-03-06_local_dev_ui_packaging.md
rename to docs/src/content/docs/architecture-decisions/2024-03-06_local_dev_ui_packaging.md
index 9254fc7a9..20a810c17 100644
--- a/docs/architecture-decisions/2024-03-06_local_dev_ui_packaging.md
+++ b/docs/src/content/docs/architecture-decisions/2024-03-06_local_dev_ui_packaging.md
@@ -1,4 +1,6 @@
-# Local dev UI packaging
+---
+title: "Local dev UI packaging"
+---
- **Status**: Draft
- **Owner:** Patrick Dinh (MakerX), Negar Abbasi (MakerX)
diff --git a/docs/articles/output_stability.md b/docs/src/content/docs/concepts/output-stability.md
similarity index 96%
rename from docs/articles/output_stability.md
rename to docs/src/content/docs/concepts/output-stability.md
index 31bbe99e2..8d9a30839 100644
--- a/docs/articles/output_stability.md
+++ b/docs/src/content/docs/concepts/output-stability.md
@@ -1,4 +1,6 @@
-# Smart Contract Output Stability
+---
+title: "Smart Contract Output Stability"
+---
Smart contracts development is analogous to low level firmware software development; it's a highly constrained environment in terms of both compute power and memory storage, with a high risk of vulnerabilities due to lower level access to memory and less developer-oriented security tooling.
Because of this, the assembly language code that is output for a smart contract is important - a seemingly innocuous minor change could inadvertently add a security vulnerability, or could significantly change the execution and memory profile.
diff --git a/docs/src/content/docs/features/compile.md b/docs/src/content/docs/features/compile.md
new file mode 100644
index 000000000..86ca49a48
--- /dev/null
+++ b/docs/src/content/docs/features/compile.md
@@ -0,0 +1,170 @@
+---
+title: "AlgoKit Compile"
+---
+
+The AlgoKit Compile feature enables you to compile smart contracts (apps) and smart signatures (logic signatures) written in a supported high-level language to a format deployable on the Algorand Virtual Machine (AVM).
+
+When running the compile command, AlgoKit will take care of working out which compiler you need and dynamically resolve it. Additionally, AlgoKit will detect if a matching compiler version is already installed globally on your machine or is included in your project and use that.
+
+## Prerequisites
+
+See [Compile Python - Prerequisites](#prerequisites-1) and [Compile TypeScript - Prerequisites](#prerequisites-2) for details.
+
+## What is Algorand Python & PuyaPy?
+
+Algorand Python is a semantically and syntactically compatible, typed Python language that works with standard Python tooling and allows you to express smart contracts (apps) and smart signatures (logic signatures) for deployment on the Algorand Virtual Machine (AVM).
+
+Algorand Python can be deployed to Algorand by using the PuyaPy optimising compiler, which takes Algorand Python and outputs [ARC-32](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0032.md) application spec files (among other formats) which, [when deployed](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/generate.md#1-typed-clients), will result in AVM bytecode execution semantics that match the given Python code.
+
+If you want to learn more, check out the [PuyaPy docs](https://github.com/algorandfoundation/puya/blob/main/docs/index.md).
+
+Below is an example Algorand Python smart contract.
+
+```py
+from algopy import ARC4Contract, arc4
+
+class HelloWorldContract(ARC4Contract):
+ @arc4.abimethod
+ def hello(self, name: arc4.String) -> arc4.String:
+ return "Hello, " + name
+```
+
+For more complex examples, see the [examples](https://github.com/algorandfoundation/puya/tree/main/examples) in the [PuyaPy repo](https://github.com/algorandfoundation/puya).
+
+## What is Algorand TypeScript & PuyaTs?
+
+Algorand TypeScript is a typed TypeScript language that allows you to express smart contracts (apps) and smart signatures (logic signatures) for deployment on the Algorand Virtual Machine (AVM). Algorand TypeScript is currently in beta.
+
+Algorand TypeScript can be deployed to Algorand by using the PuyaTs optimising compiler, which takes Algorand TypeScript and outputs [ARC-32](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0032.md) application spec files (among other formats) which, [when deployed](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/generate.md#1-typed-clients), will result in AVM bytecode execution semantics that match the given TypeScript code.
+
+Below is an example Algorand TypeScript smart contract.
+
+```typescript
+import { Contract } from "@algorandfoundation/puya-sdk";
+
+class HelloWorldContract extends Contract {
+ hello(name: string): string {
+ return "Hello, " + name;
+ }
+}
+```
+
+## Usage
+
+Available commands and possible usage are as follows:
+
+```
+Usage: algokit compile [OPTIONS] COMMAND [ARGS]...
+
+ Compile smart contracts and smart signatures written in a supported high-level language to a format deployable on
+ the Algorand Virtual Machine (AVM).
+
+Options:
+ -v, --version TEXT The compiler version to pin to, for example, 1.0.0. If no version is specified, AlgoKit checks
+ if the compiler is installed and runs the installed version. If the compiler is not installed,
+ AlgoKit runs the latest version. If a version is specified, AlgoKit checks if an installed
+ version matches and runs the installed version. Otherwise, AlgoKit runs the specified version.
+ -h, --help Show this message and exit.
+
+Commands:
+ py Compile Algorand Python contract(s) using the PuyaPy compiler.
+ python Compile Algorand Python contract(s) using the PuyaPy compiler.
+ ts Compile Algorand TypeScript contract(s) using the PuyaTs compiler.
+ typescript Compile Algorand TypeScript contract(s) using the PuyaTs compiler.
+```
+
+### Compile Python
+
+The command `algokit compile python` or `algokit compile py` will run the [PuyaPy](https://github.com/algorandfoundation/puya) compiler against the supplied Algorand Python smart contract.
+
+All arguments supplied to the command are passed directly to PuyaPy, therefore this command supports all options supported by the PuyaPy compiler.
+
+Any errors detected by PuyaPy during the compilation process will be printed to the output.
+
+#### Prerequisites
+
+PuyaPy requires Python 3.12+, so please ensure your Python version satisfies this requirement.
+
+This command will attempt to resolve a matching installed PuyaPy compiler, either globally installed in the system or locally installed in your project (via [Poetry](https://python-poetry.org/)). If no appropriate match is found, the PuyaPy compiler will be dynamically run using [pipx](https://pipx.pypa.io/stable/). In this case pipx is also required.
+
+#### Examples
+
+To see a list of the supported PuyaPy options, run the following:
+
+```shell
+algokit compile python -h
+```
+
+To determine the version of the PuyaPy compiler in use, execute the following command:
+
+```shell
+algokit compile python --version
+```
+
+To compile a single Algorand Python smart contract and write the output to a specific location, run the following:
+
+```shell
+algokit compile python hello_world/contract.py --out-dir hello_world/out
+```
+
+To compile multiple Algorand Python smart contracts and write the output to a specific location, run the following:
+
+```shell
+algokit compile python hello_world/contract.py calculator/contract.py --out-dir my_contracts
+```
+
+To compile a directory of Algorand Python smart contracts and write the output to the default location, run the following:
+
+```shell
+algokit compile python my_contracts
+```
+
+### Compile TypeScript
+
+The command `algokit compile typescript` or `algokit compile ts` will run the PuyaTs compiler against the supplied Algorand TypeScript smart contract.
+
+All arguments supplied to the command are passed directly to PuyaTs, therefore this command supports all options supported by the PuyaTs compiler.
+
+Any errors detected by PuyaTs during the compilation process will be printed to the output.
+
+#### Prerequisites
+
+PuyaTs requires Node 22+ and NPM 10+, so please ensure your versions satisfy this requirement.
+
+The command will attempt to find a correctly installed PuyaTs compiler in the following order:
+
+1. First, it checks if a matching version is installed at the project level (using `npm ls`).
+2. Next, it checks if a matching version is installed globally (using `npm --global ls`).
+3. If no appropriate match is found, it will run the compiler using npx with the `-y` flag.
+
+#### Examples
+
+To see a list of the supported PuyaTs options, run the following:
+
+```shell
+algokit compile typescript -h
+```
+
+To determine the version of the PuyaTs compiler in use, execute the following command:
+
+```shell
+algokit compile typescript --version
+```
+
+To compile a single Algorand TypeScript smart contract and write the output to a specific location, run the following:
+
+```shell
+algokit compile typescript hello_world/contract.algo.ts --out-dir hello_world/out
+```
+
+To build multiple Algorand TypeScript smart contracts and write the output to a specific location, run the following:
+
+```shell
+algokit compile typescript hello_world/contract.algo.ts calculator/contract.algo.ts --out-dir my_contracts
+```
+
+To compile a directory of Algorand TypeScript smart contracts and write the output to the default location, run the following:
+
+```shell
+algokit compile typescript my_contracts
+```
diff --git a/docs/features/completions.md b/docs/src/content/docs/features/completions.md
similarity index 65%
rename from docs/features/completions.md
rename to docs/src/content/docs/features/completions.md
index 79ef0c167..22d42e044 100644
--- a/docs/features/completions.md
+++ b/docs/src/content/docs/features/completions.md
@@ -1,18 +1,20 @@
-# AlgoKit Completions
+---
+title: "AlgoKit Completions"
+---
AlgoKit supports shell completions for zsh and bash shells, e.g.
**bash**
-```
-$ algokit
+```bash
+algokit
bootstrap completions config doctor explore goal init sandbox
```
**zsh**
-```
-$ ~ algokit
+```bash
+algokit
bootstrap -- Bootstrap AlgoKit project dependencies.
completions -- Install and Uninstall AlgoKit shell integration.
config -- Configure AlgoKit options.
@@ -30,10 +32,10 @@ To setup the completions, AlgoKit provides commands that will modify the current
> **Note**
> If you would prefer AlgoKit to not modify your interactive shell scripts you can install the completions yourself by following the instructions [here](https://click.palletsprojects.com/en/8.1.x/shell-completion/).
-To [install](../cli/index.md#install) completions for the current shell execute `algokit completions install`. You should see output similar to below:
+To [install](/algokit-cli/cli/#install) completions for the current shell execute `algokit completions install`. You should see output similar to below:
-```
-$ ~ algokit completions install
+```bash
+algokit completions install
AlgoKit completions installed for zsh 🎉
Restart shell or run `. ~/.zshrc` to enable completions
```
@@ -42,15 +44,15 @@ After installing the completions don't forget to restart the shell to begin usin
## Uninstalling
-To [uninstall](../cli/index.md#uninstall) completions for the current shell run `algokit completions uninstall`:
+To [uninstall](/algokit-cli/cli/#uninstall) completions for the current shell run `algokit completions uninstall`:
-```
-$ ~ algokit completions uninstall
+```bash
+algokit completions uninstall
AlgoKit completions uninstalled for zsh 🎉
```
## Shell Option
-To install/uninstall the completions for a specific [shell](../cli/index.md#--shell-) the `--shell` option can be used e.g. `algokit completions install --shell bash`.
+To install/uninstall the completions for a specific [shell](/algokit-cli/cli/#--shell-) the `--shell` option can be used e.g. `algokit completions install --shell bash`.
-To learn more about the `algokit completions` command, please refer to [completions](../cli/index.md#completions) in the AlgoKit CLI reference documentation.
+To learn more about the `algokit completions` command, please refer to [completions](/algokit-cli/cli/#completions) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/config.md b/docs/src/content/docs/features/config.md
similarity index 80%
rename from docs/features/config.md
rename to docs/src/content/docs/features/config.md
index b604a4d4f..2318597cc 100644
--- a/docs/features/config.md
+++ b/docs/src/content/docs/features/config.md
@@ -1,4 +1,6 @@
-# AlgoKit Config
+---
+title: "AlgoKit Config"
+---
The `algokit config` command allows you to manage various global settings used by AlgoKit CLI. This feature is essential for customizing your AlgoKit environment to suit your needs.
@@ -14,8 +16,8 @@ Subcommands
### Version Prompt Configuration
-```zsh
-$ algokit config version-prompt [OPTIONS]
+```bash
+algokit config version-prompt [OPTIONS]
```
This command configures the version prompt settings for AlgoKit.
@@ -25,8 +27,8 @@ This command configures the version prompt settings for AlgoKit.
### Container Engine Configuration
-```zsh
-$ algokit config container-engine [OPTIONS] [ENGINE]
+```bash
+algokit config container-engine [OPTIONS] [ENGINE]
```
This command configures the container engine settings for AlgoKit.
@@ -36,8 +38,8 @@ This command configures the container engine settings for AlgoKit.
### JavaScript Package Manager Configuration
-```zsh
-$ algokit config js-package-manager [OPTIONS] [PACKAGE_MANAGER]
+```bash
+algokit config js-package-manager [OPTIONS] [PACKAGE_MANAGER]
```
This command configures the default JavaScript package manager used by AlgoKit's bootstrap command.
@@ -48,8 +50,8 @@ If no package manager is specified, AlgoKit will prompt you to select one intera
### Python Package Manager Configuration
-```zsh
-$ algokit config py-package-manager [OPTIONS] [PACKAGE_MANAGER]
+```bash
+algokit config py-package-manager [OPTIONS] [PACKAGE_MANAGER]
```
This command configures the default Python package manager used by AlgoKit's bootstrap command.
@@ -60,4 +62,4 @@ If no package manager is specified, AlgoKit will prompt you to select one intera
## Further Reading
-For in-depth details, visit the [configuration section](../cli/index.md#config) in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [configuration section](/algokit-cli/cli/#config) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/dispenser.md b/docs/src/content/docs/features/dispenser.md
similarity index 85%
rename from docs/features/dispenser.md
rename to docs/src/content/docs/features/dispenser.md
index f2de4ea09..7da469a8e 100644
--- a/docs/features/dispenser.md
+++ b/docs/src/content/docs/features/dispenser.md
@@ -1,11 +1,13 @@
-# AlgoKit TestNet Dispenser
+---
+title: "AlgoKit TestNet Dispenser"
+---
The AlgoKit Dispenser feature allows you to interact with the AlgoKit TestNet Dispenser. This feature is essential for funding your wallet with TestNet ALGOs, refunding ALGOs back to the dispenser wallet, and getting information about current fund limits on your account.
## Usage
-```zsh
-$ algokit dispenser [OPTIONS] COMMAND [ARGS]...
+```bash
+algokit dispenser [OPTIONS] COMMAND [ARGS]...
```
This command provides a set of subcommands to interact with the AlgoKit TestNet Dispenser.
@@ -27,8 +29,8 @@ All dispenser commands can work in CI mode by using a CI access token that can b
## Login
-```zsh
-$ algokit dispenser login [OPTIONS]
+```bash
+algokit dispenser login [OPTIONS]
```
This command logs you into your Dispenser API account if you are not already logged in.
@@ -42,29 +44,29 @@ Options
## Logout
-```zsh
-$ algokit dispenser logout
+```bash
+algokit dispenser logout
```
This command logs you out of your Dispenser API account if you are logged in.
## Fund
-```zsh
-$ algokit dispenser fund [OPTIONS]
+```bash
+algokit dispenser fund [OPTIONS]
```
This command funds your wallet address with TestNet ALGOs.
Options
-- `--receiver`, -r: Receiver [alias](./tasks/wallet.md#add) or address to fund with TestNet ALGOs. This option is required.
+- `--receiver`, -r: Receiver [alias](/algokit-cli/features/tasks/wallet/#add) or address to fund with TestNet ALGOs. This option is required.
- `--amount`, -a: Amount to fund. Defaults to microAlgos. This option is required.
- `--whole-units`: Use whole units (Algos) instead of smallest divisible units (microAlgos). Disabled by default.
## Refund
-```zsh
-$ algokit dispenser refund [OPTIONS]
+```bash
+algokit dispenser refund [OPTIONS]
```
This command refunds ALGOs back to the dispenser wallet address.
@@ -76,8 +78,8 @@ Options
## Limit
-```zsh
-$ algokit dispenser limit [OPTIONS]
+```bash
+algokit dispenser limit [OPTIONS]
```
This command gets information about current fund limits on your account. The limits reset daily.
@@ -87,4 +89,4 @@ Options
## Further Reading
-For in-depth details, visit the [dispenser section](../cli/index.md#dispenser) in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [dispenser section](/algokit-cli/cli/#dispenser) in the AlgoKit CLI reference documentation.
diff --git a/docs/src/content/docs/features/doctor.md b/docs/src/content/docs/features/doctor.md
new file mode 100644
index 000000000..d2691f9b8
--- /dev/null
+++ b/docs/src/content/docs/features/doctor.md
@@ -0,0 +1,57 @@
+---
+title: "AlgoKit Doctor"
+---
+
+The AlgoKit Doctor feature allows you to check your AlgoKit installation along with its dependencies. This is useful for diagnosing potential issues with using AlgoKit.
+
+## Functionality
+
+The AlgoKit Doctor allows you to make sure that your system has the correct dependencies installed and that they satisfy the minimum required versions. All passed checks will appear in your command line natural color while warnings will be in yellow (warning) and errors or missing critical services will be in red (error). The critical services that AlgoKit will check for (since they are [directly used by certain commands](../../README.md#prerequisites)): Docker, docker compose and git.
+
+Please run this command to if you are facing an issue running AlgoKit. It is recommended to run it before [submitting an issue to AlgoKit](https://github.com/algorandfoundation/algokit-cli/issues/new). You can copy the contents of the Doctor command message (in Markdown format) to your clipboard by providing the `-c` flag to the command as follows `algokit doctor -c`.
+
+> NOTE: You can also use the `--verbose` or `-v` flag to show additional information including package dependencies of the AlgoKit CLI: `algokit -v doctor`. This only works when `algokit` is installed as a Python package (e.g., via `pipx install algokit`).
+
+# Examples
+
+For example, running `algokit doctor` with all prerequisites installed will result in output similar to the following:
+
+```bash
+algokit doctor
+timestamp: 2023-03-29T03:58:05+00:00
+AlgoKit: 0.6.0
+AlgoKit Python: 3.11.2 (main, Mar 24 2023, 00:16:47) [Clang 14.0.0 (clang-1400.0.29.202)] (location: /Users/algokit/.local/pipx/venvs/algokit)
+OS: macOS-13.2.1-arm64-arm-64bit
+docker: 20.10.22
+docker compose: 2.15.1
+git: 2.39.1
+python: 3.10.9 (location: /Users/algokit/.asdf/shims/python)
+python3: 3.10.9 (location: /Users/algokit/.asdf/shims/python3)
+pipx: 1.2.0
+poetry: 1.3.2
+node: 18.12.1
+npm: 8.19.2
+brew: 4.0.10-34-gb753315
+
+If you are experiencing a problem with AlgoKit, feel free to submit an issue via:
+https://github.com/algorandfoundation/algokit-cli/issues/new
+Please include this output, if you want to populate this message in your clipboard, run `algokit doctor -c`
+```
+
+The doctor command will indicate if there is any issues to address, for example:
+
+If AlgoKit detects a newer version, this will be indicated next to the AlgoKit version
+
+```bash
+AlgoKit: 1.2.3 (latest: 4.5.6)
+```
+
+If the detected version of docker compose is unsupported, this will be shown:
+
+```bash
+docker compose: 2.1.3
+ Docker Compose 2.5.0 required to run `algokit localnet command`;
+ install via https://docs.docker.com/compose/install/
+```
+
+For more details about the `AlgoKit doctor` command, please refer to the [AlgoKit CLI reference documentation](/algokit-cli/cli/#doctor).
diff --git a/docs/features/explore.md b/docs/src/content/docs/features/explore.md
similarity index 56%
rename from docs/features/explore.md
rename to docs/src/content/docs/features/explore.md
index 6eff46e4f..0550fb372 100644
--- a/docs/features/explore.md
+++ b/docs/src/content/docs/features/explore.md
@@ -1,10 +1,12 @@
-# AlgoKit explore
+---
+title: "AlgoKit Explore"
+---
-AlgoKit provides a quick shortcut to [explore](../cli/index.md#explore) various Algorand networks using [lora](https://lora.algokit.io/) including [AlgoKit LocalNet](./localnet.md)!
+AlgoKit provides a quick shortcut to [explore](/algokit-cli/cli/#explore) various Algorand networks using [lora](https://lora.algokit.io/) including [AlgoKit LocalNet](/algokit-cli/features/localnet/)!
## LocalNet
-The following three commands are all equivalent and will open lora pointing to the local [AlgoKit LocalNet](./localnet.md) instance:
+The following three commands are all equivalent and will open lora pointing to the local [AlgoKit LocalNet](/algokit-cli/features/localnet/) instance:
- `algokit explore`
- `algokit explore localnet`
@@ -18,4 +20,4 @@ The following three commands are all equivalent and will open lora pointing to t
`algokit explore mainnet` will open lora pointing to MainNet via the [node](https://algonode.io/api/).
-To learn more about the `algokit explore` command, please refer to [explore](../cli/index.md#explore) in the AlgoKit CLI reference documentation.
+To learn more about the `algokit explore` command, please refer to [explore](/algokit-cli/cli/#explore) in the AlgoKit CLI reference documentation.
diff --git a/docs/src/content/docs/features/generate.md b/docs/src/content/docs/features/generate.md
new file mode 100644
index 000000000..b4d63e3d0
--- /dev/null
+++ b/docs/src/content/docs/features/generate.md
@@ -0,0 +1,181 @@
+---
+title: "AlgoKit Generate"
+---
+
+The `algokit generate` [command](/algokit-cli/cli/#generate) is used to generate components used in an AlgoKit project. It also allows for custom generate commands which are loaded from the .algokit.toml file in your project directory.
+
+## 1. Typed clients
+
+The `algokit generate client` [command](/algokit-cli/cli/#client) can be used to generate a typed client from an [ARC-0032](https://arc.algorand.foundation/ARCs/arc-0032) or [ARC-0056](https://github.com/algorandfoundation/ARCs/pull/258) application specification with both Python and TypeScript available as target languages.
+
+### Prerequisites
+
+To generate Python clients an installation of pip and pipx is required.
+To generate TypeScript clients an installation of Node.js and npx is also required.
+
+Each generated client will also have a dependency on `algokit-utils` libraries for the target language.
+
+### Input file / directory
+
+You can either specify a path to an ARC-0032 JSON file, an ARC-0056 JSON file or to a directory that is recursively scanned for `application.json`, `*.arc32.json`, `*.arc56.json` file(s).
+
+### Output tokens
+
+The output path is interpreted as relative to the current working directory, however an absolute path may also be specified e.g.
+`algokit generate client application.json --output /absolute/path/to/client.py`
+
+There are two tokens available for use with the `-o`, `--output` [option](/algokit-cli/cli/#-o---output-output_path_pattern):
+
+- `{contract_name}`: This will resolve to a name based on the ARC-0032/ARC-0056 contract name, formatted appropriately for the target language.
+- `{app_spec_dir}`: This will resolve to the parent directory of the `application.json`, `*.arc32.json`, `*.arc56.json` file which can be useful to output a client relative to its source file.
+
+### Version Pinning
+
+If you want to ensure typed client output stability across different environments and additionally protect yourself from any potential breaking changes introduced in the client generator packages, you can specify a version you'd like to pin to.
+
+To make use of this feature, pass `-v`, `--version`, for example `algokit generate client --version 1.2.3 path/to/application.json`.
+
+Alternatively, you can achieve output stability by installing the underlying [Python](https://github.com/algorandfoundation/algokit-client-generator-py) or [TypeScript](https://github.com/algorandfoundation/algokit-client-generator-ts) client generator package either locally in your project (via `poetry` or `npm` respectively) or globally on your system (via `pipx` or `npm` respectively). AlgoKit will search for a matching installed version before dynamically resolving.
+
+### Usage
+
+Usage examples of using a generated client are below, typed clients allow your favourite IDE to provide better intellisense to provide better discoverability
+of available operations and parameters.
+
+#### Python
+
+```python
+# A similar working example can be seen in the algokit python template, when using Python deployment
+from smart_contracts.artifacts.HelloWorldApp.client import (
+ HelloWorldAppClient,
+)
+
+app_client = HelloWorldAppClient(
+ algod_client,
+ creator=deployer,
+ indexer_client=indexer_client,
+)
+deploy_response = app_client.deploy(
+ on_schema_break=OnSchemaBreak.ReplaceApp,
+ on_update=OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
+)
+
+response = app_client.hello(name="World")
+```
+
+#### TypeScript
+
+```typescript
+// A similar working example can be seen in the algokit python template with typescript deployer, when using TypeScript deployment
+import { HelloWorldAppClient } from "./artifacts/HelloWorldApp/client";
+
+const appClient = new HelloWorldAppClient(
+ {
+ resolveBy: "creatorAndName",
+ findExistingUsing: indexer,
+ sender: deployer,
+ creatorAddress: deployer.addr,
+ },
+ algod
+);
+const app = await appClient.deploy({
+ allowDelete: isLocal,
+ allowUpdate: isLocal,
+ onSchemaBreak: isLocal ? "replace" : "fail",
+ onUpdate: isLocal ? "update" : "fail",
+});
+const response = await appClient.hello({ name: "world" });
+```
+
+### Examples
+
+To output a single application.json to a python typed client:
+`algokit generate client path/to/application.json --output client.py`
+
+To process multiple application.json in a directory structure and output to a typescript client for each in the current directory:
+`algokit generate client smart_contracts/artifacts --output {contract_name}.ts`
+
+To process multiple application.json in a directory structure and output to a python client alongside each application.json:
+`algokit generate client smart_contracts/artifacts --output {app_spec_path}/client.py`
+
+## 2. Using Custom Generate Commands
+
+Custom generate commands are defined in the `.algokit.toml` file within the project directory, typically supplied by community template builders or official AlgoKit templates. These commands are specified under the `generate` key and serve to execute a generator at a designated path with provided answer key/value pairs.
+
+### Understanding `Generators`
+
+A `generator` is essentially a compact, self-sufficient `copier` template. This template can optionally be defined within the primary `algokit templates` to offer supplementary functionality after a project is initialized from the template. For instance, the official [`algokit-python-template`](https://github.com/algorandfoundation/algokit-python-template/tree/main/template_content) provides a generator within the `.algokit/generators` directory. This generator can be employed for executing extra tasks on AlgoKit projects that have been initiated from this template, such as adding new smart contracts to an existing project. For a comprehensive explanation, please refer to the [`architecture decision record`](/algokit-cli/architecture-decisions/2023-07-19_advanced_generate_command/).
+
+### Requirements
+
+To utilize custom generate commands, you must have `copier` installed. This installation is included by default in the AlgoKit CLI. Therefore, no additional installation is necessary if you have already installed the `algokit cli`.
+
+### How to Use
+
+A custom command can be defined in the `.algokit.toml` as shown:
+
+```toml
+[generate.my_generator]
+path = "path/to/my_generator"
+description = "A brief description of the function of my_generator"
+```
+
+Following this, you can execute the command as follows:
+
+`algokit generate my_generator --answer key value --path path/to/my_generator`
+
+If no `path` is given, the command will use the path specified in the `.algokit.toml`. If no `answer` is provided, the command will initiate an interactive `copier` prompt to request answers (similar to `algokit init`).
+
+The custom command employs the `copier` library to duplicate the files from the generator's path to the current working directory, substituting any values from the `answers` dictionary.
+
+### Examples
+
+As an example, let's use the `smart-contract` generator from the `algokit-python-template` to add new contract to an existing project based on that template. The `smart-contract` generator is defined as follows:
+
+```toml
+[algokit]
+min_version = "v1.3.1"
+
+... # other keys
+
+[generate.smart_contract]
+description = "Adds a new smart contract to the existing project"
+path = ".algokit/generators/create_contract"
+```
+
+To execute this generator, ensure that you are operating from the same directory as the `.algokit.toml` file, and then run:
+
+```bash
+algokit generate
+
+# The output will be as follows:
+# Note how algokit dynamically injects a new `smart-contract` command based
+# on the `.algokit.toml` file
+
+Usage: algokit generate [OPTIONS] COMMAND [ARGS]...
+
+ Generate code for an Algorand project.
+
+Options:
+ -h, --help Show this message and exit.
+
+Commands:
+ client Create a typed ApplicationClient from an ARC-32 application.json
+ smart-contract Adds a new smart contract to the existing project
+```
+
+To execute the `smart-contract` generator, run:
+
+```bash
+algokit generate smart-contract
+
+# or
+
+algokit generate smart-contract -a contract_name "MyCoolContract"
+```
+
+#### Third Party Generators
+
+It is important to understand that by default, AlgoKit will always prompt you before executing a generator to ensure it's from a trusted source. If you are confident about the source of the generator, you can use the `--force` or `-f` option to execute the generator without this confirmation prompt. Be cautious while using this option and ensure the generator is from a trusted source. At the moment, a trusted source for a generator is defined as _a generator that is included in the official AlgoKit templates (e.g. `smart-contract` generator in `algokit-python-template`)_
diff --git a/docs/features/goal.md b/docs/src/content/docs/features/goal.md
similarity index 94%
rename from docs/features/goal.md
rename to docs/src/content/docs/features/goal.md
index 58f1c7c21..2139d4a9b 100644
--- a/docs/features/goal.md
+++ b/docs/src/content/docs/features/goal.md
@@ -1,11 +1,13 @@
-# AlgoKit goal
+---
+title: "AlgoKit Goal"
+---
-AlgoKit goal command provides the user with a mechanism to run [goal cli](https://dev.algorand.co/algokit/algokit-cli/goal/) commands against the current [AlgoKit LocalNet](./localnet.md).
+AlgoKit goal command provides the user with a mechanism to run [goal cli](https://dev.algorand.co/algokit/algokit-cli/goal/) commands against the current [AlgoKit LocalNet](/algokit-cli/features/localnet/).
You can explore all possible goal commands by running `algokit goal` e.g.:
-```
-$ ~ algokit goal
+```bash
+algokit goal
GOAL is the CLI for interacting Algorand software instance. The binary 'goal' is installed alongside the algod binary and is considered an integral part of the complete installation. The binaries should be used in tandem - you should not try to use a version of goal with a different version of algod.
Usage:
@@ -41,8 +43,8 @@ $ ~ algokit goal
For instance, running `algokit goal report` would result in output like:
-```
-$ ~ algokit goal report
+```bash
+algokit goal report
12885688322
3.12.2.dev [rel/stable] (commit #181490e3)
go-algorand is licensed with AGPLv3.0
@@ -66,14 +68,14 @@ $ ~ algokit goal report
If the AlgoKit Sandbox `algod` docker container is not present or not running, the command will fail with a clear error, e.g.:
-```
-$ ~ algokit goal
+```bash
+algokit goal
Error: No such container: algokit_algod
Error: Error executing goal; ensure the Sandbox is started by executing `algokit sandbox status`
```
-```
-$ ~ algokit goal
+```bash
+algokit goal
Error response from daemon: Container 5a73961536e2c98e371465739053d174066c40d00647c8742f2bb39eb793ed7e is not running
Error: Error executing goal; ensure the Sandbox is started by executing `algokit sandbox status`
```
@@ -88,7 +90,7 @@ When you specify a file or directory path in your `goal` command, the system wil
For instance, if you want to compile a `teal` file:
-```
+```bash
algokit goal clerk compile /Path/to/inputfile/approval.teal -o /Path/to/outputfile/approval.compiled
```
@@ -98,7 +100,7 @@ Here, `/Path/to/inputfile/approval.teal` and `/Path/to/outputfile/approval.compi
In case you want to manually copy files into the container, you can do so using `docker cp`:
-```
+```bash
docker cp foo.txt algokit_algod:/root
```
@@ -111,7 +113,7 @@ Note: Manual copying is optional and generally only necessary if you have specif
If you want to run multiple commands or interact with the filesystem you can execute `algokit goal --console`. This will open a [Bash](https://www.gnu.org/software/bash/) shell session on the `algod` Docker container and from there you can execute goal directly, e.g.:
```bash
-$ algokit goal --console
+algokit goal --console
Opening Bash console on the algod node; execute `exit` to return to original console
root@82d41336608a:~# goal account list
[online] C62QEFC7MJBPHAUDMGVXGZ7WRWFAF3XYPBU3KZKOFHYVUYDGU5GNWS4NWU C62QEFC7MJBPHAUDMGVXGZ7WRWFAF3XYPBU3KZKOFHYVUYDGU5GNWS4NWU 4000000000000000 microAlgos
@@ -124,7 +126,7 @@ root@82d41336608a:~# goal account list
Some `goal` commands require interactive input from the user. By default, AlgoKit will attempt to run commands in non-interactive mode first, and automatically switch to interactive mode if needed. You can force a command to run in interactive mode by using the `--interactive` flag:
```bash
-$ algokit goal --interactive wallet new algodev
+algokit goal --interactive wallet new algodev
Please choose a password for wallet 'algodev':
Please confirm the password:
Creating wallet...
@@ -136,4 +138,4 @@ Would you like to see it now? (Y/n): n
This is particularly useful when you know a command will require user input, such as creating new accounts, importing keys, or signing transactions.
-For more details about the `AlgoKit goal` command, please refer to the [AlgoKit CLI reference documentation](../cli/index.md#goal).
+For more details about the `AlgoKit goal` command, please refer to the [AlgoKit CLI reference documentation](/algokit-cli/cli/#goal).
diff --git a/docs/features/init.md b/docs/src/content/docs/features/init.md
similarity index 90%
rename from docs/features/init.md
rename to docs/src/content/docs/features/init.md
index 5af907970..e71047550 100644
--- a/docs/features/init.md
+++ b/docs/src/content/docs/features/init.md
@@ -1,6 +1,8 @@
-# AlgoKit Init
+---
+title: "AlgoKit Init"
+---
-The `algokit init` [command](../cli/index.md#init) is used to quickly initialize new projects using official Algorand Templates or community provided templates. It supports a fully guided command line wizard experience, as well as fully scriptable / non-interactive functionality via command options.
+The `algokit init` [command](/algokit-cli/cli/#init) is used to quickly initialize new projects using official Algorand Templates or community provided templates. It supports a fully guided command line wizard experience, as well as fully scriptable / non-interactive functionality via command options.
## Quick start
@@ -14,8 +16,8 @@ Git is a prerequisite for the init command as it is used to clone templates and
As outlined in [quick start](#quick-start), the simplest use of the command is to just run `algokit init` and you will then be guided through selecting a template and configuring options for that template. e.g.
-```
-$ ~ algokit init
+```bash
+algokit init
? Which of these options best describes the project you want to start? `Smart Contract` | `Dapp Frontend` | `Smart Contract & Dapp Frontend` | `Custom`
? Name of project / directory to create the project in: my-cool-app
```
@@ -32,13 +34,13 @@ To initialize a project within a workspace, use the `--workspace` flag. If a wor
To create a standalone project, use the `--no-workspace` flag during initialization. This instructs AlgoKit to bypass the workspace structure and set up the project as an isolated entity.
-For more details on workspaces and standalone projects, refer to the [AlgoKit Project documentation](./project.md#workspaces-vs-standalone-projects).
+For more details on workspaces and standalone projects, refer to the [AlgoKit Project documentation](/algokit-cli/features/project/#workspaces-vs-standalone-projects).
## Bootstrapping
-You will also be prompted if you wish to run the [bootstrap](../cli/index.md#bootstrap) command, this is useful if you plan to immediately begin developing in the new project. If you passed in `--defaults` or `--bootstrap` then it will automatically run bootstrapping unless you passed in `--no-bootstrap`.
+You will also be prompted if you wish to run the [bootstrap](/algokit-cli/cli/#bootstrap) command, this is useful if you plan to immediately begin developing in the new project. If you passed in `--defaults` or `--bootstrap` then it will automatically run bootstrapping unless you passed in `--no-bootstrap`.
-```
+```bash
? Do you want to run `algokit bootstrap` to bootstrap dependencies for this new project so it can be run immediately? Yes
Installing Python dependencies and setting up Python virtual environment via Poetry
@@ -73,7 +75,7 @@ After bootstrapping you are also given the opportunity to initialize a git repo,
## Options
-There are a number of options that can be used to provide answers to the template prompts. Some of the options requiring further explanation are detailed below, but consult the CLI reference for all available [options](../cli/index.md#init).
+There are a number of options that can be used to provide answers to the template prompts. Some of the options requiring further explanation are detailed below, but consult the CLI reference for all available [options](/algokit-cli/cli/#init).
## Community Templates
@@ -87,7 +89,7 @@ e.g. `algokit init --template-url https://github.com/algorandfoundation/algokit-
If the URL is not an official template there is a potential security risk and so to continue you must either acknowledge this prompt, or if you are in a non-interactive environment you can pass the `--UNSAFE-SECURITY-accept-template-url` option (but we generally don't recommend this option so users can review the warning message first) e.g.
-```
+```bash
Community templates have not been reviewed, and can execute arbitrary code.
Please inspect the template repository, and pay particular attention to the values of \_tasks, \_migrations and \_jinja_extensions in copier.yml
@@ -107,9 +109,9 @@ To find out the key for a specific answer you can either look at `.algokit/.copi
By combining a number of options, it is possible to initialize a new project without any interaction. For example, to create a project named `my-smart-contract` using the `python` template with no git, no bootstrapping, the author name of `Algorand Foundation`, and defaults for all other values, you could execute the following:
-```
+```bash
-$ ~ algokit init -n my-smart-contract -t python --no-git --no-bootstrap --answer author_name "Algorand Foundation" --defaults
+algokit init -n my-smart-contract -t python --no-git --no-bootstrap --answer author_name "Algorand Foundation" --defaults
🙌 Project initialized at `my-smart-contract`! For template specific next steps, consult the documentation of your selected template 🧐
Your selected template comes from:
➡️ https://github.com/algorandfoundation/algokit-python-template
@@ -157,4 +159,4 @@ To explore what examples are available before initializing, you can run the inte
After initializing an example, AlgoKit automatically attempts to open the project in your default IDE to help you quickly start exploring and modifying the code.
-For more details about the `AlgoKit init` command, please refer to the [AlgoKit CLI reference documentation](../cli/index.md#init).
+For more details about the `AlgoKit init` command, please refer to the [AlgoKit CLI reference documentation](/algokit-cli/cli/#init).
diff --git a/docs/features/localnet.md b/docs/src/content/docs/features/localnet.md
similarity index 96%
rename from docs/features/localnet.md
rename to docs/src/content/docs/features/localnet.md
index 9c4abd61f..cf7456f4f 100644
--- a/docs/features/localnet.md
+++ b/docs/src/content/docs/features/localnet.md
@@ -1,4 +1,6 @@
-# AlgoKit LocalNet
+---
+title: "AlgoKit LocalNet"
+---
The AlgoKit LocalNet feature allows you to manage (start, stop, reset, manage) a locally sandboxed private Algorand network. This allows you to interact and deploy changes against your own Algorand network without needing to worry about funding TestNet accounts, information you submit being publicly visible or being connected to an active Internet connection (once the network has been started).
@@ -130,11 +132,11 @@ To reset the LocalNet you can execute `algokit localnet reset`, which will tear
### Viewing transactions in the LocalNet
-You can see a web-based user interface of the current state of your LocalNet including all transactions by using the [AlgoKit Explore](./explore.md) feature, e.g. by executing `algokit localnet explore`.
+You can see a web-based user interface of the current state of your LocalNet including all transactions by using the [AlgoKit Explore](/algokit-cli/features/explore/) feature, e.g. by executing `algokit localnet explore`.
### Executing goal commands against AlgoKit LocalNet
-See the [AlgoKit Goal](./goal.md) feature. You can also execute `algokit localnet console` to open a [Bash shell which allows you to run the goal commandline](./goal.md#running-multiple-commands).
+See the [AlgoKit Goal](/algokit-cli/features/goal/) feature. You can also execute `algokit localnet console` to open a [Bash shell which allows you to run the goal commandline](/algokit-cli/features/goal/#running-multiple-commands).
Note: if you want to copy files into the container so you can access them via goal then you can use the following:
@@ -164,7 +166,7 @@ AlgoKit Utils provides methods to help you do this:
- TypeScript - [`ensureFunded`](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/transfer.md#ensurefunded) and [`getDispenserAccount`](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/transfer.md#dispenser)
- Python - [`ensure_funded`](https://algorandfoundation.github.io/algokit-utils-py/html/apidocs/algokit_utils/algokit_utils.html#algokit_utils.ensure_funded) and [`get_dispenser_account`](https://algorandfoundation.github.io/algokit-utils-py/html/apidocs/algokit_utils/algokit_utils.html#algokit_utils.get_dispenser_account)
-For more details about the `AlgoKit localnet` command, please refer to the [AlgoKit CLI reference documentation](../cli/index.md#localnet).
+For more details about the `AlgoKit localnet` command, please refer to the [AlgoKit CLI reference documentation](/algokit-cli/cli/#localnet).
## GitHub Codespaces-based LocalNet
@@ -186,6 +188,6 @@ Running an interactive session ensures that you have control over the lifecycle
- `-r`, `--repo-url`: The URL of the repository to use. Defaults to the AlgoKit base template repository (`algorandfoundation/algokit-base-template`). The reason why algokit-base-template is used by default is due to [.devcontainer.json](https://github.com/algorandfoundation/algokit-base-template/blob/main/template_content/.devcontainer.json) which defines the scripts that take care of setting up AlgoKit CLI during container start. You can use any custom repo as a base, however it's important to ensure the reference [.devcontainer.json](https://github.com/algorandfoundation/algokit-base-template/blob/main/template_content/.devcontainer.json) file exists in your repository **otherwise there will be no ports to forward from the codespace**.
- `--force`, `-f`: Force deletes stale codespaces and skips confirmation prompts. Defaults to explicitly prompting for confirmation.
-For more details about managing LocalNet in GitHub Codespaces, please refer to the [AlgoKit CLI reference documentation](../cli/index.md#codespace).
+For more details about managing LocalNet in GitHub Codespaces, please refer to the [AlgoKit CLI reference documentation](/algokit-cli/cli/#codespace).
> Tip: By specifying alternative port values it is possible to have several LocalNet instances running where one is using default ports via `algokit localnet start` with Docker | Podman and the other relies on port forwarding via `algokit localnet codespace`.
diff --git a/docs/algokit.md b/docs/src/content/docs/features/overview.md
similarity index 70%
rename from docs/algokit.md
rename to docs/src/content/docs/features/overview.md
index 036fa66c1..4acf98bb0 100644
--- a/docs/algokit.md
+++ b/docs/src/content/docs/features/overview.md
@@ -1,4 +1,6 @@
-# AlgoKit
+---
+title: "AlgoKit"
+---
The Algorand AlgoKit CLI is the one-stop shop tool for developers building on the Algorand network. The goal of AlgoKit is to help developers build and launch secure, automated production-ready applications rapidly.
@@ -6,19 +8,20 @@ The Algorand AlgoKit CLI is the one-stop shop tool for developers building on th
For details on how to use individual features see the following
-- [Bootstrap](./features/project/bootstrap.md) - Bootstrap AlgoKit project dependencies
-- [Compile](./features/compile.md) - Compile Algorand Python code
-- [Completions](./features/completions.md) - Install shell completions for AlgoKit
-- [Deploy](./features/project/deploy.md) - Deploy your smart contracts effortlessly to various networks
-- [Dispenser](./features/dispenser.md) - Fund your TestNet account with ALGOs from the AlgoKit TestNet Dispenser
-- [Doctor](./features/doctor.md) - Check AlgoKit installation and dependencies
-- [Explore](./features/explore.md) - Explore Algorand Blockchains using lora
-- [Generate](./features/generate.md) - Generate code for an Algorand project
-- [Goal](./features/goal.md) - Run the Algorand goal CLI against the AlgoKit Sandbox
-- [Init](./features/init.md) - Quickly initialize new projects using official Algorand Templates or community provided templates
-- [LocalNet](./features/localnet.md) - Manage a locally sandboxed private Algorand network
-- [Project](./features/project.md) - Manage an AlgoKit project workspace on your file system
-- [Tasks](./features/tasks.md) - Perform a variety of useful operations on the Algorand blockchain
+- [Bootstrap](/algokit-cli/features/project/bootstrap/) - Bootstrap AlgoKit project dependencies
+- [Compile](/algokit-cli/features/compile/) - Compile Algorand Python code
+- [Completions](/algokit-cli/features/completions/) - Install shell completions for AlgoKit
+- [Deploy](/algokit-cli/features/project/deploy/) - Deploy your smart contracts effortlessly to various networks
+- [Dispenser](/algokit-cli/features/dispenser/) - Fund your TestNet account with ALGOs from the AlgoKit TestNet Dispenser
+- [Doctor](/algokit-cli/features/doctor/) - Check AlgoKit installation and dependencies
+- [Explore](/algokit-cli/features/explore/) - Explore Algorand Blockchains using lora
+- [Generate](/algokit-cli/features/generate/) - Generate code for an Algorand project
+- [Goal](/algokit-cli/features/goal/) - Run the Algorand goal CLI against the AlgoKit Sandbox
+- [Init](/algokit-cli/features/init/) - Quickly initialize new projects using official Algorand Templates or community provided templates
+- [LocalNet](/algokit-cli/features/localnet/) - Manage a locally sandboxed private Algorand network
+- [Project](/algokit-cli/features/project/) - Manage an AlgoKit project workspace on your file system
+- [Tasks](/algokit-cli/features/tasks/) - Perform a variety of useful operations on the Algorand blockchain
+- [Vibe](/algokit-cli/features/vibe/) - Install and initialize VibeKit for AI-assisted AlgoKit development
## Common AlgoKit CLI options
@@ -27,9 +30,9 @@ AlgoKit has a number of global options that can impact all commands. Note: these
- `-h, --help` The help option can be used on any command to get details on any command, its sub-commands and options.
- `-v, --verbose` Enables DEBUG logging, useful when troubleshooting or if you want to peek under the covers and learn what AlgoKit CLI is doing.
- `--color / --no-color` Enables or disables output of console styling, we also support the [NO_COLOR](https://no-color.org) environment variable.
-- `--skip-version-check` Skips updated AlgoKit version checking and prompting for that execution, this can also be disabled [permanently on a given machine](./cli/index.md#version-prompt) with `algokit config version-prompt disable`.
+- `--skip-version-check` Skips updated AlgoKit version checking and prompting for that execution, this can also be disabled [permanently on a given machine](/algokit-cli/cli/#version-prompt) with `algokit config version-prompt disable`.
-See also the [AlgoKit CLI Reference](./cli/index.md), which details every command, sub-command and option.
+See also the [AlgoKit CLI Reference](/algokit-cli/cli/), which details every command, sub-command and option.
## AlgoKit Tutorials
diff --git a/docs/features/project.md b/docs/src/content/docs/features/project.md
similarity index 88%
rename from docs/features/project.md
rename to docs/src/content/docs/features/project.md
index 26256e2ec..d2a431d3f 100644
--- a/docs/features/project.md
+++ b/docs/src/content/docs/features/project.md
@@ -1,6 +1,8 @@
-# AlgoKit Project
+---
+title: "AlgoKit Project"
+---
-`algokit project` is a collection of commands and command groups useful for managing AlgoKit-compliant [project workspaces](./init.md#workspaces-vs-standalone-projects).
+`algokit project` is a collection of commands and command groups useful for managing AlgoKit-compliant [project workspaces](/algokit-cli/features/init/#workspaces-vs-standalone-projects).
## Overview
@@ -82,14 +84,14 @@ type = {'backend' | 'contract' | 'frontend'} # currently support 3 generic categ
name = 'my-project' # unique name for the project inside workspace
```
-> We recommend using workspaces for most projects (hence enabled by default), as it provides a more organized and scalable approach to managing multiple sub-projects. However, standalone projects are a great choice for simple applications or when you are certain that you will not need to add more sub-projects in the future, for such cases simply append `--no-workspace` when using `algokit init` command. For more details on init command please refer to [init](./init.md) command docs.
+> We recommend using workspaces for most projects (hence enabled by default), as it provides a more organized and scalable approach to managing multiple sub-projects. However, standalone projects are a great choice for simple applications or when you are certain that you will not need to add more sub-projects in the future, for such cases simply append `--no-workspace` when using `algokit init` command. For more details on init command please refer to [init](/algokit-cli/features/init/) command docs.
## Features
Dive into the features of the `algokit project` command group:
-- [bootstrap](./project/bootstrap.md) - Bootstrap your project with AlgoKit.
-- [deploy](./project/deploy.md) - Deploy your smart contracts effortlessly to various networks.
-- [link](./project/link.md) - Powerful feature designed to streamline the integration between `frontend` and `contract` projects
-- [list](./project/list.md) - Enumerate all projects within an AlgoKit workspace.
-- [run](./project/run.md) - Define custom commands and manage their execution via `algokit` cli.
+- [bootstrap](/algokit-cli/features/project/bootstrap/) - Bootstrap your project with AlgoKit.
+- [deploy](/algokit-cli/features/project/deploy/) - Deploy your smart contracts effortlessly to various networks.
+- [link](/algokit-cli/features/project/link/) - Powerful feature designed to streamline the integration between `frontend` and `contract` projects
+- [list](/algokit-cli/features/project/list/) - Enumerate all projects within an AlgoKit workspace.
+- [run](/algokit-cli/features/project/run/) - Define custom commands and manage their execution via `algokit` cli.
diff --git a/docs/features/project/bootstrap.md b/docs/src/content/docs/features/project/bootstrap.md
similarity index 96%
rename from docs/features/project/bootstrap.md
rename to docs/src/content/docs/features/project/bootstrap.md
index bd744bb74..0b08a8d63 100644
--- a/docs/features/project/bootstrap.md
+++ b/docs/src/content/docs/features/project/bootstrap.md
@@ -1,4 +1,6 @@
-# AlgoKit Project Bootstrap
+---
+title: "AlgoKit Project Bootstrap"
+---
The AlgoKit Project Bootstrap feature allows you to bootstrap different project dependencies by looking up specific files in your current directory and immediate sub directories by convention.
@@ -17,7 +19,7 @@ You can configure which package managers are used by default via:
- `algokit config py-package-manager` - Configure Python package manager (poetry or uv)
- `algokit config js-package-manager` - Configure JavaScript package manager (npm or pnpm)
-For more details, see the [configuration documentation](../config.md).
+For more details, see the [configuration documentation](/algokit-cli/features/config/).
## Package Manager Override
@@ -136,8 +138,8 @@ This approach ensures your project commands work correctly while being transpare
Available commands and possible usage as follows:
-```
-$ ~ algokit project bootstrap
+```bash
+algokit project bootstrap
Usage: algokit project bootstrap [OPTIONS] COMMAND [ARGS]...
Options:
@@ -161,7 +163,7 @@ The command `algokit project bootstrap env` runs two main tasks in the current d
For instance, a sample `.env.template` file as follows:
-```
+```bash
SERVER_URL=https://myserver.com
# This is a mandatory field to run the server, please enter a value
# For example: 5000
@@ -170,8 +172,8 @@ SERVER_PORT=
Running the `algokit project bootstrap env` command while the above `.env.template` file in the current directory will result in the following:
-```
-$ ~ algokit project bootstrap env
+```bash
+algokit project bootstrap env
Copying /Users/me/my-project/.env.template to /Users/me/my-project/.env and prompting for empty values
# This is a mandatory field to run the server, please enter a value value
# For example: 5000
@@ -181,7 +183,7 @@ Copying /Users/me/my-project/.env.template to /Users/me/my-project/.env and prom
And when the user enters a value for `SERVER_PORT`, a new `.env` file will be created as follows (e.g. if they entered `4000` as the value):
-```
+```bash
SERVER_URL=https://myserver.com
# This is a mandatory field to run the server, please enter a value
# For example: 5000
@@ -194,8 +196,8 @@ The command `algokit project bootstrap npm` installs Node.js project dependencie
Here is an example outcome of running `algokit project bootstrap npm` command:
-```
-$ ~ algokit project bootstrap npm
+```bash
+algokit project bootstrap npm
Installing npm dependencies
npm:
npm: added 17 packages, and audited 18 packages in 3s
@@ -215,8 +217,8 @@ The command `algokit project bootstrap poetry` does two main actions:
Here is an example of running `algokit project bootstrap poetry` command:
-```
-$ ~ algokit project bootstrap poetry
+```bash
+algokit project bootstrap poetry
Installing Python dependencies and setting up Python virtual environment via Poetry
poetry:
poetry: Installing dependencies from lock file
@@ -235,7 +237,7 @@ Execute `algokit project bootstrap all` to initiate `algokit project bootstrap e
#### Filtering Options
-The `algokit project bootstrap all` command includes flags for more granular control over the bootstrapping process within [AlgoKit workspaces](../init.md#workspaces):
+The `algokit project bootstrap all` command includes flags for more granular control over the bootstrapping process within [AlgoKit workspaces](/algokit-cli/features/init/#workspaces):
- `--project-name`: This flag allows you to specify one or more project names to bootstrap. Only projects matching the provided names will be bootstrapped. This is particularly useful in monorepos or when working with multiple projects in the same directory structure.
@@ -245,4 +247,4 @@ These new flags enhance the flexibility and efficiency of the bootstrapping proc
## Further Reading
-To learn more about the `algokit project bootstrap` command, please refer to [bootstrap](../../cli/index.md#bootstrap) in the AlgoKit CLI reference documentation.
+To learn more about the `algokit project bootstrap` command, please refer to [bootstrap](/algokit-cli/cli/#bootstrap) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/project/deploy.md b/docs/src/content/docs/features/project/deploy.md
similarity index 90%
rename from docs/features/project/deploy.md
rename to docs/src/content/docs/features/project/deploy.md
index f78dffda1..0a1a2e72e 100644
--- a/docs/features/project/deploy.md
+++ b/docs/src/content/docs/features/project/deploy.md
@@ -1,4 +1,6 @@
-# AlgoKit Project Deploy
+---
+title: "AlgoKit Project Deploy"
+---
Deploy your smart contracts effortlessly to various networks with the algokit project deploy feature. This feature is essential for automation in CI/CD pipelines and for seamless deployment to various Algorand network environments.
@@ -6,8 +8,8 @@ Deploy your smart contracts effortlessly to various networks with the algokit pr
## Usage
-```sh
-$ algokit project deploy [OPTIONS] [ENVIRONMENT_NAME] [EXTRA_ARGS]
+```bash
+algokit project deploy [OPTIONS] [ENVIRONMENT_NAME] [EXTRA_ARGS]
```
This command deploys smart contracts from an AlgoKit compliant repository to the specified network.
@@ -113,8 +115,8 @@ The command requires a `ENVIRONMENT` argument, which specifies the network envir
Example:
-```sh
-$ algokit project deploy testnet
+```bash
+algokit project deploy testnet
```
This command deploys the smart contracts to the testnet.
@@ -145,7 +147,7 @@ command = "{custom_deploy_command}"
```
```bash
-$ algokit project deploy testnet --project-name myproject
+algokit project deploy testnet --project-name myproject
```
This command deploys the smart contracts to TestNet from a sub project named 'myproject', which is available within the current workspace. All `.env` loading logic described in [Environment files](#environment-files) is applicable, execution from the workspace root orchestrates invoking the deploy command from the working directory of each applicable sub project.
@@ -156,8 +158,8 @@ By default, the deploy command looks for the `.algokit.toml` file in the current
Example:
-```sh
-$ algokit project deploy testnet --project-dir="path/to/project"
+```bash
+algokit project deploy testnet --project-dir="path/to/project"
```
## Custom Deploy Command
@@ -166,11 +168,11 @@ You can provide a custom deploy command using the `--custom-deploy-command` opti
Example:
-```sh
-$ algokit project deploy testnet --custom-deploy-command="your-custom-command"
+```bash
+algokit project deploy testnet --custom-deploy-command="your-custom-command"
```
-> ⚠️ Please note, chaining multiple commands with `&&` is **not** currently supported. If you need to run multiple commands, you can defer to a custom script. Refer to [run](../project/run.md#custom-command-injection) for scenarios where multiple sub-command invocations are required.
+>⚠️ Please note, chaining multiple commands with `&&` is **not** currently supported. If you need to run multiple commands, you can defer to a custom script. Refer to [run](/algokit-cli/features/project/run/#custom-command-injection) for scenarios where multiple sub-command invocations are required.
## CI Mode
@@ -180,8 +182,8 @@ This is useful in CI/CD environments where user interaction is not possible. Whe
Example:
-```sh
-$ algokit project deploy testnet --ci
+```bash
+algokit project deploy testnet --ci
```
## Passing Extra Arguments
@@ -192,20 +194,20 @@ To pass extra arguments, use `--` after the AlgoKit command and options to mark
Example:
-```sh
-$ algokit project deploy testnet -- my_contract_name --some_contract_related_param
+```bash
+algokit project deploy testnet -- my_contract_name --some_contract_related_param
```
In this example, `my_contract_name` and `--some_contract_related_param` are extra arguments that can be utilized by the custom deploy command invocation, for instance, to filter the deployment to a specific contract or modify deployment behavior.
## Example of a Full Deployment
-```sh
-$ algokit project deploy testnet --custom-deploy-command="your-custom-command"
+```bash
+algokit project deploy testnet --custom-deploy-command="your-custom-command"
```
This example shows how to deploy smart contracts to the testnet using a custom deploy command. This also assumes that .algokit.toml file is present in the current working directory, and .env.testnet file is present in the current working directory and contains the required environment variables for deploying to TestNet environment.
## Further Reading
-For in-depth details, visit the [deploy](../../cli/index.md#deploy) section in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [deploy](/algokit-cli/cli/#deploy) section in the AlgoKit CLI reference documentation.
diff --git a/docs/features/project/link.md b/docs/src/content/docs/features/project/link.md
similarity index 88%
rename from docs/features/project/link.md
rename to docs/src/content/docs/features/project/link.md
index 08bf89097..8937979bf 100644
--- a/docs/features/project/link.md
+++ b/docs/src/content/docs/features/project/link.md
@@ -1,13 +1,15 @@
-# AlgoKit Project Link Command
+---
+title: "AlgoKit Project Link Command"
+---
-The `algokit project link` command is a powerful feature designed to streamline the integration between `frontend` and `contract` typed projects within the AlgoKit ecosystem. This command facilitates the automatic path resolution and invocation of [`algokit generate client`](../generate.md#1-typed-clients) on `contract` projects available in the workspace, making it easier to integrate smart contracts with frontend applications.
+The `algokit project link` command is a powerful feature designed to streamline the integration between `frontend` and `contract` typed projects within the AlgoKit ecosystem. This command facilitates the automatic path resolution and invocation of [`algokit generate client`](/algokit-cli/features/generate/#1-typed-clients) on `contract` projects available in the workspace, making it easier to integrate smart contracts with frontend applications.
## Usage
To use the `link` command, navigate to the root directory of your standalone frontend project and execute:
-```sh
-$ algokit project link [OPTIONS]
+```bash
+algokit project link [OPTIONS]
```
This command must be invoked from the root of a standalone 'frontend' typed project.
@@ -56,12 +58,12 @@ graph LR
Linking all contract projects with a frontend project and generating TypeScript clients:
-```sh
-$ algokit project link --all -l typescript
+```bash
+algokit project link --all -l typescript
```
This command will generate TypeScript clients for all contract projects and place them in the specified directory within the frontend project.
## Further Reading
-To learn more about the `algokit project link` command, please refer to [link](../../cli/index.md#link) in the AlgoKit CLI reference documentation.
+To learn more about the `algokit project link` command, please refer to [link](/algokit-cli/cli/#link) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/project/list.md b/docs/src/content/docs/features/project/list.md
similarity index 90%
rename from docs/features/project/list.md
rename to docs/src/content/docs/features/project/list.md
index 0f8275363..78940ea87 100644
--- a/docs/features/project/list.md
+++ b/docs/src/content/docs/features/project/list.md
@@ -1,4 +1,6 @@
-# AlgoKit Project List Command
+---
+title: "AlgoKit Project List Command"
+---
The `algokit project list` command is designed to enumerate all projects within an AlgoKit workspace. This command is particularly useful in workspace environments where multiple projects are managed under a single root directory. It provides a straightforward way to view all the projects that are part of the workspace.
@@ -6,8 +8,8 @@ The `algokit project list` command is designed to enumerate all projects within
To use the `list` command, execute the following **anywhere** within an AlgoKit workspace:
-```sh
-$ algokit project list [OPTIONS] [WORKSPACE_PATH]
+```bash
+algokit project list [OPTIONS] [WORKSPACE_PATH]
```
- `WORKSPACE_PATH` is an optional argument that specifies the path to the workspace. If not provided, the current directory (`.`) is used as the default workspace path.
@@ -22,7 +24,7 @@ $ algokit project list [OPTIONS] [WORKSPACE_PATH]
## Example Output
-```sh
+```bash
workspace: {path_to_workspace} 📁
- myapp ({path_to_myapp}) 📜
- myproject-app ({path_to_myproject_app}) 🖥️
@@ -32,7 +34,7 @@ workspace: {path_to_workspace} 📁
If the command is executed in a directory that is not recognized as an AlgoKit workspace, it will issue a warning:
-```sh
+```bash
WARNING: No AlgoKit workspace found. Check [project.type] definition at .algokit.toml
```
@@ -40,4 +42,4 @@ This message indicates that either the current directory does not contain a `.al
## Further Reading
-To learn more about the `algokit project list` command, please refer to [list](../../cli/index.md#list) in the AlgoKit CLI reference documentation.
+To learn more about the `algokit project list` command, please refer to [list](/algokit-cli/cli/#list) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/project/run.md b/docs/src/content/docs/features/project/run.md
similarity index 95%
rename from docs/features/project/run.md
rename to docs/src/content/docs/features/project/run.md
index a6031e288..295ef510a 100644
--- a/docs/features/project/run.md
+++ b/docs/src/content/docs/features/project/run.md
@@ -1,11 +1,13 @@
-# AlgoKit Project Run
+---
+title: "AlgoKit Project Run"
+---
The `algokit project run` command allows defining custom commands to execute at standalone project level or being orchestrated from a workspace containing multiple standalone projects.
## Usage
-```sh
-$ algokit project run [OPTIONS] COMMAND [ARGS]
+```bash
+algokit project run [OPTIONS] COMMAND [ARGS]
```
This command executes a custom command defined in the `.algokit.toml` file of the current project or workspace.
@@ -155,9 +157,9 @@ You can control whether commands are executed concurrently or sequentially:
1. Use command-line options:
- ```sh
- $ algokit project run hello -s # or --sequential
- $ algokit project run hello -c # or --concurrent
+ ```bash
+ algokit project run hello -s # or --sequential
+ algokit project run hello -c # or --concurrent
```
2. Behavior:
@@ -173,12 +175,12 @@ You can pass additional arguments to the custom command. These extra arguments w
Example:
-```sh
-$ algokit project run hello -- world
+```bash
+algokit project run hello -- world
```
In this example, if the `hello` command in `.algokit.toml` is defined as `echo "Hello"`, the actual command executed will be `echo "Hello" world`.
## Further Reading
-To learn more about the `algokit project run` command, please refer to [run](../../cli/index.md#run) in the AlgoKit CLI reference documentation.
+To learn more about the `algokit project run` command, please refer to [run](/algokit-cli/cli/#run) in the AlgoKit CLI reference documentation.
diff --git a/docs/src/content/docs/features/tasks.md b/docs/src/content/docs/features/tasks.md
new file mode 100644
index 000000000..d026689ce
--- /dev/null
+++ b/docs/src/content/docs/features/tasks.md
@@ -0,0 +1,18 @@
+---
+title: "AlgoKit Tasks"
+---
+
+AlgoKit Tasks are a collection of handy tasks that can be used to perform various operations on Algorand blockchain.
+
+## Features
+
+- [Wallet Aliasing](/algokit-cli/features/tasks/wallet/) - Manage your Algorand addresses and accounts effortlessly with the AlgoKit Wallet feature. This feature allows you to create short aliases for your addresses and accounts on AlgoKit CLI.
+- [Vanity Address Generation](/algokit-cli/features/tasks/vanity_address/) - Generate vanity addresses for your Algorand accounts with the AlgoKit Vanity feature. This feature allows you to generate Algorand addresses which contains a specific keyword of your choice.
+- [Transfer Assets or Algos](/algokit-cli/features/tasks/transfer/) - Transfer Algos or Assets from one account to another with the AlgoKit Transfer feature. This feature allows you to transfer Algos or Assets from one account to another on Algorand blockchain.
+- [Opt-(in|out) Assets](/algokit-cli/features/tasks/opt/) - Opt-in or opt-out of Algorand Asset(s). Supports single or multiple assets.
+- [Signing transactions](/algokit-cli/features/tasks/sign/) - Sign goal clerk compatible Algorand transactions.
+- [Sending transactions](/algokit-cli/features/tasks/send/) - Send signed goal clerk compatible Algorand transactions.
+- [NFD lookups](/algokit-cli/features/tasks/nfd/) - Perform a lookup via NFD domain or address, returning the associated address or domain respectively using the AlgoKit CLI.
+- [IPFS uploads](/algokit-cli/features/tasks/ipfs/) - Upload files to IPFS.
+- [Asset minting](/algokit-cli/features/tasks/mint/) - Mint new fungible or non-fungible assets on Algorand.
+- [Analyze TEAL code](/algokit-cli/features/tasks/analyze/) - Analyze TEAL code using [`tealer`](https://github.com/crytic/tealer) integration for common vulnerabilities.
diff --git a/docs/features/tasks/analyze.md b/docs/src/content/docs/features/tasks/analyze.md
similarity index 97%
rename from docs/features/tasks/analyze.md
rename to docs/src/content/docs/features/tasks/analyze.md
index 47da76002..c2b90568a 100644
--- a/docs/features/tasks/analyze.md
+++ b/docs/src/content/docs/features/tasks/analyze.md
@@ -1,4 +1,6 @@
-# AlgoKit Task Analyze
+---
+title: "AlgoKit Task Analyze"
+---
The `analyze` task is a command-line utility that analyzes TEAL programs for common vulnerabilities using [Tealer](https://github.com/crytic/tealer) integration. It allows you to detect a range of common vulnerabilities in code written in TEAL. For full list of vulnerability detectors refer to [Tealer documentation](https://github.com/crytic/tealer?tab=readme-ov-file#detectors).
diff --git a/docs/features/tasks/ipfs.md b/docs/src/content/docs/features/tasks/ipfs.md
similarity index 87%
rename from docs/features/tasks/ipfs.md
rename to docs/src/content/docs/features/tasks/ipfs.md
index 638038be3..2a522d05a 100644
--- a/docs/features/tasks/ipfs.md
+++ b/docs/src/content/docs/features/tasks/ipfs.md
@@ -1,4 +1,6 @@
-# AlgoKit Task IPFS
+---
+title: "AlgoKit Task IPFS"
+---
The AlgoKit IPFS feature allows you to interact with the IPFS [InterPlanetary File System](https://ipfs.tech/) using the [Piñata provider](https://www.pinata.cloud/). This feature supports logging in and out of the Piñata provider, and uploading files to IPFS.
@@ -7,7 +9,7 @@ The AlgoKit IPFS feature allows you to interact with the IPFS [InterPlanetary Fi
Available commands and possible usage as follows:
```bash
-$ ~ algokit task ipfs
+algokit task ipfs
Usage: algokit task ipfs [OPTIONS]
Upload files to IPFS using Pinata provider.
@@ -32,7 +34,7 @@ Before you can use this feature, you need to ensure that you have signed up for
Please note, you need to login to the Piñata provider before you can upload files. You can do this using the `login` command:
```bash
-$ algokit task ipfs login
+algokit task ipfs login
```
This will prompt you to enter your Piñata JWT. Once you are logged in, you can upload files to IPFS.
@@ -42,7 +44,7 @@ This will prompt you to enter your Piñata JWT. Once you are logged in, you can
To upload a file to IPFS, you can use the `ipfs` command as follows:
```bash
-$ algokit task ipfs --file {PATH_TO_YOUR_FILE}
+algokit task ipfs --file {PATH_TO_YOUR_FILE}
```
This will upload the file to IPFS using the Piñata provider and return the CID (Content Identifier) of the uploaded file.
@@ -52,7 +54,7 @@ This will upload the file to IPFS using the Piñata provider and return the CID
If you want to logout from the Piñata provider, you can use the `logout` command:
```bash
-$ algokit task ipfs logout
+algokit task ipfs logout
```
This will remove your Piñata JWT from the keyring.
@@ -63,4 +65,4 @@ Please note, the maximum file size that can be uploaded is 100MB. If you try to
## Further Reading
-For in-depth details, visit the [ipfs section](../../cli/index.md#ipfs) in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [ipfs section](/algokit-cli/cli/#ipfs) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/tasks/mint.md b/docs/src/content/docs/features/tasks/mint.md
similarity index 95%
rename from docs/features/tasks/mint.md
rename to docs/src/content/docs/features/tasks/mint.md
index 5fabda32b..58ee1e75d 100644
--- a/docs/features/tasks/mint.md
+++ b/docs/src/content/docs/features/tasks/mint.md
@@ -1,4 +1,6 @@
-# AlgoKit Task Mint
+---
+title: "AlgoKit Task Mint"
+---
The AlgoKit Mint feature allows you to mint new fungible or non-fungible assets on the Algorand blockchain. This feature supports the creation of assets, validation of asset parameters, and uploading of asset metadata and image to IPFS using the Piñata provider. Immutable assets are compliant with [ARC3](https://arc.algorand.foundation/ARCs/arc-0003), while mutable are based using [ARC19](https://arc.algorand.foundation/ARCs/arc-0019) standard.
@@ -48,7 +50,7 @@ Options:
To mint a new asset in interactive mode, you can use the mint command as follows:
```bash
-$ algokit task mint
+algokit task mint
```
This will interactively prompt you for the required information, upload the asset image and metadata to IPFS using the Piñata provider and mint a new asset on the Algorand blockchain. The [asset's metadata](https://arc.algorand.foundation/ARCs/arc-0003#json-metadata-file-schema) will be generated automatically based on the provided asset name, decimals, and image.
@@ -56,7 +58,7 @@ This will interactively prompt you for the required information, upload the asse
If you want to provide a custom metadata file, you can use the --metadata flag:
```bash
-$ algokit task mint --metadata {PATH_TO_METADATA}
+algokit task mint --metadata {PATH_TO_METADATA}
```
If the minting process is successful, the asset ID and transaction ID will be output to the console.
@@ -67,4 +69,4 @@ For non interactive mode, refer to usage section above for available options.
## Further Reading
-For in-depth details, visit the [mint section](../../cli/index.md#mint) in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [mint section](/algokit-cli/cli/#mint) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/tasks/nfd.md b/docs/src/content/docs/features/tasks/nfd.md
similarity index 83%
rename from docs/features/tasks/nfd.md
rename to docs/src/content/docs/features/tasks/nfd.md
index 813146151..5e21b8aae 100644
--- a/docs/features/tasks/nfd.md
+++ b/docs/src/content/docs/features/tasks/nfd.md
@@ -1,4 +1,6 @@
-# AlgoKit Task NFD Lookup
+---
+title: "AlgoKit Task NFD Lookup"
+---
The AlgoKit NFD Lookup feature allows you to perform a lookup via NFD domain or address, returning the associated address or domain respectively using the AlgoKit CLI. The feature is powered by [NFDomains MainNet API](https://api-docs.nf.domains/).
@@ -7,7 +9,7 @@ The AlgoKit NFD Lookup feature allows you to perform a lookup via NFD domain or
Available commands and possible usage as follows:
```bash
-$ ~ algokit task nfd-lookup
+algokit task nfd-lookup
Usage: algokit task nfd-lookup [OPTIONS] VALUE
Perform a lookup via NFD domain or address, returning the associated address or domain respectively.
@@ -29,17 +31,17 @@ Options:
To perform a lookup, you can use the nfd-lookup command as follows:
```bash
-$ algokit task nfd-lookup {NFD_DOMAIN_OR_ALGORAND_ADDRESS}
+algokit task nfd-lookup {NFD_DOMAIN_OR_ALGORAND_ADDRESS}
```
This will perform a lookup and return the associated address or domain. If you want to specify the output format, you can use the --output flag:
```bash
-$ algokit task nfd-lookup {NFD_DOMAIN_OR_ALGORAND_ADDRESS} --output full
+algokit task nfd-lookup {NFD_DOMAIN_OR_ALGORAND_ADDRESS} --output full
```
If the lookup is successful, the result will be output to the console in a JSON format.
## Further Reading
-For in-depth details, visit the [nfd-lookup section](../../cli/index.md#nfd-lookup) in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [nfd-lookup section](/algokit-cli/cli/#nfd-lookup) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/tasks/opt.md b/docs/src/content/docs/features/tasks/opt.md
similarity index 82%
rename from docs/features/tasks/opt.md
rename to docs/src/content/docs/features/tasks/opt.md
index afc5785fb..af66e2fae 100644
--- a/docs/features/tasks/opt.md
+++ b/docs/src/content/docs/features/tasks/opt.md
@@ -1,4 +1,6 @@
-# AlgoKit Task Asset opt-(in|out)
+---
+title: "AlgoKit Task Asset opt-(in|out)"
+---
AlgoKit Task Asset opt-(in|out) allows you to opt-in or opt-out of Algorand Asset(s). This task supports single or multiple assets.
@@ -49,23 +51,23 @@ Example
To opt-in to an asset(s), you can use the opt-in command as follows:
```bash
-$ algokit task opt-in --account {YOUR_ACCOUNT} {ASSET_ID_1} {ASSET_ID_2} {ASSET_ID_3} ...
+algokit task opt-in --account {YOUR_ACCOUNT} {ASSET_ID_1} {ASSET_ID_2} {ASSET_ID_3} ...
```
To opt-out of an asset(s), you can use the opt-out command as follows:
```bash
-$ algokit task opt-out --account {YOUR_ACCOUNT} {ASSET_ID_1} {ASSET_ID_2} ...
+algokit task opt-out --account {YOUR_ACCOUNT} {ASSET_ID_1} {ASSET_ID_2} ...
```
To opt-out of all assets with zero balance, you can use the opt-out command with the `--all` flag:
```bash
-$ algokit task opt-out --account {YOUR_ACCOUNT} --all
+algokit task opt-out --account {YOUR_ACCOUNT} --all
```
> Please note, the account must have sufficient balance to cover the transaction fees.
## Further Reading
-For in-depth details, visit the [opt-in](../../cli/index.md#opt-in) and [opt-out](../../cli/index#opt-out) sections in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [opt-in](/algokit-cli/cli/#opt-in) and [opt-out](../../cli/index#opt-out) sections in the AlgoKit CLI reference documentation.
diff --git a/docs/features/tasks/send.md b/docs/src/content/docs/features/tasks/send.md
similarity index 82%
rename from docs/features/tasks/send.md
rename to docs/src/content/docs/features/tasks/send.md
index c9c5bf34b..9a91a8461 100644
--- a/docs/features/tasks/send.md
+++ b/docs/src/content/docs/features/tasks/send.md
@@ -1,4 +1,6 @@
-# AlgoKit Task Send
+---
+title: "AlgoKit Task Send"
+---
The AlgoKit Send feature allows you to send signed Algorand transaction(s) to a specified network using the AlgoKit CLI. This feature supports sending single or multiple transactions, either provided directly as a base64 encoded string or from a binary file.
@@ -7,7 +9,7 @@ The AlgoKit Send feature allows you to send signed Algorand transaction(s) to a
Available commands and possible usage as follows:
```bash
-$ ~ algokit task send
+algokit task send
Usage: algokit task send [OPTIONS]
Send a signed transaction to the given network.
@@ -34,19 +36,19 @@ Options:
To send a transaction, you can use the `send` command as follows:
```bash
-$ algokit task send --file {PATH_TO_BINARY_FILE_CONTAINING_SIGNED_TRANSACTIONS}
+algokit task send --file {PATH_TO_BINARY_FILE_CONTAINING_SIGNED_TRANSACTIONS}
```
This will send the transactions to the default `localnet` network. If you want to send the transactions to a different network, you can use the `--network` flag:
```bash
-$ algokit task send --transaction {YOUR_BASE64_ENCODED_SIGNED_TRANSACTION} --network testnet
+algokit task send --transaction {YOUR_BASE64_ENCODED_SIGNED_TRANSACTION} --network testnet
```
You can also pipe in the `stdout` of `algokit sign` command:
```bash
-$ algokit task sign --account {YOUR_ACCOUNT_ALIAS OR YOUR_ADDRESS} --file {PATH_TO_BINARY_FILE_CONTAINING_TRANSACTIONS} --force | algokit task send --network {network_name}
+algokit task sign --account {YOUR_ACCOUNT_ALIAS OR YOUR_ADDRESS} --file {PATH_TO_BINARY_FILE_CONTAINING_TRANSACTIONS} --force | algokit task send --network {network_name}
```
If the transaction is successfully sent, the transaction ID (txid) will be output to the console. You can check the transaction status at the provided transaction explorer URL.
@@ -57,4 +59,4 @@ Please note, at the moment this feature only supports [`goal clerk`](https://dev
## Further Reading
-For in-depth details, visit the [send section](../../cli/index.md#send) in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [send section](/algokit-cli/cli/#send) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/tasks/sign.md b/docs/src/content/docs/features/tasks/sign.md
similarity index 86%
rename from docs/features/tasks/sign.md
rename to docs/src/content/docs/features/tasks/sign.md
index 6480dc3b3..a334e6173 100644
--- a/docs/features/tasks/sign.md
+++ b/docs/src/content/docs/features/tasks/sign.md
@@ -1,4 +1,6 @@
-# AlgoKit Task Sign
+---
+title: "AlgoKit Task Sign"
+---
The AlgoKit Sign feature allows you to sign Algorand transaction(s) using the AlgoKit CLI. This feature supports signing single or multiple transactions, either provided directly as a base64 encoded string or from a binary file.
@@ -7,7 +9,7 @@ The AlgoKit Sign feature allows you to sign Algorand transaction(s) using the Al
Available commands and possible usage as follows:
```bash
-$ ~ algokit task sign
+algokit task sign
Usage: algokit task sign [OPTIONS]
Sign goal clerk compatible Algorand transaction(s).
@@ -36,19 +38,19 @@ Options:
To sign a transaction, you can use the `sign` command as follows:
```bash
-$ algokit task sign --account {YOUR_ACCOUNT_ALIAS OR YOUR_ADDRESS} --file {PATH_TO_BINARY_FILE_CONTAINING_TRANSACTIONS}
+algokit task sign --account {YOUR_ACCOUNT_ALIAS OR YOUR_ADDRESS} --file {PATH_TO_BINARY_FILE_CONTAINING_TRANSACTIONS}
```
This will prompt you to confirm the transaction details before signing. If you want to bypass the confirmation, you can use the `--force` flag:
```bash
-$ algokit task sign --account {YOUR_ACCOUNT_ALIAS OR YOUR_ADDRESS} --transaction {YOUR_BASE64_ENCODED_TRANSACTION} --force
+algokit task sign --account {YOUR_ACCOUNT_ALIAS OR YOUR_ADDRESS} --transaction {YOUR_BASE64_ENCODED_TRANSACTION} --force
```
If the transaction is successfully signed, the signed transaction will be output to the console in a JSON format. If you want to write the signed transaction to a file, you can use the `--output` option:
```bash
-$ algokit task sign --account {YOUR_ACCOUNT_ALIAS OR YOUR_ADDRESS} --transaction {YOUR_BASE64_ENCODED_TRANSACTION} --output /path/to/output/file
+algokit task sign --account {YOUR_ACCOUNT_ALIAS OR YOUR_ADDRESS} --transaction {YOUR_BASE64_ENCODED_TRANSACTION} --output /path/to/output/file
```
This will write the signed transaction to the specified file.
@@ -85,10 +87,10 @@ Encoding simple txn object in javascript:
```ts
Buffer.from(algosdk.encodeObj({ txn: txn.get_obj_for_encoding() })).toString(
- "base64"
+ "base64",
); // Resulting string can be passed directly to algokit task sign with --transaction flag
```
## Further Reading
-For in-depth details, visit the [sign section](../../cli/index.md#sign) in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [sign section](/algokit-cli/cli/#sign) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/tasks/transfer.md b/docs/src/content/docs/features/tasks/transfer.md
similarity index 66%
rename from docs/features/tasks/transfer.md
rename to docs/src/content/docs/features/tasks/transfer.md
index 4e5034d43..06e153809 100644
--- a/docs/features/tasks/transfer.md
+++ b/docs/src/content/docs/features/tasks/transfer.md
@@ -1,4 +1,6 @@
-# AlgoKit Task Transfer
+---
+title: "AlgoKit Task Transfer"
+---
The AlgoKit Transfer feature allows you to transfer algos and assets between two accounts.
@@ -7,7 +9,7 @@ The AlgoKit Transfer feature allows you to transfer algos and assets between two
Available commands and possible usage as follows:
```bash
-$ ~ algokit task transfer
+algokit task transfer
Usage: algokit task transfer [OPTIONS]
Transfer algos or assets from one account to another.
@@ -24,14 +26,14 @@ Options:
-h, --help Show this message and exit.
```
-> Note: If you use a wallet address for the `sender` argument, you'll be asked for the mnemonic phrase. To use a wallet alias instead, see the [wallet aliasing](wallet.md) task. For wallet aliases, the sender must have a stored `private key`, but the receiver doesn't need one. This is because the sender signs and sends the transfer transaction, while the receiver reference only needs a valid Algorand address.
+> Note: If you use a wallet address for the `sender` argument, you'll be asked for the mnemonic phrase. To use a wallet alias instead, see the [wallet aliasing](/algokit-cli/features/tasks/wallet/) task. For wallet aliases, the sender must have a stored `private key`, but the receiver doesn't need one. This is because the sender signs and sends the transfer transaction, while the receiver reference only needs a valid Algorand address.
## Examples
### Transfer algo between accounts on LocalNet
```bash
-$ ~ algokit task transfer -s {SENDER_ALIAS OR SENDER_ADDRESS} -r {RECEIVER_ALIAS OR RECEIVER_ADDRESS} -a {AMOUNT}
+algokit task transfer -s {SENDER_ALIAS OR SENDER_ADDRESS} -r {RECEIVER_ALIAS OR RECEIVER_ADDRESS} -a {AMOUNT}
```
By default:
@@ -42,7 +44,7 @@ By default:
### Transfer asset between accounts on TestNet
```bash
-$ ~ algokit task transfer -s {SENDER_ALIAS OR SENDER_ADDRESS} -r {RECEIVER_ALIAS OR RECEIVER_ADDRESS} -a {AMOUNT} --id {ASSET_ID} --network testnet
+algokit task transfer -s {SENDER_ALIAS OR SENDER_ADDRESS} -r {RECEIVER_ALIAS OR RECEIVER_ADDRESS} -a {AMOUNT} --id {ASSET_ID} --network testnet
```
By default:
@@ -51,4 +53,4 @@ By default:
## Further Reading
-For in-depth details, visit the [transfer section](../../cli/index.md#transfer) in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [transfer section](/algokit-cli/cli/#transfer) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/tasks/vanity_address.md b/docs/src/content/docs/features/tasks/vanity_address.md
similarity index 77%
rename from docs/features/tasks/vanity_address.md
rename to docs/src/content/docs/features/tasks/vanity_address.md
index d8d9c3609..2a8ecf128 100644
--- a/docs/features/tasks/vanity_address.md
+++ b/docs/src/content/docs/features/tasks/vanity_address.md
@@ -1,4 +1,6 @@
-# AlgoKit Task Vanity Address
+---
+title: "AlgoKit Task Vanity Address"
+---
The AlgoKit Vanity Address feature allows you to generate a vanity Algorand address. A vanity address is an address that contains a specific keyword in it. The keyword can only include uppercase letters A-Z and numbers 2-7. The longer the keyword, the longer it may take to generate a matching address.
@@ -7,7 +9,7 @@ The AlgoKit Vanity Address feature allows you to generate a vanity Algorand addr
Available commands and possible usage as follows:
```bash
-$ ~ algokit task vanity-address
+algokit task vanity-address
Usage: algokit task vanity-address [OPTIONS] KEYWORD
Generate a vanity Algorand address. Your KEYWORD can only include letters A - Z and numbers 2 - 7. Keeping your
@@ -30,27 +32,27 @@ Options:
Generate a vanity address with the keyword "ALGO" at the start of the address with default output to `stdout`:
```bash
-$ ~ algokit task vanity-address ALGO
+algokit task vanity-address ALGO
```
Generate a vanity address with the keyword "ALGO" at the start of the address with output to a file:
```bash
-$ ~ algokit task vanity-address ALGO -o file -f vanity-address.txt
+algokit task vanity-address ALGO -o file -f vanity-address.txt
```
Generate a vanity address with the keyword "ALGO" anywhere in the address with output to a file:
```bash
-$ ~ algokit task vanity-address ALGO -m anywhere -o file -f vanity-address.txt
+algokit task vanity-address ALGO -m anywhere -o file -f vanity-address.txt
```
-Generate a vanity address with the keyword "ALGO" at the start of the address and store into a [wallet alias](wallet.md):
+Generate a vanity address with the keyword "ALGO" at the start of the address and store into a [wallet alias](/algokit-cli/features/tasks/wallet/):
```bash
-$ ~ algokit task vanity-address ALGO -o alias -a my-vanity-address
+algokit task vanity-address ALGO -o alias -a my-vanity-address
```
## Further Reading
-For in-depth details, visit the [vanity-address section](../../cli/index.md#vanity-address) in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [vanity-address section](/algokit-cli/cli/#vanity-address) in the AlgoKit CLI reference documentation.
diff --git a/docs/features/tasks/wallet.md b/docs/src/content/docs/features/tasks/wallet.md
similarity index 95%
rename from docs/features/tasks/wallet.md
rename to docs/src/content/docs/features/tasks/wallet.md
index e77fa8c05..85c2475aa 100644
--- a/docs/features/tasks/wallet.md
+++ b/docs/src/content/docs/features/tasks/wallet.md
@@ -1,4 +1,6 @@
-# AlgoKit Task Wallet
+---
+title: "AlgoKit Task Wallet"
+---
Manage your Algorand addresses and accounts effortlessly with the AlgoKit Wallet feature. This feature allows you to create short aliases for your addresses and accounts on AlgoKit CLI.
@@ -7,7 +9,7 @@ Manage your Algorand addresses and accounts effortlessly with the AlgoKit Wallet
Available commands and possible usage as follows:
```bash
-$ ~ algokit task wallet
+algokit task wallet
Usage: algokit task wallet [OPTIONS] COMMAND [ARGS]...
Create short aliases for your addresses and accounts on AlgoKit CLI.
@@ -94,4 +96,4 @@ WSL2 environments don't have a keyring backend installed by default. If you want
## Further Reading
-For in-depth details, visit the [wallet section](../../cli/index.md#wallet) in the AlgoKit CLI reference documentation.
+For in-depth details, visit the [wallet section](/algokit-cli/cli/#wallet) in the AlgoKit CLI reference documentation.
diff --git a/docs/src/content/docs/features/vibe.md b/docs/src/content/docs/features/vibe.md
new file mode 100644
index 000000000..753c32d8a
--- /dev/null
+++ b/docs/src/content/docs/features/vibe.md
@@ -0,0 +1,33 @@
+---
+title: "AlgoKit Vibe"
+---
+
+The `algokit vibe` command group helps you install and initialize [VibeKit](https://getvibekit.ai/) for AlgoKit projects.
+
+## Commands
+
+### `algokit vibe setup`
+
+Installs VibeKit (if missing) and runs `vibekit init` in your current project.
+
+- If `vibekit` is not found, AlgoKit prompts to install it.
+- Installation is OS-specific:
+ - macOS/Linux: `curl -fsSL https://getvibekit.ai/install | sh`
+ - Windows: `irm https://getvibekit.ai/install | iex`
+- If installation is declined, the command exits with manual install guidance.
+
+When initializing, AlgoKit also provides best-effort LocalNet context to VibeKit through environment variables:
+
+- `ALGOKIT_LOCALNET_ALGOD_URL`
+- `ALGOKIT_LOCALNET_ALGOD_TOKEN`
+- `ALGOKIT_LOCALNET_INDEXER_URL`
+- `ALGOKIT_LOCALNET_INDEXER_TOKEN`
+- `ALGOKIT_LOCALNET_RUNNING`
+
+If LocalNet inspection fails, `vibekit init` still runs.
+
+### `algokit vibe status`
+
+Runs `vibekit status` to check VibeKit status for the current environment.
+
+If VibeKit is missing, this command exits with installation guidance.
diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx
new file mode 100644
index 000000000..85203e54c
--- /dev/null
+++ b/docs/src/content/docs/index.mdx
@@ -0,0 +1,76 @@
+---
+title: AlgoKit CLI
+description: The one-stop shop tool for developers building on the Algorand network
+template: splash
+hero:
+ title: AlgoKit CLI
+ tagline: The one-stop shop tool for developers building on the Algorand network
+ actions:
+ - text: Get Started
+ link: /algokit-cli/tutorials/intro/
+ icon: right-arrow
+ - text: CLI Reference
+ link: /algokit-cli/cli/
+ variant: minimal
+---
+
+import { Card, CardGrid, Tabs, TabItem } from '@astrojs/starlight/components';
+
+## Installation
+
+
+
+ ```bash
+ brew install algorandfoundation/tap/algokit
+ ```
+
+
+ ```bash
+ winget install AlgoKit
+ ```
+
+
+ ```bash
+ pipx install algokit
+ ```
+
+
+
+## Quick Start
+
+```bash
+# Verify installation
+algokit --version
+
+# Create a new project from a template
+algokit init
+
+# Start a local Algorand network
+algokit localnet start
+
+# Explore the network with lora
+algokit explore
+```
+
+## Features
+
+
+
+ Quickly scaffold new Algorand projects from official templates or community templates.
+
+
+ Spin up a local isolated Algorand network for development and testing.
+
+
+ Compile Algorand Python and other smart contract languages to AVM bytecode.
+
+
+ Deploy smart contracts to LocalNet, TestNet or MainNet with a single command.
+
+
+ Perform blockchain operations: send, sign, mint, transfer assets and more.
+
+
+ Generate typed clients and other code artifacts for your Algorand project.
+
+
\ No newline at end of file
diff --git a/docs/tutorials/algokit-template.md b/docs/src/content/docs/tutorials/algokit-template.md
similarity index 98%
rename from docs/tutorials/algokit-template.md
rename to docs/src/content/docs/tutorials/algokit-template.md
index ed86d7762..268742f42 100644
--- a/docs/tutorials/algokit-template.md
+++ b/docs/src/content/docs/tutorials/algokit-template.md
@@ -1,4 +1,6 @@
-# Creating AlgoKit Templates
+---
+title: "Creating AlgoKit Templates"
+---
This README serves as a guide on how to create custom templates for AlgoKit, a tool for initializing Algorand smart contract projects.
Creating templates in AlgoKit involves the use of various configuration files and a templating engine to generate project structures that are tailored to your needs.
@@ -172,7 +174,7 @@ python_path:
After mastering the use of `copier` and building your templates based on the official AlgoKit template repositories, you can enhance your proficiency by learning to define `custom generators`. Essentially, generators are smaller-scope `copier` templates designed to provide additional functionality after a project has been initialized from the template.
-For example, the official [`algokit-python-template`](https://github.com/algorandfoundation/algokit-python-template/tree/main/template_content) incorporates a generator in the `.algokit/generators` directory. This generator can be utilized to execute auxiliary tasks on AlgoKit projects that are initiated from this template, like adding new smart contracts to an existing project. For a comprehensive understanding, please consult the [`architecture decision record`](../architecture-decisions/2023-07-19_advanced_generate_command.md) and [`algokit generate documentation`](../features/generate.md).
+For example, the official [`algokit-python-template`](https://github.com/algorandfoundation/algokit-python-template/tree/main/template_content) incorporates a generator in the `.algokit/generators` directory. This generator can be utilized to execute auxiliary tasks on AlgoKit projects that are initiated from this template, like adding new smart contracts to an existing project. For a comprehensive understanding, please consult the [`architecture decision record`](/algokit-cli/architecture-decisions/2023-07-19_advanced_generate_command/) and [`algokit generate documentation`](/algokit-cli/features/generate/).
#### How to Create a Generator
diff --git a/docs/src/content/docs/tutorials/intro.md b/docs/src/content/docs/tutorials/intro.md
new file mode 100644
index 000000000..4dcfe3900
--- /dev/null
+++ b/docs/src/content/docs/tutorials/intro.md
@@ -0,0 +1,173 @@
+---
+title: "AlgoKit Quick Start Tutorial"
+---
+
+AlgoKit is the primary tool used by the Algorand community to develop smart contracts on the Algorand blockchain. It provides the capabilities to develop, test and deploy Algorand smart contracts within minutes! This guide is intended to help you setup AlgoKit and to start developing your application.
+
+## Quick start videos
+
+If you prefer videos, take a look at this 10 minute guide to getting started.
+
+[](https://www.youtube.com/embed/dow6U8DxOGc)
+
+Detailed video guides for both [Windows](https://www.youtube.com/embed/22RvINnZsRo) and [Mac](https://www.youtube.com/embed/zsurtpCGmgE) are also available.
+
+> Please note, the videos above are to be refreshed to cover v2.0 features. For now, its best to follow the instructions below to get started.
+
+## Prequisites
+
+This guide presents installing AlgoKit using an OS agnostic procedure. For OS specific instructions take a look that the [AlgoKit install](https://github.com/algorandfoundation/algokit-cli/blob/main/README.md#install) guide.
+
+Before proceeding, ensure you have the following components installed:
+
+- [Python 3.10](https://www.python.org/downloads/) or higher
+- [pipx](https://pypa.github.io/pipx/#on-linux-install-via-pip-requires-pip-190-or-later)
+- [git](https://github.com/git-guides/install-git#install-git)
+- [Docker](https://docs.docker.com/desktop/install/mac-install/) (or [Podman](https://podman.io/getting-started/installation/), see [details](/algokit-cli/features/localnet/#podman-support))
+- [VSCode](https://code.visualstudio.com/download)
+
+## Install AlgoKit
+
+To install AlgoKit, run the following command from a terminal.
+
+```shell
+pipx install algokit
+```
+
+After the installation completes, **restart the terminal**.
+
+For more detailed installation documentation, see the [official installation guide](https://github.com/algorandfoundation/algokit-cli#install).
+
+> Please note, `pipx` is only one of the supported installation methods. You can also install AlgoKit via `brew` and _soon_ `winget` and `snap` as pre-build binaries. Refer to the official installation guide.
+
+## Verify the Installation
+
+To verify AlgoKit Installed correctly run the following.
+
+```shell
+algokit --version
+```
+
+Output similar to the following should be displayed:
+
+```shell
+algokit, version 2.0.3 # or higher
+```
+
+## Start a LocalNet
+
+AlgoKit supports using a [local version of the Algorand blockchain](/algokit-cli/features/localnet/). To start an instance of this LocalNet run the following command from the terminal:
+
+```shell
+algokit localnet start
+```
+
+This should start an instance of the LocalNet within docker. If you open the Docker Desktop application you should see something similar to the following:
+
+
+
+## Create an AlgoKit project
+
+Now that AlgoKit is installed, you can rapidly create a new project to get started quickly. This can be done by running:
+
+```shell
+algokit init
+```
+
+This will launch a guided menu system to create a specific project tailored to your needs. The templates are basic starter applications for various Algorand development scenarios. To read more about templates checkout AlgoKit detailed documentation.
+
+For now we'll use the `python` template, which is a lightweight starting point for learning Algorand smart contract development using Algorand Python. You can initialize a project using this template by running:
+
+```shell
+algokit init -t python -a preset_name "starter"
+```
+
+Next, you will be prompted for the name of your project. Finally, select the default value for the rest of the prompts (enter).
+
+Once finished, (if you have it installed) VS Code should automatically be opened with the initialised project and you will be prompted to install appropriate VS Code extensions. This starter app will contain one smart contract (built using the [Algorand Python](https://algorandfoundation.github.io/puya/) language) named `contract.py`, in the `smart_contracts/hello_world` folder, with one method (`hello`) that takes a `String` and returns a `String`. Notice that within the contract folder, there is a `deploy_config.py` which defines the parameters for deployment of your smart contract to the target chain (Algorand TestNet, Algorand MainNet, Algorand LocalNet or else).
+
+
+
+## AlgoKit Project structure
+
+The structure of your fresh algokit project instance will look similar to below:
+
+```bash
+.
+├── .algokit.toml # Configuration for AlgoKit projects in the workspace.
+├── README.md # Quick start guide for the AlgoKit Workspace.
+├── {your_workspace|project_name}.code-workspace
+└── projects
+ └── {your_project_name} # Root directory for the smart contract project. To add more projects into your algokit workspace run 'algokit init' from the root of your workspace repository.
+ ├── README.md # Quick start on Algorand Python smart contract template based project.
+ ├── .algokit # Hidden folder for AlgoKit AVM debugger and custom generators.
+ ├── .algokit.toml # Project-specific commands and custom generator references.
+ ├── poetry.lock
+ ├── poetry.toml # Dependency definitions for {your_project_name}.
+ ├── pyproject.toml # Project definitions for {your_project_name}.
+ └── smart_contracts
+ ├── README.md # Guide for adding new smart contracts.
+ ├── ...
+ ├── hello_world # Contract logic for 'hello_world'.
+ │ ├── contract.py # Contract logic.
+ │ └── deploy_config.py # Deployment logic for 'hello_world'.
+ └── helpers # Helper functions for contract build and deployment.
+```
+
+Additionally, each official smart contract template includes an interactive codespace walkthrough powered by [CodeTour](https://marketplace.visualstudio.com/items?itemName=vsls-contrib.codetour).
+
+To start the interactive walkthrough, install the extension and click on the green play button in the left bottom corner of the `Explorer` pane as demonstrated on the screenshot below (See `Getting Started with Your AlgoKit Project`).
+
+
+
+Upon execution, the walkthrough will guide you through the key components of your fresh AlgoKit project, which is an important prerequisite to learn before running and deploying your first smart contract. Certainly, not because its hard to learn, but because it will save you a lot of time and effort having the correct foundations.
+
+## Run the Demo Application
+
+Once the `Algorand Python` based project is created, you can get started by building and deploying your first smart contract. There are a few possible ways to do so as demonstrated on the following video.
+
+[](https://ipfs.algonode.xyz/ipfs/Qma6gNqxsSFc9Jbh8kBTZyVLv5gqFj1xnrsjoeT6MAAwCw/)
+
+The App ID of the deployed contract and its Algorand address is displayed, followed by the message returned from the smart contract call (`Hello, Python`).
+
+1. Start LocalNet
+2. Build the smart contract. Notice how a folder named `artifacts` is created with the [AVM (Algorand Virtual Machine)](https://dev.algorand.co/concepts/smart-contracts/avm/) related artifacts for deploying your smart contract.
+3. Deploy and call the `HelloWorld` smart contract (from `contract.py` file).
+
+After execution, the `App ID` of the deployed contract and its Algorand address are displayed, followed by the message returned from the smart contract call (`Hello, world`).
+
+At this point you have deployed a simple contract to a LocalNet Algorand network (running in your Docker environment) and called it successfully!
+
+Additionally, you can find the native AVM related artifacts and the appropriate smart contract manifest JSON files have been output to the `artifacts` folder. Note that in this example, AVM bytecode is compiled using the `PuyaPy` compiler, which is what `Algorand Python` relies on to compile your Python smart contract code to TEAL ([Transaction Execution Approval Language](https://dev.algorand.co/concepts/smart-contracts/languages/teal)).
+
+### Using AlgoKit CLI to build and deploy contracts
+
+When using official AlgoKit templates via `algokit init`, you can manage your projects using the AlgoKit CLI at the convenience of your terminal.
+
+For example, to achieve the same results as in the demo earlier, build and deploy the `HelloWorld` contract from the `contract.py` file by running the following command from the terminal:
+
+```shell
+algokit project run build
+```
+
+This command will recompile your python contracts from `contract.py` and produce the necessary artefacts for deploying your contract.
+
+```shell
+algokit project deploy localnet
+```
+
+This will then deploy to your LocalNet instance and display the same output as in the earlier demo.
+
+> Please note, as highlighted in the [structure](#algokit-project-structure) section above, the `project run ...` commands are defined in the respective `.algokit.toml` file under `[project]` sections.
+
+## Next steps
+
+We have only covered a tiny fraction of the capabilities of the AlgoKit CLI and its related ecosystem of templates and utilities for an efficient developer experience.
+
+- To get the most out of `AlgoKit`, we recommend to get started with learning more about AlgoKit and what you can do with it by checking out our extensive [AlgoKit CLI documentation](/algokit-cli/features/overview/).
+- Explore the `README.md` files at the root of any project created via `algokit init`. All official AlgoKit templates include detailed quick started guides, an interactive code tour and various presets which can be customized to your needs.
+- To learn more about `Algorand Python`, take a look at the [documentation](https://algorandfoundation.github.io/puya/).
+- To learn more about the commands demonstrated in this tutorial, refer to [`init`](/algokit-cli/features/init/) and [`project`](/algokit-cli/features/project/) to get a comprehensive understanding of their further capabilities.
+- If you'd like to learn more on structuring your `AlgoKit Project` as a monorepo, refer to `workspace` mode as described in [`init`](/algokit-cli/features/init/#workspaces-vs-standalone-projects). You can also pass the `--no-workspace` flag to setup a standalone algokit project, if preferred.
+- If you'd like to **create your own** `AlgoKit` template, refer to the [template tutorial](/algokit-cli/tutorials/algokit-template/).
+- More information on Algorand smart contracts is also available in the [smart contract documentation](https://dev.algorand.co/concepts/smart-contracts/overview).
diff --git a/docs/tutorials/smart-contracts.md b/docs/src/content/docs/tutorials/smart-contracts.md
similarity index 80%
rename from docs/tutorials/smart-contracts.md
rename to docs/src/content/docs/tutorials/smart-contracts.md
index 786587a39..6db209e4d 100644
--- a/docs/tutorials/smart-contracts.md
+++ b/docs/src/content/docs/tutorials/smart-contracts.md
@@ -1,4 +1,6 @@
-# Smart Contract Tutorial
+---
+title: "Smart Contract Tutorial"
+---
_TODO_
diff --git a/docs/src/styles/cli-reference.css b/docs/src/styles/cli-reference.css
new file mode 100644
index 000000000..73b9d7022
--- /dev/null
+++ b/docs/src/styles/cli-reference.css
@@ -0,0 +1,27 @@
+/*
+ * CLI Reference styling for auto-generated sphinx-click docs.
+ *
+ * Styles the generated CLI reference page with monospace headings
+ * and clear visual hierarchy for commands, subcommands, and options.
+ */
+
+/* ── Command headings (H3) — monospace, reduced size ── */
+.cli-ref h3 {
+ font-family: var(--sl-font-mono, ui-monospace, monospace);
+ font-size: var(--sl-text-base, 1rem);
+ font-weight: 400;
+ margin-top: 2rem;
+ padding: 0.25rem 0;
+ border-bottom: 1px solid var(--sl-color-gray-6, #343841);
+}
+
+/* ── Subcommand / option headings (H4) — compact ── */
+.cli-ref h4 {
+ font-family: var(--sl-font-mono, ui-monospace, monospace);
+ font-size: var(--sl-text-sm, 0.875rem);
+ font-weight: 600;
+ margin-top: 1.25rem;
+ margin-bottom: 0.25rem;
+ padding: 0.25rem 0;
+ border-bottom: 1px solid var(--sl-color-gray-6, #343841);
+}
\ No newline at end of file
diff --git a/docs/tsconfig.json b/docs/tsconfig.json
new file mode 100644
index 000000000..8bf91d3bb
--- /dev/null
+++ b/docs/tsconfig.json
@@ -0,0 +1,5 @@
+{
+ "extends": "astro/tsconfigs/strict",
+ "include": [".astro/types.d.ts", "**/*"],
+ "exclude": ["dist"]
+}
diff --git a/docs/tutorials/intro.md b/docs/tutorials/intro.md
index accee6658..509227999 100644
--- a/docs/tutorials/intro.md
+++ b/docs/tutorials/intro.md
@@ -18,25 +18,22 @@ This guide presents installing AlgoKit using an OS agnostic procedure. For OS sp
Before proceeding, ensure you have the following components installed:
-- [Python 3.10 - 3.14](https://www.python.org/downloads/)
-- [pipx](https://pypa.github.io/pipx/#on-linux-install-via-pip-requires-pip-190-or-later)
- [git](https://github.com/git-guides/install-git#install-git)
- [Docker](https://docs.docker.com/desktop/install/mac-install/) (or [Podman](https://podman.io/getting-started/installation/), see [details](../features/localnet.md#podman-support))
- [VSCode](https://code.visualstudio.com/download)
-
## Install AlgoKit 🛠
To install AlgoKit, run the following command from a terminal.
```shell
-pipx install algokit
+curl -fsSL https://raw.githubusercontent.com/algorandfoundation/algokit-cli/main/scripts/install/install.sh | bash
```
After the installation completes, **restart the terminal**.
For more detailed installation documentation, see the [official installation guide](https://github.com/algorandfoundation/algokit-cli#install).
-> Please note, `pipx` is only one of the supported installation methods. You can also install AlgoKit via `brew` and _soon_ `winget` and `snap` as pre-build binaries. Refer to the official installation guide.
+> The install script handles installing `uv` and Python automatically. For alternative installation methods, see the [official installation guide](https://github.com/algorandfoundation/algokit-cli#install).
## Verify the Installation ✔
@@ -100,8 +97,7 @@ The structure of your fresh algokit project instance will look similar to below:
├── README.md # Quick start on Algorand Python smart contract template based project.
├── .algokit # Hidden folder for AlgoKit AVM debugger and custom generators.
├── .algokit.toml # Project-specific commands and custom generator references.
- ├── poetry.lock
- ├── poetry.toml # Dependency definitions for {your_project_name}.
+ ├── pyproject.toml # Dependency definitions for {your_project_name}.
├── pyproject.toml # Project definitions for {your_project_name}.
└── smart_contracts
├── README.md # Guide for adding new smart contracts.
diff --git a/poetry.lock b/poetry.lock
index de1a9a67a..177e619c7 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
[[package]]
name = "alabaster"
@@ -6,7 +6,7 @@ version = "0.7.16"
description = "A light, configurable Sphinx theme"
optional = false
python-versions = ">=3.9"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"},
{file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"},
@@ -14,18 +14,22 @@ files = [
[[package]]
name = "algokit-utils"
-version = "4.1.0"
+version = "5.0.0a7"
description = "Utilities for Algorand development for use by AlgoKit"
optional = false
-python-versions = "<4.0,>=3.10"
+python-versions = "<4,>=3.10"
groups = ["main"]
files = [
- {file = "algokit_utils-4.1.0-py3-none-any.whl", hash = "sha256:d164d1ad48928040432da582883be997a2e8a7b85b06e3b07de07ad96b566550"},
+ {file = "algokit_utils-5.0.0a7-py3-none-any.whl", hash = "sha256:e409dd838e6d29aca978fe91ced43e7f94d2120ab7025eb7ccf548d2849589e1"},
+ {file = "algokit_utils-5.0.0a7.tar.gz", hash = "sha256:97212bfdf2854de7e41f8e9ec2da7194a352c90c527e1ca4a11493721b60d8aa"},
]
[package.dependencies]
httpx = ">=0.23.1,<=0.28.1"
-py-algorand-sdk = ">=2.4.0,<3.0.0"
+msgpack = ">=1.0.0,<2"
+msgpack-types = ">=0.2.0,<=0.5.0"
+pycryptodomex = ">=3.19,<4"
+pynacl = ">=1.4.0,<2"
typing-extensions = ">=4.6.0"
[[package]]
@@ -130,7 +134,7 @@ version = "2.17.0"
description = "Internationalization utilities"
optional = false
python-versions = ">=3.8"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"},
{file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"},
@@ -257,7 +261,6 @@ description = "Foreign Function Interface for Python calling C code."
optional = false
python-versions = ">=3.9"
groups = ["main", "dev"]
-markers = "platform_python_implementation != \"PyPy\""
files = [
{file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"},
{file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"},
@@ -344,6 +347,7 @@ files = [
{file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"},
{file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"},
]
+markers = {dev = "platform_python_implementation != \"PyPy\""}
[package.dependencies]
pycparser = {version = "*", markers = "implementation_name != \"PyPy\""}
@@ -468,7 +472,7 @@ version = "8.1.8"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
-groups = ["main", "dev"]
+groups = ["main", "dev", "docs"]
files = [
{file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
{file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
@@ -503,18 +507,18 @@ files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
-markers = {docs = "sys_platform == \"win32\""}
+markers = {docs = "platform_system == \"Windows\" or sys_platform == \"win32\""}
[[package]]
name = "copier"
-version = "9.11.3"
+version = "9.14.0"
description = "A library for rendering project templates."
optional = false
python-versions = ">=3.10"
groups = ["main"]
files = [
- {file = "copier-9.11.3-py3-none-any.whl", hash = "sha256:ab4bc7e2944edc030b4c14ec84fffd6bf810b9b8fd56938e8ccbab1b169ea6ca"},
- {file = "copier-9.11.3.tar.gz", hash = "sha256:f4da98c7f3dd2243480433541b3b4d9daa788bce13b7b6d43c0c6d84bd50e889"},
+ {file = "copier-9.14.0-py3-none-any.whl", hash = "sha256:e12a18cfef22e67254e5229f0b4bdab85e1e3e82926e448226be0b70d0f4de53"},
+ {file = "copier-9.14.0.tar.gz", hash = "sha256:4d1b6a19538a5d170f913afb7682fe745c74b35c84085890809cb8d8d4d8fe7a"},
]
[package.dependencies]
@@ -614,62 +618,75 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""]
[[package]]
name = "cryptography"
-version = "44.0.3"
+version = "46.0.5"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
-python-versions = "!=3.9.0,!=3.9.1,>=3.7"
+python-versions = "!=3.9.0,!=3.9.1,>=3.8"
groups = ["main", "dev"]
files = [
- {file = "cryptography-44.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:962bc30480a08d133e631e8dfd4783ab71cc9e33d5d7c1e192f0b7c06397bb88"},
- {file = "cryptography-44.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc61e8f3bf5b60346d89cd3d37231019c17a081208dfbbd6e1605ba03fa137"},
- {file = "cryptography-44.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58968d331425a6f9eedcee087f77fd3c927c88f55368f43ff7e0a19891f2642c"},
- {file = "cryptography-44.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e28d62e59a4dbd1d22e747f57d4f00c459af22181f0b2f787ea83f5a876d7c76"},
- {file = "cryptography-44.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af653022a0c25ef2e3ffb2c673a50e5a0d02fecc41608f4954176f1933b12359"},
- {file = "cryptography-44.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:157f1f3b8d941c2bd8f3ffee0af9b049c9665c39d3da9db2dc338feca5e98a43"},
- {file = "cryptography-44.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:c6cd67722619e4d55fdb42ead64ed8843d64638e9c07f4011163e46bc512cf01"},
- {file = "cryptography-44.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b424563394c369a804ecbee9b06dfb34997f19d00b3518e39f83a5642618397d"},
- {file = "cryptography-44.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c91fc8e8fd78af553f98bc7f2a1d8db977334e4eea302a4bfd75b9461c2d8904"},
- {file = "cryptography-44.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:25cd194c39fa5a0aa4169125ee27d1172097857b27109a45fadc59653ec06f44"},
- {file = "cryptography-44.0.3-cp37-abi3-win32.whl", hash = "sha256:3be3f649d91cb182c3a6bd336de8b61a0a71965bd13d1a04a0e15b39c3d5809d"},
- {file = "cryptography-44.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:3883076d5c4cc56dbef0b898a74eb6992fdac29a7b9013870b34efe4ddb39a0d"},
- {file = "cryptography-44.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:5639c2b16764c6f76eedf722dbad9a0914960d3489c0cc38694ddf9464f1bb2f"},
- {file = "cryptography-44.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ffef566ac88f75967d7abd852ed5f182da252d23fac11b4766da3957766759"},
- {file = "cryptography-44.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:192ed30fac1728f7587c6f4613c29c584abdc565d7417c13904708db10206645"},
- {file = "cryptography-44.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7d5fe7195c27c32a64955740b949070f21cba664604291c298518d2e255931d2"},
- {file = "cryptography-44.0.3-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3f07943aa4d7dad689e3bb1638ddc4944cc5e0921e3c227486daae0e31a05e54"},
- {file = "cryptography-44.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb90f60e03d563ca2445099edf605c16ed1d5b15182d21831f58460c48bffb93"},
- {file = "cryptography-44.0.3-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ab0b005721cc0039e885ac3503825661bd9810b15d4f374e473f8c89b7d5460c"},
- {file = "cryptography-44.0.3-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3bb0847e6363c037df8f6ede57d88eaf3410ca2267fb12275370a76f85786a6f"},
- {file = "cryptography-44.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0cc66c74c797e1db750aaa842ad5b8b78e14805a9b5d1348dc603612d3e3ff5"},
- {file = "cryptography-44.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6866df152b581f9429020320e5eb9794c8780e90f7ccb021940d7f50ee00ae0b"},
- {file = "cryptography-44.0.3-cp39-abi3-win32.whl", hash = "sha256:c138abae3a12a94c75c10499f1cbae81294a6f983b3af066390adee73f433028"},
- {file = "cryptography-44.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:5d186f32e52e66994dce4f766884bcb9c68b8da62d61d9d215bfe5fb56d21334"},
- {file = "cryptography-44.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:cad399780053fb383dc067475135e41c9fe7d901a97dd5d9c5dfb5611afc0d7d"},
- {file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:21a83f6f35b9cc656d71b5de8d519f566df01e660ac2578805ab245ffd8523f8"},
- {file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fc3c9babc1e1faefd62704bb46a69f359a9819eb0292e40df3fb6e3574715cd4"},
- {file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:e909df4053064a97f1e6565153ff8bb389af12c5c8d29c343308760890560aff"},
- {file = "cryptography-44.0.3-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:dad80b45c22e05b259e33ddd458e9e2ba099c86ccf4e88db7bbab4b747b18d06"},
- {file = "cryptography-44.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:479d92908277bed6e1a1c69b277734a7771c2b78633c224445b5c60a9f4bc1d9"},
- {file = "cryptography-44.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:896530bc9107b226f265effa7ef3f21270f18a2026bc09fed1ebd7b66ddf6375"},
- {file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9b4d4a5dbee05a2c390bf212e78b99434efec37b17a4bff42f50285c5c8c9647"},
- {file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02f55fb4f8b79c1221b0961488eaae21015b69b210e18c386b69de182ebb1259"},
- {file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:dd3db61b8fe5be220eee484a17233287d0be6932d056cf5738225b9c05ef4fff"},
- {file = "cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:978631ec51a6bbc0b7e58f23b68a8ce9e5f09721940933e9c217068388789fe5"},
- {file = "cryptography-44.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:5d20cc348cca3a8aa7312f42ab953a56e15323800ca3ab0706b8cd452a3a056c"},
- {file = "cryptography-44.0.3.tar.gz", hash = "sha256:fe19d8bc5536a91a24a8133328880a41831b6c5df54599a8417b62fe015d3053"},
-]
-
-[package.dependencies]
-cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
-
-[package.extras]
-docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0) ; python_version >= \"3.8\""]
+ {file = "cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731"},
+ {file = "cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82"},
+ {file = "cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1"},
+ {file = "cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48"},
+ {file = "cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4"},
+ {file = "cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663"},
+ {file = "cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826"},
+ {file = "cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d"},
+ {file = "cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a"},
+ {file = "cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4"},
+ {file = "cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c"},
+ {file = "cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4"},
+ {file = "cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9"},
+ {file = "cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72"},
+ {file = "cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7"},
+ {file = "cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d"},
+]
+
+[package.dependencies]
+cffi = {version = ">=2.0.0", markers = "python_full_version >= \"3.9.0\" and platform_python_implementation != \"PyPy\""}
+typing-extensions = {version = ">=4.13.2", markers = "python_full_version < \"3.11.0\""}
+
+[package.extras]
+docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"]
docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"]
-nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""]
-pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"]
+nox = ["nox[uv] (>=2024.4.15)"]
+pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"]
sdist = ["build (>=1.0.0)"]
ssh = ["bcrypt (>=3.1.5)"]
-test = ["certifi (>=2024)", "cryptography-vectors (==44.0.3)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
+test = ["certifi (>=2024)", "cryptography-vectors (==46.0.5)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
test-randomorder = ["pytest-randomly"]
[[package]]
@@ -986,7 +1003,7 @@ version = "1.4.1"
description = "Getting image size from png/jpeg/jpeg2000/gif file"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"},
{file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
@@ -1062,26 +1079,22 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-ena
[[package]]
name = "jaraco-context"
-version = "6.1.0"
+version = "6.0.1"
description = "Useful decorators and context managers"
optional = false
-python-versions = ">=3.9"
+python-versions = ">=3.8"
groups = ["main", "dev"]
files = [
- {file = "jaraco_context-6.1.0-py3-none-any.whl", hash = "sha256:a43b5ed85815223d0d3cfdb6d7ca0d2bc8946f28f30b6f3216bda070f68badda"},
- {file = "jaraco_context-6.1.0.tar.gz", hash = "sha256:129a341b0a85a7db7879e22acd66902fda67882db771754574338898b2d5d86f"},
+ {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"},
+ {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"},
]
[package.dependencies]
"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""}
[package.extras]
-check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
-cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
-enabler = ["pytest-enabler (>=3.4)"]
-test = ["jaraco.test (>=5.6.0)", "portend", "pytest (>=6,!=8.1.*)"]
-type = ["mypy (<1.19) ; platform_python_implementation == \"PyPy\"", "pytest-mypy (>=1.0.1)"]
+test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
[[package]]
name = "jaraco-functools"
@@ -1129,7 +1142,7 @@ version = "3.1.6"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
-groups = ["main", "dev", "docs"]
+groups = ["main", "docs"]
files = [
{file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"},
{file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"},
@@ -1297,7 +1310,7 @@ version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.9"
-groups = ["main", "dev", "docs"]
+groups = ["main", "docs"]
files = [
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
@@ -1502,6 +1515,22 @@ files = [
{file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"},
]
+[[package]]
+name = "msgpack-types"
+version = "0.5.0"
+description = "Type stubs for msgpack"
+optional = false
+python-versions = "<4.0,>=3.8"
+groups = ["main"]
+files = [
+ {file = "msgpack_types-0.5.0-py3-none-any.whl", hash = "sha256:8b633ed75e495a555fa0615843de559a74b1d176828d59bb393d266e51f6bda7"},
+ {file = "msgpack_types-0.5.0.tar.gz", hash = "sha256:aebd1b8da23f8f9966d66ebb1a43bd261b95751c6a267bd21a124d2ccac84201"},
+]
+
+[package.dependencies]
+msgpack = ">=1.1.0,<1.2.0"
+typing-extensions = ">=4.6.0"
+
[[package]]
name = "mslex"
version = "1.3.0"
@@ -1949,23 +1978,6 @@ files = [
[package.dependencies]
wcwidth = "*"
-[[package]]
-name = "py-algorand-sdk"
-version = "2.8.0"
-description = "Algorand SDK in Python"
-optional = false
-python-versions = ">=3.10"
-groups = ["main"]
-files = [
- {file = "py-algorand-sdk-2.8.0.tar.gz", hash = "sha256:2a2ddc94ab5c0989ed90f1b97eebb9857531b1e9c9d0d3437a57c17539ed6367"},
- {file = "py_algorand_sdk-2.8.0-py3-none-any.whl", hash = "sha256:0647a5aae4c87f0780048f98c1ee1b57a6c8fcec2c38306e3a50e42f0a81eb37"},
-]
-
-[package.dependencies]
-msgpack = ">=1.0.0,<2"
-pycryptodomex = ">=3.6.0,<4"
-pynacl = ">=1.4.0,<2"
-
[[package]]
name = "py-serializable"
version = "2.0.0"
@@ -2007,11 +2019,11 @@ description = "C parser in Python"
optional = false
python-versions = ">=3.8"
groups = ["main", "dev"]
-markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
]
+markers = {main = "implementation_name != \"PyPy\"", dev = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""}
[[package]]
name = "pycryptodomex"
@@ -2054,21 +2066,21 @@ files = [
[[package]]
name = "pydantic"
-version = "2.12.5"
+version = "2.11.4"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
- {file = "pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d"},
- {file = "pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49"},
+ {file = "pydantic-2.11.4-py3-none-any.whl", hash = "sha256:d9615eaa9ac5a063471da949c8fc16376a84afb5024688b3ff885693506764eb"},
+ {file = "pydantic-2.11.4.tar.gz", hash = "sha256:32738d19d63a226a52eed76645a98ee07c1f410ee41d93b4afbfa85ed8111c2d"},
]
[package.dependencies]
annotated-types = ">=0.6.0"
-pydantic-core = "2.41.5"
-typing-extensions = ">=4.14.1"
-typing-inspection = ">=0.4.2"
+pydantic-core = "2.33.2"
+typing-extensions = ">=4.12.2"
+typing-inspection = ">=0.4.0"
[package.extras]
email = ["email-validator (>=2.0.0)"]
@@ -2076,137 +2088,115 @@ timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows
[[package]]
name = "pydantic-core"
-version = "2.41.5"
+version = "2.33.2"
description = "Core functionality for Pydantic validation and serialization"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
- {file = "pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146"},
- {file = "pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2"},
- {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97"},
- {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9"},
- {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52"},
- {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941"},
- {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a"},
- {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c"},
- {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2"},
- {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556"},
- {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49"},
- {file = "pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba"},
- {file = "pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9"},
- {file = "pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6"},
- {file = "pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b"},
- {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a"},
- {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8"},
- {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e"},
- {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1"},
- {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b"},
- {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b"},
- {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284"},
- {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594"},
- {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e"},
- {file = "pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b"},
- {file = "pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe"},
- {file = "pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f"},
- {file = "pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7"},
- {file = "pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0"},
- {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69"},
- {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75"},
- {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05"},
- {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc"},
- {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c"},
- {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5"},
- {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c"},
- {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294"},
- {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1"},
- {file = "pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d"},
- {file = "pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815"},
- {file = "pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3"},
- {file = "pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9"},
- {file = "pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34"},
- {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0"},
- {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33"},
- {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e"},
- {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2"},
- {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586"},
- {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d"},
- {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740"},
- {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e"},
- {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858"},
- {file = "pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36"},
- {file = "pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11"},
- {file = "pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd"},
- {file = "pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a"},
- {file = "pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14"},
- {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1"},
- {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66"},
- {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869"},
- {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2"},
- {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375"},
- {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553"},
- {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90"},
- {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07"},
- {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb"},
- {file = "pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23"},
- {file = "pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf"},
- {file = "pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c"},
- {file = "pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008"},
- {file = "pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf"},
- {file = "pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5"},
- {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d"},
- {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60"},
- {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82"},
- {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5"},
- {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3"},
- {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425"},
- {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504"},
- {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5"},
- {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3"},
- {file = "pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460"},
- {file = "pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b"},
- {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034"},
- {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c"},
- {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2"},
- {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad"},
- {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd"},
- {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc"},
- {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56"},
- {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b"},
- {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8"},
- {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a"},
- {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b"},
- {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2"},
- {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093"},
- {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a"},
- {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963"},
- {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a"},
- {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26"},
- {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808"},
- {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc"},
- {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1"},
- {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84"},
- {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770"},
- {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f"},
- {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51"},
- {file = "pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e"},
-]
-
-[package.dependencies]
-typing-extensions = ">=4.14.1"
+ {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"},
+ {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"},
+ {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"},
+ {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"},
+ {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"},
+]
+
+[package.dependencies]
+typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
[[package]]
name = "pydash"
@@ -2243,24 +2233,24 @@ windows-terminal = ["colorama (>=0.4.6)"]
[[package]]
name = "pyinstaller"
-version = "6.18.0"
+version = "6.19.0"
description = "PyInstaller bundles a Python application and all its dependencies into a single package."
optional = false
python-versions = "<3.15,>=3.8"
groups = ["dev"]
files = [
- {file = "pyinstaller-6.18.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:cb7aa5a71bfa7c0af17a4a4e21855663c89e4bd7c40f1d337c8370636d8847c3"},
- {file = "pyinstaller-6.18.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:07785459b3bf8a48889eac0b4d0667ade84aef8930ce030bc7cbb32f41283b33"},
- {file = "pyinstaller-6.18.0-py3-none-manylinux2014_i686.whl", hash = "sha256:f998675b7ccb2dabbb1dc2d6f18af61d55428ad6d38e6c4d700417411b697d37"},
- {file = "pyinstaller-6.18.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:779817a0cf69604cddcdb5be1fd4959dc2ce048d6355c73e5da97884df2f3387"},
- {file = "pyinstaller-6.18.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:31b5d109f8405be0b7cddcede43e7b074792bc9a5bbd54ec000a3e779183c2af"},
- {file = "pyinstaller-6.18.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:4328c9837f1aef4fe1a127d4ff1b09a12ce53c827ce87c94117628b0e1fd098b"},
- {file = "pyinstaller-6.18.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:3638fc81eb948e5e5eab1d4ad8f216e3fec6d4a350648304f0adb227b746ee5e"},
- {file = "pyinstaller-6.18.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe59da34269e637f97fd3c43024f764586fc319141d245ff1a2e9af1036aa3"},
- {file = "pyinstaller-6.18.0-py3-none-win32.whl", hash = "sha256:496205e4fa92ec944f9696eb597962a83aef4d4c3479abfab83d730e1edf016b"},
- {file = "pyinstaller-6.18.0-py3-none-win_amd64.whl", hash = "sha256:976fabd90ecfbda47571c87055ad73413ec615ff7dea35e12a4304174de78de9"},
- {file = "pyinstaller-6.18.0-py3-none-win_arm64.whl", hash = "sha256:dba4b70e3c9ba09aab51152c72a08e58a751851548f77ad35944d32a300c8381"},
- {file = "pyinstaller-6.18.0.tar.gz", hash = "sha256:cdc507542783511cad4856fce582fdc37e9f29665ca596889c663c83ec8c6ec9"},
+ {file = "pyinstaller-6.19.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:4190e76b74f0c4b5c5f11ac360928cd2e36ec8e3194d437bf6b8648c7bc0c134"},
+ {file = "pyinstaller-6.19.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8bd68abd812d8a6ba33b9f1810e91fee0f325969733721b78151f0065319ca11"},
+ {file = "pyinstaller-6.19.0-py3-none-manylinux2014_i686.whl", hash = "sha256:1ec54ef967996ca61dacba676227e2b23219878ccce5ee9d6f3aada7b8ed8abf"},
+ {file = "pyinstaller-6.19.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:4ab2bb52e58448e14ddf9450601bdedd66800465043501c1d8f1cab87b60b122"},
+ {file = "pyinstaller-6.19.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:da6d5c6391ccefe73554b9fa29b86001c8e378e0f20c2a4004f836ba537eff63"},
+ {file = "pyinstaller-6.19.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a0fc5f6b3c55aa54353f0c74ffa59b1115433c1850c6f655d62b461a2ed6cbbe"},
+ {file = "pyinstaller-6.19.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:e649ba6bd1b0b89b210ad92adb5fbdc8a42dd2c5ca4f72ef3a0bfec83a424b83"},
+ {file = "pyinstaller-6.19.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:481a909c8e60c8692fc60fcb1344d984b44b943f8bc9682f2fcdae305ad297e6"},
+ {file = "pyinstaller-6.19.0-py3-none-win32.whl", hash = "sha256:3c5c251054fe4cfaa04c34a363dcfbf811545438cb7198304cd444756bc2edd2"},
+ {file = "pyinstaller-6.19.0-py3-none-win_amd64.whl", hash = "sha256:b5bb6536c6560330d364d91522250f254b107cf69129d9cbcd0e6727c570be33"},
+ {file = "pyinstaller-6.19.0-py3-none-win_arm64.whl", hash = "sha256:c2d5a539b0bfe6159d5522c8c70e1c0e487f22c2badae0f97d45246223b798ea"},
+ {file = "pyinstaller-6.19.0.tar.gz", hash = "sha256:ec73aeb8bd9b7f2f1240d328a4542e90b3c6e6fbc106014778431c616592a865"},
]
[package.dependencies]
@@ -2268,7 +2258,7 @@ altgraph = "*"
macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""}
packaging = ">=22.0"
pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""}
-pyinstaller-hooks-contrib = ">=2025.9"
+pyinstaller-hooks-contrib = ">=2026.0"
pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""}
setuptools = ">=42.0.0"
@@ -2278,14 +2268,14 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"]
[[package]]
name = "pyinstaller-hooks-contrib"
-version = "2026.0"
+version = "2026.3"
description = "Community maintained hooks for PyInstaller"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
- {file = "pyinstaller_hooks_contrib-2026.0-py3-none-any.whl", hash = "sha256:0590db8edeba3e6c30c8474937021f5cd39c0602b4d10f74a064c73911efaca5"},
- {file = "pyinstaller_hooks_contrib-2026.0.tar.gz", hash = "sha256:0120893de491a000845470ca9c0b39284731ac6bace26f6849dea9627aaed48e"},
+ {file = "pyinstaller_hooks_contrib-2026.3-py3-none-any.whl", hash = "sha256:5ecd1068ad262afecadf07556279d2be52ca93a88b049fae17f1a2eb2969254a"},
+ {file = "pyinstaller_hooks_contrib-2026.3.tar.gz", hash = "sha256:800d3a198a49a6cd0de2d7fb795005fdca7a0222ed9cb47c0691abd1c27b9310"},
]
[package.dependencies]
@@ -2312,45 +2302,30 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
[[package]]
name = "pynacl"
-version = "1.6.2"
+version = "1.5.0"
description = "Python binding to the Networking and Cryptography (NaCl) library"
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.6"
groups = ["main"]
files = [
- {file = "pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594"},
- {file = "pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0"},
- {file = "pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9"},
- {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574"},
- {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634"},
- {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88"},
- {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14"},
- {file = "pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444"},
- {file = "pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b"},
- {file = "pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145"},
- {file = "pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590"},
- {file = "pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2"},
- {file = "pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465"},
- {file = "pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0"},
- {file = "pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4"},
- {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87"},
- {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c"},
- {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130"},
- {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6"},
- {file = "pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e"},
- {file = "pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577"},
- {file = "pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa"},
- {file = "pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0"},
- {file = "pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c"},
- {file = "pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c"},
-]
-
-[package.dependencies]
-cffi = {version = ">=2.0.0", markers = "platform_python_implementation != \"PyPy\" and python_version >= \"3.9\""}
-
-[package.extras]
-docs = ["sphinx (<7)", "sphinx_rtd_theme"]
-tests = ["hypothesis (>=3.27.0)", "pytest (>=7.4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
+ {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"},
+ {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"},
+ {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"},
+ {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"},
+ {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"},
+ {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"},
+ {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"},
+ {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"},
+ {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"},
+ {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"},
+]
+
+[package.dependencies]
+cffi = ">=1.4.1"
+
+[package.extras]
+docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"]
+tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"]
[[package]]
name = "pyparsing"
@@ -2903,7 +2878,7 @@ version = "3.0.1"
description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"},
{file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"},
@@ -2939,7 +2914,7 @@ version = "6.2.1"
description = "Python documentation generator"
optional = false
python-versions = ">=3.8"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "Sphinx-6.2.1.tar.gz", hash = "sha256:6d56a34697bb749ffa0152feafc4b19836c755d90a7c59b72bc7dfd371b9cc6b"},
{file = "sphinx-6.2.1-py3-none-any.whl", hash = "sha256:97787ff1fa3256a3eef9eda523a63dbf299f7b47e053cfcf684a1c2a8380c912"},
@@ -2974,7 +2949,7 @@ version = "4.4.0"
description = "Sphinx extension that automatically documents click applications"
optional = false
python-versions = ">=3.7"
-groups = ["dev"]
+groups = ["docs"]
files = [
{file = "sphinx-click-4.4.0.tar.gz", hash = "sha256:cc67692bd28f482c7f01531c61b64e9d2f069bfcf3d24cbbb51d4a84a749fa48"},
{file = "sphinx_click-4.4.0-py3-none-any.whl", hash = "sha256:2821c10a68fc9ee6ce7c92fad26540d8d8c8f45e6d7258f0e4fb7529ae8fab49"},
@@ -2991,7 +2966,7 @@ version = "2.0.0"
description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books"
optional = false
python-versions = ">=3.9"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"},
{file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"},
@@ -3008,7 +2983,7 @@ version = "2.0.0"
description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents"
optional = false
python-versions = ">=3.9"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"},
{file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"},
@@ -3025,7 +3000,7 @@ version = "2.1.0"
description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
optional = false
python-versions = ">=3.9"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"},
{file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"},
@@ -3042,7 +3017,7 @@ version = "1.0.1"
description = "A sphinx extension which renders display math in HTML via JavaScript"
optional = false
python-versions = ">=3.5"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"},
{file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"},
@@ -3057,7 +3032,7 @@ version = "2.0.0"
description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents"
optional = false
python-versions = ">=3.9"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"},
{file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"},
@@ -3074,7 +3049,7 @@ version = "2.0.0"
description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)"
optional = false
python-versions = ">=3.9"
-groups = ["dev", "docs"]
+groups = ["docs"]
files = [
{file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"},
{file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"},
@@ -3267,26 +3242,26 @@ files = [
[[package]]
name = "typing-extensions"
-version = "4.15.0"
-description = "Backported and Experimental Type Hints for Python 3.9+"
+version = "4.13.2"
+description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
-python-versions = ">=3.9"
+python-versions = ">=3.8"
groups = ["main", "dev", "docs"]
files = [
- {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"},
- {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"},
+ {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"},
+ {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"},
]
[[package]]
name = "typing-inspection"
-version = "0.4.2"
+version = "0.4.0"
description = "Runtime typing introspection tools"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
- {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"},
- {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"},
+ {file = "typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f"},
+ {file = "typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122"},
]
[package.dependencies]
@@ -3352,14 +3327,14 @@ files = [
[[package]]
name = "urllib3"
-version = "2.6.3"
+version = "2.6.0"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.9"
groups = ["main", "dev", "docs"]
files = [
- {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"},
- {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"},
+ {file = "urllib3-2.6.0-py3-none-any.whl", hash = "sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f"},
+ {file = "urllib3-2.6.0.tar.gz", hash = "sha256:cb9bcef5a4b345d5da5d145dc3e30834f58e8018828cbc724d30b4cb7d4d49f1"},
]
[package.extras]
@@ -3456,4 +3431,4 @@ type = ["pytest-mypy"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.10,<3.15"
-content-hash = "1aafa2e9f1424c37ee9138f4674f333b5d42ecec3c50077fc92fd7cc7d87c5d3"
+content-hash = "906409e55fab17afe12987d1c72debb5e82737999b9ac3480b87a54bc44ee000"
diff --git a/poetry.toml b/poetry.toml
deleted file mode 100644
index ab1033bd3..000000000
--- a/poetry.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[virtualenvs]
-in-project = true
diff --git a/pyproject.toml b/pyproject.toml
index 5af926c44..ba1195e06 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,77 +1,83 @@
-[tool.poetry]
+[project]
name = "algokit"
version = "2.10.2"
description = "Algorand development kit command-line interface"
-authors = ["Algorand Foundation "]
-license = "MIT"
+authors = [{name = "Algorand Foundation", email = "contact@algorand.foundation"}]
+license = {text = "MIT"}
readme = "README.md"
+requires-python = ">=3.10,<3.15"
+dependencies = [
+ "click==8.1.8", # TODO: 8.2.0 upgrade requires refinements in click_invoker.py due to breaking changes
+ "httpx>=0.23.1,<=0.28.1",
+ "copier>=9.11.3,<10.0.0",
+ "questionary>=1.10.0,<2.0.0",
+ "pyclip>=0.7.0,<0.8.0",
+ "shellingham>=1.5.4,<2.0.0",
+ "tomli>=2.0.1,<3.0.0; python_version < '3.11'",
+ "python-dotenv>=1.0.0,<2.0.0",
+ "mslex>=1.1.0,<2.0.0",
+ "keyring==25.6.0",
+ # pyjwt is locked because it's explicitly vendored from auth0 repo,
+ # to reduce dependency on auth0 package that caused many adhoc transitive dependency errors.
+ # See header in src/algokit/core/_vendor/auth0/authentication/token_verifier.py
+ "pyjwt>=2.10.1,<3.0.0",
+ "cryptography>=46.0.5,<47.0.0", # pyjwt weak dependency, explicitly required in vendored file
+ "algokit-utils>=5.0.0a7,<6.0.0",
+ "multiformats==0.3.1",
+ "multiformats-config==0.3.1", # pinned in lockstep with multiformats
+ "jsondiff>=2.0.0,<3.0.0",
+ "requests>=2.31.0,<3.0.0",
+ "textual>=3.0.1,<4.0.0",
+ "prompt-toolkit==3.0.51", # dependency of questionary, pinned to avoid 3.0.52 breaking changes
+ "pywin32>=311,<312; sys_platform == 'win32'", # transitive dep of pyclip, pinned for Python 3.14 on Windows
+]
-[tool.poetry.dependencies]
-python = ">=3.10,<3.15"
-click = "8.1.8" # TODO: 8.2.0 upgrade requires refinements in click_invoker.py due to breaking changes
-httpx = ">=0.23.1,<=0.28.1"
-copier = "^9.11.3" # Using caret to allow patch updates. Major/minor updates should be tested before bumping.
-questionary = "^1.10.0"
-pyclip = "^0.7.0"
-shellingham = "^1.5.4"
-tomli = { version = "^2.0.1", python = "<3.11" }
-python-dotenv = "^1.0.0"
-mslex = "^1.1.0"
-keyring = "25.6.0"
-# pyjwt is locked to version ^2.10.1 because its explicitly
-# vendored from auth0 repo, to reduce depedency on auth0 package that caused many adhoc transitive dependency errors in cli
-# see header in src/algokit/core/_vendor/auth0/authentication/token_verifier.py
-# this version has been tested to work with the vendored file
-pyjwt = "^2.10.1"
-cryptography = "^44.0.2" # pyjwt has a weak dependency on cryptography and explicitly requires it in the vendored file, hence the lock
-algokit-utils = "^4.0.1"
-multiformats = "0.3.1"
-multiformats_config = "0.3.1" # pinned this to be in lockstep with multiformats
-jsondiff = "^2.0.0"
-requests = "^2.31.0"
-textual = "^3.0.1"
-prompt_toolkit = "3.0.51" # dependency of questionary, pinned to avoid 3.0.52 which has breaking changes
-pywin32 = { version = "^311", markers = "sys_platform == 'win32'" } # transitive dep of pyclip, pinned to support Python 3.14 on Windows
+[project.scripts]
+algokit = "algokit.cli:algokit"
-[tool.poetry.group.dev.dependencies]
-pyinstaller = {version = "^6.10.0"}
-pytest = "^8"
-ruff = ">=0.1.6,<0.13.0"
-pip-audit = "^2.4.7"
-approvaltests = "^7.2.0"
-pytest-mock = "^3.10.0"
-mypy = "^1.0.0"
-pytest-httpx = "^0.35.0"
-python-semantic-release = "^7.32.2"
-pytest-cov = "^4.0.0"
-pre-commit = ">=2.20,<4.0"
+[tool.poetry.group.docs.dependencies]
sphinx = "^6.0.0"
sphinx-click = "^4.4.0"
-poethepoet = ">=0.17.1,<0.37.0"
-gfm-toc = "^0.0.7"
-pytest-xdist = "^3.4.0"
-pytest-sugar = "^1.0.0"
-types-pyyaml = "^6.0.12.20250402"
-
-[tool.poetry.group.docs]
-optional = true
-
-[tool.poetry.group.docs.dependencies]
sphinxnotes-markdown-builder = "^0.5.6"
[build-system]
-requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
+requires = ["hatchling"]
+build-backend = "hatchling.build"
-[tool.poetry.scripts]
-algokit = "algokit.cli:algokit"
+[tool.hatch.build.targets.wheel]
+packages = ["src/algokit"]
+
+[dependency-groups]
+dev = [
+ "pyinstaller>=6.10.0,<7.0.0",
+ "pytest>=8,<9",
+ "ruff>=0.1.6,<0.13.0",
+ "pip-audit>=2.4.7,<3.0.0",
+ "approvaltests>=7.2.0,<8.0.0",
+ "pytest-mock>=3.10.0,<4.0.0",
+ "mypy>=1.0.0,<2.0.0",
+ "pytest-httpx>=0.35.0,<0.36.0",
+ "python-semantic-release>=7.32.2,<8.0.0",
+ "pytest-cov>=4.0.0,<5.0.0",
+ "pre-commit>=2.20,<4.0",
+ "poethepoet>=0.17.1,<0.37.0",
+ "gfm-toc>=0.0.7,<0.0.8",
+ "pytest-xdist>=3.4.0,<4.0.0",
+ "pytest-sugar>=1.0.0,<2.0.0",
+ "types-pyyaml>=6.0.12.20250402,<7.0.0",
+]
+docs = [
+ "sphinx>=6.0.0,<7.0.0",
+ "sphinx-click>=4.4.0,<5.0.0",
+ "sphinxnotes-markdown-builder>=0.5.6,<0.6.0",
+]
[tool.poe.tasks]
-docs_generate = "sphinx-build -b markdown -E docs/sphinx docs/cli"
-docs_toc = "gfm-toc docs/cli/index.md -e 3"
-docs_title = {shell = "(echo \"# AlgoKit CLI Reference Documentation\\n\\n\"; cat docs/cli/index.md) > docs/cli/temp.md && mv docs/cli/temp.md docs/cli/index.md"}
-docs = ["docs_generate", "docs_toc", "docs_title"]
-package_unix = "pyinstaller --clean --onedir --hidden-import jinja2_ansible_filters --hidden-import multiformats_config --copy-metadata algokit --name algokit --noconfirm src/algokit/__main__.py --add-data './misc/multiformats_config:multiformats_config/' --add-data './src/algokit/resources:algokit/resources/'"
+docs-cli = "python docs/cli_build.py"
+docs-dev = { shell = "python docs/cli_build.py && pnpm --dir docs run dev" }
+docs-build = { shell = "python docs/cli_build.py && pnpm --dir docs run build" }
+docs-preview = "npm run --prefix docs preview"
+package_unix = "pyinstaller --clean --onedir --hidden-import jinja2_ansible_filters --hidden-import multiformats_config --hidden-import algokit_utils.algo25 --hidden-import algokit_utils.transact --hidden-import algokit_utils.common --hidden-import algokit_utils.clients --hidden-import algokit_utils.transactions.builders --hidden-import algokit_utils.transactions.types --copy-metadata algokit --name algokit --noconfirm src/algokit/__main__.py --add-data './misc/multiformats_config:multiformats_config/' --add-data './src/algokit/resources:algokit/resources/'"
package_windows = { cmd = "scripts/package_windows.bat" }
package_mac = { cmd = "scripts/package_mac.sh" }
@@ -165,6 +171,7 @@ target-version = "py310"
[tool.ruff.lint.per-file-ignores]
"tests/**/test_*.py" = ["PLR0913"] # too many args
+"docs/cli_build.py" = ["T201"] # print is intentional in build scripts
[tool.ruff.lint.flake8-annotations]
allow-star-arg-any = true
@@ -198,9 +205,9 @@ module = ["approvaltests.*", "jsondiff.*"]
ignore_missing_imports = true
[tool.semantic_release]
-version_toml = "pyproject.toml:tool.poetry.version"
+version_toml = "pyproject.toml:project.version"
remove_dist = false
-build_command = "poetry build --format wheel"
+build_command = "uv build --wheel"
version_source = "tag"
major_on_zero = true
upload_to_repository = false
diff --git a/scripts/install/install.ps1 b/scripts/install/install.ps1
new file mode 100644
index 000000000..fa2b565a5
--- /dev/null
+++ b/scripts/install/install.ps1
@@ -0,0 +1,124 @@
+# AlgoKit CLI Installer for Windows (PowerShell)
+# Usage: irm https://raw.githubusercontent.com/algorandfoundation/algokit-cli/main/scripts/install/install.ps1 | iex
+[CmdletBinding()]
+param()
+
+$ErrorActionPreference = "Stop"
+$UV_INSTALL_URL = "https://astral.sh/uv/install.ps1"
+$PYTHON_VERSION = "3.12"
+$PACKAGE = "algokit"
+
+function Write-Log {
+ param([string]$Message, [string]$Level = "INFO")
+ $color = switch ($Level) {
+ "INFO" { "Green" }
+ "WARN" { "Yellow" }
+ "ERROR" { "Red" }
+ default { "White" }
+ }
+ Write-Host "[algokit] $Message" -ForegroundColor $color
+}
+
+function Stop-WithError {
+ param([string]$Message)
+ Write-Log $Message "ERROR"
+ exit 1
+}
+
+function Install-UV {
+ if (Get-Command uv -ErrorAction SilentlyContinue) {
+ $uvVersion = (uv --version 2>$null) -replace 'uv ', '' -replace '\n', ''
+ Write-Log "uv found: uv $uvVersion"
+ return
+ }
+
+ Write-Log "Installing uv..."
+ try {
+ $uvInstallerScript = [string](Invoke-RestMethod $UV_INSTALL_URL)
+ if ($uvInstallerScript.Length -lt 1000) {
+ Stop-WithError "uv installer appears corrupted (too small)."
+ }
+ Invoke-Expression $uvInstallerScript
+ }
+ catch {
+ Stop-WithError "Failed to install uv: $($_.Exception.Message)"
+ }
+
+ $env:PATH = "$env:USERPROFILE\.cargo\bin;$env:USERPROFILE\.local\bin;$env:PATH"
+
+ if (-not (Get-Command uv -ErrorAction SilentlyContinue)) {
+ Stop-WithError "uv installed but not found on PATH. Restart your shell and try again."
+ }
+ Write-Log "uv installed successfully."
+}
+
+function Install-Python {
+ try {
+ $pythonList = uv python list 2>$null | Out-String
+ if ($pythonList -match "cpython-$PYTHON_VERSION") {
+ Write-Log "Python $PYTHON_VERSION found."
+ return
+ }
+ }
+ catch {
+ Write-Log "Could not query Python versions: $($_.Exception.Message)" "WARN"
+ }
+
+ Write-Log "Installing Python $PYTHON_VERSION via uv..."
+ try {
+ uv python install $PYTHON_VERSION
+ Write-Log "Python $PYTHON_VERSION installed."
+ }
+ catch {
+ Stop-WithError "Failed to install Python $PYTHON_VERSION."
+ }
+}
+
+function Install-AlgoKit {
+ Write-Log "Installing $PACKAGE..."
+ try {
+ uv tool install $PACKAGE
+ Write-Log "$PACKAGE installed successfully."
+ }
+ catch {
+ Stop-WithError "Failed to install ${PACKAGE}: $($_.Exception.Message)"
+ }
+
+ $toolPath = Get-Command algokit -ErrorAction SilentlyContinue
+ if ($toolPath) {
+ $allToolPaths = @(Get-Command algokit -All -ErrorAction SilentlyContinue | ForEach-Object { $_.Source } | Where-Object { $_ })
+ $version = algokit --version 2>$null
+ Write-Log "Installed: $version"
+ Write-Log "Run 'algokit --help' to get started."
+
+ if ($allToolPaths.Count -gt 1) {
+ Write-Log "Multiple algokit executables were found on PATH." "WARN"
+ Write-Log "Active executable: $($toolPath.Source)" "WARN"
+ Write-Log "All PATH matches:" "WARN"
+ foreach ($path in $allToolPaths) {
+ Write-Log " - $path" "WARN"
+ }
+ Write-Log "If this is not the uv-managed executable, move $env:USERPROFILE\.local\bin earlier on PATH or remove legacy binary." "WARN"
+ Write-Log "Restart your shell and run: algokit --version" "WARN"
+ }
+ }
+ else {
+ Write-Log "$PACKAGE installed but not found on PATH. Restart your shell and try again." "WARN"
+ }
+}
+
+try {
+ Write-Log "AlgoKit CLI Installer"
+ Write-Host ""
+
+ Install-UV
+ Install-Python
+ Install-AlgoKit
+
+ Write-Host ""
+ Write-Log "Done."
+}
+catch {
+ Write-Log "Unexpected error: $($_.Exception.Message)" "ERROR"
+ exit 1
+}
diff --git a/scripts/install/install.sh b/scripts/install/install.sh
new file mode 100755
index 000000000..ccfea490e
--- /dev/null
+++ b/scripts/install/install.sh
@@ -0,0 +1,126 @@
+#!/usr/bin/env bash
+# AlgoKit CLI Installer for Unix/macOS
+# Usage: curl -fsSL https://raw.githubusercontent.com/algorandfoundation/algokit-cli/main/scripts/install/install.sh | bash
+set -euo pipefail
+
+UV_INSTALL_URL="https://astral.sh/uv/install.sh"
+PYTHON_VERSION="3.12"
+PACKAGE="algokit"
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[0;33m'
+BOLD='\033[1m'
+NC='\033[0m'
+
+log() { printf "${GREEN}[algokit]${NC} %b\n" "$*"; }
+warn() { printf "${YELLOW}[algokit]${NC} %b\n" "$*"; }
+die() { printf "${RED}[algokit]${NC} %b\n" "$*" >&2; exit 1; }
+
+check_curl() {
+ command -v curl >/dev/null 2>&1 || die "curl is required but not installed."
+}
+
+ensure_uv() {
+ if command -v uv >/dev/null 2>&1; then
+ log "uv found: $(uv --version 2>/dev/null || echo 'unknown')"
+ return 0
+ fi
+
+ log "Installing uv..."
+
+ local temp_file
+ temp_file=$(mktemp)
+ trap 'rm -f "$temp_file"' EXIT
+
+ curl -fsSL --connect-timeout 30 --max-time 300 "$UV_INSTALL_URL" > "$temp_file" \
+ || die "Failed to download uv installer."
+
+ [[ $(wc -c < "$temp_file") -ge 1000 ]] \
+ || die "uv installer appears corrupted (too small)."
+
+ bash "$temp_file" || die "uv installation failed."
+ rm -f "$temp_file"
+ trap - EXIT
+
+ export PATH="$HOME/.cargo/bin:$HOME/.local/bin:$PATH"
+
+ command -v uv >/dev/null 2>&1 \
+ || die "uv installed but not found on PATH. Restart your shell and try again."
+ log "uv installed successfully."
+}
+
+ensure_python() {
+ if uv python find "${PYTHON_VERSION}" >/dev/null 2>&1; then
+ log "Python ${PYTHON_VERSION} found."
+ return 0
+ fi
+
+ log "Installing Python ${PYTHON_VERSION} via uv..."
+ uv python install "$PYTHON_VERSION" \
+ || die "Failed to install Python ${PYTHON_VERSION}."
+ log "Python ${PYTHON_VERSION} installed."
+}
+
+install_algokit() {
+ log "Installing ${PACKAGE}..."
+ uv tool install "$PACKAGE" \
+ || die "Failed to install ${PACKAGE}."
+
+ if command -v algokit >/dev/null 2>&1; then
+ local active_algokit
+ active_algokit=$(command -v algokit)
+ local -a all_algokit_paths=()
+ local -a path_entries=()
+ local seen_paths=":"
+ local path_entry
+ IFS=: read -r -a path_entries <<< "$PATH"
+ for path_entry in "${path_entries[@]}"; do
+ [[ -z "$path_entry" ]] && continue
+ local candidate="$path_entry/algokit"
+ if [[ -f "$candidate" && -x "$candidate" ]]; then
+ case "$seen_paths" in
+ *":$candidate:"*) ;;
+ *)
+ seen_paths="${seen_paths}${candidate}:"
+ all_algokit_paths+=("$candidate")
+ ;;
+ esac
+ fi
+ done
+
+ log "Installed: $(algokit --version 2>/dev/null || echo "${PACKAGE}")"
+ log "Run ${BOLD}algokit --help${NC} to get started."
+
+ if [[ ${#all_algokit_paths[@]} -gt 1 ]]; then
+ warn "Multiple algokit executables were found on PATH."
+ warn "Active executable: ${active_algokit}"
+ warn "All PATH matches:"
+ local match_path
+ for match_path in "${all_algokit_paths[@]}"; do
+ warn " - ${match_path}"
+ done
+ warn "If this is not the uv-managed executable, move ~/.local/bin earlier on PATH or remove legacy binary."
+ warn "Restart your shell and run: algokit --version"
+ fi
+ else
+ warn "${PACKAGE} installed but not found on PATH."
+ warn "Add ~/.local/bin to your PATH:"
+ printf ' export PATH="$HOME/.local/bin:$PATH"\n'
+ fi
+}
+
+main() {
+ log "AlgoKit CLI Installer"
+ echo ""
+
+ check_curl
+ ensure_uv
+ ensure_python
+ install_algokit
+
+ echo ""
+ log "Done."
+}
+
+main "$@"
diff --git a/scripts/package_mac.sh b/scripts/package_mac.sh
index c66c46a39..8e9bc151e 100755
--- a/scripts/package_mac.sh
+++ b/scripts/package_mac.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-CMD="pyinstaller --clean --onedir --hidden-import jinja2_ansible_filters --hidden-import multiformats_config --copy-metadata algokit --name algokit --noconfirm src/algokit/__main__.py --add-data './misc/multiformats_config/multibase-table.json:multiformats_config/' --add-data './misc/multiformats_config/multicodec-table.json:multiformats_config/' --add-data './src/algokit/resources:algokit/resources/'"
+CMD="pyinstaller --clean --onedir --hidden-import jinja2_ansible_filters --hidden-import multiformats_config --hidden-import algokit_utils.algo25 --hidden-import algokit_utils.transact --hidden-import algokit_utils.common --hidden-import algokit_utils.clients --hidden-import algokit_utils.transactions.builders --hidden-import algokit_utils.transactions.types --copy-metadata algokit --name algokit --noconfirm src/algokit/__main__.py --add-data './misc/multiformats_config/multibase-table.json:multiformats_config/' --add-data './misc/multiformats_config/multicodec-table.json:multiformats_config/' --add-data './src/algokit/resources:algokit/resources/'"
if [ ! -z "$APPLE_BUNDLE_ID" ]; then
CMD="$CMD --osx-bundle-identifier \"$APPLE_BUNDLE_ID\""
diff --git a/scripts/package_windows.bat b/scripts/package_windows.bat
index 10eb82fd7..f310901b7 100644
--- a/scripts/package_windows.bat
+++ b/scripts/package_windows.bat
@@ -1,2 +1,2 @@
@echo off
-pyinstaller --clean --onedir --hidden-import jinja2_ansible_filters --hidden-import multiformats_config --copy-metadata algokit --name algokit --noconfirm src/algokit/__main__.py --add-data ./misc/multiformats_config;multiformats_config/ --add-data ./src/algokit/resources;algokit/resources/
+pyinstaller --clean --onedir --hidden-import jinja2_ansible_filters --hidden-import multiformats_config --hidden-import algokit_utils.algo25 --hidden-import algokit_utils.transact --hidden-import algokit_utils.common --hidden-import algokit_utils.clients --hidden-import algokit_utils.transactions.builders --hidden-import algokit_utils.transactions.types --copy-metadata algokit --name algokit --noconfirm src/algokit/__main__.py --add-data ./misc/multiformats_config;multiformats_config/ --add-data ./src/algokit/resources;algokit/resources/
diff --git a/src/algokit/cli/__init__.py b/src/algokit/cli/__init__.py
index 2da233502..fd44ca836 100644
--- a/src/algokit/cli/__init__.py
+++ b/src/algokit/cli/__init__.py
@@ -1,3 +1,8 @@
+import logging
+import platform
+import sys
+from pathlib import Path
+
import click
from algokit.cli.compile import compile_group
@@ -14,9 +19,19 @@
from algokit.cli.project.bootstrap import bootstrap_group
from algokit.cli.project.deploy import deploy_command
from algokit.cli.task import task_group
+from algokit.cli.vibe import vibe_group
from algokit.core.conf import PACKAGE_NAME
from algokit.core.config_commands.version_prompt import do_version_prompt, skip_version_check_option
from algokit.core.log_handlers import color_option, verbose_option
+from algokit.core.utils import find_all_on_path, is_binary_mode
+
+_INSTALL_URL_BASE = "https://raw.githubusercontent.com/algorandfoundation/algokit-cli/main/scripts/install"
+_INSTALL_URL_SH = f"{_INSTALL_URL_BASE}/install.sh"
+_INSTALL_URL_PS1 = f"{_INSTALL_URL_BASE}/install.ps1"
+_ADR_URL = (
+ "https://github.com/algorandfoundation/algokit-cli/blob/main/"
+ "docs/architecture-decisions/2025-03-03_uv_distribution.md"
+)
HIDDEN_COMMANDS: dict[str, click.Command] = {"deploy": deploy_command, "bootstrap": bootstrap_group}
@@ -54,6 +69,8 @@ def algokit(*, skip_version_check: bool) -> None:
if not skip_version_check:
do_version_prompt()
+ _check_binary_deprecation()
+
algokit.add_command(completions_group)
algokit.add_command(config_group)
@@ -67,3 +84,50 @@ def algokit(*, skip_version_check: bool) -> None:
algokit.add_command(task_group)
algokit.add_command(compile_group)
algokit.add_command(project_group)
+algokit.add_command(vibe_group)
+
+
+def _check_binary_deprecation() -> None:
+ if not is_binary_mode():
+ return
+
+ install_cmd = (
+ f"irm {_INSTALL_URL_PS1} | iex" if platform.system() == "Windows" else f"curl -fsSL {_INSTALL_URL_SH} | bash"
+ )
+
+ logger = logging.getLogger(__name__)
+ logger.warning(
+ "\n"
+ " WARNING: AlgoKit binary installation is being phased out.\n"
+ " Starting from the next major version, AlgoKit will be distributed via uv.\n"
+ " To migrate now, run:\n"
+ "\n"
+ " %s\n"
+ "\n"
+ " For more information, see:\n"
+ " %s\n",
+ install_cmd,
+ _ADR_URL,
+ )
+
+ algokit_paths = find_all_on_path("algokit")
+ if len(algokit_paths) <= 1:
+ return
+
+ active_path = algokit_paths[0]
+ current_binary_path = Path(sys.executable)
+ all_paths = "\n".join(f" - {path}" for path in algokit_paths)
+
+ logger.warning(
+ "\n"
+ " WARNING: Multiple `algokit` executables were found on PATH.\n"
+ " Active executable: %s\n"
+ " Current binary: %s\n"
+ " All PATH matches:\n"
+ "%s\n"
+ " If this is not the uv-managed executable, move ~/.local/bin (or %%USERPROFILE%%\\.local\\bin)\n"
+ " earlier in PATH or remove the legacy binary. Then restart your shell and run `algokit --version`.\n",
+ active_path,
+ current_binary_path,
+ all_paths,
+ )
diff --git a/src/algokit/cli/doctor.py b/src/algokit/cli/doctor.py
index d281abe14..2fd9e1ce5 100644
--- a/src/algokit/cli/doctor.py
+++ b/src/algokit/cli/doctor.py
@@ -86,19 +86,25 @@ def doctor_command(*, copy_to_clipboard: bool) -> None: # noqa: C901, PLR0912
),
"python": check_dependency(["python", "--version"], include_location=True),
"python3": check_dependency(["python3", "--version"], include_location=True),
+ "uv": check_dependency(
+ ["uv", "--version"],
+ missing_help=[
+ "uv is the recommended tool runner for AlgoKit;",
+ "install via https://docs.astral.sh/uv/",
+ ],
+ ),
"pipx": check_dependency(
["pipx", "--version"],
missing_help=[
- "pipx is required if poetry is not installed in order to install it automatically;",
+ "pipx can be used as a fallback tool runner if uv is not installed;",
"install via https://pypa.github.io/pipx/",
],
),
"poetry": check_dependency(
["poetry", "--version"],
missing_help=[
- "Poetry is required for some Python-based templates;",
- "install via `algokit project bootstrap` within project directory, or via:",
- "https://python-poetry.org/docs/#installation",
+ "Poetry may be needed for older Python-based templates;",
+ "install via https://python-poetry.org/docs/#installation",
],
),
"node": check_dependency(
@@ -160,7 +166,7 @@ def doctor_command(*, copy_to_clipboard: bool) -> None: # noqa: C901, PLR0912
pyclip.copy("\n".join(output_lines))
- if any(not value.ok for value in service_outputs.values()):
+ if any(not value.ok for key, value in service_outputs.items() if key in critical_services):
raise click.exceptions.Exit(code=1)
diff --git a/src/algokit/cli/init/command.py b/src/algokit/cli/init/command.py
index 4e242f6d9..23a3ed484 100644
--- a/src/algokit/cli/init/command.py
+++ b/src/algokit/cli/init/command.py
@@ -226,6 +226,8 @@ def initialize_new_project( # noqa: PLR0913, C901, PLR0915
# Below must be ensured to run after all required filesystem changes are applied to ensure first commit captures
# all the changes introduced by init invocation
+ _maybe_setup_vibecode(project_path=project_path, use_defaults=use_defaults, run_bootstrap=run_bootstrap)
+
_maybe_git_init(
workspace_path or project_path,
use_git=use_git,
@@ -254,6 +256,31 @@ def initialize_new_project( # noqa: PLR0913, C901, PLR0915
logger.info(f"Your template includes a {readme_path.name} file, you might want to review that as a next step.")
+def _maybe_setup_vibecode(*, project_path: Path, use_defaults: bool, run_bootstrap: bool | None) -> None:
+ # Keep this spike opt-in and interactive only, avoiding new prompts for non-interactive/default flows.
+ should_prompt = not use_defaults and run_bootstrap is None
+ if not should_prompt:
+ return
+
+ should_run_vibe_setup = questionary_extensions.prompt_confirm(
+ "Would you like to run `algokit vibe setup` to enable VibeCode for this project?",
+ default=False,
+ )
+ if not should_run_vibe_setup:
+ return
+
+ try:
+ from algokit.cli.vibe import run_vibe_setup
+
+ run_vibe_setup(cwd=project_path)
+ except Exception as ex:
+ logger.error(f"Received an error while attempting VibeCode setup: {ex}")
+ logger.exception(
+ "VibeCode setup failed. Once any errors above are resolved, run `algokit vibe setup`.",
+ exc_info=ex,
+ )
+
+
def _maybe_bootstrap(
project_path: Path, *, run_bootstrap: bool | None, use_defaults: bool, use_workspace: bool
) -> None:
@@ -548,7 +575,14 @@ def git(*args: str, bad_exit_warn_message: str) -> bool:
git("init", bad_exit_warn_message="Failed to initialise git repository")
and git("checkout", "-b", "main", bad_exit_warn_message="Failed to name initial branch")
and git("add", "--all", bad_exit_warn_message="Failed to add generated project files")
- and git("commit", "-m", commit_message, bad_exit_warn_message="Initial commit failed")
+ and git(
+ "-c",
+ "commit.gpgsign=false",
+ "commit",
+ "-m",
+ commit_message,
+ bad_exit_warn_message="Initial commit failed",
+ )
):
logger.info("🎉 Performed initial git commit successfully! 🎉")
diff --git a/src/algokit/cli/project/__init__.py b/src/algokit/cli/project/__init__.py
index ddbf83826..da493463e 100644
--- a/src/algokit/cli/project/__init__.py
+++ b/src/algokit/cli/project/__init__.py
@@ -1,6 +1,3 @@
-import logging
-import re
-
import click
from algokit.cli.project.bootstrap import bootstrap_group
@@ -8,9 +5,6 @@
from algokit.cli.project.link import link_command
from algokit.cli.project.list import list_command
from algokit.cli.project.run import run_group
-from algokit.core import proc
-
-logger = logging.getLogger(__name__)
@click.group(
@@ -20,18 +14,6 @@ def project_group() -> None:
"""Provides a suite of commands for managing your AlgoKit project.
This includes initializing project dependencies, deploying smart contracts,
and executing predefined or custom commands within your project environment."""
- try:
- poetry_version_result = proc.run(
- ["poetry", "--version"],
- )
- except Exception:
- return
-
- if re.search(r"1\.\d+\.\d+", poetry_version_result.output):
- logger.warning(
- "You are using Poetry 1.x, which is deprecated. "
- "Please upgrade to Poetry 2.x for better support and features."
- )
project_group.add_command(deploy_command)
diff --git a/src/algokit/cli/project/deploy.py b/src/algokit/cli/project/deploy.py
index f07577667..0db77351a 100644
--- a/src/algokit/cli/project/deploy.py
+++ b/src/algokit/cli/project/deploy.py
@@ -1,10 +1,11 @@
+import base64
import logging
import os
import typing as t
from pathlib import Path
import click
-from algosdk.mnemonic import from_private_key
+from algokit_utils.algo25 import secret_key_to_mnemonic
from algokit.cli.common.utils import MutuallyExclusiveOption, sanitize_extra_args
from algokit.core import proc
@@ -47,7 +48,9 @@ def _ensure_aliases(
raise click.ClickException(f"Error: missing {alias} alias")
if not alias_data.private_key:
raise click.ClickException(f"Error: missing private key for {alias} alias")
- config_env[key] = from_private_key(alias_data.private_key) # type: ignore[no-untyped-call]
+ # Private key is stored as base64 string, decode to bytes for mnemonic conversion
+ private_key_bytes = base64.b64decode(alias_data.private_key)
+ config_env[key] = secret_key_to_mnemonic(private_key_bytes)
logger.debug(f"Loaded {alias} alias mnemonic as {key} environment variable")
diff --git a/src/algokit/cli/tasks/assets.py b/src/algokit/cli/tasks/assets.py
index c68f803a5..ad1913e6e 100644
--- a/src/algokit/cli/tasks/assets.py
+++ b/src/algokit/cli/tasks/assets.py
@@ -1,13 +1,11 @@
import logging
import click
-from algosdk import error
-from algosdk.v2client.algod import AlgodClient
+from algokit_utils.clients import AlgodClient, UnexpectedStatusError
from algokit.cli.common.constants import AlgorandNetwork, ExplorerEntityType
from algokit.cli.common.utils import get_explorer_url
from algokit.cli.tasks.utils import (
- get_account_info,
get_account_with_private_key,
load_algod_client,
validate_account_balance_to_opt_in,
@@ -23,10 +21,10 @@ def _get_zero_balanced_assets(
) -> list[int]:
asset_ids_list = []
if all_assets:
- account_info = get_account_info(algod_client, address)
- for asset in account_info.get("assets", []):
- if asset.get("amount", 0) == 0:
- asset_ids_list.append(int(asset["asset-id"]))
+ account_info = algod_client.account_information(address)
+ for asset in account_info.assets or ():
+ if asset.amount == 0:
+ asset_ids_list.append(asset.asset_id)
else:
for asset_id in provided_asset_ids:
asset_ids_list.append(asset_id)
@@ -73,7 +71,7 @@ def opt_in_command(asset_ids: tuple[int], account: str, network: AlgorandNetwork
for asset_opt_int_result in response:
explorer_url = get_explorer_url(asset_opt_int_result.transaction_id, network, ExplorerEntityType.ASSET)
click.echo(f"Check opt-in status for asset {asset_opt_int_result.asset_id} at: {explorer_url}")
- except error.AlgodHTTPError as err:
+ except UnexpectedStatusError as err:
raise click.ClickException(str(err)) from err
except ValueError as err:
logger.debug(err, exc_info=True)
@@ -140,7 +138,7 @@ def opt_out_command(*, asset_ids: tuple[int], account: str, network: AlgorandNet
asset_opt_out_result.transaction_id, network, ExplorerEntityType.TRANSACTION
)
click.echo(f"Check opt-in status for asset {asset_opt_out_result.asset_id} at: {transaction_url}")
- except error.AlgodHTTPError as err:
+ except UnexpectedStatusError as err:
raise click.ClickException(str(err)) from err
except ConnectionRefusedError as err:
raise click.ClickException(str(err)) from err
diff --git a/src/algokit/cli/tasks/mint.py b/src/algokit/cli/tasks/mint.py
index 381580bbe..3d7837052 100644
--- a/src/algokit/cli/tasks/mint.py
+++ b/src/algokit/cli/tasks/mint.py
@@ -5,8 +5,8 @@
from pathlib import Path
import click
-from algokit_utils import AlgoAmount, SigningAccount
-from algosdk.error import AlgodHTTPError
+from algokit_utils import AlgoAmount
+from algokit_utils.clients import UnexpectedStatusError
from algokit.cli.common.constants import AlgorandNetwork, ExplorerEntityType
from algokit.cli.common.utils import get_explorer_url
@@ -16,6 +16,7 @@
run_callback_once,
validate_balance,
)
+from algokit.core.signing_account import SigningAccount
from algokit.core.tasks.ipfs import (
PinataBadRequestError,
PinataForbiddenError,
@@ -332,7 +333,7 @@ def mint( # noqa: PLR0913
) as ex:
logger.debug(ex)
raise click.ClickException(repr(ex)) from ex
- except AlgodHTTPError as ex:
+ except UnexpectedStatusError as ex:
raise click.ClickException(str(ex)) from ex
except Exception as ex:
logger.debug(ex, exc_info=True)
diff --git a/src/algokit/cli/tasks/send_transaction.py b/src/algokit/cli/tasks/send_transaction.py
index 6d80c7a6f..55f02bb19 100644
--- a/src/algokit/cli/tasks/send_transaction.py
+++ b/src/algokit/cli/tasks/send_transaction.py
@@ -1,11 +1,13 @@
+import base64
import json
import logging
from pathlib import Path
from typing import TYPE_CHECKING, cast
import click
-from algosdk import encoding, error
-from algosdk.transaction import SignedTransaction, retrieve_from_file
+import msgpack
+from algokit_utils.clients import UnexpectedStatusError
+from algokit_utils.transact import SignedTransaction, decode_signed_transaction, encode_signed_transaction
from algokit.cli.common.constants import AlgorandNetwork, ExplorerEntityType
from algokit.cli.common.utils import MutuallyExclusiveOption, get_explorer_url
@@ -34,6 +36,60 @@ def _is_sign_task_output_txn(item: dict) -> bool:
return isinstance(item, dict) and all(key in item for key in ["transaction_id", "content"])
+def _retrieve_transactions_from_file(file_path: Path) -> list[SignedTransaction]:
+ """
+ Load signed transactions from a file containing msgpack-encoded data.
+
+ Args:
+ file_path: Path to the file containing signed transaction(s)
+
+ Returns:
+ A list of SignedTransaction objects
+
+ Raises:
+ click.ClickException: If the file cannot be read or decoded
+ """
+ try:
+ file_content = file_path.read_bytes()
+
+ # Try to decode as a single transaction first
+ try:
+ return [decode_signed_transaction(file_content)]
+ except Exception:
+ pass
+
+ # Try to parse multiple concatenated msgpack objects
+ transactions: list[SignedTransaction] = []
+ offset = 0
+
+ while offset < len(file_content):
+ # Use msgpack Unpacker to find the boundaries of each msgpack object
+ unpacker = msgpack.Unpacker(raw=True, strict_map_key=False)
+ unpacker.feed(file_content[offset:])
+ try:
+ _ = unpacker.unpack() # Advance to get the position
+ msgpack_bytes_consumed = unpacker.tell()
+
+ # Extract just this msgpack object
+ encoded_txn = file_content[offset : offset + msgpack_bytes_consumed]
+ offset += msgpack_bytes_consumed
+
+ # Decode the signed transaction
+ stx = decode_signed_transaction(encoded_txn)
+ transactions.append(stx)
+ except msgpack.OutOfData:
+ break
+ except Exception:
+ break
+
+ if transactions:
+ return transactions
+ raise ValueError("No valid transactions found in file") from None
+ except Exception as ex:
+ logger.debug(ex, exc_info=True)
+ raise click.ClickException(f"Failed to read transactions from file: {ex}") from ex
+
+
def _load_from_stdin() -> list[SignedTransaction]:
"""
Load transaction data from standard input and convert it into a list of SignedTransaction objects.
@@ -59,7 +115,7 @@ def _load_from_stdin() -> list[SignedTransaction]:
raise click.ClickException("Invalid piped transaction content!")
# Convert the content into SignedTransaction objects
- return [encoding.msgpack_decode(item["content"]) for item in file_content] # type: ignore[no-untyped-call]
+ return [decode_signed_transaction(base64.b64decode(item["content"])) for item in file_content]
def _get_signed_transactions(file: Path | None = None, transaction: str | None = None) -> list[SignedTransaction]:
@@ -80,9 +136,9 @@ def _get_signed_transactions(file: Path | None = None, transaction: str | None =
"""
try:
if file:
- txns = retrieve_from_file(str(file)) # type: ignore[no-untyped-call]
+ txns = _retrieve_transactions_from_file(file)
elif transaction:
- txns = [encoding.msgpack_decode(transaction)] # type: ignore[no-untyped-call]
+ txns = [decode_signed_transaction(base64.b64decode(transaction))]
else:
txns = _load_from_stdin()
@@ -90,7 +146,7 @@ def _get_signed_transactions(file: Path | None = None, transaction: str | None =
if not isinstance(txn, SignedTransaction):
raise click.ClickException("Supplied transaction is not signed!")
- return cast("list[SignedTransaction]", txns)
+ return txns
except Exception as ex:
logger.debug(ex, exc_info=True)
@@ -112,8 +168,11 @@ def _send_transactions(network: AlgorandNetwork, txns: list[SignedTransaction])
"""
algod_client = load_algod_client(network)
- if any(txn.transaction.group for txn in txns):
- txid = algod_client.send_transactions(txns)
+ if any(txn.txn.group for txn in txns):
+ # Send all transactions as a group
+ encoded_txns = [encode_signed_transaction(txn) for txn in txns]
+ result = algod_client.send_raw_transaction(encoded_txns)
+ txid = result.tx_id
click.echo(f"Transaction group successfully sent with txid: {txid}")
click.echo(
f"Check transaction group status at: {get_explorer_url(txid, network, ExplorerEntityType.TRANSACTION)}"
@@ -121,7 +180,9 @@ def _send_transactions(network: AlgorandNetwork, txns: list[SignedTransaction])
else:
for index, txn in enumerate(txns, start=1):
click.echo(f"\nSending transaction {index}/{len(txns)}")
- txid = algod_client.send_transaction(txn)
+ encoded_txn = encode_signed_transaction(txn)
+ result = algod_client.send_raw_transaction(encoded_txn)
+ txid = result.tx_id
click.echo(f"Transaction successfully sent with txid: {txid}")
click.echo(
f"Check transaction status at: {get_explorer_url(txid, network, ExplorerEntityType.TRANSACTION)}"
@@ -169,7 +230,7 @@ def send(*, file: Path | None, transaction: str | None, network: AlgorandNetwork
try:
_send_transactions(network, txns)
- except error.AlgodHTTPError as ex:
+ except UnexpectedStatusError as ex:
raise click.ClickException(str(ex)) from ex
except Exception as ex:
logger.debug(ex, exc_info=True)
diff --git a/src/algokit/cli/tasks/sign_transaction.py b/src/algokit/cli/tasks/sign_transaction.py
index 1fdb55e2a..37674347b 100644
--- a/src/algokit/cli/tasks/sign_transaction.py
+++ b/src/algokit/cli/tasks/sign_transaction.py
@@ -1,15 +1,25 @@
import base64
import json
import logging
+from collections.abc import Sequence
from pathlib import Path
-from typing import Any, cast
+from typing import Any
import click
-from algosdk import encoding
-from algosdk.transaction import SignedTransaction, Transaction, retrieve_from_file, write_to_file
+import msgpack
+from algokit_utils.transact import (
+ SignedTransaction,
+ Transaction,
+ decode_signed_transaction,
+ decode_transaction,
+ encode_signed_transactions,
+ get_transaction_id,
+ to_transaction_dto,
+)
from algokit.cli.common.utils import MutuallyExclusiveOption
from algokit.cli.tasks.utils import get_account_with_private_key
+from algokit.core.signing_account import SigningAccount
logger = logging.getLogger(__name__)
@@ -21,11 +31,81 @@ def default(self, obj: Any) -> Any: # noqa: ANN401
return super().default(obj)
-def _validate_for_signed_txns(txns: list[Transaction]) -> None:
+def retrieve_from_file(file_path: str) -> list[Transaction | SignedTransaction]:
+ """Load transactions from a file (msgpack encoded).
+
+ The file format is concatenated msgpack-encoded transactions, each prefixed with "TX".
+ Each transaction can be either a Transaction or a SignedTransaction.
+
+ Args:
+ file_path: Path to the file containing encoded transactions.
+
+ Returns:
+ List of Transaction or SignedTransaction objects.
+ """
+ with Path(file_path).open("rb") as f:
+ data = f.read()
+
+ tx_prefix = b"TX"
+ txns: list[Transaction | SignedTransaction] = []
+ offset = 0
+
+ while offset < len(data):
+ # Check for TX prefix and skip it if present
+ has_prefix = data[offset:].startswith(tx_prefix)
+ if has_prefix:
+ msgpack_start = offset + len(tx_prefix)
+ else:
+ msgpack_start = offset
+
+ # Use Unpacker to find the end of the msgpack object
+ unpacker = msgpack.Unpacker(raw=True, strict_map_key=False)
+ unpacker.feed(data[msgpack_start:])
+ try:
+ _ = unpacker.unpack() # Just to advance the position
+ msgpack_bytes_consumed = unpacker.tell()
+
+ # Include the prefix in the encoded transaction if present
+ if has_prefix:
+ encoded_txn = data[offset : msgpack_start + msgpack_bytes_consumed]
+ else:
+ encoded_txn = data[offset : offset + msgpack_bytes_consumed]
+ offset = msgpack_start + msgpack_bytes_consumed
+
+ # Try to decode as SignedTransaction first, then Transaction
+ try:
+ txns.append(decode_signed_transaction(encoded_txn))
+ except Exception:
+ txns.append(decode_transaction(encoded_txn))
+ except msgpack.OutOfData:
+ break
+
+ return txns
+
+
+def write_to_file(signed_txns: list[SignedTransaction], file_path: str) -> None:
+ """Write signed transactions to a file (msgpack encoded).
+
+ The file format is concatenated msgpack-encoded signed transactions.
+
+ Args:
+ signed_txns: List of SignedTransaction objects to write.
+ file_path: Path to the output file.
+ """
+ # Encode each signed transaction
+ encoded_txns = encode_signed_transactions(signed_txns)
+
+ # Write concatenated msgpack objects (not an array)
+ with Path(file_path).open("wb") as f:
+ for encoded_txn in encoded_txns:
+ f.write(encoded_txn)
+
+
+def _validate_for_signed_txns(txns: Sequence[Transaction | SignedTransaction]) -> None:
signed_txns = [txn for txn in txns if isinstance(txn, SignedTransaction)]
if signed_txns:
- transaction_ids = ", ".join([txn.get_txid() for txn in signed_txns]) # type: ignore[no-untyped-call]
+ transaction_ids = ", ".join([get_transaction_id(txn.txn) for txn in signed_txns])
message = f"Supplied transactions {transaction_ids} are already signed!"
raise click.ClickException(message)
@@ -33,10 +113,14 @@ def _validate_for_signed_txns(txns: list[Transaction]) -> None:
def _get_transactions(file: Path | None, transaction: str | None) -> list[Transaction]:
try:
if file:
- txns: list[Transaction] = retrieve_from_file(str(file)) # type: ignore[no-untyped-call]
- return txns
+ txns_or_signed = retrieve_from_file(str(file))
+ # Extract unsigned transactions, filter out any that are already signed
+ return [txn if isinstance(txn, Transaction) else txn.txn for txn in txns_or_signed]
else:
- return [cast("Transaction", encoding.msgpack_decode(transaction))] # type: ignore[no-untyped-call]
+ # Decode base64 string to bytes, then decode as transaction
+ assert transaction is not None, "Either file or transaction must be provided"
+ txn_bytes = base64.b64decode(transaction)
+ return [decode_transaction(txn_bytes)]
except Exception as ex:
logger.debug(ex, exc_info=True)
raise click.ClickException(
@@ -49,8 +133,8 @@ def _confirm_transaction(txns: list[Transaction]) -> bool:
json.dumps(
[
{
- "transaction_id": txn.get_txid(), # type: ignore[no-untyped-call]
- "content": txn.dictify(), # type: ignore[no-untyped-call]
+ "transaction_id": get_transaction_id(txn),
+ "content": to_transaction_dto(txn),
}
for txn in txns
],
@@ -64,16 +148,25 @@ def _confirm_transaction(txns: list[Transaction]) -> bool:
return bool(response == "y")
-def _sign_and_output_transaction(txns: list[Transaction], private_key: str, output: Path | None) -> None:
- signed_txns = [txn.sign(private_key) for txn in txns] # type: ignore[no-untyped-call]
+def _sign_and_output_transaction(txns: list[Transaction], signing_account: SigningAccount, output: Path | None) -> None:
+ # Create a transaction signer from the private key
+
+ # Sign all transactions - signer returns encoded SignedTransaction bytes
+ signed_txn_bytes_list = signing_account.signer(txns, list(range(len(txns))))
+
+ # Decode the signed transaction bytes to get SignedTransaction objects
+ signed_txns = [decode_signed_transaction(stx_bytes) for stx_bytes in signed_txn_bytes_list]
if output:
- write_to_file(signed_txns, str(output)) # type: ignore[no-untyped-call]
+ write_to_file(signed_txns, str(output))
click.echo(f"Signed transaction written to {output}")
else:
encoded_signed_txns = [
- {"transaction_id": txn.get_txid(), "content": encoding.msgpack_encode(txn)} # type: ignore[no-untyped-call]
- for txn in signed_txns
+ {
+ "transaction_id": get_transaction_id(txn.txn),
+ "content": base64.b64encode(stx_bytes).decode(),
+ }
+ for txn, stx_bytes in zip(signed_txns, signed_txn_bytes_list, strict=False)
]
click.echo(json.dumps(encoded_signed_txns, indent=2))
@@ -122,4 +215,4 @@ def sign(*, account: str, file: Path | None, transaction: str | None, output: Pa
if not force and not _confirm_transaction(txns):
return
- _sign_and_output_transaction(txns, signer_account.private_key, output)
+ _sign_and_output_transaction(txns, signer_account, output)
diff --git a/src/algokit/cli/tasks/transfer.py b/src/algokit/cli/tasks/transfer.py
index a8d971bc9..65fa2f34d 100644
--- a/src/algokit/cli/tasks/transfer.py
+++ b/src/algokit/cli/tasks/transfer.py
@@ -1,7 +1,7 @@
import logging
import click
-from algokit_utils import AlgoAmount, AssetTransferParams, PaymentParams, SendAtomicTransactionComposerResults
+from algokit_utils import AlgoAmount, AssetTransferParams, PaymentParams, SendTransactionComposerResults
from algokit.cli.common.constants import AlgorandNetwork, ExplorerEntityType
from algokit.cli.common.utils import get_explorer_url
@@ -85,7 +85,7 @@ def transfer( # noqa: PLR0913
validate_balance(algod_client, receiver_address, asset_id)
# Transfer algos or assets depending on asset_id
- txn_response: SendAtomicTransactionComposerResults | None = None
+ txn_response: SendTransactionComposerResults | None = None
algorand = get_algorand_client_for_network(network)
try:
if asset_id == 0:
diff --git a/src/algokit/cli/tasks/utils.py b/src/algokit/cli/tasks/utils.py
index 343b919d8..40e708c54 100644
--- a/src/algokit/cli/tasks/utils.py
+++ b/src/algokit/cli/tasks/utils.py
@@ -1,5 +1,6 @@
# AlgoKit Tasks related utility functions
+import base64
import logging
import os
import stat
@@ -9,35 +10,40 @@
from functools import wraps
from typing import Any
-import algosdk
-import algosdk.encoding
import click
-from algokit_utils import AlgoAmount, ClientManager, SigningAccount
+import nacl.signing
+from algokit_algod_client import models as algod
+from algokit_utils import AlgoAmount, ClientManager
+from algokit_utils.algo25 import seed_from_mnemonic
+from algokit_utils.clients import AlgodClient
+from algokit_utils.common import ADDRESS_LENGTH
from algokit.cli.common.constants import AlgorandNetwork
+from algokit.core.address_utils import is_valid_address
+from algokit.core.signing_account import SigningAccount
from algokit.core.tasks.wallet import get_alias
logger = logging.getLogger(__name__)
-def _validate_asset_balance(account_info: dict, asset_id: int, decimals: int, amount: int = 0) -> None:
- asset_record = next((asset for asset in account_info.get("assets", []) if asset["asset-id"] == asset_id), None)
-
- if not asset_record:
- raise click.ClickException("SigningAccount is not opted into the asset")
+def _validate_asset_balance(account_info: algod.Account, asset_id: int, decimals: int, amount: int = 0) -> None:
+ try:
+ (asset_record,) = (asset for asset in (account_info.assets or ()) if asset.asset_id == asset_id)
+ except ValueError:
+ raise click.ClickException("SigningAccount is not opted into the asset") from None
- if amount > 0 and asset_record["amount"] < amount:
+ if amount > 0 and asset_record.amount < amount:
required = amount / 10**decimals
- available = asset_record["amount"] / 10**decimals
+ available = asset_record.amount / 10**decimals
raise click.ClickException(
f"Insufficient asset balance in account, required: {required}, available: {available}"
)
-def _validate_algo_balance(account_info: dict, amount: int) -> None:
- if account_info.get("amount", 0) < amount:
+def _validate_algo_balance(account_info: algod.Account, amount: int) -> None:
+ if account_info.amount < amount:
required = AlgoAmount.from_micro_algo(amount)
- available = AlgoAmount.from_micro_algo(account_info.get("amount", 0))
+ available = AlgoAmount.from_micro_algo(account_info.amount)
raise click.ClickException(
f"Insufficient Algos balance in account, required: {required.algo} Algos, available: {available.algo} Algos"
)
@@ -48,7 +54,7 @@ def get_private_key_from_mnemonic() -> str:
Converts a mnemonic phrase into a private key.
Returns:
- str: The private key generated from the mnemonic phrase.
+ str: The base64-encoded private key (64 bytes: seed + public key) generated from the mnemonic phrase.
Raises:
click.ClickException: If the entered mnemonic phrase is invalid.
@@ -62,27 +68,34 @@ def get_private_key_from_mnemonic() -> str:
Flow:
1. Prompts the user to enter a mnemonic phrase.
- 2. Converts the entered mnemonic phrase into a private key using `algosdk.mnemonic.to_private_key`.
- 3. Returns the private key.
+ 2. Converts the entered mnemonic phrase into a seed using `seed_from_mnemonic`.
+ 3. Derives the public key from the seed.
+ 4. Returns the base64-encoded concatenation of seed + public key.
"""
mnemonic_phrase = click.prompt("Enter the mnemonic phrase (25 words separated by whitespace)", hide_input=True)
try:
- return str(algosdk.mnemonic.to_private_key(mnemonic_phrase)) # type: ignore[no-untyped-call]
+ # Get the 32-byte seed from the mnemonic
+ seed = seed_from_mnemonic(mnemonic_phrase)
+ # Generate the public key from the seed using nacl
+ signing_key = nacl.signing.SigningKey(seed)
+ public_key = signing_key.verify_key.encode()
+ # Return base64-encoded 64-byte private key (seed + public key)
+ return base64.b64encode(seed + public_key).decode()
except Exception as err:
raise click.ClickException("Invalid mnemonic. Please provide a valid Algorand mnemonic.") from err
-def load_algod_client(network: AlgorandNetwork) -> algosdk.v2client.algod.AlgodClient:
+def load_algod_client(network: AlgorandNetwork) -> AlgodClient:
"""
- Returns an instance of the `algosdk.v2client.algod.AlgodClient` class for the specified network.
+ Returns an instance of the `AlgodClient` class for the specified network.
Args:
network (str): The network for which the `AlgodClient` instance needs to be loaded.
Returns:
- algosdk.v2client.algod.AlgodClient: An instance of the `AlgodClient` class for the specified network.
+ AlgodClient: An instance of the `AlgodClient` class for the specified network.
Raises:
click.ClickException: If the specified network is invalid.
@@ -99,13 +112,13 @@ def load_algod_client(network: AlgorandNetwork) -> algosdk.v2client.algod.AlgodC
raise click.ClickException("Invalid network") from err
-def get_asset_decimals(asset_id: int, algod_client: algosdk.v2client.algod.AlgodClient) -> int:
+def get_asset_decimals(asset_id: int, algod_client: AlgodClient) -> int:
"""
Retrieves the number of decimal places for a given asset.
Args:
asset_id (int): The ID of the asset for which the number of decimal places is to be retrieved. (0 for Algo)
- algod_client (algosdk.v2client.algod.AlgodClient): An instance of the AlgodClient class.
+ algod_client (AlgodClient): An instance of the AlgodClient class.
Returns:
int: The number of decimal places for the given asset.
@@ -115,7 +128,7 @@ def get_asset_decimals(asset_id: int, algod_client: algosdk.v2client.algod.Algod
Example:
asset_id = 123
- algod_client = algosdk.v2client.algod.AlgodClient("https://mainnet-api.algonode.cloud", "API_KEY")
+ algod_client = AlgodClient(...)
decimals = get_asset_decimals(asset_id, algod_client)
print(decimals)
"""
@@ -123,22 +136,16 @@ def get_asset_decimals(asset_id: int, algod_client: algosdk.v2client.algod.Algod
if asset_id == 0:
return 6
- asset_info = algod_client.asset_info(asset_id)
-
- if not isinstance(asset_info, dict) or "params" not in asset_info or "decimals" not in asset_info["params"]:
- raise click.ClickException("Invalid asset info response")
-
- return int(asset_info["params"]["decimals"])
+ asset_response = algod_client.asset_by_id(asset_id)
+ return asset_response.params.decimals
-def validate_balance(
- algod_client: algosdk.v2client.algod.AlgodClient, account: SigningAccount | str, asset_id: int, amount: int = 0
-) -> None:
+def validate_balance(algod_client: AlgodClient, account: SigningAccount | str, asset_id: int, amount: int = 0) -> None:
"""
Validates the balance of an account before an operation.
Args:
- algod_client (algosdk.v2client.algod.AlgodClient): The AlgodClient object for
+ algod_client (AlgodClient): The AlgodClient object for
interacting with the Algorand blockchain.
account (SigningAccount | str): The account object.
asset_id (int): The ID of the asset to be checked (0 for Algos).
@@ -148,10 +155,7 @@ def validate_balance(
click.ClickException: If any validation check fails.
"""
address = account.address if isinstance(account, SigningAccount) else account
- account_info = algod_client.account_info(address)
-
- if not isinstance(account_info, dict):
- raise click.ClickException("Invalid account info response")
+ account_info = algod_client.account_information(address)
if asset_id == 0:
_validate_algo_balance(account_info, amount)
@@ -174,7 +178,7 @@ def validate_address(address: str) -> None:
None
"""
- if not algosdk.encoding.is_valid_address(address): # type: ignore[no-untyped-call]
+ if not is_valid_address(address):
raise click.ClickException(f"`{address}` is an invalid account address")
@@ -234,7 +238,7 @@ def get_address(address: str) -> str:
validate_address(parsed_address)
return parsed_address
except click.ClickException as ex:
- if len(parsed_address) == algosdk.constants.address_len:
+ if len(parsed_address) == ADDRESS_LENGTH:
raise click.ClickException(f"`{parsed_address}` is an invalid account address") from ex
alias_data = get_alias(parsed_address)
@@ -257,15 +261,13 @@ def stdin_has_content() -> bool:
return stat.S_ISFIFO(mode) or stat.S_ISREG(mode)
-def validate_account_balance_to_opt_in(
- algod_client: algosdk.v2client.algod.AlgodClient, account: SigningAccount, num_assets: int
-) -> None:
+def validate_account_balance_to_opt_in(algod_client: AlgodClient, account: SigningAccount, num_assets: int) -> None:
"""
Validates the balance of an account before opt in operation.
Each asset requires 0.1 Algos to opt in.
Args:
- algod_client (algosdk.v2client.algod.AlgodClient): The AlgodClient object for
+ algod_client (AlgodClient): The AlgodClient object for
interacting with the Algorand blockchain.
account (SigningAccount | str): The account object.
num_assets (int): The number of the assets for opt in (0 for Algos).
@@ -275,13 +277,10 @@ def validate_account_balance_to_opt_in(
"""
address = account.address if isinstance(account, SigningAccount) else account
- account_info = algod_client.account_info(address)
-
- if not isinstance(account_info, dict):
- raise click.ClickException("Invalid account info response")
+ account_info = algod_client.account_information(address)
required_microalgos = num_assets * AlgoAmount.from_algo(Decimal("0.1")).micro_algo
- available_microalgos = account_info.get("amount", 0)
+ available_microalgos = account_info.amount
if available_microalgos < required_microalgos:
required_algo = AlgoAmount.from_micro_algo(required_microalgos).algo
available_algos = AlgoAmount.from_micro_algo(available_microalgos).algo
@@ -291,12 +290,6 @@ def validate_account_balance_to_opt_in(
)
-def get_account_info(algod_client: algosdk.v2client.algod.AlgodClient, account_address: str) -> dict:
- account_info = algod_client.account_info(account_address)
- assert isinstance(account_info, dict)
- return account_info
-
-
def run_callback_once(callback: Callable) -> Callable:
"""
Click option callbacks run twice, first to validate the prompt input,
diff --git a/src/algokit/cli/tasks/wallet.py b/src/algokit/cli/tasks/wallet.py
index 0fd0f6d58..ef2271e6d 100644
--- a/src/algokit/cli/tasks/wallet.py
+++ b/src/algokit/cli/tasks/wallet.py
@@ -2,9 +2,9 @@
import re
import click
-from algosdk import account
from algokit.cli.tasks.utils import get_private_key_from_mnemonic, validate_address
+from algokit.core.address_utils import address_from_private_key
from algokit.core.tasks.wallet import (
WALLET_ALIASING_MAX_LIMIT,
WalletAliasingLimitError,
@@ -49,7 +49,7 @@ def add(*, alias_name: str, address: str, use_mnemonic: bool, force: bool) -> No
private_key = get_private_key_from_mnemonic() if use_mnemonic else None
if use_mnemonic:
- derived_address = account.address_from_private_key(private_key) # type: ignore[no-untyped-call]
+ derived_address = address_from_private_key(private_key) # type: ignore[arg-type]
if derived_address != address:
click.echo(
"Warning: Address from the mnemonic doesn't match the provided address. "
diff --git a/src/algokit/cli/vibe.py b/src/algokit/cli/vibe.py
new file mode 100644
index 000000000..85b026ad6
--- /dev/null
+++ b/src/algokit/cli/vibe.py
@@ -0,0 +1,122 @@
+import logging
+import os
+import platform
+from pathlib import Path
+
+import click
+
+from algokit.core import proc
+from algokit.core.sandbox import (
+ DEFAULT_ALGOD_PORT,
+ DEFAULT_ALGOD_SERVER,
+ DEFAULT_ALGOD_TOKEN,
+ DEFAULT_INDEXER_PORT,
+ DEFAULT_INDEXER_TOKEN,
+ ComposeSandbox,
+)
+from algokit.core.utils import resolve_command_path
+
+logger = logging.getLogger(__name__)
+
+VIBEKIT_INSTALL_URL = "https://getvibekit.ai/install"
+
+
+@click.group("vibe", short_help="Give your AI assistant Algorand superpowers using VibeKit.")
+def vibe_group() -> None:
+ """Give your AI assistant Algorand superpowers using VibeKit."""
+
+
+def _resolve_vibekit_command() -> list[str] | None:
+ try:
+ return resolve_command_path(["vibekit"])
+ except click.ClickException:
+ return None
+
+
+def _get_install_command() -> list[str]:
+ if platform.system() == "Windows":
+ return ["powershell", "-ExecutionPolicy", "ByPass", "-c", f"irm {VIBEKIT_INSTALL_URL} | iex"]
+ return ["sh", "-c", f"curl -fsSL {VIBEKIT_INSTALL_URL} | sh"]
+
+
+def _build_vibekit_init_env() -> dict[str, str]:
+ env = dict(os.environ)
+
+ is_running = False
+ try:
+ sandbox = ComposeSandbox.from_environment()
+ if sandbox is not None:
+ ps_by_name = {stats["Service"]: stats for stats in sandbox.ps()}
+ required_services = ("algod", "indexer")
+ is_running = all(name in ps_by_name for name in required_services) and all(
+ ps_by_name[name].get("State") == "running" for name in required_services
+ )
+ except Exception as ex:
+ # Context injection should never block initialization.
+ logger.warning("Unable to inspect AlgoKit LocalNet status; proceeding without confirmed LocalNet state.")
+ logger.debug("LocalNet inspection failed", exc_info=ex)
+
+ env["ALGOKIT_LOCALNET_ALGOD_URL"] = f"{DEFAULT_ALGOD_SERVER}:{DEFAULT_ALGOD_PORT}"
+ env["ALGOKIT_LOCALNET_ALGOD_TOKEN"] = DEFAULT_ALGOD_TOKEN
+ env["ALGOKIT_LOCALNET_INDEXER_URL"] = f"{DEFAULT_ALGOD_SERVER}:{DEFAULT_INDEXER_PORT}"
+ env["ALGOKIT_LOCALNET_INDEXER_TOKEN"] = DEFAULT_INDEXER_TOKEN
+ env["ALGOKIT_LOCALNET_RUNNING"] = "true" if is_running else "false"
+ return env
+
+
+@vibe_group.command("setup")
+def setup() -> None:
+ """Install and initialize VibeKit for the current project."""
+ run_vibe_setup()
+
+
+def run_vibe_setup(cwd: Path | None = None) -> None:
+ """Run VibeKit setup flow."""
+ vibekit_cmd = _resolve_vibekit_command()
+ if vibekit_cmd is None:
+ click.echo(click.style("VibeKit not found.", fg="yellow"))
+ if not click.confirm("Would you like to install VibeKit now?", default=True):
+ raise click.ClickException(
+ f"Please install VibeKit manually from {VIBEKIT_INSTALL_URL} and re-run `algokit vibe setup`."
+ )
+
+ install_error_message = (
+ f"Failed to install VibeKit automatically. Install manually from {VIBEKIT_INSTALL_URL} "
+ "and re-run `algokit vibe setup`."
+ )
+ try:
+ proc.run(_get_install_command(), bad_return_code_error_message=install_error_message)
+ except OSError as ex:
+ raise click.ClickException(install_error_message) from ex
+
+ vibekit_cmd = _resolve_vibekit_command()
+ if vibekit_cmd is None:
+ raise click.ClickException(
+ f"VibeKit was installed but isn't available on PATH yet. Restart your shell and run "
+ f"`algokit vibe setup`, or install manually from {VIBEKIT_INSTALL_URL}."
+ )
+
+ logger.info("Initializing VibeKit context...")
+ env = _build_vibekit_init_env()
+ result = proc.run_interactive([*vibekit_cmd, "init"], env=env, cwd=cwd)
+ if result.exit_code != 0:
+ raise click.ClickException("VibeKit initialization failed.")
+
+
+@vibe_group.command("status")
+def status() -> None:
+ """Check the status of VibeKit AI skills and MCP servers."""
+ run_vibe_status()
+
+
+def run_vibe_status(cwd: Path | None = None) -> None:
+ """Run VibeKit status flow."""
+ vibekit_cmd = _resolve_vibekit_command()
+ if vibekit_cmd is None:
+ raise click.ClickException(
+ f"VibeKit is not installed. Install it from {VIBEKIT_INSTALL_URL} and run `algokit vibe setup`."
+ )
+
+ result = proc.run_interactive([*vibekit_cmd, "status"], cwd=cwd)
+ if result.exit_code != 0:
+ raise click.ClickException("VibeKit status check failed.")
diff --git a/src/algokit/core/address_utils.py b/src/algokit/core/address_utils.py
new file mode 100644
index 000000000..1b651b0d4
--- /dev/null
+++ b/src/algokit/core/address_utils.py
@@ -0,0 +1,59 @@
+"""Address utilities for the CLI.
+
+This module provides address validation and derivation utilities using algokit_common.
+"""
+
+import base64
+
+from algokit_utils.common import (
+ ADDRESS_LENGTH,
+ address_from_public_key,
+ public_key_from_address,
+)
+
+PRIVATE_KEY_LENGTH = 64 # 32-byte seed + 32-byte public key
+
+
+def is_valid_address(address: str) -> bool:
+ """Check if an address is a valid Algorand address.
+
+ Args:
+ address: The address string to validate.
+
+ Returns:
+ True if the address is valid, False otherwise.
+ """
+ if len(address) != ADDRESS_LENGTH:
+ return False
+
+ try:
+ # public_key_from_address will raise if invalid
+ public_key_from_address(address)
+ return True
+ except Exception:
+ return False
+
+
+def address_from_private_key(private_key: str) -> str:
+ """Derive the address from a private key.
+
+ The private key is expected to be a base64-encoded string of 64 bytes
+ (32-byte seed + 32-byte public key).
+
+ Args:
+ private_key: Base64-encoded private key string.
+
+ Returns:
+ The Algorand address corresponding to the private key.
+ """
+ # Decode the base64 private key
+ key_bytes = base64.b64decode(private_key)
+
+ if len(key_bytes) != PRIVATE_KEY_LENGTH:
+ raise ValueError(f"Invalid private key: expected {PRIVATE_KEY_LENGTH} bytes, got {len(key_bytes)}")
+
+ # Extract the public key (last 32 bytes of the 64-byte key)
+ public_key = key_bytes[32:64]
+
+ # Derive the address from the public key
+ return address_from_public_key(public_key)
diff --git a/src/algokit/core/compilers/python.py b/src/algokit/core/compilers/python.py
index de3ad7879..955fbcedb 100644
--- a/src/algokit/core/compilers/python.py
+++ b/src/algokit/core/compilers/python.py
@@ -1,7 +1,7 @@
from collections.abc import Iterator
from algokit.core.proc import run
-from algokit.core.utils import extract_version_triple, find_valid_pipx_command
+from algokit.core.utils import extract_version_triple, find_valid_tool_runner_command, get_tool_run_command
def find_valid_puyapy_command(version: str | None) -> list[str]:
@@ -11,7 +11,7 @@ def find_valid_puyapy_command(version: str | None) -> list[str]:
def _find_puyapy_command_at_version(version: str) -> list[str]:
"""
Find puyapy command with a specific version.
- If the puyapy version isn't installed, install it with pipx run.
+ If the puyapy version isn't installed, run it via uvx/pipx.
"""
for puyapy_command in _get_candidate_puyapy_commands():
try:
@@ -24,24 +24,19 @@ def _find_puyapy_command_at_version(version: str) -> list[str]:
):
return puyapy_command
- pipx_command = find_valid_pipx_command(
- "Unable to find pipx install so that the `PuyaPy` compiler can be run; "
- "please install pipx via https://pypa.github.io/pipx/ "
+ tool_runner_command = find_valid_tool_runner_command(
+ "Unable to find uvx or pipx so that `PuyaPy` can be run; "
+ "please install uv via https://docs.astral.sh/uv/ "
"and then try `algokit compile python ...` again."
)
- return [
- *pipx_command,
- "run",
- f"--spec=puyapy=={version}",
- "puyapy",
- ]
+ return get_tool_run_command(tool_runner_command, spec=f"puyapy=={version}", binary="puyapy")
def _find_puyapy_command() -> list[str]:
"""
Find puyapy command.
- If puyapy isn't installed, install the latest version with pipx.
+ If puyapy isn't installed, run the latest version via uvx/pipx.
"""
for puyapy_command in _get_candidate_puyapy_commands():
try:
@@ -52,21 +47,15 @@ def _find_puyapy_command() -> list[str]:
if puyapy_help_result.exit_code == 0:
return puyapy_command
- pipx_command = find_valid_pipx_command(
- "Unable to find pipx install so that the `PuyaPy` compiler can be run; "
- "please install pipx via https://pypa.github.io/pipx/ "
+ tool_runner_command = find_valid_tool_runner_command(
+ "Unable to find uvx or pipx so that `PuyaPy` can be run; "
+ "please install uv via https://docs.astral.sh/uv/ "
"and then try `algokit compile python ...` again."
)
- return [
- *pipx_command,
- "run",
- "--spec=puyapy",
- "puyapy",
- ]
+ return get_tool_run_command(tool_runner_command, spec="puyapy", binary="puyapy")
def _get_candidate_puyapy_commands() -> Iterator[list[str]]:
- # when puyapy is installed at the project level
+ yield ["uv", "run", "puyapy"]
yield ["poetry", "run", "puyapy"]
- # when puyapy is installed at the global level
yield ["puyapy"]
diff --git a/src/algokit/core/config_commands/py_package_manager.py b/src/algokit/core/config_commands/py_package_manager.py
index 7dcf3dbca..c73505d5b 100644
--- a/src/algokit/core/config_commands/py_package_manager.py
+++ b/src/algokit/core/config_commands/py_package_manager.py
@@ -46,10 +46,10 @@ def py_package_manager_configuration_command(*, package_manager: str | None) ->
"""Set the default Python package manager for use by AlgoKit CLI."""
if package_manager is None:
- current_manager = get_py_package_manager() or PyPackageManager.POETRY
+ current_manager = get_py_package_manager() or PyPackageManager.UV
choices = [
- f"poetry {'(active)' if current_manager == PyPackageManager.POETRY else ''}".strip(),
f"uv {'(active)' if current_manager == PyPackageManager.UV else ''}".strip(),
+ f"poetry {'(active)' if current_manager == PyPackageManager.POETRY else ''}".strip(),
]
manager = questionary.select(
"Which Python package manager would you prefer `bootstrap` command to use by default?", choices=choices
@@ -58,5 +58,8 @@ def py_package_manager_configuration_command(*, package_manager: str | None) ->
raise click.ClickException("No valid Python package manager selected. Aborting...")
package_manager = manager.split()[0].lower()
+ if package_manager is None:
+ raise click.ClickException("No valid Python package manager selected. Aborting...")
+
save_py_package_manager(package_manager)
logger.info(f"Python package manager set to `{package_manager}`")
diff --git a/src/algokit/core/config_commands/version_prompt.py b/src/algokit/core/config_commands/version_prompt.py
index 75838da4f..417e2db25 100644
--- a/src/algokit/core/config_commands/version_prompt.py
+++ b/src/algokit/core/config_commands/version_prompt.py
@@ -22,7 +22,10 @@
"brew": "`brew upgrade algokit`",
}
UNKNOWN_DISTRIBUTION_METHOD_UPDATE_INSTRUCTION = "the tool used to install AlgoKit"
-# TODO: Set this version as part of releasing the binary distributions.
+# Sentinel version used by binary distributions (winget, brew, snap).
+# Any version >= this value that is NOT running in binary mode is assumed
+# to have been installed via uv. This should be replaced with a proper
+# detection mechanism if the sentinel is ever changed.
BINARY_DISTRIBUTION_RELEASE_VERSION = "99.99.99"
@@ -47,11 +50,9 @@ def do_version_prompt() -> None:
if distribution
else UNKNOWN_DISTRIBUTION_METHOD_UPDATE_INSTRUCTION
)
- # If you're not using the binary mode, then you've used pipx to install AlgoKit.
- # One exception is that older versions of the brew package used pipx,
- # however require updating via brew, so we show the default update instruction instead.
+ # If not using binary mode, it was installed via uv or pipx.
elif current_version_sequence >= _get_version_sequence(BINARY_DISTRIBUTION_RELEASE_VERSION):
- update_instruction = "`pipx upgrade algokit`"
+ update_instruction = "`uv tool upgrade algokit`"
logger.info(
f"You are using AlgoKit version {current_version}, however version {latest_version} is available. "
@@ -97,7 +98,7 @@ def get_latest_version_or_cached() -> str | None:
def get_latest_github_version() -> str:
headers = {"ACCEPT": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28"}
- response = httpx.get(LATEST_URL, headers=headers)
+ response = httpx.get(LATEST_URL, headers=headers, timeout=5)
response.raise_for_status()
json = response.json()
diff --git a/src/algokit/core/dispenser.py b/src/algokit/core/dispenser.py
index 58a021ac8..0821887e5 100644
--- a/src/algokit/core/dispenser.py
+++ b/src/algokit/core/dispenser.py
@@ -281,7 +281,7 @@ def set_dispenser_credentials(token_data: dict[str, str]) -> None:
keyring.set_password(
DISPENSER_KEYRING_NAMESPACE, DISPENSER_KEYRING_REFRESH_TOKEN_KEY, token_data.get("refresh_token", "")
)
- keyring.set_password(DISPENSER_KEYRING_NAMESPACE, DISPENSER_KEYRING_USER_ID_KEY, decoded_id_token.get("sub"))
+ keyring.set_password(DISPENSER_KEYRING_NAMESPACE, DISPENSER_KEYRING_USER_ID_KEY, decoded_id_token.get("sub") or "")
def clear_dispenser_credentials() -> None:
diff --git a/src/algokit/core/project/bootstrap.py b/src/algokit/core/project/bootstrap.py
index f3c51ef22..1b613665c 100644
--- a/src/algokit/core/project/bootstrap.py
+++ b/src/algokit/core/project/bootstrap.py
@@ -20,7 +20,14 @@
get_py_package_manager,
save_py_package_manager,
)
-from algokit.core.utils import find_valid_pipx_command, is_windows
+from algokit.core.utils import (
+ find_valid_tool_runner_command,
+ get_tool_install_command,
+ get_tool_run_command,
+ is_uv,
+ is_uvx,
+ is_windows,
+)
ENV_TEMPLATE_PATTERN = ".env*.template"
MAX_BOOTSTRAP_DEPTH = 2
@@ -123,6 +130,9 @@ def _determine_python_package_manager(project_dir: Path) -> str:
poetry_path = project_dir / "poetry.toml"
pyproject_path = project_dir / "pyproject.toml"
+ if is_uv_project(project_dir):
+ return PyPackageManager.UV
+
if poetry_path.exists():
# Standalone poetry.toml suggests Poetry
return PyPackageManager.POETRY
@@ -134,11 +144,10 @@ def _determine_python_package_manager(project_dir: Path) -> str:
# 4. Interactive prompt for first-time users
manager = questionary.select(
"Which Python package manager would you prefer `bootstrap` command to use?",
- choices=[PyPackageManager.POETRY, PyPackageManager.UV],
+ choices=[PyPackageManager.UV, PyPackageManager.POETRY],
).ask()
if manager is None:
- # Default to Poetry if user cancels
- manager = PyPackageManager.POETRY
+ manager = PyPackageManager.UV
save_py_package_manager(manager)
return str(manager)
@@ -186,7 +195,7 @@ def _bootstrap_python_project(project_dir: Path, manager: str) -> None:
if manager == PyPackageManager.UV:
logger.debug("Running `algokit project bootstrap uv`")
bootstrap_uv(project_dir)
- else: # Default to Poetry for backward compatibility
+ else:
logger.debug("Running `algokit project bootstrap poetry`")
bootstrap_poetry(project_dir)
@@ -430,6 +439,7 @@ def bootstrap_env(project_dir: Path, *, ci_mode: bool) -> None:
def bootstrap_poetry(project_dir: Path) -> None:
+ tool_command: list[str] = []
try:
proc.run(
["poetry", "--version"],
@@ -438,26 +448,28 @@ def bootstrap_poetry(project_dir: Path) -> None:
try_install_poetry = False
except OSError:
try_install_poetry = True
-
if try_install_poetry:
logger.info("Poetry not found; attempting to install it...")
+ tool_command = find_valid_tool_runner_command(
+ "Unable to find uv or pipx so that poetry can be installed; "
+ "please install uv via https://docs.astral.sh/uv/ "
+ "and then try `algokit project bootstrap poetry` again."
+ )
+ tool_name = "uv" if is_uvx(tool_command) or is_uv(tool_command) else "pipx"
if not questionary_extensions.prompt_confirm(
- "We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies?",
+ f"We couldn't find `poetry`; can we install it for you via {tool_name} "
+ "so we can install Python dependencies?",
default=True,
):
raise click.ClickException(
- "Unable to install poetry via pipx; please install poetry "
+ f"Unable to install poetry via {tool_name}; please install poetry "
"manually via https://python-poetry.org/docs/ and try `algokit project bootstrap poetry` again."
)
- pipx_command = find_valid_pipx_command(
- "Unable to find pipx install so that poetry can be installed; "
- "please install pipx via https://pypa.github.io/pipx/ "
- "and then try `algokit project bootstrap poetry` again."
- )
+ install_cmd = get_tool_install_command(tool_command, package="poetry")
proc.run(
- [*pipx_command, "install", "poetry"],
+ install_cmd,
bad_return_code_error_message=(
- "Unable to install poetry via pipx; please install poetry "
+ f"Unable to install poetry via {tool_name}; please install poetry "
"manually via https://python-poetry.org/docs/ and try `algokit project bootstrap poetry` again."
),
)
@@ -465,14 +477,23 @@ def bootstrap_poetry(project_dir: Path) -> None:
logger.info("Installing Python dependencies and setting up Python virtual environment via Poetry")
try:
proc.run(["poetry", "install"], stdout_log_level=logging.INFO, cwd=project_dir)
- except OSError as e:
+ except OSError:
if try_install_poetry:
- raise click.ClickException(
- "Unable to access Poetry on PATH after installing it via pipx; "
- "check pipx installations are on your path by running `pipx ensurepath` "
- "and try `algokit project bootstrap poetry` again."
- ) from e
- raise # unexpected error, we already ran without IOError before
+ tool_name = "uv" if is_uvx(tool_command) or is_uv(tool_command) else "pipx"
+ logger.info(
+ "Poetry is not available on PATH yet after installation; retrying via %s tool runner", tool_name
+ )
+ fallback_cmd = [*get_tool_run_command(tool_command, spec="poetry", binary="poetry"), "install"]
+ try:
+ proc.run(fallback_cmd, stdout_log_level=logging.INFO, cwd=project_dir)
+ return
+ except Exception as fallback_error:
+ raise click.ClickException(
+ f"Unable to access Poetry on PATH after installing it via {tool_name}; "
+ "and fallback execution failed. Please restart your terminal and try "
+ "`algokit project bootstrap poetry` again."
+ ) from fallback_error
+ raise
def bootstrap_npm(project_dir: Path, *, ci_mode: bool) -> None:
@@ -542,90 +563,86 @@ def migrate_pyproject_to_uv(project_dir: Path) -> None:
) from e
-def bootstrap_uv(project_dir: Path) -> None: # noqa: C901
+def _ensure_uv_installed() -> bool:
+ """Ensure uv is installed, prompting to install if missing. Returns True if freshly installed."""
try:
proc.run(
["uv", "--version"],
bad_return_code_error_message="uv --version failed, please check your uv install",
)
- try_install_uv = False
+ return False
except OSError:
- try_install_uv = True
+ pass
- if try_install_uv:
- logger.info("UV not found; attempting to install it...")
- if not questionary_extensions.prompt_confirm(
- "We couldn't find `uv`; can we install it for you via curl so we can install Python dependencies?",
- default=True,
- ):
- raise click.ClickException(
- "Unable to install uv; please install uv "
- "manually via https://github.com/astral-sh/uv and try `algokit project bootstrap uv` again."
- )
+ logger.info("UV not found; attempting to install it...")
+ if not questionary_extensions.prompt_confirm(
+ "We couldn't find `uv`; can we install it for you so we can install Python dependencies?",
+ default=True,
+ ):
+ raise click.ClickException(
+ "Unable to install uv; please install uv "
+ "manually via https://docs.astral.sh/uv/ and try `algokit project bootstrap uv` again."
+ )
- # Use the standalone installer as recommended in the UV docs
- if is_windows():
- cmd = ["powershell", "-ExecutionPolicy", "ByPass", "-c", "irm https://astral.sh/uv/install.ps1 | iex"]
- try:
- proc.run(
- cmd,
- bad_return_code_error_message=(
- "Unable to install uv; please install uv "
- "manually via https://github.com/astral-sh/uv and try `algokit project bootstrap uv` again."
- ),
- )
- except Exception as e:
- raise click.ClickException(
- "Failed to install uv. Please install it manually via "
- "https://github.com/astral-sh/uv and try `algokit project bootstrap uv` again."
- ) from e
- else:
- # For Unix platforms, use proc.run with sh -c to handle the pipe safely
- try:
- proc.run(
- ["sh", "-c", "curl -LsSf https://astral.sh/uv/install.sh | sh"],
- bad_return_code_error_message=(
- "Unable to install uv; please install uv "
- "manually via https://github.com/astral-sh/uv and try `algokit project bootstrap uv` again."
- ),
- )
- except Exception as e:
- raise click.ClickException(
- "Failed to install uv. Please install it manually via "
- "https://github.com/astral-sh/uv and try `algokit project bootstrap uv` again."
- ) from e
+ install_error_message = (
+ "Unable to install uv; please install uv "
+ "manually via https://docs.astral.sh/uv/ and try `algokit project bootstrap uv` again."
+ )
- # Check if pyproject.toml contains poetry configuration
+ if is_windows():
+ cmd = ["powershell", "-ExecutionPolicy", "ByPass", "-c", "irm https://astral.sh/uv/install.ps1 | iex"]
+ else:
+ cmd = ["sh", "-c", "curl -LsSf https://astral.sh/uv/install.sh | sh"]
+
+ try:
+ proc.run(cmd, bad_return_code_error_message=install_error_message)
+ except Exception as e:
+ raise click.ClickException(install_error_message) from e
+
+ return True
+
+
+def _maybe_migrate_poetry_project(project_dir: Path) -> None:
+ """If the project uses Poetry, offer to migrate to uv-compatible format."""
pyproject_path = project_dir / "pyproject.toml"
- is_poetry_project = pyproject_path.exists() and "[tool.poetry]" in pyproject_path.read_text("utf-8")
- if is_poetry_project:
- if questionary_extensions.prompt_confirm(
- "Would you like to attempt to migrate the pyproject configuration to uv compliant format?\n"
- "⚠️ This will run a third-party tool (https://mkniewallner.github.io/migrate-to-uv/) "
- "that will attempt to convert your poetry project to uv. "
- "You are advised to double check the migrated file and it's recommended to run this "
- "in a version controlled repository to revert changes if needed.",
- default=False,
- ):
- migrate_pyproject_to_uv(project_dir)
- else:
- raise click.ClickException(
- "This project is configured to use Poetry. Please use `algokit project bootstrap poetry`, "
- "set poetry as default package manager via `algokit config py-package-manager`, "
- "or modify your pyproject.toml to be compatible with UV."
- )
+ if not pyproject_path.exists():
+ return
+
+ if "[tool.poetry]" not in pyproject_path.read_text("utf-8"):
+ return
+
+ if questionary_extensions.prompt_confirm(
+ "Would you like to attempt to migrate the pyproject configuration to uv compliant format?\n"
+ "\u26a0\ufe0f This will run a third-party tool (https://mkniewallner.github.io/migrate-to-uv/) "
+ "that will attempt to convert your poetry project to uv. "
+ "You are advised to double check the migrated file and it's recommended to run this "
+ "in a version controlled repository to revert changes if needed.",
+ default=False,
+ ):
+ migrate_pyproject_to_uv(project_dir)
+ else:
+ raise click.ClickException(
+ "This project is configured to use Poetry. Please use `algokit project bootstrap poetry`, "
+ "set poetry as default package manager via `algokit config py-package-manager`, "
+ "or modify your pyproject.toml to be compatible with UV."
+ )
+
+
+def bootstrap_uv(project_dir: Path) -> None:
+ freshly_installed = _ensure_uv_installed()
+
+ _maybe_migrate_poetry_project(project_dir)
logger.info("Installing Python dependencies and setting up Python virtual environment via UV")
try:
- # Sync will create/update the virtual environment and install dependencies
proc.run(["uv", "sync"], stdout_log_level=logging.INFO, cwd=project_dir)
except OSError as e:
- if try_install_uv:
+ if freshly_installed:
raise click.ClickException(
"Unable to access UV on PATH after installing it; "
"try restarting your terminal and running `algokit project bootstrap uv` again."
) from e
- raise # unexpected error, we already ran without IOError before
+ raise
def get_min_algokit_version(project_dir: Path) -> str | None:
diff --git a/src/algokit/core/project/run.py b/src/algokit/core/project/run.py
index dfdd7bb9b..05f89d9e2 100644
--- a/src/algokit/core/project/run.py
+++ b/src/algokit/core/project/run.py
@@ -1,6 +1,7 @@
import dataclasses
import logging
import os
+import shutil
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from typing import Any
@@ -19,6 +20,21 @@
logger = logging.getLogger("rich")
+def _normalize_legacy_runner_command(command: list[str]) -> list[str]:
+ """Normalize legacy runner commands to supported equivalents."""
+ if command[:2] == ["poetry", "run"] and command[2:]:
+ if shutil.which("poetry"):
+ return command
+ if shutil.which("uv"):
+ logger.debug("poetry not found, rewriting 'poetry run' -> 'uv run' for: %s", " ".join(command))
+ return ["uv", "run", *command[2:]]
+ raise click.ClickException(
+ "Unable to run legacy `poetry run` command because neither `poetry` nor `uv` is installed. "
+ "Install uv via https://docs.astral.sh/uv/ and then try again."
+ )
+ return command
+
+
@dataclasses.dataclass(kw_only=True)
class ProjectCommand:
"""Represents a command to be executed within a project context.
@@ -188,7 +204,8 @@ def run_command(
for index, cmd in enumerate(command.commands):
try:
- resolved_command = resolve_command_path(cmd)
+ normalized_command = _normalize_legacy_runner_command(cmd)
+ resolved_command = resolve_command_path(normalized_command)
if index == len(command.commands) - 1 and extra_args:
resolved_command.extend(extra_args)
except click.ClickException as e:
diff --git a/src/algokit/core/signing_account.py b/src/algokit/core/signing_account.py
new file mode 100644
index 000000000..b70a17247
--- /dev/null
+++ b/src/algokit/core/signing_account.py
@@ -0,0 +1,24 @@
+"""SigningAccount compatibility class for CLI.
+
+This module provides a SigningAccount class that mimics the old algokit-utils
+SigningAccount interface for CLI compatibility during the migration to the
+new decoupled architecture.
+"""
+
+from algokit_utils.transact import make_basic_account_transaction_signer
+
+
+class SigningAccount:
+ """A simple account with signing capability.
+
+ This class provides compatibility with the old algokit-utils SigningAccount
+ interface while working with the new decoupled architecture.
+
+ Attributes:
+ address: The Algorand address of the account.
+ signer: A TransactionSigner from supplied private key
+ """
+
+ def __init__(self, address: str, private_key: str) -> None:
+ self.address = address
+ self.signer = make_basic_account_transaction_signer(private_key)
diff --git a/src/algokit/core/tasks/analyze.py b/src/algokit/core/tasks/analyze.py
index ef63e2afd..2b8a9d523 100644
--- a/src/algokit/core/tasks/analyze.py
+++ b/src/algokit/core/tasks/analyze.py
@@ -8,7 +8,7 @@
from pydantic import BaseModel, Field
from algokit.core.proc import RunResult, run
-from algokit.core.utils import find_valid_pipx_command
+from algokit.core.utils import find_valid_tool_runner_command, get_tool_install_command, is_uvx
logger = logging.getLogger(__name__)
@@ -97,19 +97,21 @@ def ensure_tealer_installed() -> None:
except Exception as e:
logger.debug(e)
logger.info("Tealer not found; attempting to install it...")
- pipx_command = find_valid_pipx_command(
- "Unable to find pipx install so that `tealer` static analyzer can be installed; "
- "please install pipx via https://pypa.github.io/pipx/ "
+ tool_runner_command = find_valid_tool_runner_command(
+ "Unable to find uvx or pipx so that `tealer` can be installed; "
+ "please install uv via https://docs.astral.sh/uv/ "
"and then try `algokit task analyze ...` again."
)
+ install_cmd = get_tool_install_command(tool_runner_command, package=f"tealer=={TEALER_VERSION}")
+ tool_name = "uv" if is_uvx(tool_runner_command) else "pipx"
run(
- [*pipx_command, "install", f"tealer=={TEALER_VERSION}"],
+ install_cmd,
bad_return_code_error_message=(
- "Unable to install tealer via pipx; please install tealer "
+ f"Unable to install tealer via {tool_name}; please install tealer "
"manually and try `algokit task analyze ...` again."
),
)
- logger.info("Tealer installed successfully via pipx!")
+ logger.info("Tealer installed successfully via %s!", tool_name)
def generate_tealer_command(cur_file: Path, report_output_path: Path, detectors_to_exclude: list[str]) -> list[str]:
diff --git a/src/algokit/core/tasks/mint/mint.py b/src/algokit/core/tasks/mint/mint.py
index 979dc3b9e..c560f5c96 100644
--- a/src/algokit/core/tasks/mint/mint.py
+++ b/src/algokit/core/tasks/mint/mint.py
@@ -5,16 +5,17 @@
import mimetypes
import pathlib
import re
-from dataclasses import asdict
-from algokit_utils import SigningAccount
-from algosdk import encoding, transaction
-from algosdk.transaction import wait_for_confirmation
-from algosdk.v2client import algod
+from algokit_utils.clients import AlgodClient, algod_models
+from algokit_utils.common import address_from_public_key, sha512_256
+from algokit_utils.transact import get_transaction_id
+from algokit_utils.transactions.builders.asset import build_asset_create_transaction
+from algokit_utils.transactions.types import AssetCreateParams
from multiformats import CID
+from algokit.core.signing_account import SigningAccount
from algokit.core.tasks.ipfs import upload_to_pinata
-from algokit.core.tasks.mint.models import AssetConfigTxnParams, TokenMetadata
+from algokit.core.tasks.mint.models import TokenMetadata
logger = logging.getLogger(__name__)
@@ -33,9 +34,7 @@ def _reserve_address_from_cid(cid: str) -> str:
# Workaround to fix `multiformats` package issue, remove first two bytes before using `encode_address`.
# Initial fix using `py-multiformats-cid` and `multihash.decode` was dropped due to PEP 517 incompatibility.
digest = CID.decode(cid).digest[2:]
- reserve_address = str(encoding.encode_address(digest)) # type: ignore[no-untyped-call]
- assert encoding.is_valid_address(reserve_address) # type: ignore[no-untyped-call]
- return reserve_address
+ return address_from_public_key(digest)
def _create_url_from_cid(cid: str) -> str:
@@ -95,55 +94,72 @@ def _file_mimetype(filename: pathlib.Path) -> str:
return mimetypes.types_map[extension]
-def _create_asset_txn(
+def _wait_for_confirmation(client: AlgodClient, txid: str, rounds: int) -> algod_models.PendingTransactionResponse:
+ """Wait for transaction confirmation.
+
+ Args:
+ client: AlgodClient instance
+ txid: Transaction ID to wait for
+ rounds: Maximum number of rounds to wait
+
+ Returns:
+ algod_models.PendingTransactionResponse: Transaction confirmation info
+
+ Raises:
+ Exception: If transaction is rejected or not confirmed in time
+ """
+ status = client.status()
+ last_round = getattr(status, "last_round", 0)
+ current_round = last_round
+
+ while current_round <= last_round + rounds:
+ txinfo = client.pending_transaction_information(txid)
+ confirmed_round = getattr(txinfo, "confirmed_round", None)
+ if confirmed_round is not None and confirmed_round > 0:
+ return txinfo
+ pool_error = getattr(txinfo, "pool_error", None)
+ if pool_error:
+ raise Exception(f"Transaction rejected: {pool_error}")
+ current_round += 1
+ client.status_after_block(current_round)
+
+ raise Exception(f"Transaction {txid} not confirmed after {rounds} rounds")
+
+
+def _compute_metadata_hash(
*,
- asset_config_params: AssetConfigTxnParams,
token_metadata: TokenMetadata,
use_metadata_hash: bool = True,
-) -> transaction.AssetConfigTxn:
+) -> bytes:
"""
- Create an instance of the AssetConfigTxn class by setting the parameters and metadata
- for the asset configuration transaction.
+ Compute the metadata hash for an asset.
Args:
- asset_config_params (AssetConfigTxnParams): An instance of the AssetConfigTxnParams class
- that contains the parameters for the asset configuration transaction.
token_metadata (TokenMetadata): An instance of the TokenMetadata class that contains the metadata for the asset.
- use_metadata_hash (bool, optional): A boolean flag indicating whether to use the metadata hash
- in the asset configuration transaction. Defaults to True.
+ use_metadata_hash (bool, optional): A boolean flag indicating whether to use the metadata hash.
+ Defaults to True.
Returns:
- AssetConfigTxn: An instance of the AssetConfigTxn class representing the asset configuration transaction.
+ bytes: The computed metadata hash, or empty bytes if use_metadata_hash is False.
"""
+ if not use_metadata_hash:
+ return b""
+
json_metadata = token_metadata.to_json()
+ json_metadata_bytes = json_metadata.encode("utf-8")
metadata = json.loads(json_metadata)
- if use_metadata_hash:
- if "extra_metadata" in metadata:
- h = hashlib.new("sha512_256")
- h.update(b"arc0003/amj")
- h.update(json_metadata.encode("utf-8"))
- json_metadata_hash = h.digest()
-
- h = hashlib.new("sha512_256")
- h.update(b"arc0003/am")
-
- h.update(json_metadata_hash)
- h.update(base64.b64decode(metadata["extra_metadata"]))
- asset_config_params.metadata_hash = h.digest()
- else:
- h = hashlib.new("sha256")
- h.update(json_metadata.encode("utf-8"))
- asset_config_params.metadata_hash = h.digest()
- else:
- asset_config_params.metadata_hash = b""
+ if "extra_metadata" in metadata:
+ json_metadata_hash = sha512_256(b"arc0003/amj" + json_metadata_bytes)
- return transaction.AssetConfigTxn(**asdict(asset_config_params)) # type: ignore[no-untyped-call]
+ return sha512_256(b"arc0003/am" + json_metadata_hash + base64.b64decode(metadata["extra_metadata"]))
+ else:
+ return hashlib.sha256(json_metadata_bytes).digest()
def mint_token( # noqa: PLR0913
*,
- client: algod.AlgodClient,
+ client: AlgodClient,
jwt: str,
creator_account: SigningAccount,
unit_name: str,
@@ -156,26 +172,19 @@ def mint_token( # noqa: PLR0913
Mint new token on the Algorand blockchain.
Args:
- client (algod.AlgodClient): An instance of the `algod.AlgodClient` class representing the Algorand node.
+ client (AlgodClient): An instance of the `AlgodClient` class representing the Algorand node.
jwt (str): The JWT for accessing the Piñata API.
creator_account (SigningAccount): An instance of the `SigningAccount` class representing the account that
will create the token.
- asset_name (str): A string representing the name of the token.
unit_name (str): A string representing the unit name of the token.
total (int): An integer representing the total supply of the token.
token_metadata (TokenMetadata): An instance of the `TokenMetadata` class representing the metadata of the token.
mutable (bool): A boolean indicating whether the token is mutable or not.
image_path (pathlib.Path | None, optional): A `pathlib.Path` object representing the path to the
image file associated with the token. Defaults to None.
- decimals (int | None, optional): An integer representing the number of decimal places for the token.
- Defaults to 0.
Returns:
tuple[int, str]: A tuple containing the asset index and transaction ID of the minted token.
-
- Raises:
- ValueError: If the token name in the metadata JSON does not match the provided asset name.
- ValueError: If the decimals in the metadata JSON does not match the provided decimals amount.
"""
if image_path:
@@ -192,26 +201,78 @@ def mint_token( # noqa: PLR0913
)
logger.info(f"Metadata uploaded to pinata: {metadata_cid}")
- asset_config_params = AssetConfigTxnParams(
+ # Compute metadata hash
+ metadata_hash = _compute_metadata_hash(
+ token_metadata=token_metadata,
+ use_metadata_hash=not mutable,
+ )
+
+ # Build asset creation parameters
+ asset_create_params = AssetCreateParams(
sender=creator_account.address,
- sp=client.suggested_params(),
- reserve=_reserve_address_from_cid(metadata_cid) if mutable else "",
+ total=total,
+ decimals=token_metadata.decimals,
+ default_frozen=False,
unit_name=unit_name,
asset_name=token_metadata.name,
url=_create_url_from_cid(metadata_cid) + "#arc3" if mutable else "ipfs://" + metadata_cid + "#arc3",
- manager=creator_account.address if mutable else "",
- total=total,
- decimals=token_metadata.decimals,
+ metadata_hash=metadata_hash if metadata_hash else None,
+ manager=creator_account.address if mutable else None,
+ reserve=_reserve_address_from_cid(metadata_cid) if mutable else None,
+ freeze=None,
+ clawback=None,
)
- logger.debug(f"Asset config params: {asset_config_params.to_json()}")
- asset_config_txn = _create_asset_txn(
- asset_config_params=asset_config_params,
- token_metadata=token_metadata,
- use_metadata_hash=not mutable,
+ logger.debug(
+ "Asset config params: "
+ + json.dumps(
+ {
+ "sender": asset_create_params.sender,
+ "unit_name": asset_create_params.unit_name or "",
+ "asset_name": asset_create_params.asset_name or "",
+ "url": asset_create_params.url or "",
+ "manager": asset_create_params.manager or "",
+ "reserve": asset_create_params.reserve or "",
+ "total": asset_create_params.total,
+ "freeze": asset_create_params.freeze or "",
+ "clawback": asset_create_params.clawback or "",
+ "metadata_hash": base64.b64encode(asset_create_params.metadata_hash).decode("ascii")
+ if asset_create_params.metadata_hash
+ else None,
+ "note": "",
+ "decimals": asset_create_params.decimals,
+ "default_frozen": asset_create_params.default_frozen or False,
+ "lease": "",
+ "rekey_to": "",
+ "strict_empty_address_check": False,
+ },
+ indent=4,
+ )
+ )
+
+ # Build the transaction
+ suggested_params = client.suggested_params()
+ built_txn = build_asset_create_transaction(
+ params=asset_create_params,
+ suggested_params=suggested_params,
+ default_validity_window=1000,
+ default_validity_window_is_explicit=False,
+ is_localnet=False,
)
- signed_asset_config_txn = asset_config_txn.sign(creator_account.private_key) # type: ignore[no-untyped-call]
- asset_config_txn_id = client.send_transaction(signed_asset_config_txn)
- response = wait_for_confirmation(client, asset_config_txn_id, 4)
- return response["asset-index"], asset_config_txn_id
+ # Sign the transaction
+ signer = creator_account.signer
+ signed_txn_bytes = signer([built_txn.txn], [0])[0]
+
+ # Send the transaction (signer returns encoded signed transaction bytes)
+ txid = get_transaction_id(built_txn.txn)
+ client.send_raw_transaction(signed_txn_bytes)
+
+ # Wait for confirmation
+ response = _wait_for_confirmation(client, txid, 4)
+
+ asset_index = getattr(response, "asset_index", None)
+ if asset_index is None:
+ raise Exception("Asset creation failed: no asset-index in response")
+
+ return asset_index, txid
diff --git a/src/algokit/core/tasks/mint/models.py b/src/algokit/core/tasks/mint/models.py
index ba51c546f..788f2a131 100644
--- a/src/algokit/core/tasks/mint/models.py
+++ b/src/algokit/core/tasks/mint/models.py
@@ -3,7 +3,7 @@
from dataclasses import asdict, dataclass
from pathlib import Path
-from algosdk.transaction import SuggestedParams
+from algokit_utils.clients import algod_models
MIN_BG_COLOR_LENGTH = 6 # Based on ARC-0003 spec, must be a 6 character hex without a pre-pended #
@@ -93,7 +93,7 @@ def from_json_file(cls, file_path: Path | None, name: str, decimals: int = 0) ->
@dataclass
class AssetConfigTxnParams:
sender: str
- sp: SuggestedParams
+ sp: algod_models.SuggestedParams
unit_name: str
asset_name: str
url: str
diff --git a/src/algokit/core/tasks/vanity_address.py b/src/algokit/core/tasks/vanity_address.py
index 426cefd9f..a8b031dc5 100644
--- a/src/algokit/core/tasks/vanity_address.py
+++ b/src/algokit/core/tasks/vanity_address.py
@@ -1,3 +1,4 @@
+import base64
import logging
import multiprocessing
import signal
@@ -10,14 +11,37 @@
from multiprocessing import Process, Queue, cpu_count
from timeit import default_timer as timer
-import algosdk
-from algosdk.mnemonic import from_private_key, to_private_key
+import nacl.signing
+from algokit_utils.algo25 import secret_key_to_mnemonic, seed_from_mnemonic
+from algokit_utils.common import address_from_public_key
logger = logging.getLogger(__name__)
PROGRESS_REFRESH_INTERVAL_SECONDS = 5
+def _generate_account() -> tuple[bytes, str]:
+ """
+ Generate a new Algorand account.
+
+ Returns:
+ tuple[bytes, str]: A tuple containing the secret key (64 bytes) and the address (string).
+ The secret key format is seed (32 bytes) + public key (32 bytes).
+ """
+ # Generate a random signing key
+ signing_key = nacl.signing.SigningKey.generate()
+ public_key = signing_key.verify_key.encode()
+ seed = bytes(signing_key)
+
+ # Secret key is seed + public key
+ secret_key = seed + public_key
+
+ # Generate the address from the public key
+ address = address_from_public_key(public_key)
+
+ return secret_key, address
+
+
class MatchType(Enum):
START = "start"
ANYWHERE = "anywhere"
@@ -94,14 +118,14 @@ def _search_for_matching_address(keyword: str, match: MatchType, counter: Counte
batch_size = 100
while True:
- private_key, address = algosdk.account.generate_account() # type: ignore[no-untyped-call]
+ secret_key, address = _generate_account()
local_count += 1
if local_count % batch_size == 0:
counter.increment(local_count)
local_count = 0
if MATCH_FUNCTIONS[match](address, keyword):
- generated_mnemonic = from_private_key(private_key) # type: ignore[no-untyped-call]
+ generated_mnemonic = secret_key_to_mnemonic(secret_key)
queue.put((address, generated_mnemonic))
return
except KeyboardInterrupt:
@@ -155,8 +179,14 @@ def signal_handler(sig: int, frame: types.FrameType | None) -> typing.NoReturn:
for p in jobs:
p.terminate()
+ # Get seed and derive public key to create 64-byte private key (seed + pubkey)
+ seed = seed_from_mnemonic(mnemonic)
+ signing_key = nacl.signing.SigningKey(seed)
+ public_key = signing_key.verify_key.encode()
+ private_key = base64.b64encode(seed + public_key).decode()
+
return VanityAccount(
mnemonic=mnemonic,
address=address,
- private_key=to_private_key(mnemonic), # type: ignore[no-untyped-call]
+ private_key=private_key,
)
diff --git a/src/algokit/core/typed_client_generation.py b/src/algokit/core/typed_client_generation.py
index 5864c1d39..eea4177e7 100644
--- a/src/algokit/core/typed_client_generation.py
+++ b/src/algokit/core/typed_client_generation.py
@@ -15,8 +15,10 @@
from algokit.core.utils import (
extract_semantic_version,
extract_version_triple,
- find_valid_pipx_command,
+ find_valid_tool_runner_command,
get_npm_command,
+ get_tool_list_command,
+ get_tool_run_command,
)
logger = logging.getLogger(__name__)
@@ -216,14 +218,46 @@ def format_contract_name(self, contract_name: str) -> str:
def find_project_generate_command(self, version: str | None) -> list[str] | None:
"""
Try find the generate command in the project.
+ Checks uv-based projects first, then falls back to Poetry.
"""
+ # Try uv first (modern projects)
+ result = self._find_project_command_via_uv(version)
+ if result is not None:
+ return result
+
+ # Fall back to Poetry (legacy projects)
+ return self._find_project_command_via_poetry(version)
+
+ def _find_project_command_via_uv(self, version: str | None) -> list[str] | None:
+ """Check if the generator is installed in a uv-managed project."""
+ try:
+ result = proc.run(["uv", "pip", "show", PYTHON_PYPI_PACKAGE])
+ if result.exit_code == 0:
+ generate_command = ["uv", "run", PYTHON_GENERATE_COMMAND]
+ if version is not None:
+ for line in result.output.splitlines():
+ if line.startswith("Version:"):
+ installed_version = extract_version_triple(line.split(":", 1)[1].strip())
+ if extract_version_triple(version) == installed_version:
+ return generate_command
+ return None # version mismatch
+ else:
+ return generate_command
+ except OSError:
+ pass
+ except ValueError:
+ pass
+
+ return None
+
+ def _find_project_command_via_poetry(self, version: str | None) -> list[str] | None:
+ """Check if the generator is installed in a Poetry-managed project."""
try:
# Use the tree output as it puts the package info on the first line of the output
result = proc.run(["poetry", "show", PYTHON_PYPI_PACKAGE, "--tree"])
if result.exit_code == 0:
generate_command = ["poetry", "run", PYTHON_GENERATE_COMMAND]
if version is not None:
- installed_version = None
lines = result.output.splitlines()
if len(lines) > 0:
installed_version = extract_version_triple(lines[0])
@@ -238,12 +272,12 @@ def find_project_generate_command(self, version: str | None) -> list[str] | None
return None
- def find_global_generate_command(self, pipx_command: list[str], version: str | None) -> list[str] | None:
+ def find_global_generate_command(self, tool_command: list[str], version: str | None) -> list[str] | None:
"""
Try find the generate command installed globally.
"""
try:
- result = proc.run([*pipx_command, "list", "--short"])
+ result = proc.run(get_tool_list_command(tool_command))
if result.exit_code == 0:
generate_command = [PYTHON_GENERATE_COMMAND]
for line in result.output.splitlines():
@@ -267,7 +301,7 @@ def find_generate_command(self, version: str | None) -> list[str]:
Find Python generator command.
If a matching version is installed at a project level, use that.
If a matching version is installed at a global level, use that.
- Otherwise, run the matching version via pipx.
+ Otherwise, run via uvx/pipx.
"""
logger.debug("Searching for project installed client generator")
@@ -275,25 +309,20 @@ def find_generate_command(self, version: str | None) -> list[str]:
if project_result is not None:
return project_result
- pipx_command = find_valid_pipx_command(
- f"Unable to find pipx install so that the `{PYTHON_PYPI_PACKAGE}` can be run; "
- "please install pipx via https://pypa.github.io/pipx/ "
+ tool_command = find_valid_tool_runner_command(
+ f"Unable to find uvx or pipx so that `{PYTHON_PYPI_PACKAGE}` can be run; "
+ "please install uv via https://docs.astral.sh/uv/ "
"and then try `algokit generate client ...` again."
)
logger.debug("Searching for globally installed client generator")
- global_result = self.find_global_generate_command(pipx_command, version)
+ global_result = self.find_global_generate_command(tool_command, version)
if global_result is not None:
return global_result
- # when not installed, run via pipx
- logger.debug("No matching installed client generator found, run client generator via pipx")
- return [
- *pipx_command,
- "run",
- f"--spec={PYTHON_PYPI_PACKAGE}{f'=={version}' if version is not None else ''}",
- PYTHON_GENERATE_COMMAND,
- ]
+ spec = f"{PYTHON_PYPI_PACKAGE}{f'=={version}' if version is not None else ''}"
+ logger.debug("No matching installed client generator found, running via %s", tool_command[0])
+ return get_tool_run_command(tool_command, spec=spec, binary=PYTHON_GENERATE_COMMAND)
class TypeScriptClientGenerator(ClientGenerator, language="typescript", extension=".ts"):
diff --git a/src/algokit/core/utils.py b/src/algokit/core/utils.py
index cfff91090..e54f03aa0 100644
--- a/src/algokit/core/utils.py
+++ b/src/algokit/core/utils.py
@@ -103,30 +103,66 @@ def run_with_animation(
return result
-def find_valid_pipx_command(error_message: str) -> list[str]:
- for pipx_command in get_candidate_pipx_commands():
+def find_valid_tool_runner_command(error_message: str) -> list[str]:
+ """Find uvx (preferred) or pipx command. Returns base command list."""
+ # prefer uvx (uv's tool runner)
+ uvx_path = shutil.which("uvx")
+ if uvx_path:
+ return ["uvx"]
+
+ uv_path = shutil.which("uv")
+ if uv_path:
+ return ["uv"]
+
+ for pipx_command in _get_candidate_pipx_commands():
try:
pipx_version_result = proc.run([*pipx_command, "--version"])
except OSError:
- pass # in case of path/permission issues, go to next candidate
+ pass
else:
if pipx_version_result.exit_code == 0:
return pipx_command
- # If pipx isn't found in global path or python -m pipx then bail out
- # this is an exceptional circumstance since pipx should always be present with algokit
- # since it's installed with brew / winget as a dependency, and otherwise is used to install algokit
raise click.ClickException(error_message)
-def get_candidate_pipx_commands() -> Iterator[list[str]]:
- # first try is pipx via PATH
+def _get_candidate_pipx_commands() -> Iterator[list[str]]:
yield ["pipx"]
- # otherwise try getting an interpreter with pipx installed as a module,
- # this won't work if pipx is installed in its own venv but worth a shot
for python_path in get_python_paths():
yield [python_path, "-m", "pipx"]
+def is_uvx(command: list[str]) -> bool:
+ """Check if the resolved tool runner is uvx."""
+ return len(command) == 1 and command[0] == "uvx"
+
+
+def is_uv(command: list[str]) -> bool:
+ return len(command) == 1 and command[0] == "uv"
+
+
+def get_tool_run_command(base_command: list[str], *, spec: str, binary: str) -> list[str]:
+ """Build a command to run a tool via uvx or pipx."""
+ if is_uvx(base_command):
+ return ["uvx", f"--from={spec}", binary]
+ if is_uv(base_command):
+ return ["uv", "tool", "run", f"--from={spec}", binary]
+ return [*base_command, "run", f"--spec={spec}", binary]
+
+
+def get_tool_install_command(base_command: list[str], *, package: str) -> list[str]:
+ """Build a command to install a tool via uv or pipx."""
+ if is_uvx(base_command) or is_uv(base_command):
+ return ["uv", "tool", "install", package]
+ return [*base_command, "install", package]
+
+
+def get_tool_list_command(base_command: list[str]) -> list[str]:
+ """Build a command to list installed tools via uv or pipx."""
+ if is_uvx(base_command) or is_uv(base_command):
+ return ["uv", "tool", "list"]
+ return [*base_command, "list", "--short"]
+
+
def get_npm_command(error_message: str, *, is_npx: bool = False) -> list[str]:
command = "npx" if is_npx else "npm"
path = shutil.which(command)
@@ -204,6 +240,37 @@ def is_windows() -> bool:
return platform.system() == "Windows"
+def find_all_on_path(command: str) -> list[Path]:
+ matches: list[Path] = []
+ seen: set[str] = set()
+
+ for path_entry in environ.get("PATH", "").split(os.pathsep):
+ if not path_entry:
+ continue
+
+ match = shutil.which(command, path=path_entry)
+ if not match:
+ continue
+
+ match_path = Path(match)
+ try:
+ canonical_path = match_path.resolve()
+ except OSError:
+ canonical_path = match_path.absolute()
+
+ dedupe_key = str(canonical_path)
+ if is_windows():
+ dedupe_key = dedupe_key.lower()
+
+ if dedupe_key in seen:
+ continue
+
+ seen.add(dedupe_key)
+ matches.append(match_path)
+
+ return matches
+
+
def is_wsl() -> bool:
"""
detects if Python is running in WSL
diff --git a/tests/compile/test_python.py b/tests/compile/test_python.py
index cf0610522..41c62aeeb 100644
--- a/tests/compile/test_python.py
+++ b/tests/compile/test_python.py
@@ -38,6 +38,7 @@ def output_path(cwd: Path) -> Path:
def test_compile_py_help(mocker: MockerFixture) -> None:
proc_mock = ProcMock()
+ proc_mock.should_bad_exit_on(["uv", "run", "puyapy", "--version"], exit_code=1, output=["uv: not found"])
proc_mock.set_output(["poetry", "run", "puyapy", "--version"], output=["puyapy 1.0.0"])
proc_mock.set_output(["poetry", "run", "puyapy", "-h"], output=["Puyapy help"])
@@ -50,15 +51,14 @@ def test_compile_py_help(mocker: MockerFixture) -> None:
def test_puyapy_is_not_installed_anywhere(dummy_contract_path: Path, mocker: MockerFixture) -> None:
proc_mock = ProcMock()
+ proc_mock.should_bad_exit_on(["uv", "run", "puyapy", "--version"], exit_code=1, output=["uv: not found"])
proc_mock.should_bad_exit_on(["poetry", "run", "puyapy", "--version"], exit_code=1, output=["Puyapy not found"])
proc_mock.should_bad_exit_on(["puyapy", "--version"], exit_code=1, output=["Puyapy not found"])
- proc_mock.set_output(["pipx", "--version"], ["1.0.0"])
-
- proc_mock.set_output(["pipx", "install", "puya"], ["Puyapy is installed"])
- proc_mock.set_output(["puyapy", str(dummy_contract_path)], ["Done"])
+ proc_mock.set_output(["uvx", "--from=puyapy", "puyapy", str(dummy_contract_path)], ["Done"])
mocker.patch("algokit.core.proc.Popen").side_effect = proc_mock.popen
+ mocker.patch("algokit.core.utils.shutil.which", return_value="/bin/uvx")
result = invoke(f"compile python {_normalize_path(dummy_contract_path)}")
@@ -71,13 +71,14 @@ def test_specificed_puyapy_version_is_not_installed(dummy_contract_path: Path, m
target_version = "1.1.0"
proc_mock = ProcMock()
+ proc_mock.should_bad_exit_on(["uv", "run", "puyapy", "--version"], exit_code=1, output=["uv: not found"])
proc_mock.set_output(["poetry", "run", "puyapy", "--version"], output=[f"puyapy {current_version}"])
proc_mock.should_bad_exit_on(["puyapy", "--version"], exit_code=1, output=["Puyapy not found"])
- proc_mock.set_output(["pipx", "--version"], ["1.0.0"])
- proc_mock.set_output(["pipx", "run", f"puya=={target_version}", str(dummy_contract_path)], ["Done"])
+ proc_mock.set_output(["uvx", f"--from=puyapy=={target_version}", "puyapy", str(dummy_contract_path)], ["Done"])
mocker.patch("algokit.core.proc.Popen").side_effect = proc_mock.popen
+ mocker.patch("algokit.core.utils.shutil.which", return_value="/bin/uvx")
result = invoke(f"compile --version {target_version} py {_normalize_path(dummy_contract_path)}")
@@ -87,6 +88,7 @@ def test_specificed_puyapy_version_is_not_installed(dummy_contract_path: Path, m
def test_puyapy_is_installed_in_project(dummy_contract_path: Path, mocker: MockerFixture) -> None:
proc_mock = ProcMock()
+ proc_mock.should_bad_exit_on(["uv", "run", "puyapy", "--version"], exit_code=1, output=["uv: not found"])
proc_mock.set_output(["poetry", "run", "puyapy", "--version"], output=["puyapy 1.0.0"])
proc_mock.set_output(["poetry", "run", "puyapy", str(dummy_contract_path)], ["Done"])
@@ -101,6 +103,7 @@ def test_puyapy_is_installed_in_project(dummy_contract_path: Path, mocker: Mocke
def test_puyapy_is_installed_globally(dummy_contract_path: Path, mocker: MockerFixture) -> None:
proc_mock = ProcMock()
+ proc_mock.should_bad_exit_on(["uv", "run", "puyapy", "--version"], exit_code=1, output=["uv: not found"])
proc_mock.should_bad_exit_on(["poetry", "run", "puyapy", "--version"], exit_code=1, output=["Puyapy not found"])
proc_mock.set_output(["puyapy", "--version"], output=["puyapy 1.0.0"])
diff --git a/tests/compile/test_python.test_compile_py_help.approved.txt b/tests/compile/test_python.test_compile_py_help.approved.txt
index 4239a0ef4..40045bd3b 100644
--- a/tests/compile/test_python.test_compile_py_help.approved.txt
+++ b/tests/compile/test_python.test_compile_py_help.approved.txt
@@ -1,3 +1,5 @@
+DEBUG: Running 'uv run puyapy --version' in '{current_working_directory}'
+DEBUG: uv: uv: not found
DEBUG: Running 'poetry run puyapy --version' in '{current_working_directory}'
DEBUG: poetry: puyapy 1.0.0
DEBUG: Running 'poetry run puyapy -h' in '{current_working_directory}'
diff --git a/tests/compile/test_python.test_puyapy_is_installed_globally.approved.txt b/tests/compile/test_python.test_puyapy_is_installed_globally.approved.txt
index e08133acc..a539deec5 100644
--- a/tests/compile/test_python.test_puyapy_is_installed_globally.approved.txt
+++ b/tests/compile/test_python.test_puyapy_is_installed_globally.approved.txt
@@ -1,3 +1,5 @@
+DEBUG: Running 'uv run puyapy --version' in '{current_working_directory}'
+DEBUG: uv: uv: not found
DEBUG: Running 'poetry run puyapy --version' in '{current_working_directory}'
DEBUG: poetry: Puyapy not found
DEBUG: Running 'puyapy --version' in '{current_working_directory}'
diff --git a/tests/compile/test_python.test_puyapy_is_installed_in_project.approved.txt b/tests/compile/test_python.test_puyapy_is_installed_in_project.approved.txt
index ec7a6523a..840564fba 100644
--- a/tests/compile/test_python.test_puyapy_is_installed_in_project.approved.txt
+++ b/tests/compile/test_python.test_puyapy_is_installed_in_project.approved.txt
@@ -1,3 +1,5 @@
+DEBUG: Running 'uv run puyapy --version' in '{current_working_directory}'
+DEBUG: uv: uv: not found
DEBUG: Running 'poetry run puyapy --version' in '{current_working_directory}'
DEBUG: poetry: puyapy 1.0.0
DEBUG: Running 'poetry run puyapy {current_working_directory}/tests/compile/dummy_contract.py' in '{current_working_directory}'
diff --git a/tests/compile/test_python.test_puyapy_is_not_installed_anywhere.approved.txt b/tests/compile/test_python.test_puyapy_is_not_installed_anywhere.approved.txt
index d512daa25..a80ae7dbf 100644
--- a/tests/compile/test_python.test_puyapy_is_not_installed_anywhere.approved.txt
+++ b/tests/compile/test_python.test_puyapy_is_not_installed_anywhere.approved.txt
@@ -1,11 +1,9 @@
+DEBUG: Running 'uv run puyapy --version' in '{current_working_directory}'
+DEBUG: uv: uv: not found
DEBUG: Running 'poetry run puyapy --version' in '{current_working_directory}'
DEBUG: poetry: Puyapy not found
DEBUG: Running 'puyapy --version' in '{current_working_directory}'
DEBUG: puyapy: Puyapy not found
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: 1.0.0
-DEBUG: Running 'pipx run --spec=puyapy puyapy {current_working_directory}/tests/compile/dummy_contract.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-STDOUT
-STDERR
+DEBUG: Running 'uvx --from=puyapy puyapy {current_working_directory}/tests/compile/dummy_contract.py' in '{current_working_directory}'
+DEBUG: uvx: Done
+Done
diff --git a/tests/compile/test_python.test_specificed_puyapy_version_is_not_installed.approved.txt b/tests/compile/test_python.test_specificed_puyapy_version_is_not_installed.approved.txt
index 83e05df4e..df96629f9 100644
--- a/tests/compile/test_python.test_specificed_puyapy_version_is_not_installed.approved.txt
+++ b/tests/compile/test_python.test_specificed_puyapy_version_is_not_installed.approved.txt
@@ -1,11 +1,9 @@
+DEBUG: Running 'uv run puyapy --version' in '{current_working_directory}'
+DEBUG: uv: uv: not found
DEBUG: Running 'poetry run puyapy --version' in '{current_working_directory}'
DEBUG: poetry: puyapy 1.0.0
DEBUG: Running 'puyapy --version' in '{current_working_directory}'
DEBUG: puyapy: Puyapy not found
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: 1.0.0
-DEBUG: Running 'pipx run --spec=puyapy==1.1.0 puyapy {current_working_directory}/tests/compile/dummy_contract.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-STDOUT
-STDERR
+DEBUG: Running 'uvx --from=puyapy==1.1.0 puyapy {current_working_directory}/tests/compile/dummy_contract.py' in '{current_working_directory}'
+DEBUG: uvx: Done
+Done
diff --git a/tests/conftest.py b/tests/conftest.py
index 31939d2eb..8164af6af 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -241,3 +241,27 @@ def _always_check_image_versions(mocker: MockerFixture, request: pytest.FixtureR
return
mocker.patch("algokit.core.sandbox._should_check_image_versions", return_value=True)
mocker.patch("algokit.core.sandbox._update_image_version_cache")
+
+
+def generate_test_account() -> tuple[str, str, str]:
+ """Generate a random test account.
+
+ Returns:
+ tuple of (private_key_b64, address, mnemonic)
+ """
+ import base64
+
+ import nacl.signing
+ from algokit_utils.algo25 import secret_key_to_mnemonic
+ from algokit_utils.common import address_from_public_key
+
+ signing_key = nacl.signing.SigningKey.generate()
+ public_key = signing_key.verify_key.encode()
+ address = address_from_public_key(public_key)
+
+ # Private key is seed (32 bytes) + public key (32 bytes), base64 encoded
+ private_key_bytes = bytes(signing_key) + public_key
+ private_key_b64 = base64.b64encode(private_key_bytes).decode()
+ mnemonic = secret_key_to_mnemonic(private_key_bytes)
+
+ return private_key_b64, address, mnemonic
diff --git a/tests/doctor/test_doctor.py b/tests/doctor/test_doctor.py
index 68503d5af..322a1dc18 100644
--- a/tests/doctor/test_doctor.py
+++ b/tests/doctor/test_doctor.py
@@ -54,6 +54,7 @@ def _mock_happy_values(proc_mock: ProcMock) -> None:
proc_mock.set_output(["git", "--version"], ["git version 2.37.1 (Apple Git-137.1)"])
proc_mock.set_output(["python", "--version"], ["Python 3.10.0"])
proc_mock.set_output(["python3", "--version"], ["Python 3.11.0"])
+ proc_mock.set_output(["uv", "--version"], ["uv 0.6.0"])
proc_mock.set_output(["pipx", "--version"], ["1.1.0"])
proc_mock.set_output(["poetry", "--version"], ["blah blah", "", "Poetry (version 1.2.2)"])
proc_mock.set_output(["node", "--version"], ["v18.12.1"])
@@ -148,6 +149,7 @@ def test_doctor_with_docker_compose_version_unparseable(proc_mock: ProcMock) ->
["git", "--version"],
["python", "--version"],
["python3", "--version"],
+ ["uv", "--version"],
["pipx", "--version"],
["poetry", "--version"],
["node", "--version"],
@@ -221,7 +223,7 @@ def test_npm_permission_denied(proc_mock: ProcMock) -> None:
result = invoke("doctor")
- assert result.exit_code == 1
+ assert result.exit_code == 0
verify(result.output, scrubber=make_output_scrubber())
diff --git a/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[linux].approved.txt b/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[linux].approved.txt
index e78b2d5d7..40e788e84 100644
--- a/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[linux].approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[linux].approved.txt
@@ -8,9 +8,10 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: I AM A TEAPOT
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: I AM A TEAPOT
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: I AM A TEAPOT
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: I AM A TEAPOT
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: I AM A TEAPOT
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: I AM A TEAPOT
@@ -30,6 +31,8 @@ python: Command exited with code: -1
I AM A TEAPOT
python3: Command exited with code: -1
I AM A TEAPOT
+uv: Command exited with code: -1
+ I AM A TEAPOT
pipx: Command exited with code: -1
I AM A TEAPOT
poetry: Command exited with code: -1
diff --git a/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[macOS].approved.txt b/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[macOS].approved.txt
index 452c66ea4..e13eca0ac 100644
--- a/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[macOS].approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[macOS].approved.txt
@@ -8,9 +8,10 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: I AM A TEAPOT
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: I AM A TEAPOT
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: I AM A TEAPOT
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: I AM A TEAPOT
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: I AM A TEAPOT
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: I AM A TEAPOT
@@ -32,6 +33,8 @@ python: Command exited with code: -1
I AM A TEAPOT
python3: Command exited with code: -1
I AM A TEAPOT
+uv: Command exited with code: -1
+ I AM A TEAPOT
pipx: Command exited with code: -1
I AM A TEAPOT
poetry: Command exited with code: -1
diff --git a/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[windows].approved.txt b/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[windows].approved.txt
index f08da2249..296929287 100644
--- a/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[windows].approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[windows].approved.txt
@@ -8,9 +8,10 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: I AM A TEAPOT
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: I AM A TEAPOT
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: I AM A TEAPOT
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: I AM A TEAPOT
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: I AM A TEAPOT
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: I AM A TEAPOT
@@ -32,6 +33,8 @@ python: Command exited with code: -1
I AM A TEAPOT
python3: Command exited with code: -1
I AM A TEAPOT
+uv: Command exited with code: -1
+ I AM A TEAPOT
pipx: Command exited with code: -1
I AM A TEAPOT
poetry: Command exited with code: -1
diff --git a/tests/doctor/test_doctor.test_doctor_all_commands_not_found[linux].approved.txt b/tests/doctor/test_doctor.test_doctor_all_commands_not_found[linux].approved.txt
index e42f875ac..554df8f38 100644
--- a/tests/doctor/test_doctor.test_doctor_all_commands_not_found[linux].approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_all_commands_not_found[linux].approved.txt
@@ -8,9 +8,10 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: Command not found
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: Command not found
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: Command not found
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: Command not found
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Command not found
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: Command not found
@@ -27,13 +28,15 @@ git: Command not found!
Git required to run `algokit init`; install via https://github.com/git-guides/install-git
python: Command not found!
python3: Command not found!
+uv: Command not found!
+ uv is the recommended tool runner for AlgoKit;
+ install via https://docs.astral.sh/uv/
pipx: Command not found!
- pipx is required if poetry is not installed in order to install it automatically;
+ pipx can be used as a fallback tool runner if uv is not installed;
install via https://pypa.github.io/pipx/
poetry: Command not found!
- Poetry is required for some Python-based templates;
- install via `algokit project bootstrap` within project directory, or via:
- https://python-poetry.org/docs/#installation
+ Poetry may be needed for older Python-based templates;
+ install via https://python-poetry.org/docs/#installation
node: Command not found!
Node.js is required for some Node.js-based templates;
install via `algokit project bootstrap` within project directory, or via:
diff --git a/tests/doctor/test_doctor.test_doctor_all_commands_not_found[macOS].approved.txt b/tests/doctor/test_doctor.test_doctor_all_commands_not_found[macOS].approved.txt
index bb19a1e32..1f48feb23 100644
--- a/tests/doctor/test_doctor.test_doctor_all_commands_not_found[macOS].approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_all_commands_not_found[macOS].approved.txt
@@ -8,9 +8,10 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: Command not found
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: Command not found
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: Command not found
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: Command not found
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Command not found
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: Command not found
@@ -29,13 +30,15 @@ git: Command not found!
Git required to run `algokit init`; install via https://github.com/git-guides/install-git
python: Command not found!
python3: Command not found!
+uv: Command not found!
+ uv is the recommended tool runner for AlgoKit;
+ install via https://docs.astral.sh/uv/
pipx: Command not found!
- pipx is required if poetry is not installed in order to install it automatically;
+ pipx can be used as a fallback tool runner if uv is not installed;
install via https://pypa.github.io/pipx/
poetry: Command not found!
- Poetry is required for some Python-based templates;
- install via `algokit project bootstrap` within project directory, or via:
- https://python-poetry.org/docs/#installation
+ Poetry may be needed for older Python-based templates;
+ install via https://python-poetry.org/docs/#installation
node: Command not found!
Node.js is required for some Node.js-based templates;
install via `algokit project bootstrap` within project directory, or via:
diff --git a/tests/doctor/test_doctor.test_doctor_all_commands_not_found[windows].approved.txt b/tests/doctor/test_doctor.test_doctor_all_commands_not_found[windows].approved.txt
index bd58ce708..09ec30e9e 100644
--- a/tests/doctor/test_doctor.test_doctor_all_commands_not_found[windows].approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_all_commands_not_found[windows].approved.txt
@@ -8,9 +8,10 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: Command not found
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: Command not found
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: Command not found
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: Command not found
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Command not found
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: Command not found
@@ -30,13 +31,15 @@ git: Command not found!
or via https://github.com/git-guides/install-git#install-git-on-windows
python: Command not found!
python3: Command not found!
+uv: Command not found!
+ uv is the recommended tool runner for AlgoKit;
+ install via https://docs.astral.sh/uv/
pipx: Command not found!
- pipx is required if poetry is not installed in order to install it automatically;
+ pipx can be used as a fallback tool runner if uv is not installed;
install via https://pypa.github.io/pipx/
poetry: Command not found!
- Poetry is required for some Python-based templates;
- install via `algokit project bootstrap` within project directory, or via:
- https://python-poetry.org/docs/#installation
+ Poetry may be needed for older Python-based templates;
+ install via https://python-poetry.org/docs/#installation
node: Command not found!
Node.js is required for some Node.js-based templates;
install via `algokit project bootstrap` within project directory, or via:
diff --git a/tests/doctor/test_doctor.test_doctor_successful[linux].approved.txt b/tests/doctor/test_doctor.test_doctor_successful[linux].approved.txt
index 8288c32b1..62b6c0bd9 100644
--- a/tests/doctor/test_doctor.test_doctor_successful[linux].approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_successful[linux].approved.txt
@@ -8,12 +8,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -27,6 +27,7 @@ docker compose: 2.12.2
git: 2.37.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_doctor_successful[macOS].approved.txt b/tests/doctor/test_doctor.test_doctor_successful[macOS].approved.txt
index 07262e72e..fcf0cffd2 100644
--- a/tests/doctor/test_doctor.test_doctor_successful[macOS].approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_successful[macOS].approved.txt
@@ -8,12 +8,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -30,6 +30,7 @@ docker compose: 2.12.2
git: 2.37.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_doctor_successful[windows].approved.txt b/tests/doctor/test_doctor.test_doctor_successful[windows].approved.txt
index f1b84287a..e57fe39bc 100644
--- a/tests/doctor/test_doctor.test_doctor_successful[windows].approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_successful[windows].approved.txt
@@ -8,12 +8,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm.cmd --version' in '{current_working_directory}'
@@ -29,6 +29,7 @@ docker compose: 2.12.2
git: 2.37.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_doctor_with_copy.approved.txt b/tests/doctor/test_doctor.test_doctor_with_copy.approved.txt
index 07262e72e..fcf0cffd2 100644
--- a/tests/doctor/test_doctor.test_doctor_with_copy.approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_with_copy.approved.txt
@@ -8,12 +8,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -30,6 +30,7 @@ docker compose: 2.12.2
git: 2.37.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_gitpod.approved.txt b/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_gitpod.approved.txt
index c8d076d9f..6b74929c9 100644
--- a/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_gitpod.approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_gitpod.approved.txt
@@ -8,12 +8,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -30,6 +30,7 @@ docker compose: 2.10.0-gitpod.0
git: 2.37.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_unparseable.approved.txt b/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_unparseable.approved.txt
index 05b43bcd1..5f57d6968 100644
--- a/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_unparseable.approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_unparseable.approved.txt
@@ -9,12 +9,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -34,6 +34,7 @@ docker compose: {"version": "TEAPOT"}
git: 2.37.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_warning.approved.txt b/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_warning.approved.txt
index b48ee2e16..a8ad1b08e 100644
--- a/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_warning.approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_with_docker_compose_version_warning.approved.txt
@@ -8,12 +8,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -32,6 +32,7 @@ docker compose: 2.1.3
git: 2.37.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_doctor_with_weird_values_on_mac.approved.txt b/tests/doctor/test_doctor.test_doctor_with_weird_values_on_mac.approved.txt
index cc7820a12..488fbf0f7 100644
--- a/tests/doctor/test_doctor.test_doctor_with_weird_values_on_mac.approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_with_weird_values_on_mac.approved.txt
@@ -8,12 +8,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -29,6 +29,7 @@ docker compose: 2.12.2
git: 2.37.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_doctor_with_weird_values_on_windows.approved.txt b/tests/doctor/test_doctor.test_doctor_with_weird_values_on_windows.approved.txt
index fc6cf3da3..c4b7f4f02 100644
--- a/tests/doctor/test_doctor.test_doctor_with_weird_values_on_windows.approved.txt
+++ b/tests/doctor/test_doctor.test_doctor_with_weird_values_on_windows.approved.txt
@@ -8,12 +8,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm.cmd --version' in '{current_working_directory}'
@@ -30,6 +30,7 @@ docker compose: 2.12.2
git: 2.31.0.windows.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_new_algokit_version_available.approved.txt b/tests/doctor/test_doctor.test_new_algokit_version_available.approved.txt
index d56dee2e5..f699bca80 100644
--- a/tests/doctor/test_doctor.test_new_algokit_version_available.approved.txt
+++ b/tests/doctor/test_doctor.test_new_algokit_version_available.approved.txt
@@ -8,12 +8,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -30,6 +30,7 @@ docker compose: 2.12.2
git: 2.37.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_npm_permission_denied.approved.txt b/tests/doctor/test_doctor.test_npm_permission_denied.approved.txt
index 103704a6c..ae6419819 100644
--- a/tests/doctor/test_doctor.test_npm_permission_denied.approved.txt
+++ b/tests/doctor/test_doctor.test_npm_permission_denied.approved.txt
@@ -8,12 +8,12 @@ DEBUG: Running 'python --version' in '{current_working_directory}'
DEBUG: python: Python 3.10.0
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -30,6 +30,7 @@ docker compose: 2.12.2
git: 2.37.1
python: 3.10.0 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_unexpected_exception_locating_executable.approved.txt b/tests/doctor/test_doctor.test_unexpected_exception_locating_executable.approved.txt
index dd9d4a17c..60384a82b 100644
--- a/tests/doctor/test_doctor.test_unexpected_exception_locating_executable.approved.txt
+++ b/tests/doctor/test_doctor.test_unexpected_exception_locating_executable.approved.txt
@@ -10,12 +10,12 @@ DEBUG: Failed to locate python: OH NO
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
DEBUG: Failed to locate python3: OH NO
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -32,6 +32,7 @@ docker compose: 2.12.2
git: 2.37.1
python: 3.10.0f (location: unknown)
python3: 3.11.0f (location: unknown)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/doctor/test_doctor.test_unparseable_python_version.approved.txt b/tests/doctor/test_doctor.test_unparseable_python_version.approved.txt
index 368395e5b..73c311da8 100644
--- a/tests/doctor/test_doctor.test_unparseable_python_version.approved.txt
+++ b/tests/doctor/test_doctor.test_unparseable_python_version.approved.txt
@@ -10,12 +10,12 @@ DEBUG: python: 1-2-3
DEBUG: python: abc
DEBUG: Running 'python3 --version' in '{current_working_directory}'
DEBUG: python3: Python 3.11.0
+DEBUG: Running 'uv --version' in '{current_working_directory}'
+DEBUG: uv: uv 0.6.0
DEBUG: Running 'pipx --version' in '{current_working_directory}'
DEBUG: pipx: 1.1.0
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: blah blah
DEBUG: poetry:
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Running 'node --version' in '{current_working_directory}'
DEBUG: node: v18.12.1
DEBUG: Running 'npm --version' in '{current_working_directory}'
@@ -32,6 +32,7 @@ docker compose: 2.12.2
git: 2.37.1
python: 1-2-3 (location: /usr/local/bin/python)
python3: 3.11.0 (location: /usr/local/bin/python3)
+uv: 0.6.0
pipx: 1.1.0
poetry: 1.2.2
node: 18.12.1
diff --git a/tests/explore/test_explore.py b/tests/explore/test_explore.py
index 87678f0b2..e20e0ee5e 100644
--- a/tests/explore/test_explore.py
+++ b/tests/explore/test_explore.py
@@ -16,7 +16,7 @@ def test_explore(command: str, mocker: MockerFixture) -> None:
assert result.exit_code == 0
verify(
- get_combined_verify_output(result.output, "launch args", launch_mock.call_args),
+ get_combined_verify_output(result.output, "launch args", str(launch_mock.call_args)),
options=NamerFactory.with_parameters(command or "localnet"),
)
diff --git a/tests/generate/test_generate_client.py b/tests/generate/test_generate_client.py
index 99273297d..d283ff93c 100644
--- a/tests/generate/test_generate_client.py
+++ b/tests/generate/test_generate_client.py
@@ -36,7 +36,7 @@ def _get_npm_command() -> str:
def _get_python_generate_command(version: str | None, application_json: Path, expected_output_path: Path) -> str:
return (
- f"pipx run --spec={PYTHON_PYPI_PACKAGE}{f'=={version}' if version is not None else ''} "
+ f"uvx --from={PYTHON_PYPI_PACKAGE}{f'=={version}' if version is not None else ''} "
f"algokitgen-py -a {application_json} -o {expected_output_path}"
)
@@ -86,6 +86,7 @@ def which_mock(mocker: MockerFixture) -> WhichMock:
which_mock.add("npx")
which_mock.add("npm")
which_mock.add("pipx")
+ which_mock.add("uvx")
mocker.patch("algokit.core.typed_client_generation.shutil.which").side_effect = which_mock.which
return which_mock
@@ -122,17 +123,19 @@ def test_generate_client_python(
expected_output_path: Path,
request: pytest.FixtureRequest,
) -> None:
+ proc_mock.should_bad_exit_on(["uv", "pip", "show", PYTHON_PYPI_PACKAGE])
proc_mock.should_bad_exit_on(["poetry", "show", PYTHON_PYPI_PACKAGE, "--tree"])
- proc_mock.should_bad_exit_on(["pipx", "list", "--short"])
+ proc_mock.should_bad_exit_on(["uv", "tool", "list"])
result = invoke(f"generate client {application_json.name} {options}", cwd=application_json.parent)
assert result.exit_code == 0
+ option_args = options.split()
verify(
_normalize_output(result.output),
namer=PyTestNamer(request),
- options=NamerFactory.with_parameters(*options.split()),
+ options=NamerFactory.with_parameters(*option_args),
)
- version = options.split()[-1] if "--version" in options or "-v" in options else None
+ version = option_args[-1] if "--version" in options or "-v" in options else None
assert len(proc_mock.called) == 4 # noqa: PLR2004
assert " ".join(proc_mock.called[3].command).startswith(
_get_python_generate_command(version, application_json, expected_output_path)
@@ -154,9 +157,10 @@ def test_python_generator_is_installed_in_project(application_json: Path, proc_m
@pytest.mark.usefixtures("proc_mock")
def test_python_generator_is_installed_globally(application_json: Path, proc_mock: ProcMock) -> None:
+ proc_mock.should_bad_exit_on(["uv", "pip", "show", PYTHON_PYPI_PACKAGE])
proc_mock.should_bad_exit_on(["poetry", "show", PYTHON_PYPI_PACKAGE, "--tree"])
proc_mock.set_output(
- ["pipx", "list", "--short"],
+ ["uv", "tool", "list"],
output=["algokit 1.13.0", "poetry 1.6.1", f"{PYTHON_PYPI_PACKAGE} 1.1.2"],
)
@@ -168,12 +172,13 @@ def test_python_generator_is_installed_globally(application_json: Path, proc_moc
@pytest.mark.usefixtures("proc_mock")
def test_python_generator_version_is_not_installed_anywhere(application_json: Path, proc_mock: ProcMock) -> None:
+ proc_mock.should_bad_exit_on(["uv", "pip", "show", PYTHON_PYPI_PACKAGE])
proc_mock.set_output(
["poetry", "show", PYTHON_PYPI_PACKAGE, "--tree"],
output=[f"{PYTHON_PYPI_PACKAGE} 1.1.2 Algorand typed client Generator", "└── algokit-utils 2.2.1"],
)
proc_mock.set_output(
- ["pipx", "list", "--short"],
+ ["uv", "tool", "list"],
output=["algokit 1.13.0", "poetry 1.6.1", f"{PYTHON_PYPI_PACKAGE} 1.1.2"],
)
@@ -187,8 +192,10 @@ def test_python_generator_version_is_not_installed_anywhere(application_json: Pa
@pytest.mark.usefixtures("proc_mock")
def test_pipx_missing(application_json: Path, mocker: MockerFixture, proc_mock: ProcMock) -> None:
+ proc_mock.should_bad_exit_on(["uv", "pip", "show", PYTHON_PYPI_PACKAGE])
proc_mock.should_bad_exit_on(["poetry", "show", PYTHON_PYPI_PACKAGE, "--tree"])
- mocker.patch("algokit.core.utils.get_candidate_pipx_commands", return_value=[])
+ mocker.patch("algokit.core.utils.shutil.which", return_value=None)
+ mocker.patch("algokit.core.utils._get_candidate_pipx_commands", return_value=[])
result = invoke(f"generate client -o client.py -l python {application_json.name}", cwd=application_json.parent)
assert result.exit_code == 1
@@ -204,8 +211,9 @@ def test_pipx_missing(application_json: Path, mocker: MockerFixture, proc_mock:
def test_generate_client_python_arc32_filename(
proc_mock: ProcMock, arc32_json: Path, options: str, expected_output_path: Path
) -> None:
+ proc_mock.should_bad_exit_on(["uv", "pip", "show", PYTHON_PYPI_PACKAGE])
proc_mock.should_bad_exit_on(["poetry", "show", PYTHON_PYPI_PACKAGE, "--tree"])
- proc_mock.should_bad_exit_on(["pipx", "list", "--short"])
+ proc_mock.should_bad_exit_on(["uv", "tool", "list"])
result = invoke(f"generate client {options} {arc32_json.name}", cwd=arc32_json.parent)
@@ -227,8 +235,9 @@ def test_generate_client_python_arc56_filename(
options: str,
expected_output_path: Path,
) -> None:
+ proc_mock.should_bad_exit_on(["uv", "pip", "show", PYTHON_PYPI_PACKAGE])
proc_mock.should_bad_exit_on(["poetry", "show", PYTHON_PYPI_PACKAGE, "--tree"])
- proc_mock.should_bad_exit_on(["pipx", "list", "--short"])
+ proc_mock.should_bad_exit_on(["uv", "tool", "list"])
result = invoke(f"generate client {options} {arc56_json.name}", cwd=arc56_json.parent)
@@ -252,8 +261,9 @@ def test_generate_client_python_multiple_app_specs_in_directory(
options: str,
expected_output_path: Path,
) -> None:
+ proc_mock.should_bad_exit_on(["uv", "pip", "show", PYTHON_PYPI_PACKAGE])
proc_mock.should_bad_exit_on(["poetry", "show", PYTHON_PYPI_PACKAGE, "--tree"])
- proc_mock.should_bad_exit_on(["pipx", "list", "--short"])
+ proc_mock.should_bad_exit_on(["uv", "tool", "list"])
result = invoke(f"generate client {options} .", cwd=arc56_json.parent)
@@ -295,12 +305,13 @@ def test_generate_client_typescript(
result = invoke(f"generate client {application_json.name} {options}", cwd=application_json.parent)
assert result.exit_code == 0
+ option_args = options.split()
verify(
_normalize_output(result.output),
namer=PyTestNamer(request),
- options=NamerFactory.with_parameters(*options.split()),
+ options=NamerFactory.with_parameters(*option_args),
)
- version = options.split()[-1] if "--version" in options or "-v" in options else "latest"
+ version = option_args[-1] if "--version" in options or "-v" in options else "latest"
assert len(proc_mock.called) == 3 # noqa: PLR2004
assert " ".join(proc_mock.called[2].command).startswith(
_get_typescript_generate_command(version, application_json, expected_output_path)
diff --git a/tests/generate/test_generate_client.test_generate_client_no_app_spec_found.approved.txt b/tests/generate/test_generate_client.test_generate_client_no_app_spec_found.approved.txt
index 1ce175b48..a2e5aa1eb 100644
--- a/tests/generate/test_generate_client.test_generate_client_no_app_spec_found.approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_no_app_spec_found.approved.txt
@@ -1,5 +1,5 @@
DEBUG: Searching for project installed client generator
-DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
Error: No app specs found
diff --git a/tests/generate/test_generate_client.test_generate_client_output_path_is_dir.approved.txt b/tests/generate/test_generate_client.test_generate_client_output_path_is_dir.approved.txt
index 1f0b38813..1ce0f0aee 100644
--- a/tests/generate/test_generate_client.test_generate_client_output_path_is_dir.approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_output_path_is_dir.approved.txt
@@ -1,5 +1,5 @@
DEBUG: Searching for project installed client generator
-DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
ERROR: Could not output to hello_world_app.py as it already exists and is a directory
diff --git a/tests/generate/test_generate_client.test_generate_client_python[--output {contract_name}.py-hello_world_app.py].approved.txt b/tests/generate/test_generate_client.test_generate_client_python[--output {contract_name}.py-hello_world_app.py].approved.txt
index 13b76eaa3..1bc267577 100644
--- a/tests/generate/test_generate_client.test_generate_client_python[--output {contract_name}.py-hello_world_app.py].approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_python[--output {contract_name}.py-hello_world_app.py].approved.txt
@@ -1,18 +1,18 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/application.json and writing to hello_world_app.py
-DEBUG: Running 'pipx run --spec=algokit-client-generator algokitgen-py -a {current_working_directory}/application.json -o hello_world_app.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator algokitgen-py -a {current_working_directory}/application.json -o hello_world_app.py' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_generate_client_python[-l python -v 1.1.0-hello_world_app_client.py].approved.txt b/tests/generate/test_generate_client.test_generate_client_python[-l python -v 1.1.0-hello_world_app_client.py].approved.txt
index e2d9e0751..14f40dda0 100644
--- a/tests/generate/test_generate_client.test_generate_client_python[-l python -v 1.1.0-hello_world_app_client.py].approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_python[-l python -v 1.1.0-hello_world_app_client.py].approved.txt
@@ -1,18 +1,18 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/application.json and writing to hello_world_app_client.py
-DEBUG: Running 'pipx run --spec=algokit-client-generator==1.1.0 algokitgen-py -a {current_working_directory}/application.json -o hello_world_app_client.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator==1.1.0 algokitgen-py -a {current_working_directory}/application.json -o hello_world_app_client.py' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_generate_client_python[-l python-hello_world_app_client.py].approved.txt b/tests/generate/test_generate_client.test_generate_client_python[-l python-hello_world_app_client.py].approved.txt
index 588fc447f..4d1e277e4 100644
--- a/tests/generate/test_generate_client.test_generate_client_python[-l python-hello_world_app_client.py].approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_python[-l python-hello_world_app_client.py].approved.txt
@@ -1,18 +1,18 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/application.json and writing to hello_world_app_client.py
-DEBUG: Running 'pipx run --spec=algokit-client-generator algokitgen-py -a {current_working_directory}/application.json -o hello_world_app_client.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator algokitgen-py -a {current_working_directory}/application.json -o hello_world_app_client.py' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_generate_client_python[-o client.py --language python --version 1.1.2-client.py].approved.txt b/tests/generate/test_generate_client.test_generate_client_python[-o client.py --language python --version 1.1.2-client.py].approved.txt
index fc72588b4..55b6fd063 100644
--- a/tests/generate/test_generate_client.test_generate_client_python[-o client.py --language python --version 1.1.2-client.py].approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_python[-o client.py --language python --version 1.1.2-client.py].approved.txt
@@ -1,18 +1,18 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/application.json and writing to client.py
-DEBUG: Running 'pipx run --spec=algokit-client-generator==1.1.2 algokitgen-py -a {current_working_directory}/application.json -o client.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator==1.1.2 algokitgen-py -a {current_working_directory}/application.json -o client.py' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_generate_client_python[-o client.py -p --mode minimal-client.py].approved.txt b/tests/generate/test_generate_client.test_generate_client_python[-o client.py -p --mode minimal-client.py].approved.txt
index 695a8ca57..25f514e20 100644
--- a/tests/generate/test_generate_client.test_generate_client_python[-o client.py -p --mode minimal-client.py].approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_python[-o client.py -p --mode minimal-client.py].approved.txt
@@ -1,18 +1,18 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/application.json and writing to client.py
-DEBUG: Running 'pipx run --spec=algokit-client-generator algokitgen-py -a {current_working_directory}/application.json -o client.py -p --mode minimal' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator algokitgen-py -a {current_working_directory}/application.json -o client.py -p --mode minimal' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_generate_client_python[-o client.py-client.py].approved.txt b/tests/generate/test_generate_client.test_generate_client_python[-o client.py-client.py].approved.txt
index 05a1fb6cb..9cc91cf10 100644
--- a/tests/generate/test_generate_client.test_generate_client_python[-o client.py-client.py].approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_python[-o client.py-client.py].approved.txt
@@ -1,18 +1,18 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/application.json and writing to client.py
-DEBUG: Running 'pipx run --spec=algokit-client-generator algokitgen-py -a {current_working_directory}/application.json -o client.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator algokitgen-py -a {current_working_directory}/application.json -o client.py' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_generate_client_python[-o client.ts --language python-client.ts].approved.txt b/tests/generate/test_generate_client.test_generate_client_python[-o client.ts --language python-client.ts].approved.txt
index ce6a82e6f..6c10188a3 100644
--- a/tests/generate/test_generate_client.test_generate_client_python[-o client.ts --language python-client.ts].approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_python[-o client.ts --language python-client.ts].approved.txt
@@ -1,18 +1,18 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/application.json and writing to client.ts
-DEBUG: Running 'pipx run --spec=algokit-client-generator algokitgen-py -a {current_working_directory}/application.json -o client.ts' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator algokitgen-py -a {current_working_directory}/application.json -o client.ts' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_generate_client_python_arc32_filename.-o.client.py.approved.txt b/tests/generate/test_generate_client.test_generate_client_python_arc32_filename.-o.client.py.approved.txt
index c5c7930f5..15a9d72d5 100644
--- a/tests/generate/test_generate_client.test_generate_client_python_arc32_filename.-o.client.py.approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_python_arc32_filename.-o.client.py.approved.txt
@@ -1,18 +1,18 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/app.arc32.json and writing to client.py
-DEBUG: Running 'pipx run --spec=algokit-client-generator algokitgen-py -a {current_working_directory}/app.arc32.json -o client.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator algokitgen-py -a {current_working_directory}/app.arc32.json -o client.py' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_generate_client_python_arc56_filename.-o.client.py.approved.txt b/tests/generate/test_generate_client.test_generate_client_python_arc56_filename.-o.client.py.approved.txt
index 0025cbc82..60b666f16 100644
--- a/tests/generate/test_generate_client.test_generate_client_python_arc56_filename.-o.client.py.approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_python_arc56_filename.-o.client.py.approved.txt
@@ -1,18 +1,18 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/app.arc56.json and writing to client.py
-DEBUG: Running 'pipx run --spec=algokit-client-generator algokitgen-py -a {current_working_directory}/app.arc56.json -o client.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator algokitgen-py -a {current_working_directory}/app.arc56.json -o client.py' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_generate_client_python_multiple_app_specs_in_directory.-o.client.py.approved.txt b/tests/generate/test_generate_client.test_generate_client_python_multiple_app_specs_in_directory.-o.client.py.approved.txt
index 0025cbc82..60b666f16 100644
--- a/tests/generate/test_generate_client.test_generate_client_python_multiple_app_specs_in_directory.-o.client.py.approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_python_multiple_app_specs_in_directory.-o.client.py.approved.txt
@@ -1,18 +1,18 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/app.arc56.json and writing to client.py
-DEBUG: Running 'pipx run --spec=algokit-client-generator algokitgen-py -a {current_working_directory}/app.arc56.json -o client.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator algokitgen-py -a {current_working_directory}/app.arc56.json -o client.py' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_generate_client_recursive.approved.txt b/tests/generate/test_generate_client.test_generate_client_recursive.approved.txt
index 45f41d9a4..782ab9916 100644
--- a/tests/generate/test_generate_client.test_generate_client_recursive.approved.txt
+++ b/tests/generate/test_generate_client.test_generate_client_recursive.approved.txt
@@ -1,22 +1,22 @@
DEBUG: Searching for project installed client generator
-DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
Generating Python client code for application specified in {current_working_directory}/dir1/application.json and writing to {current_working_directory}/dir1/output.py
-DEBUG: Running 'poetry run algokitgen-py -a {current_working_directory}/dir1/application.json -o {current_working_directory}/dir1/output.py' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
+DEBUG: Running 'uv run algokitgen-py -a {current_working_directory}/dir1/application.json -o {current_working_directory}/dir1/output.py' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
STDOUT
STDERR
Generating Python client code for application specified in {current_working_directory}/dir2/application.json and writing to {current_working_directory}/dir2/output.py
-DEBUG: Running 'poetry run algokitgen-py -a {current_working_directory}/dir2/application.json -o {current_working_directory}/dir2/output.py' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
+DEBUG: Running 'uv run algokitgen-py -a {current_working_directory}/dir2/application.json -o {current_working_directory}/dir2/output.py' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
STDOUT
STDERR
Generating Python client code for application specified in {current_working_directory}/dir2/sub_dir/application.json and writing to {current_working_directory}/dir2/sub_dir/output.py
-DEBUG: Running 'poetry run algokitgen-py -a {current_working_directory}/dir2/sub_dir/application.json -o {current_working_directory}/dir2/sub_dir/output.py' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
+DEBUG: Running 'uv run algokitgen-py -a {current_working_directory}/dir2/sub_dir/application.json -o {current_working_directory}/dir2/sub_dir/output.py' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_pipx_missing.approved.txt b/tests/generate/test_generate_client.test_pipx_missing.approved.txt
index ba509bec1..4cf17f0c2 100644
--- a/tests/generate/test_generate_client.test_pipx_missing.approved.txt
+++ b/tests/generate/test_generate_client.test_pipx_missing.approved.txt
@@ -1,5 +1,8 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-Error: Unable to find pipx install so that the `algokit-client-generator` can be run; please install pipx via https://pypa.github.io/pipx/ and then try `algokit generate client ...` again.
+Error: Unable to find uvx or pipx so that `algokit-client-generator` can be run; please install uv via https://docs.astral.sh/uv/ and then try `algokit generate client ...` again.
diff --git a/tests/generate/test_generate_client.test_python_generator_is_installed_globally.approved.txt b/tests/generate/test_generate_client.test_python_generator_is_installed_globally.approved.txt
index 13318dab0..9f716597e 100644
--- a/tests/generate/test_generate_client.test_python_generator_is_installed_globally.approved.txt
+++ b/tests/generate/test_generate_client.test_python_generator_is_installed_globally.approved.txt
@@ -1,15 +1,15 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: algokit 1.13.0
-DEBUG: pipx: poetry 1.6.1
-DEBUG: pipx: algokit-client-generator 1.1.2
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: algokit 1.13.0
+DEBUG: uv: poetry 1.6.1
+DEBUG: uv: algokit-client-generator 1.1.2
Generating Python client code for application specified in {current_working_directory}/application.json and writing to client.py
DEBUG: Running 'algokitgen-py -a {current_working_directory}/application.json -o client.py' in '{current_working_directory}'
DEBUG: algokitgen-py: STDOUT
diff --git a/tests/generate/test_generate_client.test_python_generator_is_installed_in_project.approved.txt b/tests/generate/test_generate_client.test_python_generator_is_installed_in_project.approved.txt
index 6193cbe6e..b78b253a0 100644
--- a/tests/generate/test_generate_client.test_python_generator_is_installed_in_project.approved.txt
+++ b/tests/generate/test_generate_client.test_python_generator_is_installed_in_project.approved.txt
@@ -1,10 +1,10 @@
DEBUG: Searching for project installed client generator
-DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
-DEBUG: poetry: algokit-client-generator 1.1.2 Algorand typed client Generator
-DEBUG: poetry: └── algokit-utils 2.2.1
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
Generating Python client code for application specified in {current_working_directory}/application.json and writing to client.py
-DEBUG: Running 'poetry run algokitgen-py -a {current_working_directory}/application.json -o client.py' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
+DEBUG: Running 'uv run algokitgen-py -a {current_working_directory}/application.json -o client.py' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
STDOUT
STDERR
diff --git a/tests/generate/test_generate_client.test_python_generator_version_is_not_installed_anywhere.approved.txt b/tests/generate/test_generate_client.test_python_generator_version_is_not_installed_anywhere.approved.txt
index c5d101d51..d335b6ab8 100644
--- a/tests/generate/test_generate_client.test_python_generator_version_is_not_installed_anywhere.approved.txt
+++ b/tests/generate/test_generate_client.test_python_generator_version_is_not_installed_anywhere.approved.txt
@@ -1,19 +1,19 @@
DEBUG: Searching for project installed client generator
+DEBUG: Running 'uv pip show algokit-client-generator' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
DEBUG: Running 'poetry show algokit-client-generator --tree' in '{current_working_directory}'
DEBUG: poetry: algokit-client-generator 1.1.2 Algorand typed client Generator
DEBUG: poetry: └── algokit-utils 2.2.1
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
DEBUG: Searching for globally installed client generator
-DEBUG: Running 'pipx list --short' in '{current_working_directory}'
-DEBUG: pipx: algokit 1.13.0
-DEBUG: pipx: poetry 1.6.1
-DEBUG: pipx: algokit-client-generator 1.1.2
-DEBUG: No matching installed client generator found, run client generator via pipx
+DEBUG: Running 'uv tool list' in '{current_working_directory}'
+DEBUG: uv: algokit 1.13.0
+DEBUG: uv: poetry 1.6.1
+DEBUG: uv: algokit-client-generator 1.1.2
+DEBUG: No matching installed client generator found, running via uvx
Generating Python client code for application specified in {current_working_directory}/application.json and writing to client.py
-DEBUG: Running 'pipx run --spec=algokit-client-generator==1.2.0 algokitgen-py -a {current_working_directory}/application.json -o client.py' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+DEBUG: Running 'uvx --from=algokit-client-generator==1.2.0 algokitgen-py -a {current_working_directory}/application.json -o client.py' in '{current_working_directory}'
+DEBUG: uvx: STDOUT
+DEBUG: uvx: STDERR
STDOUT
STDERR
diff --git a/tests/init/test_init.test_init_minimal_interaction_required_yes_git_no_network.approved.txt b/tests/init/test_init.test_init_minimal_interaction_required_yes_git_no_network.approved.txt
index e9c1df1a8..6eb9a120a 100644
--- a/tests/init/test_init.test_init_minimal_interaction_required_yes_git_no_network.approved.txt
+++ b/tests/init/test_init.test_init_minimal_interaction_required_yes_git_no_network.approved.txt
@@ -3,6 +3,14 @@ DEBUG: No .algokit.toml file found in the project directory.
WARNING: Community templates have not been reviewed, and can execute arbitrary code.
Please inspect the template repository, and pay particular attention to the values of _tasks, _migrations and _jinja_extensions in copier.yml
? Continue anyway? (y/N)
+? Continue anyway? (y/N)
+? Continue anyway? (y/N)
+? Continue anyway? (y/N)
+? Continue anyway? (y/N)
+? Continue anyway? (y/N)
+? Continue anyway? (y/N)
+? Continue anyway? (y/N)
+? Continue anyway? (y/N)
DEBUG: template source = {test_parent_directory}/copier-helloworld.bundle
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
@@ -34,7 +42,7 @@ DEBUG: git: Initialized empty Git repository in {current_working_directory}/myap
DEBUG: Running 'git checkout -b main' in '{current_working_directory}/myapp'
DEBUG: git: Switched to a new branch 'main'
DEBUG: Running 'git add --all' in '{current_working_directory}/myapp'
-DEBUG: Running 'git commit -m Project initialised with AlgoKit CLI using template: {test_parent_directory}/copier-helloworld.bundle' in '{current_working_directory}/myapp'
+DEBUG: Running 'git -c commit.gpgsign=false commit -m Project initialised with AlgoKit CLI using template: {test_parent_directory}/copier-helloworld.bundle' in '{current_working_directory}/myapp'
DEBUG: git: [main (root-commit) {git_initial_commit_hash}] Project initialised with AlgoKit CLI using template: {test_parent_directory}/copier-helloworld.bundle
DEBUG: git: 1 file changed, 1 insertion(+)
DEBUG: git: create mode 100644 myapp/helloworld.txt
diff --git a/tests/init/test_init_vibe.py b/tests/init/test_init_vibe.py
new file mode 100644
index 000000000..4daddbb8d
--- /dev/null
+++ b/tests/init/test_init_vibe.py
@@ -0,0 +1,67 @@
+from pathlib import Path
+from typing import cast
+
+import pytest
+from pytest_mock import MockerFixture
+
+from algokit.cli.init.command import _maybe_setup_vibecode
+
+
+@pytest.mark.parametrize("run_bootstrap", [True, False, None])
+def test_maybe_setup_vibecode_skips_when_using_defaults(mocker: MockerFixture, run_bootstrap: object) -> None:
+ prompt_mock = mocker.patch("algokit.cli.init.command.questionary_extensions.prompt_confirm")
+ vibe_setup_mock = mocker.patch("algokit.cli.vibe.run_vibe_setup")
+
+ _maybe_setup_vibecode(
+ project_path=Path("/tmp/project"),
+ use_defaults=True,
+ run_bootstrap=cast("bool | None", run_bootstrap),
+ )
+
+ prompt_mock.assert_not_called()
+ vibe_setup_mock.assert_not_called()
+
+
+@pytest.mark.parametrize("run_bootstrap", [True, False])
+def test_maybe_setup_vibecode_skips_when_bootstrap_flag_is_explicit(
+ mocker: MockerFixture, run_bootstrap: object
+) -> None:
+ prompt_mock = mocker.patch("algokit.cli.init.command.questionary_extensions.prompt_confirm")
+ vibe_setup_mock = mocker.patch("algokit.cli.vibe.run_vibe_setup")
+
+ _maybe_setup_vibecode(
+ project_path=Path("/tmp/project"),
+ use_defaults=False,
+ run_bootstrap=cast("bool", run_bootstrap),
+ )
+
+ prompt_mock.assert_not_called()
+ vibe_setup_mock.assert_not_called()
+
+
+def test_maybe_setup_vibecode_prompt_no(mocker: MockerFixture) -> None:
+ prompt_mock = mocker.patch("algokit.cli.init.command.questionary_extensions.prompt_confirm", return_value=False)
+ vibe_setup_mock = mocker.patch("algokit.cli.vibe.run_vibe_setup")
+
+ _maybe_setup_vibecode(project_path=Path("/tmp/project"), use_defaults=False, run_bootstrap=None)
+
+ prompt_mock.assert_called_once()
+ vibe_setup_mock.assert_not_called()
+
+
+def test_maybe_setup_vibecode_prompt_yes_runs_setup_in_project_dir(mocker: MockerFixture) -> None:
+ prompt_mock = mocker.patch("algokit.cli.init.command.questionary_extensions.prompt_confirm", return_value=True)
+ vibe_setup_mock = mocker.patch("algokit.cli.vibe.run_vibe_setup")
+ project_path = Path("/tmp/project")
+
+ _maybe_setup_vibecode(project_path=project_path, use_defaults=False, run_bootstrap=None)
+
+ prompt_mock.assert_called_once()
+ vibe_setup_mock.assert_called_once_with(cwd=project_path)
+
+
+def test_maybe_setup_vibecode_setup_error_does_not_raise(mocker: MockerFixture) -> None:
+ mocker.patch("algokit.cli.init.command.questionary_extensions.prompt_confirm", return_value=True)
+ mocker.patch("algokit.cli.vibe.run_vibe_setup", side_effect=RuntimeError("boom"))
+
+ _maybe_setup_vibecode(project_path=Path("/tmp/project"), use_defaults=False, run_bootstrap=None)
diff --git a/tests/init/test_init_with_bootstrap.test_init_bootstrap_broken_poetry.approved.txt b/tests/init/test_init_with_bootstrap.test_init_bootstrap_broken_poetry.approved.txt
index aa5649515..0d35c9972 100644
--- a/tests/init/test_init_with_bootstrap.test_init_bootstrap_broken_poetry.approved.txt
+++ b/tests/init/test_init_with_bootstrap.test_init_bootstrap_broken_poetry.approved.txt
@@ -32,7 +32,6 @@ DEBUG: Checking {current_working_directory}/myapp for bootstrapping needs
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Running `algokit project bootstrap poetry`
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
ERROR: Received an error while attempting bootstrap: poetry --version failed, please check your poetry install
diff --git a/tests/portability/test_pyinstaller_binary.py b/tests/portability/test_pyinstaller_binary.py
index 459f86f6a..aa6cc7a3e 100644
--- a/tests/portability/test_pyinstaller_binary.py
+++ b/tests/portability/test_pyinstaller_binary.py
@@ -1,4 +1,6 @@
import logging
+import os
+import shutil
import subprocess
import sys
import time
@@ -7,38 +9,72 @@
import pytest
-algokit = "algokit"
logger = logging.getLogger(__name__)
pytestmark = pytest.mark.pyinstaller_binary_tests
-def command_str_to_list(command: str) -> list[str]:
- return command.split(" ")
+def _get_algokit_binary() -> str:
+ """Get the path to the algokit binary, preferring the PyInstaller binary over venv-installed version.
+
+ When running via 'poetry run', the .venv/bin directory is prepended to PATH, which causes
+ the venv-installed algokit to be found before the PyInstaller binary. This function
+ explicitly looks for the binary in the dist directory first.
+ """
+ # Check for explicit binary path from environment variable
+ if binary_path := environ.get("PYINSTALLER_BINARY_PATH"):
+ return binary_path
+
+ # Look for the binary in the dist directory (relative to the repo root)
+ # This works both locally and in CI
+ repo_root = Path(__file__).parent.parent.parent
+ is_windows = sys.platform in ("win32", "cygwin")
+ binary_name = "algokit.exe" if is_windows else "algokit"
+ dist_binary = repo_root / "dist" / "algokit" / binary_name
+ if dist_binary.exists():
+ return str(dist_binary)
+
+ # Fall back to PATH resolution, but skip the venv bin directory
+ # to avoid finding the venv-installed version
+ venv_subdir = "Scripts" if is_windows else "bin"
+ venv_bin = repo_root / ".venv" / venv_subdir
+ original_path = environ.get("PATH", "")
+ filtered_path = os.pathsep.join(p for p in original_path.split(os.pathsep) if not p.startswith(str(venv_bin)))
+
+ # Use shutil.which with the filtered PATH
+ if binary := shutil.which("algokit", path=filtered_path):
+ return binary
+
+ # Last resort: just use 'algokit' and hope it's in PATH
+ return "algokit"
+
+
+algokit = _get_algokit_binary()
@pytest.mark.parametrize(
- ("command", "exit_codes"),
+ ("args", "exit_codes"),
[
- (command_str_to_list("algokit --help"), [0]),
- (command_str_to_list("algokit doctor"), [0]),
- (command_str_to_list("algokit task vanity-address PY"), [0]),
+ (["--help"], [0]),
+ (["doctor"], [0]),
+ (["task", "vanity-address", "PY"], [0]),
],
)
def test_non_interactive_algokit_commands(
- command: list[str], exit_codes: list[int], tmp_path_factory: pytest.TempPathFactory
+ args: list[str], exit_codes: list[int], tmp_path_factory: pytest.TempPathFactory
) -> None:
cwd = tmp_path_factory.mktemp("cwd")
# Create a 'playground' directory
- if "build" in command:
+ if "build" in args:
cwd = cwd / "playground"
cwd.mkdir(exist_ok=True)
+ command = [algokit, *args]
execution_result = subprocess.run(command, capture_output=True, text=True, check=False, cwd=cwd)
logger.info(f"Command {command} returned {execution_result.stdout}")
# Parts of doctor will fail in CI on macOS and windows on github actions since docker isn't available by default
- if "doctor" in command and sys.platform in ["darwin", "windows", "win32"] and environ.get("CI"):
+ if "doctor" in args and sys.platform in ["darwin", "windows", "win32"] and environ.get("CI"):
exit_codes.append(1)
assert execution_result.returncode in exit_codes, f"Command {command} failed with {execution_result.stderr}"
@@ -48,15 +84,25 @@ def test_algokit_init_and_project_run(tmp_path_factory: pytest.TempPathFactory)
cwd = tmp_path_factory.mktemp("cwd")
# Run algokit init
- init_command = command_str_to_list("algokit init --name playground -t python --no-git --no-ide --defaults")
+ init_command = [algokit, "init", "--name", "playground", "-t", "python", "--no-git", "--no-ide", "--defaults"]
init_result = subprocess.run(init_command, capture_output=True, text=True, check=False, cwd=cwd)
logger.info(f"Command {init_command} returned {init_result.stdout}")
assert init_result.returncode == 0, f"Init command failed with {init_result.stderr}"
- # Run algokit project run build
+ # Add a deterministic project command to avoid template-specific dependency failures
+ project_config_path = cwd / "playground" / "projects" / "playground" / ".algokit.toml"
+ project_config_path.write_text(
+ project_config_path.read_text(encoding="utf-8")
+ + "\n[project.run.binary_smoke]\n"
+ + 'commands = ["python --version"]\n'
+ + 'description = "Binary smoke test"\n',
+ encoding="utf-8",
+ )
+
+ # Run algokit project run for the deterministic command
build_cwd = cwd / "playground"
build_cwd.mkdir(exist_ok=True)
- build_command = command_str_to_list("algokit -v project run build -- hello_world")
+ build_command = [algokit, "-v", "project", "run", "binary_smoke"]
build_result = subprocess.run(build_command, capture_output=True, text=True, check=False, cwd=build_cwd)
logger.info(f"Command {build_command} returned {build_result.stdout}")
assert build_result.returncode == 0, f"Build command failed with {build_result.stderr}"
@@ -70,15 +116,22 @@ def test_algokit_init_with_template_url(
# template. To cover and test workspace creation on real templates, we need to find a way to have `algokit`
# available globally within the worker running the binary IF the template defined custom copier tasks that invoke
# global `algokit` executable as part of instantiation of child template (for example fullstack).
- command = command_str_to_list(
- "init --name testproject "
- "--UNSAFE-SECURITY-accept-template-url "
- f"--template-url {dummy_algokit_template_with_python_task['template_path']} "
- "--template-url-ref=HEAD --no-git --no-ide --defaults --no-workspace"
- )
+ args = [
+ "init",
+ "--name",
+ "testproject",
+ "--UNSAFE-SECURITY-accept-template-url",
+ "--template-url",
+ str(dummy_algokit_template_with_python_task["template_path"]),
+ "--template-url-ref=HEAD",
+ "--no-git",
+ "--no-ide",
+ "--defaults",
+ "--no-workspace",
+ ]
process = subprocess.Popen(
- [algokit, *command],
+ [algokit, *args],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
@@ -87,7 +140,7 @@ def test_algokit_init_with_template_url(
)
full_output = ""
- logger.info(f"Running command: {' '.join([algokit, *command])}")
+ logger.info(f"Running command: {' '.join([algokit, *args])}")
while process.poll() is None and process.stdout and process.stdin:
output = process.stdout.readline()
full_output += output # Accumulate the output
diff --git a/tests/project/bootstrap/test_bootstrap.test_bootstrap_help.approved.txt b/tests/project/bootstrap/test_bootstrap.test_bootstrap_help.approved.txt
index 83e1abc62..f7dcf305a 100644
--- a/tests/project/bootstrap/test_bootstrap.test_bootstrap_help.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap.test_bootstrap_help.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
Usage: algokit project bootstrap [OPTIONS] COMMAND [ARGS]...
Expedited initial setup for any developer by installing and configuring
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version.approved.txt
index a8d986221..2e16ac99a 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version.approved.txt
@@ -1,4 +1,2 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
Error: This template requires AlgoKit version 999.99.99 or higher, but you have AlgoKit version {current_version}. Please update AlgoKit.
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version_ignore_error.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version_ignore_error.approved.txt
index 9c7ec47f9..3c45df043 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version_ignore_error.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version_ignore_error.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
WARNING: This template requires AlgoKit version 999.99.99 or higher, but you have AlgoKit version {current_version}. Please update AlgoKit.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_empty.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_empty.approved.txt
index 27ff2d24d..9291edade 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_empty.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_empty.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_env.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_env.approved.txt
index fabdf2088..988c91f10 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_env.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_env.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[linux].approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[linux].approved.txt
index edfd6524b..7e4a158bc 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[linux].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[linux].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[macOS].approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[macOS].approved.txt
index edfd6524b..7e4a158bc 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[macOS].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[macOS].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[windows].approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[windows].approved.txt
index 7c6af915d..d74851dc8 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[windows].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[windows].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry.approved.txt
index 504098c8d..6dabf3ee6 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
@@ -9,7 +6,6 @@ DEBUG: Checking {current_working_directory} for bootstrapping needs
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Running `algokit project bootstrap poetry`
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry_via_pyproject.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry_via_pyproject.approved.txt
index 10f7ef6e0..398522684 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry_via_pyproject.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry_via_pyproject.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
@@ -9,7 +6,6 @@ DEBUG: Checking {current_working_directory} for bootstrapping needs
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Running `algokit project bootstrap poetry`
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_filter.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_filter.approved.txt
index cabcc7483..a9a0491e8 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_filter.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_filter.approved.txt
@@ -12,7 +12,6 @@ DEBUG: {current_working_directory}/artifacts/project1/.env doesn't exist yet
DEBUG: {current_working_directory}/artifacts/project1/.env.template exists
Copying {current_working_directory}/artifacts/project1/.env.template to {current_working_directory}/artifacts/project1/.env and prompting for empty values
DEBUG: Running `algokit bootstrap poetry`
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_name_filter.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_name_filter.approved.txt
index 9c8b6daa8..b9854e7db 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_name_filter.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_name_filter.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No 'min_version' specified in .algokit.toml file.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
@@ -16,7 +13,6 @@ DEBUG: {current_working_directory}/artifacts/project_1/.env.template exists
Copying {current_working_directory}/artifacts/project_1/.env.template to {current_working_directory}/artifacts/project_1/.env and prompting for empty values
DEBUG: Attempting to load project config from {current_working_directory}/artifacts/project_1/.algokit.toml
DEBUG: Running `algokit project bootstrap poetry`
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_name_filter_not_found.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_name_filter_not_found.approved.txt
index 798b5d67d..45d7103af 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_name_filter_not_found.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_name_filter_not_found.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No 'min_version' specified in .algokit.toml file.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_type_filter.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_type_filter.approved.txt
index ca2a113e8..5277accbb 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_type_filter.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_type_filter.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No 'min_version' specified in .algokit.toml file.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_type_filter_not_found.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_type_filter_not_found.approved.txt
index 13f1384cf..2cf95a3d2 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_type_filter_not_found.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_projects_type_filter_not_found.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No 'min_version' specified in .algokit.toml file.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_skip_dirs.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_skip_dirs.approved.txt
index c289e4bfc..ef2d1ae37 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_skip_dirs.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_skip_dirs.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_sub_dir.approved.txt b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_sub_dir.approved.txt
index 9ca6f0ff5..c4e9f6585 100644
--- a/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_sub_dir.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_all.test_bootstrap_all_sub_dir.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
@@ -19,7 +16,6 @@ Copying {current_working_directory}/live_dir/.env.template to {current_working_d
DEBUG: Attempting to load project config from {current_working_directory}/live_dir/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Running `algokit project bootstrap poetry`
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
diff --git a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_different_prompt_scenarios.approved.txt b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_different_prompt_scenarios.approved.txt
index f40dc64cb..ea196028e 100644
--- a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_different_prompt_scenarios.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_different_prompt_scenarios.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: {current_working_directory}/.env doesn't exist yet
diff --git a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_exists.approved.txt b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_exists.approved.txt
index d20f2d4b2..4287df7f0 100644
--- a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_exists.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_exists.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
.env already exists; skipping bootstrap of .env
diff --git a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_missing_template_exists.approved.txt b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_missing_template_exists.approved.txt
index 0a4679082..49e3f94c2 100644
--- a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_missing_template_exists.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_missing_template_exists.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: {current_working_directory}/.env doesn't exist yet
diff --git a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_with_values.approved.txt b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_with_values.approved.txt
index 9021db23b..d3b043434 100644
--- a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_with_values.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_with_values.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: {current_working_directory}/.env doesn't exist yet
diff --git a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_multiple_templates.approved.txt b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_multiple_templates.approved.txt
index 131cacedd..3ae31ea5b 100644
--- a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_multiple_templates.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_multiple_templates.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: {current_working_directory}/.env.localnet doesn't exist yet
diff --git a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_no_files.approved.txt b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_no_files.approved.txt
index afc931625..243e68837 100644
--- a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_no_files.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_env_no_files.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
No .env or .env.{network_name}.template files found; nothing to do here, skipping bootstrap.
diff --git a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.approved.txt b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.approved.txt
index d20f2d4b2..4287df7f0 100644
--- a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
.env already exists; skipping bootstrap of .env
diff --git a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.approved.txt b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.approved.txt
index 42de608ee..64291a773 100644
--- a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
.env.localnet already exists; skipping bootstrap of .env.localnet
diff --git a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.template.approved.txt b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.template.approved.txt
index 61ffa8565..6405284cd 100644
--- a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.template.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.template.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: {current_working_directory}/.env.localnet doesn't exist yet
diff --git a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.template.approved.txt b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.template.approved.txt
index 749d0e0aa..d855a6927 100644
--- a/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.template.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.template.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: {current_working_directory}/.env doesn't exist yet
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[linux].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[linux].approved.txt
index 552beb18e..efe0520d4 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[linux].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[linux].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[macOS].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[macOS].approved.txt
index 552beb18e..efe0520d4 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[macOS].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[macOS].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[windows].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[windows].approved.txt
index 93394f053..fd6a9cffd 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[windows].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_with_lock_file[windows].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[linux].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[linux].approved.txt
index ec456b8b6..7f2ef9676 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[linux].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[linux].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[macOS].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[macOS].approved.txt
index ec456b8b6..7f2ef9676 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[macOS].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[macOS].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[windows].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[windows].approved.txt
index ec456b8b6..7f2ef9676 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[windows].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_ci_mode_without_lock_file[windows].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[linux].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[linux].approved.txt
index b0f7caa94..730e00366 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[linux].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[linux].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[macOS].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[macOS].approved.txt
index b0f7caa94..730e00366 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[macOS].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[macOS].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[windows].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[windows].approved.txt
index 19190f6be..142f4ef0d 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[windows].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[windows].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[linux].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[linux].approved.txt
index bcfd8490a..437d6c53d 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[linux].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[linux].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[macOS].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[macOS].approved.txt
index bcfd8490a..437d6c53d 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[macOS].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[macOS].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[windows].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[windows].approved.txt
index 56da8a11a..72b8ec579 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[windows].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[windows].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing npm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[linux].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[linux].approved.txt
index d1ece60bf..019f040ee 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[linux].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[linux].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
{current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[macOS].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[macOS].approved.txt
index d1ece60bf..019f040ee 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[macOS].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[macOS].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
{current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[windows].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[windows].approved.txt
index d1ece60bf..019f040ee 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[windows].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[windows].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
{current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[linux].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[linux].approved.txt
index d1ece60bf..019f040ee 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[linux].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[linux].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
{current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[macOS].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[macOS].approved.txt
index d1ece60bf..019f040ee 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[macOS].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[macOS].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
{current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm
diff --git a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[windows].approved.txt b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[windows].approved.txt
index d1ece60bf..019f040ee 100644
--- a/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[windows].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[windows].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
{current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm
diff --git a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[linux].approved.txt b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[linux].approved.txt
index 13ead76b9..0f55a004f 100644
--- a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[linux].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[linux].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[macOS].approved.txt b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[macOS].approved.txt
index 13ead76b9..0f55a004f 100644
--- a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[macOS].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[macOS].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[windows].approved.txt b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[windows].approved.txt
index af965933d..4ecfa422d 100644
--- a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[windows].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_bootstrap_respects_configured_package_managers[windows].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
diff --git a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[linux].approved.txt b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[linux].approved.txt
index 8a9cbccb4..24b2e3c06 100644
--- a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[linux].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[linux].approved.txt
@@ -1,4 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
@@ -8,7 +7,6 @@ DEBUG: Checking {current_working_directory} for bootstrapping needs
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Using Python package manager from .algokit.toml: poetry
DEBUG: Running `algokit project bootstrap poetry`
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
diff --git a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[macOS].approved.txt b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[macOS].approved.txt
index 8a9cbccb4..24b2e3c06 100644
--- a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[macOS].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[macOS].approved.txt
@@ -1,4 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
@@ -8,7 +7,6 @@ DEBUG: Checking {current_working_directory} for bootstrapping needs
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Using Python package manager from .algokit.toml: poetry
DEBUG: Running `algokit project bootstrap poetry`
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
diff --git a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[windows].approved.txt b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[windows].approved.txt
index 828aa8237..f1df2071b 100644
--- a/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[windows].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_package_manager_selection.test_project_override_takes_precedence_over_user_preference[windows].approved.txt
@@ -1,4 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
@@ -8,7 +7,6 @@ DEBUG: Checking {current_working_directory} for bootstrapping needs
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Using Python package manager from .algokit.toml: poetry
DEBUG: Running `algokit project bootstrap poetry`
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
diff --git a/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_ci_mode_without_lock_file.approved.txt b/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_ci_mode_without_lock_file.approved.txt
index f5cafd3c0..dce0707bc 100644
--- a/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_ci_mode_without_lock_file.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_ci_mode_without_lock_file.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing pnpm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[linux].approved.txt b/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[linux].approved.txt
index 67b6a805e..7300a0bd9 100644
--- a/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[linux].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[linux].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing pnpm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[macOS].approved.txt b/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[macOS].approved.txt
index 67b6a805e..7300a0bd9 100644
--- a/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[macOS].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[macOS].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing pnpm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[windows].approved.txt b/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[windows].approved.txt
index 7524bbe36..0590a94bb 100644
--- a/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[windows].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_happy_path[windows].approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
Installing pnpm dependencies
diff --git a/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_without_package_file.approved.txt b/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_without_package_file.approved.txt
index bf03c5b82..f9e9d15a3 100644
--- a/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_without_package_file.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_pnpm.test_bootstrap_pnpm_without_package_file.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
{current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of pnpm
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.py b/tests/project/bootstrap/test_bootstrap_poetry.py
index 604a7087c..24a373e22 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.py
+++ b/tests/project/bootstrap/test_bootstrap_poetry.py
@@ -36,6 +36,11 @@ def which(cmd: str) -> str | None:
return mock
+@pytest.fixture(autouse=True)
+def uvx_which_mock(mocker: MockerFixture) -> None:
+ mocker.patch("algokit.core.utils.shutil.which", side_effect=lambda cmd: "/bin/uvx" if cmd == "uvx" else None)
+
+
def test_base_python_path(python_base_executable: str) -> None:
"""When running in a venv (expected test mode), we should be able to resolve to base python.
Otherwise, they should be the same"""
@@ -63,7 +68,7 @@ def test_bootstrap_poetry_without_poetry(proc_mock: ProcMock, mock_questionary_i
def test_bootstrap_poetry_without_poetry_failed_install(proc_mock: ProcMock, mock_questionary_input: PipeInput) -> None:
proc_mock.should_fail_on("poetry --version")
- proc_mock.should_bad_exit_on("pipx install poetry")
+ proc_mock.should_bad_exit_on("uv tool install poetry")
# Yes, install poetry
mock_questionary_input.send_text("Y")
@@ -83,8 +88,8 @@ def test_bootstrap_poetry_without_poetry_failed_poetry_path(
result = invoke("project bootstrap poetry")
- assert result.exit_code == 1
- verify(result.output)
+ assert result.exit_code == 0
+ assert any(call.command == ["uvx", "--from=poetry", "poetry", "install"] for call in proc_mock.called)
@pytest.mark.parametrize(
@@ -105,7 +110,6 @@ def test_bootstrap_poetry_without_poetry_or_pipx_path(
mock_questionary_input: PipeInput,
) -> None:
proc_mock.should_fail_on("poetry --version")
- proc_mock.should_fail_on("pipx --version")
# Yes, install poetry
mock_questionary_input.send_text("Y")
@@ -120,8 +124,7 @@ def test_bootstrap_poetry_without_poetry_or_pipx_path_failed_install(
proc_mock: ProcMock, python_base_executable: str, mock_questionary_input: PipeInput
) -> None:
proc_mock.should_fail_on("poetry --version")
- proc_mock.should_fail_on("pipx --version")
- proc_mock.should_bad_exit_on(f"{python_base_executable} -m pipx install poetry")
+ proc_mock.should_bad_exit_on("uv tool install poetry")
# Yes, install poetry
mock_questionary_input.send_text("Y")
@@ -133,27 +136,29 @@ def test_bootstrap_poetry_without_poetry_or_pipx_path_failed_install(
@pytest.mark.usefixtures("system_python_paths")
def test_bootstrap_poetry_without_poetry_or_pipx_path_failed_poetry_path(
- proc_mock: ProcMock, python_base_executable: str, mock_questionary_input: PipeInput
+ proc_mock: ProcMock, mock_questionary_input: PipeInput
) -> None:
proc_mock.should_fail_on("poetry --version")
- proc_mock.should_fail_on("pipx --version")
proc_mock.should_fail_on("poetry install")
# Yes, install poetry
mock_questionary_input.send_text("Y")
result = invoke("project bootstrap poetry")
- assert result.exit_code == 1
- verify(result.output.replace(python_base_executable, "{python_base_executable}"))
+ assert result.exit_code == 0
+ assert any(call.command == ["uvx", "--from=poetry", "poetry", "install"] for call in proc_mock.called)
@pytest.mark.usefixtures("system_python_paths")
def test_bootstrap_poetry_without_poetry_or_pipx_path_or_pipx_module(
- proc_mock: ProcMock, python_base_executable: str, mock_questionary_input: PipeInput
+ proc_mock: ProcMock,
+ python_base_executable: str,
+ mock_questionary_input: PipeInput,
+ mocker: MockerFixture,
) -> None:
proc_mock.should_fail_on("poetry --version")
- proc_mock.should_fail_on("pipx --version")
- proc_mock.should_bad_exit_on(f"{python_base_executable} -m pipx --version")
+ mocker.patch("algokit.core.utils.shutil.which", return_value=None)
+ mocker.patch("algokit.core.utils._get_candidate_pipx_commands", return_value=[])
# Yes, install poetry
mock_questionary_input.send_text("Y")
@@ -161,3 +166,17 @@ def test_bootstrap_poetry_without_poetry_or_pipx_path_or_pipx_module(
assert result.exit_code == 1
verify(result.output.replace(python_base_executable, "{python_base_executable}"))
+
+
+def test_bootstrap_poetry_without_poetry_with_uv_no_uvx_uses_runner_fallback(
+ proc_mock: ProcMock, mock_questionary_input: PipeInput, mocker: MockerFixture
+) -> None:
+ proc_mock.should_fail_on("poetry --version")
+ proc_mock.should_fail_on("poetry install")
+ mocker.patch("algokit.core.utils.shutil.which", side_effect=lambda cmd: "/bin/uv" if cmd == "uv" else None)
+ mock_questionary_input.send_text("Y")
+
+ result = invoke("project bootstrap poetry")
+
+ assert result.exit_code == 0
+ assert any(call.command == ["uv", "tool", "run", "--from=poetry", "poetry", "install"] for call in proc_mock.called)
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_with_poetry.approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_with_poetry.approved.txt
index 66cee1a4c..8787f5107 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_with_poetry.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_with_poetry.approved.txt
@@ -1,9 +1,5 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: poetry: STDOUT
DEBUG: poetry: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry.approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry.approved.txt
index bb9bfde37..ba751635f 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry.approved.txt
@@ -1,15 +1,10 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
Poetry not found; attempting to install it...
-? We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies? (Y/n)
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: Running 'pipx install poetry' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+? We couldn't find `poetry`; can we install it for you via uv so we can install Python dependencies? (Y/n)
+DEBUG: Running 'uv tool install poetry' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
DEBUG: Running 'poetry install' in '{current_working_directory}'
poetry: STDOUT
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_install.approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_install.approved.txt
index 5b8c87d8b..7f229299d 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_install.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_install.approved.txt
@@ -1,13 +1,8 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
Poetry not found; attempting to install it...
-? We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies? (Y/n)
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: Running 'pipx install poetry' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-Error: Unable to install poetry via pipx; please install poetry manually via https://python-poetry.org/docs/ and try `algokit project bootstrap poetry` again.
+? We couldn't find `poetry`; can we install it for you via uv so we can install Python dependencies? (Y/n)
+DEBUG: Running 'uv tool install poetry' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+Error: Unable to install poetry via uv; please install poetry manually via https://python-poetry.org/docs/ and try `algokit project bootstrap poetry` again.
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_poetry_path.approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_poetry_path.approved.txt
index 0da47061e..89fd34f7a 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_poetry_path.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_poetry_path.approved.txt
@@ -1,15 +1,10 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
Poetry not found; attempting to install it...
-? We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies? (Y/n)
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
-DEBUG: Running 'pipx install poetry' in '{current_working_directory}'
-DEBUG: pipx: STDOUT
-DEBUG: pipx: STDERR
+? We couldn't find `poetry`; can we install it for you via uv so we can install Python dependencies? (Y/n)
+DEBUG: Running 'uv tool install poetry' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
DEBUG: Running 'poetry install' in '{current_working_directory}'
-Error: Unable to access Poetry on PATH after installing it via pipx; check pipx installations are on your path by running `pipx ensurepath` and try `algokit project bootstrap poetry` again.
+Error: Unable to access Poetry on PATH after installing it via uv; check installations are on your path and try `algokit project bootstrap poetry` again.
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[no_system_pythons].approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[no_system_pythons].approved.txt
index 07f664f4e..ba751635f 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[no_system_pythons].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[no_system_pythons].approved.txt
@@ -1,16 +1,10 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
Poetry not found; attempting to install it...
-? We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies? (Y/n)
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: Running '{python_base_executable} -m pipx --version' in '{current_working_directory}'
-DEBUG: {python_base_executable}: STDOUT
-DEBUG: {python_base_executable}: STDERR
-DEBUG: Running '{python_base_executable} -m pipx install poetry' in '{current_working_directory}'
-DEBUG: {python_base_executable}: STDOUT
-DEBUG: {python_base_executable}: STDERR
+? We couldn't find `poetry`; can we install it for you via uv so we can install Python dependencies? (Y/n)
+DEBUG: Running 'uv tool install poetry' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
DEBUG: Running 'poetry install' in '{current_working_directory}'
poetry: STDOUT
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python3_only].approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python3_only].approved.txt
index 5c1017c74..ba751635f 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python3_only].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python3_only].approved.txt
@@ -1,16 +1,10 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
Poetry not found; attempting to install it...
-? We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies? (Y/n)
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: Running '/bin/python3 -m pipx --version' in '{current_working_directory}'
-DEBUG: /bin/python3: STDOUT
-DEBUG: /bin/python3: STDERR
-DEBUG: Running '/bin/python3 -m pipx install poetry' in '{current_working_directory}'
-DEBUG: /bin/python3: STDOUT
-DEBUG: /bin/python3: STDERR
+? We couldn't find `poetry`; can we install it for you via uv so we can install Python dependencies? (Y/n)
+DEBUG: Running 'uv tool install poetry' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
DEBUG: Running 'poetry install' in '{current_working_directory}'
poetry: STDOUT
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_and_python3].approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_and_python3].approved.txt
index 5c1017c74..ba751635f 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_and_python3].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_and_python3].approved.txt
@@ -1,16 +1,10 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
Poetry not found; attempting to install it...
-? We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies? (Y/n)
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: Running '/bin/python3 -m pipx --version' in '{current_working_directory}'
-DEBUG: /bin/python3: STDOUT
-DEBUG: /bin/python3: STDERR
-DEBUG: Running '/bin/python3 -m pipx install poetry' in '{current_working_directory}'
-DEBUG: /bin/python3: STDOUT
-DEBUG: /bin/python3: STDERR
+? We couldn't find `poetry`; can we install it for you via uv so we can install Python dependencies? (Y/n)
+DEBUG: Running 'uv tool install poetry' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
DEBUG: Running 'poetry install' in '{current_working_directory}'
poetry: STDOUT
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_only].approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_only].approved.txt
index bbd7a3a53..ba751635f 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_only].approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_only].approved.txt
@@ -1,16 +1,10 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
Poetry not found; attempting to install it...
-? We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies? (Y/n)
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: Running '/bin/python -m pipx --version' in '{current_working_directory}'
-DEBUG: /bin/python: STDOUT
-DEBUG: /bin/python: STDERR
-DEBUG: Running '/bin/python -m pipx install poetry' in '{current_working_directory}'
-DEBUG: /bin/python: STDOUT
-DEBUG: /bin/python: STDERR
+? We couldn't find `poetry`; can we install it for you via uv so we can install Python dependencies? (Y/n)
+DEBUG: Running 'uv tool install poetry' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
DEBUG: Running 'poetry install' in '{current_working_directory}'
poetry: STDOUT
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_install.approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_install.approved.txt
index 1251fcd24..7f229299d 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_install.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_install.approved.txt
@@ -1,14 +1,8 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
Poetry not found; attempting to install it...
-? We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies? (Y/n)
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: Running '{python_base_executable} -m pipx --version' in '{current_working_directory}'
-DEBUG: {python_base_executable}: STDOUT
-DEBUG: {python_base_executable}: STDERR
-DEBUG: Running '{python_base_executable} -m pipx install poetry' in '{current_working_directory}'
-DEBUG: {python_base_executable}: STDOUT
-DEBUG: {python_base_executable}: STDERR
-Error: Unable to install poetry via pipx; please install poetry manually via https://python-poetry.org/docs/ and try `algokit project bootstrap poetry` again.
+? We couldn't find `poetry`; can we install it for you via uv so we can install Python dependencies? (Y/n)
+DEBUG: Running 'uv tool install poetry' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
+Error: Unable to install poetry via uv; please install poetry manually via https://python-poetry.org/docs/ and try `algokit project bootstrap poetry` again.
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_poetry_path.approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_poetry_path.approved.txt
index 82625fab7..89fd34f7a 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_poetry_path.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_poetry_path.approved.txt
@@ -1,16 +1,10 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
Poetry not found; attempting to install it...
-? We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies? (Y/n)
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: Running '{python_base_executable} -m pipx --version' in '{current_working_directory}'
-DEBUG: {python_base_executable}: STDOUT
-DEBUG: {python_base_executable}: STDERR
-DEBUG: Running '{python_base_executable} -m pipx install poetry' in '{current_working_directory}'
-DEBUG: {python_base_executable}: STDOUT
-DEBUG: {python_base_executable}: STDERR
+? We couldn't find `poetry`; can we install it for you via uv so we can install Python dependencies? (Y/n)
+DEBUG: Running 'uv tool install poetry' in '{current_working_directory}'
+DEBUG: uv: STDOUT
+DEBUG: uv: STDERR
Installing Python dependencies and setting up Python virtual environment via Poetry
DEBUG: Running 'poetry install' in '{current_working_directory}'
-Error: Unable to access Poetry on PATH after installing it via pipx; check pipx installations are on your path by running `pipx ensurepath` and try `algokit project bootstrap poetry` again.
+Error: Unable to access Poetry on PATH after installing it via uv; check installations are on your path and try `algokit project bootstrap poetry` again.
diff --git a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_or_pipx_module.approved.txt b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_or_pipx_module.approved.txt
index f1201201e..a37ca5c78 100644
--- a/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_or_pipx_module.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_or_pipx_module.approved.txt
@@ -1,11 +1,4 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
Poetry not found; attempting to install it...
-? We couldn't find `poetry`; can we install it for you via pipx so we can install Python dependencies? (Y/n)
-DEBUG: Running 'pipx --version' in '{current_working_directory}'
-DEBUG: Running '{python_base_executable} -m pipx --version' in '{current_working_directory}'
-DEBUG: {python_base_executable}: STDOUT
-DEBUG: {python_base_executable}: STDERR
-Error: Unable to find pipx install so that poetry can be installed; please install pipx via https://pypa.github.io/pipx/ and then try `algokit project bootstrap poetry` again.
+Error: Unable to find uv or pipx so that poetry can be installed; please install uv via https://docs.astral.sh/uv/ and then try `algokit project bootstrap poetry` again.
diff --git a/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_happy_path.approved.txt b/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_happy_path.approved.txt
index 34d260806..16cef2c08 100644
--- a/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_happy_path.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_happy_path.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Running 'uv --version' in '{current_working_directory}'
diff --git a/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_poetry_project_migration_declined.approved.txt b/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_poetry_project_migration_declined.approved.txt
index 40257d5fc..b3d018adb 100644
--- a/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_poetry_project_migration_declined.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_poetry_project_migration_declined.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Running 'uv --version' in '{current_working_directory}'
diff --git a/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_user_declines_install.approved.txt b/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_user_declines_install.approved.txt
index 0f618260c..207d73f5e 100644
--- a/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_user_declines_install.approved.txt
+++ b/tests/project/bootstrap/test_bootstrap_uv.test_bootstrap_uv_user_declines_install.approved.txt
@@ -1,8 +1,5 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Running 'uv --version' in '{current_working_directory}'
UV not found; attempting to install it...
-Error: Unable to install uv; please install uv manually via https://github.com/astral-sh/uv and try `algokit project bootstrap uv` again.
+Error: Unable to install uv; please install uv manually via https://docs.astral.sh/uv/ and try `algokit project bootstrap uv` again.
diff --git a/tests/project/deploy/test_deploy.py b/tests/project/deploy/test_deploy.py
index 3e3ff5d38..a3acc2896 100644
--- a/tests/project/deploy/test_deploy.py
+++ b/tests/project/deploy/test_deploy.py
@@ -4,14 +4,13 @@
import pytest
from _pytest.tmpdir import TempPathFactory
-from algosdk.account import generate_account
-from algosdk.mnemonic import from_private_key
from approvaltests.namer import NamerFactory
from pytest_mock import MockerFixture
from algokit.cli.common.utils import sanitize_extra_args
from algokit.core.conf import ALGOKIT_CONFIG
from algokit.core.tasks.wallet import WALLET_ALIASES_KEYRING_USERNAME
+from tests.conftest import generate_test_account
from tests.utils.approvals import verify
from tests.utils.click_invoker import invoke
from tests.utils.proc_mock import ProcMock
@@ -231,8 +230,8 @@ def test_algokit_env_and_name_correct_set(
result = invoke(["project", "deploy", "localnet"], cwd=cwd)
- assert proc_mock.called[1].env
- passed_env_vars = proc_mock.called[1].env
+ assert proc_mock.called[0].env
+ passed_env_vars = proc_mock.called[0].env
assert passed_env_vars["ENV_A"] == "ENVIRON_ENV_A" # os.environ is highest loading priority
assert passed_env_vars["ENV_B"] == "LOCALNET_ENV_B" # then .env.{name}
@@ -263,8 +262,8 @@ def test_algokit_deploy_only_base_deploy_config(
result = invoke(["project", "deploy"], cwd=cwd)
assert result.exit_code == 0
- assert proc_mock.called[1].env
- passed_env_vars = proc_mock.called[1].env
+ assert proc_mock.called[0].env
+ passed_env_vars = proc_mock.called[0].env
assert passed_env_vars["ENV_A"] == "GENERIC_ENV_A"
@@ -368,8 +367,8 @@ def test_secrets_prompting_via_stdin(
assert result.exit_code == 0 # ensure success
# assert that entered value is passed to proc run
- assert proc_mock.called[1].env
- called_env = proc_mock.called[1].env
+ assert proc_mock.called[0].env
+ called_env = proc_mock.called[0].env
assert "DEPLOYER_MNEMONIC" in called_env
assert called_env["DEPLOYER_MNEMONIC"] == "secret_value"
@@ -453,7 +452,7 @@ def test_deploy_dispenser_alias(
]
""".strip()
- dummy_account_pk, dummy_account_addr = generate_account() # type: ignore[no-untyped-call]
+ dummy_account_pk, dummy_account_addr, dummy_account_mnemonic = generate_test_account()
mock_keyring[alias] = json.dumps({"alias": alias, "address": dummy_account_addr, "private_key": dummy_account_pk})
mock_keyring[WALLET_ALIASES_KEYRING_USERNAME] = json.dumps([alias])
@@ -463,10 +462,10 @@ def test_deploy_dispenser_alias(
which_mock.add("command_a")
result = invoke(["project", "deploy", f"--{alias}", alias], cwd=cwd)
- assert proc_mock.called[1].env
- passed_env_vars = proc_mock.called[1].env
+ assert proc_mock.called[0].env
+ passed_env_vars = proc_mock.called[0].env
- assert passed_env_vars[env_var_name] == from_private_key(dummy_account_pk) # type: ignore[no-untyped-call]
+ assert passed_env_vars[env_var_name] == dummy_account_mnemonic
verify(result.output, options=NamerFactory.with_parameters(alias))
@@ -488,7 +487,7 @@ def test_deploy_with_extra_args(tmp_path_factory: TempPathFactory, proc_mock: Pr
result = invoke(["project", "deploy", "--", *extra_args], cwd=cwd)
assert result.exit_code == 0
- assert proc_mock.called[1].command == [cmd_resolved, *sanitize_extra_args(extra_args)]
+ assert proc_mock.called[0].command == [cmd_resolved, *sanitize_extra_args(extra_args)]
verify(result.output)
@@ -506,5 +505,5 @@ def test_deploy_with_extra_args_and_custom_command(
result = invoke(["project", "deploy", "localnet", "--command", custom_command, "--", *extra_args], cwd=cwd)
assert result.exit_code == 0
- assert proc_mock.called[1].command == [cmd_resolved, *sanitize_extra_args(extra_args)]
+ assert proc_mock.called[0].command == [cmd_resolved, *sanitize_extra_args(extra_args)]
verify(result.output)
diff --git a/tests/project/deploy/test_deploy.test_algokit_config_empty_array.approved.txt b/tests/project/deploy/test_deploy.test_algokit_config_empty_array.approved.txt
index 31022d5da..1495b327c 100644
--- a/tests/project/deploy/test_deploy.test_algokit_config_empty_array.approved.txt
+++ b/tests/project/deploy/test_deploy.test_algokit_config_empty_array.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_algokit_config_invalid_syntax.approved.txt b/tests/project/deploy/test_deploy.test_algokit_config_invalid_syntax.approved.txt
index 32597854e..b654dce55 100644
--- a/tests/project/deploy/test_deploy.test_algokit_config_invalid_syntax.approved.txt
+++ b/tests/project/deploy/test_deploy.test_algokit_config_invalid_syntax.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Error parsing .algokit.toml file: Invalid statement (at line 1, column 1)
DEBUG: Deploying from project directory: {current_working_directory}
diff --git a/tests/project/deploy/test_deploy.test_algokit_config_name_no_base.approved.txt b/tests/project/deploy/test_deploy.test_algokit_config_name_no_base.approved.txt
index da3b57909..daa8240f0 100644
--- a/tests/project/deploy/test_deploy.test_algokit_config_name_no_base.approved.txt
+++ b/tests/project/deploy/test_deploy.test_algokit_config_name_no_base.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_algokit_config_name_overrides.approved.txt b/tests/project/deploy/test_deploy.test_algokit_config_name_overrides.approved.txt
index de7054716..ad845aec3 100644
--- a/tests/project/deploy/test_deploy.test_algokit_config_name_overrides.approved.txt
+++ b/tests/project/deploy/test_deploy.test_algokit_config_name_overrides.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_algokit_deploy_only_base_deploy_config.approved.txt b/tests/project/deploy/test_deploy.test_algokit_deploy_only_base_deploy_config.approved.txt
index 547013284..45dd697d5 100644
--- a/tests/project/deploy/test_deploy.test_algokit_deploy_only_base_deploy_config.approved.txt
+++ b/tests/project/deploy/test_deploy.test_algokit_deploy_only_base_deploy_config.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_algokit_env_and_name_correct_set.approved.txt b/tests/project/deploy/test_deploy.test_algokit_env_and_name_correct_set.approved.txt
index 559486337..317ee393b 100644
--- a/tests/project/deploy/test_deploy.test_algokit_env_and_name_correct_set.approved.txt
+++ b/tests/project/deploy/test_deploy.test_algokit_env_and_name_correct_set.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_algokit_env_name_missing.approved.txt b/tests/project/deploy/test_deploy.test_algokit_env_name_missing.approved.txt
index 44371e6ce..dccb0a3aa 100644
--- a/tests/project/deploy/test_deploy.test_algokit_env_name_missing.approved.txt
+++ b/tests/project/deploy/test_deploy.test_algokit_env_name_missing.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_ci_flag_interactivity_mode_via_cli.approved.txt b/tests/project/deploy/test_deploy.test_ci_flag_interactivity_mode_via_cli.approved.txt
index f9791ed35..295beb6d4 100644
--- a/tests/project/deploy/test_deploy.test_ci_flag_interactivity_mode_via_cli.approved.txt
+++ b/tests/project/deploy/test_deploy.test_ci_flag_interactivity_mode_via_cli.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_ci_flag_interactivity_mode_via_env.approved.txt b/tests/project/deploy/test_deploy.test_ci_flag_interactivity_mode_via_env.approved.txt
index f9791ed35..295beb6d4 100644
--- a/tests/project/deploy/test_deploy.test_ci_flag_interactivity_mode_via_env.approved.txt
+++ b/tests/project/deploy/test_deploy.test_ci_flag_interactivity_mode_via_env.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_command_bad_exit_code.approved.txt b/tests/project/deploy/test_deploy.test_command_bad_exit_code.approved.txt
index d1e5cf2f8..4c4a813d9 100644
--- a/tests/project/deploy/test_deploy.test_command_bad_exit_code.approved.txt
+++ b/tests/project/deploy/test_deploy.test_command_bad_exit_code.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Deploying from project directory: {current_working_directory}
diff --git a/tests/project/deploy/test_deploy.test_command_invocation_and_command_splitting.approved.txt b/tests/project/deploy/test_deploy.test_command_invocation_and_command_splitting.approved.txt
index b522b7495..c4d0b879c 100644
--- a/tests/project/deploy/test_deploy.test_command_invocation_and_command_splitting.approved.txt
+++ b/tests/project/deploy/test_deploy.test_command_invocation_and_command_splitting.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_command_not_executable.approved.txt b/tests/project/deploy/test_deploy.test_command_not_executable.approved.txt
index 6b87cc56d..c2037a580 100644
--- a/tests/project/deploy/test_deploy.test_command_not_executable.approved.txt
+++ b/tests/project/deploy/test_deploy.test_command_not_executable.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Deploying from project directory: {current_working_directory}
diff --git a/tests/project/deploy/test_deploy.test_command_not_found_and_no_config.approved.txt b/tests/project/deploy/test_deploy.test_command_not_found_and_no_config.approved.txt
index 441f56e9f..8a4f6acaf 100644
--- a/tests/project/deploy/test_deploy.test_command_not_found_and_no_config.approved.txt
+++ b/tests/project/deploy/test_deploy.test_command_not_found_and_no_config.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Deploying from project directory: {current_working_directory}
diff --git a/tests/project/deploy/test_deploy.test_command_splitting_from_config.approved.txt b/tests/project/deploy/test_deploy.test_command_splitting_from_config.approved.txt
index b522b7495..c4d0b879c 100644
--- a/tests/project/deploy/test_deploy.test_command_splitting_from_config.approved.txt
+++ b/tests/project/deploy/test_deploy.test_command_splitting_from_config.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_command_without_splitting_from_config.approved.txt b/tests/project/deploy/test_deploy.test_command_without_splitting_from_config.approved.txt
index b522b7495..c4d0b879c 100644
--- a/tests/project/deploy/test_deploy.test_command_without_splitting_from_config.approved.txt
+++ b/tests/project/deploy/test_deploy.test_command_without_splitting_from_config.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_deploy_custom_project_dir.approved.txt b/tests/project/deploy/test_deploy.test_deploy_custom_project_dir.approved.txt
index d245548c8..a1273934e 100644
--- a/tests/project/deploy/test_deploy.test_deploy_custom_project_dir.approved.txt
+++ b/tests/project/deploy/test_deploy.test_deploy_custom_project_dir.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Deploying from project directory: {current_working_directory}/custom_folder
diff --git a/tests/project/deploy/test_deploy.test_deploy_dispenser_alias.deployer.approved.txt b/tests/project/deploy/test_deploy.test_deploy_dispenser_alias.deployer.approved.txt
index c3f7ce561..08270d6af 100644
--- a/tests/project/deploy/test_deploy.test_deploy_dispenser_alias.deployer.approved.txt
+++ b/tests/project/deploy/test_deploy.test_deploy_dispenser_alias.deployer.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_deploy_dispenser_alias.dispenser.approved.txt b/tests/project/deploy/test_deploy.test_deploy_dispenser_alias.dispenser.approved.txt
index e8c123df2..0bd44db08 100644
--- a/tests/project/deploy/test_deploy.test_deploy_dispenser_alias.dispenser.approved.txt
+++ b/tests/project/deploy/test_deploy.test_deploy_dispenser_alias.dispenser.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_deploy_shutil_command_not_found.approved.txt b/tests/project/deploy/test_deploy.test_deploy_shutil_command_not_found.approved.txt
index d0fa1b670..b3c6a6b70 100644
--- a/tests/project/deploy/test_deploy.test_deploy_shutil_command_not_found.approved.txt
+++ b/tests/project/deploy/test_deploy.test_deploy_shutil_command_not_found.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_deploy_with_extra_args.approved.txt b/tests/project/deploy/test_deploy.test_deploy_with_extra_args.approved.txt
index f1c80d1f4..b06334c1c 100644
--- a/tests/project/deploy/test_deploy.test_deploy_with_extra_args.approved.txt
+++ b/tests/project/deploy/test_deploy.test_deploy_with_extra_args.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/deploy/test_deploy.test_deploy_with_extra_args_and_custom_command.approved.txt b/tests/project/deploy/test_deploy.test_deploy_with_extra_args_and_custom_command.approved.txt
index 38ee155d9..26e687c11 100644
--- a/tests/project/deploy/test_deploy.test_deploy_with_extra_args_and_custom_command.approved.txt
+++ b/tests/project/deploy/test_deploy.test_deploy_with_extra_args_and_custom_command.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Deploying from project directory: {current_working_directory}
diff --git a/tests/project/deploy/test_deploy.test_secrets_prompting_via_stdin.approved.txt b/tests/project/deploy/test_deploy.test_secrets_prompting_via_stdin.approved.txt
index 547013284..45dd697d5 100644
--- a/tests/project/deploy/test_deploy.test_secrets_prompting_via_stdin.approved.txt
+++ b/tests/project/deploy/test_deploy.test_secrets_prompting_via_stdin.approved.txt
@@ -1,6 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: STDOUT
-DEBUG: poetry: STDERR
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: Deploying from project directory: {current_working_directory}
DEBUG: Loading deploy command from project config
diff --git a/tests/project/list/test_list.test_list_command_from_empty_folder.approved.txt b/tests/project/list/test_list.test_list_command_from_empty_folder.approved.txt
index d1a7e0133..9e2695dcf 100644
--- a/tests/project/list/test_list.test_list_command_from_empty_folder.approved.txt
+++ b/tests/project/list/test_list.test_list_command_from_empty_folder.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from /.algokit.toml
diff --git a/tests/project/list/test_list.test_list_command_no_args.approved.txt b/tests/project/list/test_list.test_list_command_no_args.approved.txt
index d1a7e0133..9e2695dcf 100644
--- a/tests/project/list/test_list.test_list_command_no_args.approved.txt
+++ b/tests/project/list/test_list.test_list_command_no_args.approved.txt
@@ -1,5 +1,3 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
DEBUG: Attempting to load project config from /.algokit.toml
diff --git a/tests/project/run/test_run.py b/tests/project/run/test_run.py
index fb08ba21b..7f083b182 100644
--- a/tests/project/run/test_run.py
+++ b/tests/project/run/test_run.py
@@ -355,6 +355,24 @@ def test_run_command_from_standalone_resolution_error(
verify(_format_output(result.output))
+def test_run_command_from_standalone_poetry_run_falls_back_to_uv(
+ tmp_path_factory: pytest.TempPathFactory,
+ which_mock: WhichMock,
+ proc_mock: ProcMock,
+) -> None:
+ cwd = tmp_path_factory.mktemp("cwd") / "algokit_project"
+ cwd.mkdir()
+
+ uv_path = which_mock.add("uv")
+ proc_mock.set_output([uv_path, "run", "echo", "hello"], ["hello"])
+ _create_project_config(cwd, "contract", "contract_project", "poetry run echo hello", "Runs hello")
+
+ result = invoke("project run hello", cwd=cwd)
+
+ assert result.exit_code == 0
+ assert proc_mock.called[0].command == [uv_path, "run", "echo", "hello"]
+
+
def test_run_command_from_standalone_execution_error(tmp_path_factory: pytest.TempPathFactory) -> None:
"""
Verifies the behavior when a command execution error occurs within a standalone project.
diff --git a/tests/tasks/conftest.py b/tests/tasks/conftest.py
index 5ffeacbbd..95d36100c 100644
--- a/tests/tasks/conftest.py
+++ b/tests/tasks/conftest.py
@@ -1,17 +1,28 @@
-from algokit_utils import SigningAccount
-from algosdk import transaction
+import base64
+from dataclasses import dataclass
-DUMMY_SUGGESTED_PARAMS = transaction.SuggestedParams( # type: ignore[no-untyped-call]
+from algokit_algod_client.models.suggested_params import SuggestedParams
+
+
+@dataclass
+class DummyAccount:
+ """Simple account holder for testing purposes."""
+
+ private_key: str
+ address: str
+
+
+DUMMY_SUGGESTED_PARAMS = SuggestedParams(
fee=0,
- first=33652328,
- last=33653328,
- gen="testnet-v1.0",
- gh="SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ first_valid=33652328,
+ last_valid=33653328,
+ genesis_id="testnet-v1.0",
+ genesis_hash=base64.b64decode("SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="),
min_fee=1000,
flat_fee=True,
consensus_version="https://github.com/algorandfoundation/specs/tree/abd3d4823c6f77349fc04c3af7b1e99fe4df699f",
)
-DUMMY_ACCOUNT = SigningAccount(
+DUMMY_ACCOUNT = DummyAccount(
private_key="iLsfFiRDwi0ijFdvdyO1PGkYxooOanbJSgpJ4pPKjKZluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAg==",
address="MW5E55FG7OHV7B2YB5JGFL6ONZSP7ABCMM77CIDGOT2GSBJEYUBOF3UYKA",
)
diff --git a/tests/tasks/test_analyze.py b/tests/tasks/test_analyze.py
index 6db1f628e..f9fed5bfc 100644
--- a/tests/tasks/test_analyze.py
+++ b/tests/tasks/test_analyze.py
@@ -235,7 +235,8 @@ def test_analyze_diff_flag_missing_old_report(
def test_analyze_error_no_pipx(cwd: Path, mocker: MockerFixture, proc_mock: ProcMock) -> None:
proc_mock.should_fail_on("tealer --version")
- mocker.patch("algokit.core.utils.get_candidate_pipx_commands", return_value=[])
+ mocker.patch("algokit.core.utils.shutil.which", return_value=None)
+ mocker.patch("algokit.core.utils._get_candidate_pipx_commands", return_value=[])
teal_file = cwd / "dummy.teal"
teal_file.touch()
diff --git a/tests/tasks/test_analyze.test_analyze_error_no_pipx.approved.txt b/tests/tasks/test_analyze.test_analyze_error_no_pipx.approved.txt
index b3cad5c68..45b27efec 100644
--- a/tests/tasks/test_analyze.test_analyze_error_no_pipx.approved.txt
+++ b/tests/tasks/test_analyze.test_analyze_error_no_pipx.approved.txt
@@ -1,4 +1,4 @@
DEBUG: Running 'tealer --version' in '{current_working_directory}'
DEBUG: No such file or directory: tealer
Tealer not found; attempting to install it...
-Error: Unable to find pipx install so that `tealer` static analyzer can be installed; please install pipx via https://pypa.github.io/pipx/ and then try `algokit task analyze ...` again.
+Error: Unable to find uvx or pipx so that `tealer` can be installed; please install uv via https://docs.astral.sh/uv/ and then try `algokit task analyze ...` again.
diff --git a/tests/tasks/test_asset.py b/tests/tasks/test_asset.py
index fa93c2dce..aab16067c 100644
--- a/tests/tasks/test_asset.py
+++ b/tests/tasks/test_asset.py
@@ -1,23 +1,15 @@
import json
+from algokit_algod_client.models import Account, AssetHolding
from algokit_utils import BulkAssetOptInOutResult
-from algosdk import account, mnemonic
from pytest_mock import MockerFixture
from algokit.core.tasks.wallet import WALLET_ALIASES_KEYRING_USERNAME
+from tests.conftest import generate_test_account
from tests.utils.approvals import verify
from tests.utils.click_invoker import invoke
-def _generate_account() -> tuple[str, str]:
- pk, addr = account.generate_account() # type: ignore[no-untyped-call]
- return pk, addr
-
-
-def _get_mnemonic_from_private_key(private_key: str) -> str:
- return str(mnemonic.from_private_key(private_key)) # type: ignore[no-untyped-call]
-
-
def test_opt_in_no_args() -> None:
result = invoke("task opt-in")
@@ -26,7 +18,7 @@ def test_opt_in_no_args() -> None:
def test_opt_in_invalid_network() -> None:
- _, addr = _generate_account()
+ _, addr, _ = generate_test_account()
asset_id = 123
result = invoke(f"task opt-in {addr} {asset_id} --network invalid-network")
@@ -42,11 +34,11 @@ def test_opt_in_to_assets_from_account_address_successful(mocker: MockerFixture)
algorand_mock = mocker.patch("algokit.cli.tasks.assets.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.assets.validate_address")
mocker.patch("algokit.cli.tasks.assets.validate_account_balance_to_opt_in")
- dummy_account_pk, dummy_account_address = _generate_account()
+ dummy_account_pk, dummy_account_address, dummy_account_mnemonic = generate_test_account()
asset_id = 123
result = invoke(
f"task opt-in -a {dummy_account_address} {asset_id} --network localnet",
- input=_get_mnemonic_from_private_key(dummy_account_pk),
+ input=dummy_account_mnemonic,
)
assert result.exit_code == 0
@@ -61,7 +53,7 @@ def test_opt_in_of_assets_from_account_alias_successful(mocker: MockerFixture, m
algorand_mock = mocker.patch("algokit.cli.tasks.assets.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.assets.validate_address")
mocker.patch("algokit.cli.tasks.assets.validate_account_balance_to_opt_in")
- dummy_account_pk, dummy_account_address = _generate_account()
+ dummy_account_pk, dummy_account_address, dummy_account_mnemonic = generate_test_account()
alias_name = "dummy_alias"
mock_keyring[alias_name] = json.dumps(
@@ -75,7 +67,7 @@ def test_opt_in_of_assets_from_account_alias_successful(mocker: MockerFixture, m
result = invoke(
f"task opt-in -a {alias_name} {123} --network localnet",
- input=_get_mnemonic_from_private_key(dummy_account_pk),
+ input=dummy_account_mnemonic,
)
assert result.exit_code == 0
@@ -88,11 +80,11 @@ def test_opt_in_to_assets_from_account_address_failed(mocker: MockerFixture) ->
algorand_mock = mocker.patch("algokit.cli.tasks.assets.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.assets.validate_address")
mocker.patch("algokit.cli.tasks.assets.validate_account_balance_to_opt_in")
- dummy_account_pk, dummy_account_address = _generate_account()
+ dummy_account_pk, dummy_account_address, dummy_account_mnemonic = generate_test_account()
asset_id = 123
result = invoke(
f"task opt-in -a {dummy_account_address} {asset_id} --network localnet",
- input=_get_mnemonic_from_private_key(dummy_account_pk),
+ input=dummy_account_mnemonic,
)
assert result.exit_code == 1
@@ -107,7 +99,7 @@ def test_opt_out_no_args() -> None:
def test_opt_out_invalid_network() -> None:
- _, addr = _generate_account()
+ _, addr, _ = generate_test_account()
asset_id = 123
result = invoke(f"task opt-out {asset_id} {addr} --network invalid-network")
@@ -122,11 +114,11 @@ def test_opt_out_of_assets_from_account_address_successful(mocker: MockerFixture
]
algorand_mock = mocker.patch("algokit.cli.tasks.assets.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.assets.validate_address")
- dummy_account_pk, dummy_account_address = _generate_account()
+ dummy_account_pk, dummy_account_address, dummy_account_mnemonic = generate_test_account()
asset_id = 123
result = invoke(
f"task opt-out -a {dummy_account_address} {asset_id} --network localnet",
- input=_get_mnemonic_from_private_key(dummy_account_pk),
+ input=dummy_account_mnemonic,
)
assert result.exit_code == 0
@@ -134,18 +126,18 @@ def test_opt_out_of_assets_from_account_address_successful(mocker: MockerFixture
def test_opt_out_of_all_assets_from_account_address_successful(mocker: MockerFixture) -> None:
- dummy_account_info = {"assets": [{"asset-id": 1, "amount": 0}]}
- mocker.patch("algokit.cli.tasks.assets.get_account_info", return_value=dummy_account_info)
+ dummy_account_info = Account(assets=[AssetHolding(asset_id=1)])
+ mocker.patch("algokit_algod_client.client.AlgodClient.account_information", return_value=dummy_account_info)
algorand_mock = mocker.MagicMock()
algorand_mock.asset.bulk_opt_out.return_value = [
BulkAssetOptInOutResult(asset_id=123, transaction_id="dummy_txn_id")
]
algorand_mock = mocker.patch("algokit.cli.tasks.assets.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.assets.validate_address")
- dummy_account_pk, dummy_account_address = _generate_account()
+ dummy_account_pk, dummy_account_address, dummy_account_mnemonic = generate_test_account()
result = invoke(
f"task opt-out -a {dummy_account_address} --network localnet --all",
- input=_get_mnemonic_from_private_key(dummy_account_pk),
+ input=dummy_account_mnemonic,
)
assert result.exit_code == 0
@@ -159,7 +151,7 @@ def test_opt_out_of_assets_from_account_alias_successful(mocker: MockerFixture,
]
algorand_mock = mocker.patch("algokit.cli.tasks.assets.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.assets.validate_address")
- dummy_account_pk, dummy_account_address = _generate_account()
+ dummy_account_pk, dummy_account_address, dummy_account_mnemonic = generate_test_account()
alias_name = "dummy_alias"
mock_keyring[alias_name] = json.dumps(
@@ -173,7 +165,7 @@ def test_opt_out_of_assets_from_account_alias_successful(mocker: MockerFixture,
result = invoke(
f"task opt-out -a {alias_name} 123 --network localnet",
- input=_get_mnemonic_from_private_key(dummy_account_pk),
+ input=dummy_account_mnemonic,
)
assert result.exit_code == 0
@@ -185,11 +177,11 @@ def test_opt_out_assets_from_account_address_failed(mocker: MockerFixture) -> No
algorand_mock.asset.bulk_opt_out.side_effect = Exception("dummy error")
algorand_mock = mocker.patch("algokit.cli.tasks.assets.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.assets.validate_address")
- dummy_account_pk, dummy_account_address = _generate_account()
+ dummy_account_pk, dummy_account_address, dummy_account_mnemonic = generate_test_account()
asset_id = 123
result = invoke(
f"task opt-out -a {dummy_account_address} {asset_id} --network localnet",
- input=_get_mnemonic_from_private_key(dummy_account_pk),
+ input=dummy_account_mnemonic,
)
assert result.exit_code == 1
diff --git a/tests/tasks/test_mint.py b/tests/tasks/test_mint.py
index 3e648ecf6..be1640834 100644
--- a/tests/tasks/test_mint.py
+++ b/tests/tasks/test_mint.py
@@ -1,10 +1,11 @@
+import base64
import json
import re
from pathlib import Path
import click
import pytest
-from algosdk.mnemonic import from_private_key
+from algokit_utils.algo25 import secret_key_to_mnemonic
from approvaltests.namer import NamerFactory
from pytest_httpx import HTTPXMock
from pytest_mock import MockerFixture
@@ -16,6 +17,12 @@
from tests.utils.click_invoker import invoke
+def _get_mnemonic_from_private_key(private_key: str) -> str:
+ """Convert base64-encoded private key to mnemonic."""
+ private_key_bytes = base64.b64decode(private_key)
+ return secret_key_to_mnemonic(private_key_bytes)
+
+
@pytest.mark.parametrize(("account_type", "mutability"), [("alias", "mutable"), ("address", "immutable")])
@pytest.mark.parametrize("network", ["localnet", "testnet", "mainnet"])
def test_mint_token_successful(
@@ -34,7 +41,7 @@ def test_mint_token_successful(
prompt_input = None
if account_type == "address":
account = DUMMY_ACCOUNT.address
- prompt_input = from_private_key(DUMMY_ACCOUNT.private_key) # type: ignore[no-untyped-call]
+ prompt_input = _get_mnemonic_from_private_key(DUMMY_ACCOUNT.private_key)
else:
account = "my_alias"
mock_keyring[account] = json.dumps(
@@ -54,7 +61,7 @@ def test_mint_token_successful(
"bafkreiftmc4on252dnckhv7jdqnhkxjkpvlrekpevjwm3gjszygxkus5oe",
],
)
- mocker.patch("algokit.core.tasks.mint.mint.wait_for_confirmation", return_value={"asset-index": 123})
+ mocker.patch("algokit.core.tasks.mint.mint._wait_for_confirmation", return_value=mocker.MagicMock(asset_index=123))
mocker.patch(
"algokit.cli.tasks.mint.get_pinata_jwt",
return_value="dummy_key",
@@ -63,7 +70,7 @@ def test_mint_token_successful(
"algokit.cli.tasks.mint.validate_balance",
)
algod_mock = mocker.MagicMock()
- algod_mock.send_transaction.return_value = "dummy_tx_id"
+ algod_mock.send_raw_transaction.return_value = mocker.MagicMock(tx_id="dummy_tx_id")
algod_mock.suggested_params.return_value = DUMMY_SUGGESTED_PARAMS
mocker.patch("algokit.cli.tasks.mint.load_algod_client", return_value=algod_mock)
@@ -123,7 +130,7 @@ def test_mint_token_successful_on_decimals(
"bafkreiftmc4on252dnckhv7jdqnhkxjkpvlrekpevjwm3gjszygxkus5oe",
],
)
- mocker.patch("algokit.core.tasks.mint.mint.wait_for_confirmation", return_value={"asset-index": 123})
+ mocker.patch("algokit.core.tasks.mint.mint._wait_for_confirmation", return_value=mocker.MagicMock(asset_index=123))
mocker.patch(
"algokit.cli.tasks.mint.get_pinata_jwt",
return_value="dummy_key",
@@ -132,7 +139,7 @@ def test_mint_token_successful_on_decimals(
"algokit.cli.tasks.mint.validate_balance",
)
algod_mock = mocker.MagicMock()
- algod_mock.send_transaction.return_value = "dummy_tx_id"
+ algod_mock.send_raw_transaction.return_value = mocker.MagicMock(tx_id="dummy_tx_id")
algod_mock.suggested_params.return_value = DUMMY_SUGGESTED_PARAMS
mocker.patch("algokit.cli.tasks.mint.load_algod_client", return_value=algod_mock)
@@ -157,7 +164,7 @@ def test_mint_token_pure_fractional_nft_ft_validation(
network = "localnet"
cwd = tmp_path_factory.mktemp("cwd")
account = DUMMY_ACCOUNT.address
- prompt_input = from_private_key(DUMMY_ACCOUNT.private_key) # type: ignore[no-untyped-call]
+ prompt_input = _get_mnemonic_from_private_key(DUMMY_ACCOUNT.private_key)
(cwd / "image.png").touch()
# Act
@@ -181,7 +188,7 @@ def test_mint_token_pinata_error(
cwd = tmp_path_factory.mktemp("cwd")
account = ""
account = DUMMY_ACCOUNT.address
- prompt_input = from_private_key(DUMMY_ACCOUNT.private_key) # type: ignore[no-untyped-call]
+ prompt_input = _get_mnemonic_from_private_key(DUMMY_ACCOUNT.private_key)
(cwd / "image.png").touch()
httpx_mock.add_response(status_code=403, json={"ok": False})
@@ -216,7 +223,7 @@ def test_mint_token_no_pinata_jwt_error(
cwd = tmp_path_factory.mktemp("cwd")
account = ""
account = DUMMY_ACCOUNT.address
- prompt_input = from_private_key(DUMMY_ACCOUNT.private_key) # type: ignore[no-untyped-call]
+ prompt_input = _get_mnemonic_from_private_key(DUMMY_ACCOUNT.private_key)
(cwd / "image.png").touch()
mocker.patch(
diff --git a/tests/tasks/test_mint.test_mint_token_successful.address.False.localnet.approved.txt b/tests/tasks/test_mint.test_mint_token_successful.address.False.localnet.approved.txt
index 42048fc78..11140d24c 100644
--- a/tests/tasks/test_mint.test_mint_token_successful.address.False.localnet.approved.txt
+++ b/tests/tasks/test_mint.test_mint_token_successful.address.False.localnet.approved.txt
@@ -13,6 +13,7 @@ DEBUG: Asset config params: {
"total": 1,
"freeze": "",
"clawback": "",
+ "metadata_hash": "VR1UyM4COBDD1TEmAj0U8FwpZ0b6J+V1Mi6YqzDSWvg=",
"note": "",
"decimals": 0,
"default_frozen": false,
@@ -23,4 +24,4 @@ DEBUG: Asset config params: {
Successfully minted the asset!
Browse your asset at: https://explore.algokit.io/localnet/asset/123
-Check transaction status at: https://explore.algokit.io/localnet/transaction/dummy_tx_id
+Check transaction status at: https://explore.algokit.io/localnet/transaction/MCT6IZK25IBEHYCXCCXVYFRHBSSDT3CK6YVBCSRNJ7L36DDLR5YQ
diff --git a/tests/tasks/test_mint.test_mint_token_successful.address.False.mainnet.approved.txt b/tests/tasks/test_mint.test_mint_token_successful.address.False.mainnet.approved.txt
index be3fd9fd4..7519547d8 100644
--- a/tests/tasks/test_mint.test_mint_token_successful.address.False.mainnet.approved.txt
+++ b/tests/tasks/test_mint.test_mint_token_successful.address.False.mainnet.approved.txt
@@ -13,6 +13,7 @@ DEBUG: Asset config params: {
"total": 1,
"freeze": "",
"clawback": "",
+ "metadata_hash": "VR1UyM4COBDD1TEmAj0U8FwpZ0b6J+V1Mi6YqzDSWvg=",
"note": "",
"decimals": 0,
"default_frozen": false,
@@ -23,4 +24,4 @@ DEBUG: Asset config params: {
Successfully minted the asset!
Browse your asset at: https://explore.algokit.io/mainnet/asset/123
-Check transaction status at: https://explore.algokit.io/mainnet/transaction/dummy_tx_id
+Check transaction status at: https://explore.algokit.io/mainnet/transaction/MCT6IZK25IBEHYCXCCXVYFRHBSSDT3CK6YVBCSRNJ7L36DDLR5YQ
diff --git a/tests/tasks/test_mint.test_mint_token_successful.address.False.testnet.approved.txt b/tests/tasks/test_mint.test_mint_token_successful.address.False.testnet.approved.txt
index 8aa9f3724..abbd35cfa 100644
--- a/tests/tasks/test_mint.test_mint_token_successful.address.False.testnet.approved.txt
+++ b/tests/tasks/test_mint.test_mint_token_successful.address.False.testnet.approved.txt
@@ -13,6 +13,7 @@ DEBUG: Asset config params: {
"total": 1,
"freeze": "",
"clawback": "",
+ "metadata_hash": "VR1UyM4COBDD1TEmAj0U8FwpZ0b6J+V1Mi6YqzDSWvg=",
"note": "",
"decimals": 0,
"default_frozen": false,
@@ -23,4 +24,4 @@ DEBUG: Asset config params: {
Successfully minted the asset!
Browse your asset at: https://explore.algokit.io/testnet/asset/123
-Check transaction status at: https://explore.algokit.io/testnet/transaction/dummy_tx_id
+Check transaction status at: https://explore.algokit.io/testnet/transaction/MCT6IZK25IBEHYCXCCXVYFRHBSSDT3CK6YVBCSRNJ7L36DDLR5YQ
diff --git a/tests/tasks/test_mint.test_mint_token_successful.alias.True.localnet.approved.txt b/tests/tasks/test_mint.test_mint_token_successful.alias.True.localnet.approved.txt
index f0a9da0de..fed895e9b 100644
--- a/tests/tasks/test_mint.test_mint_token_successful.alias.True.localnet.approved.txt
+++ b/tests/tasks/test_mint.test_mint_token_successful.alias.True.localnet.approved.txt
@@ -12,6 +12,7 @@ DEBUG: Asset config params: {
"total": 1,
"freeze": "",
"clawback": "",
+ "metadata_hash": null,
"note": "",
"decimals": 0,
"default_frozen": false,
@@ -22,4 +23,4 @@ DEBUG: Asset config params: {
Successfully minted the asset!
Browse your asset at: https://explore.algokit.io/localnet/asset/123
-Check transaction status at: https://explore.algokit.io/localnet/transaction/dummy_tx_id
+Check transaction status at: https://explore.algokit.io/localnet/transaction/I3UTXWJIS25PAOP7KBFCQDHZC3PMDQJDOO4XUQFJHQTB3ZBYBPYA
diff --git a/tests/tasks/test_mint.test_mint_token_successful.alias.True.mainnet.approved.txt b/tests/tasks/test_mint.test_mint_token_successful.alias.True.mainnet.approved.txt
index 9c9497bc0..84a6f5d74 100644
--- a/tests/tasks/test_mint.test_mint_token_successful.alias.True.mainnet.approved.txt
+++ b/tests/tasks/test_mint.test_mint_token_successful.alias.True.mainnet.approved.txt
@@ -12,6 +12,7 @@ DEBUG: Asset config params: {
"total": 1,
"freeze": "",
"clawback": "",
+ "metadata_hash": null,
"note": "",
"decimals": 0,
"default_frozen": false,
@@ -22,4 +23,4 @@ DEBUG: Asset config params: {
Successfully minted the asset!
Browse your asset at: https://explore.algokit.io/mainnet/asset/123
-Check transaction status at: https://explore.algokit.io/mainnet/transaction/dummy_tx_id
+Check transaction status at: https://explore.algokit.io/mainnet/transaction/I3UTXWJIS25PAOP7KBFCQDHZC3PMDQJDOO4XUQFJHQTB3ZBYBPYA
diff --git a/tests/tasks/test_mint.test_mint_token_successful.alias.True.testnet.approved.txt b/tests/tasks/test_mint.test_mint_token_successful.alias.True.testnet.approved.txt
index 892d78ae1..89f149b6d 100644
--- a/tests/tasks/test_mint.test_mint_token_successful.alias.True.testnet.approved.txt
+++ b/tests/tasks/test_mint.test_mint_token_successful.alias.True.testnet.approved.txt
@@ -12,6 +12,7 @@ DEBUG: Asset config params: {
"total": 1,
"freeze": "",
"clawback": "",
+ "metadata_hash": null,
"note": "",
"decimals": 0,
"default_frozen": false,
@@ -22,4 +23,4 @@ DEBUG: Asset config params: {
Successfully minted the asset!
Browse your asset at: https://explore.algokit.io/testnet/asset/123
-Check transaction status at: https://explore.algokit.io/testnet/transaction/dummy_tx_id
+Check transaction status at: https://explore.algokit.io/testnet/transaction/I3UTXWJIS25PAOP7KBFCQDHZC3PMDQJDOO4XUQFJHQTB3ZBYBPYA
diff --git a/tests/tasks/test_mint.test_mint_token_successful_on_decimals.decimals_given_params.approved.txt b/tests/tasks/test_mint.test_mint_token_successful_on_decimals.decimals_given_params.approved.txt
index 2d84885d9..55a770937 100644
--- a/tests/tasks/test_mint.test_mint_token_successful_on_decimals.decimals_given_params.approved.txt
+++ b/tests/tasks/test_mint.test_mint_token_successful_on_decimals.decimals_given_params.approved.txt
@@ -12,6 +12,7 @@ DEBUG: Asset config params: {
"total": 100,
"freeze": "",
"clawback": "",
+ "metadata_hash": null,
"note": "",
"decimals": 2,
"default_frozen": false,
@@ -22,4 +23,4 @@ DEBUG: Asset config params: {
Successfully minted the asset!
Browse your asset at: https://explore.algokit.io/localnet/asset/123
-Check transaction status at: https://explore.algokit.io/localnet/transaction/dummy_tx_id
+Check transaction status at: https://explore.algokit.io/localnet/transaction/Z7YFUSBBC4TQBYZQ3L7PHW75ZZNJ57C6M5LORMFNDRZGJOWIVAZQ
diff --git a/tests/tasks/test_mint.test_mint_token_successful_on_decimals.no_decimals_given.approved.txt b/tests/tasks/test_mint.test_mint_token_successful_on_decimals.no_decimals_given.approved.txt
index b2ee8eb6c..10dafd259 100644
--- a/tests/tasks/test_mint.test_mint_token_successful_on_decimals.no_decimals_given.approved.txt
+++ b/tests/tasks/test_mint.test_mint_token_successful_on_decimals.no_decimals_given.approved.txt
@@ -13,6 +13,7 @@ DEBUG: Asset config params: {
"total": 100,
"freeze": "",
"clawback": "",
+ "metadata_hash": null,
"note": "",
"decimals": 2,
"default_frozen": false,
@@ -23,4 +24,4 @@ DEBUG: Asset config params: {
Successfully minted the asset!
Browse your asset at: https://explore.algokit.io/localnet/asset/123
-Check transaction status at: https://explore.algokit.io/localnet/transaction/dummy_tx_id
+Check transaction status at: https://explore.algokit.io/localnet/transaction/Z7YFUSBBC4TQBYZQ3L7PHW75ZZNJ57C6M5LORMFNDRZGJOWIVAZQ
diff --git a/tests/tasks/test_nfd_lookup.py b/tests/tasks/test_nfd_lookup.py
index 5eacb29c0..9e37ad5b1 100644
--- a/tests/tasks/test_nfd_lookup.py
+++ b/tests/tasks/test_nfd_lookup.py
@@ -1,6 +1,6 @@
-import algosdk
from pytest_httpx import HTTPXMock
+from tests.conftest import generate_test_account
from tests.utils.approvals import verify
from tests.utils.click_invoker import invoke
@@ -27,7 +27,7 @@ def test_nfd_lookup_by_domain_success(httpx_mock: HTTPXMock) -> None:
def test_nfd_lookup_by_address_success(httpx_mock: HTTPXMock) -> None:
# Arrange
- _, dummy_wallet = algosdk.account.generate_account() # type: ignore[no-untyped-call]
+ _, dummy_wallet, _ = generate_test_account()
httpx_mock.add_response(
url=f"https://api.nf.domains/nfd/lookup?address={dummy_wallet}&view=thumbnail&allowUnverified=false",
json={
diff --git a/tests/tasks/test_send_transaction.py b/tests/tasks/test_send_transaction.py
index 7087ed6e1..a2c79fce9 100644
--- a/tests/tasks/test_send_transaction.py
+++ b/tests/tasks/test_send_transaction.py
@@ -1,8 +1,20 @@
+import base64
import json
+from pathlib import Path
+from typing import cast
import click
import pytest
-from algosdk import encoding, transaction
+from algokit_transact import (
+ PaymentTransactionFields,
+ SignedTransaction,
+ Transaction,
+ TransactionType,
+ decode_signed_transaction,
+ encode_signed_transaction,
+ group_transactions,
+ make_basic_account_transaction_signer,
+)
from pytest_mock import MockerFixture
from tests.tasks.conftest import DUMMY_ACCOUNT, DUMMY_SUGGESTED_PARAMS
@@ -10,42 +22,87 @@
from tests.utils.click_invoker import invoke
-def _generate_dummy_signed_txn(*, amount: int = 1, encode: bool = False) -> transaction.SignedTransaction | str:
- unsigned_txn = transaction.PaymentTxn( # type: ignore[no-untyped-call]
- DUMMY_ACCOUNT.address, DUMMY_SUGGESTED_PARAMS, DUMMY_ACCOUNT.address, amt=amount
+def _write_signed_transactions_to_file(signed_txns: list[SignedTransaction], file_path: Path) -> None:
+ """Write signed transactions to a file in msgpack format.
+
+ This mimics the behavior of algosdk's transaction.write_to_file() but uses
+ algokit_transact's encode_signed_transaction.
+ """
+ with file_path.open("wb") as f:
+ for stx in signed_txns:
+ f.write(encode_signed_transaction(stx))
+
+
+def _generate_dummy_signed_txn(*, amount: int = 1, encode: bool = False) -> SignedTransaction | str:
+ # Create unsigned transaction
+ unsigned_txn = Transaction(
+ transaction_type=TransactionType.Payment,
+ sender=DUMMY_ACCOUNT.address,
+ first_valid=DUMMY_SUGGESTED_PARAMS.first_valid,
+ last_valid=DUMMY_SUGGESTED_PARAMS.last_valid,
+ fee=DUMMY_SUGGESTED_PARAMS.fee,
+ genesis_hash=DUMMY_SUGGESTED_PARAMS.genesis_hash,
+ genesis_id=DUMMY_SUGGESTED_PARAMS.genesis_id,
+ payment=PaymentTransactionFields(
+ receiver=DUMMY_ACCOUNT.address,
+ amount=amount,
+ close_remainder_to=None,
+ ),
)
- txn = unsigned_txn.sign(DUMMY_ACCOUNT.private_key) # type: ignore[no-untyped-call]
+
+ # Sign the transaction
+ signer = make_basic_account_transaction_signer(DUMMY_ACCOUNT.private_key)
+ signed_txn_bytes = signer([unsigned_txn], [0])[0]
if encode:
- return str(encoding.msgpack_encode(txn)) # type: ignore[no-untyped-call]
+ # Return base64-encoded string for CLI input
+ return base64.b64encode(signed_txn_bytes).decode()
- return txn # type: ignore[no-any-return]
+ # Decode back to SignedTransaction object if not encoding
+ return decode_signed_transaction(signed_txn_bytes)
-def _generate_dummy_signed_txn_group() -> list[transaction.SignedTransaction]:
+def _generate_dummy_signed_txn_group() -> list[SignedTransaction]:
+ # Create unsigned transactions
txns = [
- transaction.PaymentTxn(DUMMY_ACCOUNT.address, DUMMY_SUGGESTED_PARAMS, DUMMY_ACCOUNT.address, amt=i) # type: ignore[no-untyped-call]
+ Transaction(
+ transaction_type=TransactionType.Payment,
+ sender=DUMMY_ACCOUNT.address,
+ first_valid=DUMMY_SUGGESTED_PARAMS.first_valid,
+ last_valid=DUMMY_SUGGESTED_PARAMS.last_valid,
+ fee=DUMMY_SUGGESTED_PARAMS.fee if i != 0 else 3000,
+ genesis_hash=DUMMY_SUGGESTED_PARAMS.genesis_hash,
+ genesis_id=DUMMY_SUGGESTED_PARAMS.genesis_id,
+ payment=PaymentTransactionFields(
+ receiver=DUMMY_ACCOUNT.address,
+ amount=i,
+ close_remainder_to=None,
+ ),
+ )
for i in range(3)
]
- txns[0].fee = 3000
- gid = transaction.calculate_group_id(txns) # type: ignore[no-untyped-call]
- signed_txns = []
- for txn in txns:
- txn.group = gid
- signed_txns.append(txn.sign(DUMMY_ACCOUNT.private_key)) # type: ignore[no-untyped-call]
+ # Group the transactions
+ grouped_txns = group_transactions(txns)
+
+ # Sign all transactions
+ signer = make_basic_account_transaction_signer(DUMMY_ACCOUNT.private_key)
+ signed_txn_bytes_list = signer(grouped_txns, list(range(len(grouped_txns))))
- return signed_txns
+ # Decode back to SignedTransaction objects
+ from algokit_transact import decode_signed_transaction
+
+ return [decode_signed_transaction(stx_bytes) for stx_bytes in signed_txn_bytes_list]
def test_send_atomic_txn_group_successful(tmp_path_factory: pytest.TempPathFactory, mocker: MockerFixture) -> None:
# Arrange
cwd = tmp_path_factory.mktemp("cwd")
txns = _generate_dummy_signed_txn_group()
- transaction.write_to_file(txns, str(cwd / "dummy.txns")) # type: ignore[no-untyped-call]
+ _write_signed_transactions_to_file(txns, cwd / "dummy.txns")
algod_mock = mocker.MagicMock()
- algod_mock.send_transactions.return_value = "dummy_tx_id"
+ algod_mock.send_raw_transaction.return_value = mocker.MagicMock(tx_id="dummy_tx_id")
mocker.patch("algokit.cli.tasks.send_transaction.load_algod_client", return_value=algod_mock)
# Act
@@ -59,7 +116,7 @@ def test_send_atomic_txn_group_successful(tmp_path_factory: pytest.TempPathFacto
def test_send_from_transaction_successful(mocker: MockerFixture) -> None:
# Arrange
algod_mock = mocker.MagicMock()
- algod_mock.send_transaction.return_value = "dummy_tx_id"
+ algod_mock.send_raw_transaction.return_value = mocker.MagicMock(tx_id="dummy_tx_id")
mocker.patch("algokit.cli.tasks.send_transaction.load_algod_client", return_value=algod_mock)
# Act
@@ -77,13 +134,11 @@ def test_send_from_file_successful(
# Arrange
cwd = tmp_path_factory.mktemp("cwd")
- transaction.write_to_file( # type: ignore[no-untyped-call]
- [_generate_dummy_signed_txn(amount=i) for i in range(20)],
- str(cwd / "dummy.txns"),
- )
+ signed_txns = [cast("SignedTransaction", _generate_dummy_signed_txn(amount=i)) for i in range(20)]
+ _write_signed_transactions_to_file(signed_txns, cwd / "dummy.txns")
algod_mock = mocker.MagicMock()
- algod_mock.send_transaction.side_effect = [f"dummy_tx_id_{i}" for i in range(20)]
+ algod_mock.send_raw_transaction.side_effect = [mocker.MagicMock(tx_id=f"dummy_tx_id_{i}") for i in range(20)]
mocker.patch("algokit.cli.tasks.send_transaction.load_algod_client", return_value=algod_mock)
# Act
@@ -105,7 +160,7 @@ def test_send_from_piped_input_successful(
txns = [{"content": _generate_dummy_signed_txn(amount=i, encode=True), "transaction_id": str(i)} for i in range(20)]
algod_mock = mocker.MagicMock()
- algod_mock.send_transaction.side_effect = [f"dummy_tx_id_{i}" for i in range(20)]
+ algod_mock.send_raw_transaction.side_effect = [mocker.MagicMock(tx_id=f"dummy_tx_id_{i}") for i in range(20)]
mocker.patch("algokit.cli.tasks.send_transaction.load_algod_client", return_value=algod_mock)
mocker.patch("algokit.cli.tasks.send_transaction.stdin_has_content", return_value=True)
diff --git a/tests/tasks/test_send_transaction.test_decoding_error.approved.txt b/tests/tasks/test_send_transaction.test_decoding_error.approved.txt
index f85218692..a46c58ded 100644
--- a/tests/tasks/test_send_transaction.test_decoding_error.approved.txt
+++ b/tests/tasks/test_send_transaction.test_decoding_error.approved.txt
@@ -1,2 +1,3 @@
-DEBUG: argument of type 'int' is not iterable
+DEBUG: No valid transactions found in file
+DEBUG: Failed to read transactions from file: No valid transactions found in file
Error: Failed to decode transaction! If you are intending to send multiple transactions use `--file` instead.
diff --git a/tests/tasks/test_send_transaction.test_file_decoding_no_txn_error.approved.txt b/tests/tasks/test_send_transaction.test_file_decoding_no_txn_error.approved.txt
index ec447b1cb..a46c58ded 100644
--- a/tests/tasks/test_send_transaction.test_file_decoding_no_txn_error.approved.txt
+++ b/tests/tasks/test_send_transaction.test_file_decoding_no_txn_error.approved.txt
@@ -1 +1,3 @@
-Error: No valid transactions found!
+DEBUG: No valid transactions found in file
+DEBUG: Failed to read transactions from file: No valid transactions found in file
+Error: Failed to decode transaction! If you are intending to send multiple transactions use `--file` instead.
diff --git a/tests/tasks/test_sign_transaction.py b/tests/tasks/test_sign_transaction.py
index defc82ebc..81e917712 100644
--- a/tests/tasks/test_sign_transaction.py
+++ b/tests/tasks/test_sign_transaction.py
@@ -1,8 +1,13 @@
+import base64
import json
+from pathlib import Path
import click
import pytest
-from algosdk import encoding, mnemonic, transaction
+from algokit_transact.models.payment import PaymentTransactionFields
+from algokit_transact.models.transaction import Transaction, TransactionType
+from algokit_utils.algo25 import secret_key_to_mnemonic
+from algokit_utils.transact import decode_transactions, encode_transactions, group_transactions
from algokit.core.tasks.wallet import WALLET_ALIASES_KEYRING_USERNAME
from tests.tasks.conftest import DUMMY_ACCOUNT, DUMMY_SUGGESTED_PARAMS
@@ -10,12 +15,67 @@
from tests.utils.click_invoker import invoke
-def _generate_dummy_txn(sender: str, amount: int = 1) -> transaction.PaymentTxn:
- return transaction.PaymentTxn(sender, DUMMY_SUGGESTED_PARAMS, sender, amt=amount) # type: ignore[no-untyped-call]
+def _write_transactions_to_file(transactions: list[Transaction], file_path: Path | str) -> None:
+ """Write transactions to a file in msgpack format (compatible with algosdk's write_to_file)."""
+ encoded_txns = encode_transactions(transactions)
+ with Path(file_path).open("wb") as f:
+ for encoded_txn in encoded_txns:
+ f.write(encoded_txn)
+
+
+def _read_transactions_from_file(file_path: Path | str) -> list[Transaction]:
+ """Read transactions from a file in msgpack format (compatible with algosdk's retrieve_from_file)."""
+ import msgpack
+
+ with Path(file_path).open("rb") as f:
+ content = f.read()
+
+ # Split the concatenated msgpack messages into individual transaction dicts
+ unpacker = msgpack.Unpacker()
+ unpacker.feed(content)
+
+ # Collect all top-level msgpack objects (each should be a dict representing a transaction)
+ transaction_dicts = []
+ for unpacked_obj in unpacker:
+ if isinstance(unpacked_obj, dict):
+ transaction_dicts.append(unpacked_obj)
+
+ # Re-encode each dict to bytes for decode_transactions
+ transaction_bytes = [msgpack.packb(txn_dict) for txn_dict in transaction_dicts]
+
+ # Decode using algokit_utils
+ return decode_transactions(transaction_bytes)
+
+
+def _generate_dummy_txn(sender: str, amount: int = 1) -> Transaction:
+ """Generate a dummy payment transaction for testing."""
+ return Transaction(
+ transaction_type=TransactionType.Payment,
+ sender=sender,
+ first_valid=DUMMY_SUGGESTED_PARAMS.first_valid,
+ last_valid=DUMMY_SUGGESTED_PARAMS.last_valid,
+ fee=DUMMY_SUGGESTED_PARAMS.min_fee,
+ genesis_id=DUMMY_SUGGESTED_PARAMS.genesis_id,
+ genesis_hash=DUMMY_SUGGESTED_PARAMS.genesis_hash,
+ payment=PaymentTransactionFields(
+ amount=amount,
+ receiver=sender,
+ ),
+ )
def _get_mnemonic_from_private_key(private_key: str) -> str:
- return str(mnemonic.from_private_key(private_key)) # type: ignore[no-untyped-call]
+ """Convert a private key to a mnemonic phrase.
+
+ Args:
+ private_key: Base64-encoded private key string (64 bytes when decoded: 32-byte seed + 32-byte public key)
+
+ Returns:
+ 25-word mnemonic phrase
+ """
+ # Decode the base64 string to get the actual bytes
+ private_key_bytes = base64.b64decode(private_key)
+ return secret_key_to_mnemonic(private_key_bytes)
def test_sign_atomic_txn_group_successful(
@@ -34,10 +94,8 @@ def test_sign_atomic_txn_group_successful(
mock_keyring[WALLET_ALIASES_KEYRING_USERNAME] = json.dumps([alias_name])
txn_a = _generate_dummy_txn(DUMMY_ACCOUNT.address)
txn_b = _generate_dummy_txn(DUMMY_ACCOUNT.address)
- gid = transaction.calculate_group_id([txn_a, txn_b]) # type: ignore[no-untyped-call]
- txn_a.group = gid
- txn_b.group = gid
- transaction.write_to_file([txn_a, txn_b], str(cwd / "dummy.txns")) # type: ignore[no-untyped-call]
+ grouped_txns = group_transactions([txn_a, txn_b])
+ _write_transactions_to_file(grouped_txns, cwd / "dummy.txns")
# Act
result = invoke(f"task sign -a {alias_name} --file dummy.txns", input="y", cwd=cwd)
@@ -61,7 +119,8 @@ def test_sign_from_stdin_with_alias_successful(mock_keyring: dict[str, str]) ->
dummy_txn = _generate_dummy_txn(DUMMY_ACCOUNT.address)
# Act
- txn = encoding.msgpack_encode({"txn": dummy_txn.dictify()}) # type: ignore[no-untyped-call]
+ encoded_txns = encode_transactions([dummy_txn])
+ txn = base64.b64encode(encoded_txns[0]).decode()
result = invoke(f"task sign -a {alias_name} --transaction {txn}", input="y")
# Assert
@@ -74,7 +133,8 @@ def test_sign_from_stdin_with_address_successful() -> None:
dummy_txn = _generate_dummy_txn(DUMMY_ACCOUNT.address)
# Act
- txn = encoding.msgpack_encode({"txn": dummy_txn.dictify()}) # type: ignore[no-untyped-call]
+ encoded_txns = encode_transactions([dummy_txn])
+ txn = base64.b64encode(encoded_txns[0]).decode()
result = invoke(
f"task sign -a {DUMMY_ACCOUNT.address} --transaction {txn}",
input=f"{_get_mnemonic_from_private_key(DUMMY_ACCOUNT.private_key)}\ny",
@@ -100,13 +160,13 @@ def test_sign_many_from_file_with_alias_successful(
)
mock_keyring[WALLET_ALIASES_KEYRING_USERNAME] = json.dumps([alias_name])
_generate_dummy_txn(DUMMY_ACCOUNT.address)
- transaction.write_to_file( # type: ignore[no-untyped-call]
+ _write_transactions_to_file(
[
_generate_dummy_txn(DUMMY_ACCOUNT.address, 1),
_generate_dummy_txn(DUMMY_ACCOUNT.address, 2),
_generate_dummy_txn(DUMMY_ACCOUNT.address, 3),
],
- str(cwd / "dummy.txns"),
+ cwd / "dummy.txns",
)
# Act
@@ -123,13 +183,13 @@ def test_sign_many_from_file_with_address_successful(
# Arrange
cwd = tmp_path_factory.mktemp("cwd")
_generate_dummy_txn(DUMMY_ACCOUNT.address)
- transaction.write_to_file( # type: ignore[no-untyped-call]
+ _write_transactions_to_file(
[
_generate_dummy_txn(DUMMY_ACCOUNT.address, 1),
_generate_dummy_txn(DUMMY_ACCOUNT.address, 2),
_generate_dummy_txn(DUMMY_ACCOUNT.address, 3),
],
- str(cwd / "dummy.txns"),
+ cwd / "dummy.txns",
)
# Act
diff --git a/tests/tasks/test_sign_transaction.test_sign_atomic_txn_group_successful.approved.txt b/tests/tasks/test_sign_transaction.test_sign_atomic_txn_group_successful.approved.txt
index 33a9a5a6a..ae3ce3686 100644
--- a/tests/tasks/test_sign_transaction.test_sign_atomic_txn_group_successful.approved.txt
+++ b/tests/tasks/test_sign_transaction.test_sign_atomic_txn_group_successful.approved.txt
@@ -1,41 +1,43 @@
[
{
- "transaction_id": "RUU4DMAYJ5TLIEZ3ZT3PWTDPUOHCGOFY26JAXMOQXE52J2W6D7UA",
+ "transaction_id": "LSDGHVZFPJBI5XFP54OMS4PQMLLLNCRSKCEQH556XKA54DLSXBDQ",
"content": {
- "amt": 1,
+ "type": "pay",
+ "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
"fv": 33652328,
- "gen": "testnet-v1.0",
- "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
- "grp": "Vyhyt7HcQWkkBxcIR4zP+GkJLUAmN2H2D5Hx03fAVvo=",
"lv": 33653328,
- "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "type": "pay"
+ "fee": 1000,
+ "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ "gen": "testnet-v1.0",
+ "grp": "FasevOeBXn9mn+ASh4lTgNY6K4T3aI4RP++2NsukL2M=",
+ "amt": 1,
+ "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI="
}
},
{
- "transaction_id": "RUU4DMAYJ5TLIEZ3ZT3PWTDPUOHCGOFY26JAXMOQXE52J2W6D7UA",
+ "transaction_id": "LSDGHVZFPJBI5XFP54OMS4PQMLLLNCRSKCEQH556XKA54DLSXBDQ",
"content": {
- "amt": 1,
+ "type": "pay",
+ "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
"fv": 33652328,
- "gen": "testnet-v1.0",
- "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
- "grp": "Vyhyt7HcQWkkBxcIR4zP+GkJLUAmN2H2D5Hx03fAVvo=",
"lv": 33653328,
- "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "type": "pay"
+ "fee": 1000,
+ "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ "gen": "testnet-v1.0",
+ "grp": "FasevOeBXn9mn+ASh4lTgNY6K4T3aI4RP++2NsukL2M=",
+ "amt": 1,
+ "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI="
}
}
]
Would you like to proceed with signing the above? (y, n) [n]: y
[
{
- "transaction_id": "RUU4DMAYJ5TLIEZ3ZT3PWTDPUOHCGOFY26JAXMOQXE52J2W6D7UA",
- "content": "gqNzaWfEQMSdIjL5dbUk+/lVCi0AWs84ikMH0gEErgYxuNHpY/dYkKIvY9XlhiszYNMhk2XlkvTCkrrWGOWmblX3Af43tg+jdHhuiaNhbXQBomZ2zgIBfmijZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKjZ3JwxCBXKHK3sdxBaSQHFwhHjM/4aQktQCY3YfYPkfHTd8BW+qJsds4CAYJQo3JjdsQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKjc25kxCBluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAqR0eXBlo3BheQ=="
+ "transaction_id": "LSDGHVZFPJBI5XFP54OMS4PQMLLLNCRSKCEQH556XKA54DLSXBDQ",
+ "content": "gqNzaWfEQPJQBvnTFZ8GDLTNH41LqGXH4my3oO/PL0tnqS1aHsXRYnYSXc7rf7zjgw8h7l7ReRcvY0o60dCMMecNlW9EGAWjdHhuiqNhbXQBo2ZlZc0D6KJmds4CAX5oo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToio2dycMQgFasevOeBXn9mn+ASh4lTgNY6K4T3aI4RP++2NsukL2OibHbOAgGCUKNyY3bEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCo3NuZMQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKkdHlwZaNwYXk="
},
{
- "transaction_id": "RUU4DMAYJ5TLIEZ3ZT3PWTDPUOHCGOFY26JAXMOQXE52J2W6D7UA",
- "content": "gqNzaWfEQMSdIjL5dbUk+/lVCi0AWs84ikMH0gEErgYxuNHpY/dYkKIvY9XlhiszYNMhk2XlkvTCkrrWGOWmblX3Af43tg+jdHhuiaNhbXQBomZ2zgIBfmijZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKjZ3JwxCBXKHK3sdxBaSQHFwhHjM/4aQktQCY3YfYPkfHTd8BW+qJsds4CAYJQo3JjdsQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKjc25kxCBluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAqR0eXBlo3BheQ=="
+ "transaction_id": "LSDGHVZFPJBI5XFP54OMS4PQMLLLNCRSKCEQH556XKA54DLSXBDQ",
+ "content": "gqNzaWfEQPJQBvnTFZ8GDLTNH41LqGXH4my3oO/PL0tnqS1aHsXRYnYSXc7rf7zjgw8h7l7ReRcvY0o60dCMMecNlW9EGAWjdHhuiqNhbXQBo2ZlZc0D6KJmds4CAX5oo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToio2dycMQgFasevOeBXn9mn+ASh4lTgNY6K4T3aI4RP++2NsukL2OibHbOAgGCUKNyY3bEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCo3NuZMQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKkdHlwZaNwYXk="
}
]
diff --git a/tests/tasks/test_sign_transaction.test_sign_from_stdin_with_address_successful.approved.txt b/tests/tasks/test_sign_transaction.test_sign_from_stdin_with_address_successful.approved.txt
index b34b60143..11f512b90 100644
--- a/tests/tasks/test_sign_transaction.test_sign_from_stdin_with_address_successful.approved.txt
+++ b/tests/tasks/test_sign_transaction.test_sign_from_stdin_with_address_successful.approved.txt
@@ -1,23 +1,24 @@
Enter the mnemonic phrase (25 words separated by whitespace):
[
{
- "transaction_id": "YGSOMX5QSASQALR5V4MH47L4GEHFJZVGSUETJAWUFM2I6PJAQL4Q",
+ "transaction_id": "FXAXUBFEV7TTXNDPNWDEVIPHP5FFILUBHLFZUU5ZUWO6PDBDHNBA",
"content": {
- "amt": 1,
+ "type": "pay",
+ "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
"fv": 33652328,
- "gen": "testnet-v1.0",
- "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 33653328,
- "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "type": "pay"
+ "fee": 1000,
+ "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ "gen": "testnet-v1.0",
+ "amt": 1,
+ "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI="
}
}
]
Would you like to proceed with signing the above? (y, n) [n]: y
[
{
- "transaction_id": "YGSOMX5QSASQALR5V4MH47L4GEHFJZVGSUETJAWUFM2I6PJAQL4Q",
- "content": "gqNzaWfEQHHuPbhkAADyq8eKU/NiDCuJ+cnW9MrHT3iAAEPm+okmoio/rmgctA7QUpqqd4eF5aYlUcgz9EbU+uUXS1rFOg2jdHhuiKNhbXQBomZ2zgIBfmijZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAgGCUKNyY3bEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCo3NuZMQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKkdHlwZaNwYXk="
+ "transaction_id": "FXAXUBFEV7TTXNDPNWDEVIPHP5FFILUBHLFZUU5ZUWO6PDBDHNBA",
+ "content": "gqNzaWfEQOQpODGqNgY91HdDDSGiDNaAa10DK3TTGBrDclzUpppvRkvxvQtB3GQWVVFXqIg4zsZn6a3xxT5dYmTFixo4gw+jdHhuiaNhbXQBo2ZlZc0D6KJmds4CAX5oo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgIBglCjcmN2xCBluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAqNzbmTEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCpHR5cGWjcGF5"
}
]
diff --git a/tests/tasks/test_sign_transaction.test_sign_from_stdin_with_alias_successful.approved.txt b/tests/tasks/test_sign_transaction.test_sign_from_stdin_with_alias_successful.approved.txt
index c4e9e2b3b..ef92889e5 100644
--- a/tests/tasks/test_sign_transaction.test_sign_from_stdin_with_alias_successful.approved.txt
+++ b/tests/tasks/test_sign_transaction.test_sign_from_stdin_with_alias_successful.approved.txt
@@ -1,22 +1,23 @@
[
{
- "transaction_id": "YGSOMX5QSASQALR5V4MH47L4GEHFJZVGSUETJAWUFM2I6PJAQL4Q",
+ "transaction_id": "FXAXUBFEV7TTXNDPNWDEVIPHP5FFILUBHLFZUU5ZUWO6PDBDHNBA",
"content": {
- "amt": 1,
+ "type": "pay",
+ "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
"fv": 33652328,
- "gen": "testnet-v1.0",
- "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 33653328,
- "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "type": "pay"
+ "fee": 1000,
+ "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ "gen": "testnet-v1.0",
+ "amt": 1,
+ "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI="
}
}
]
Would you like to proceed with signing the above? (y, n) [n]: y
[
{
- "transaction_id": "YGSOMX5QSASQALR5V4MH47L4GEHFJZVGSUETJAWUFM2I6PJAQL4Q",
- "content": "gqNzaWfEQHHuPbhkAADyq8eKU/NiDCuJ+cnW9MrHT3iAAEPm+okmoio/rmgctA7QUpqqd4eF5aYlUcgz9EbU+uUXS1rFOg2jdHhuiKNhbXQBomZ2zgIBfmijZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAgGCUKNyY3bEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCo3NuZMQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKkdHlwZaNwYXk="
+ "transaction_id": "FXAXUBFEV7TTXNDPNWDEVIPHP5FFILUBHLFZUU5ZUWO6PDBDHNBA",
+ "content": "gqNzaWfEQOQpODGqNgY91HdDDSGiDNaAa10DK3TTGBrDclzUpppvRkvxvQtB3GQWVVFXqIg4zsZn6a3xxT5dYmTFixo4gw+jdHhuiaNhbXQBo2ZlZc0D6KJmds4CAX5oo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgIBglCjcmN2xCBluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAqNzbmTEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCpHR5cGWjcGF5"
}
]
diff --git a/tests/tasks/test_sign_transaction.test_sign_many_from_file_with_address_successful.approved.txt b/tests/tasks/test_sign_transaction.test_sign_many_from_file_with_address_successful.approved.txt
index 906bb31b1..a3f1da84b 100644
--- a/tests/tasks/test_sign_transaction.test_sign_many_from_file_with_address_successful.approved.txt
+++ b/tests/tasks/test_sign_transaction.test_sign_many_from_file_with_address_successful.approved.txt
@@ -1,57 +1,60 @@
Enter the mnemonic phrase (25 words separated by whitespace):
[
{
- "transaction_id": "YGSOMX5QSASQALR5V4MH47L4GEHFJZVGSUETJAWUFM2I6PJAQL4Q",
+ "transaction_id": "FXAXUBFEV7TTXNDPNWDEVIPHP5FFILUBHLFZUU5ZUWO6PDBDHNBA",
"content": {
- "amt": 1,
+ "type": "pay",
+ "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
"fv": 33652328,
- "gen": "testnet-v1.0",
- "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 33653328,
- "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "type": "pay"
+ "fee": 1000,
+ "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ "gen": "testnet-v1.0",
+ "amt": 1,
+ "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI="
}
},
{
- "transaction_id": "MLS7IUJQVK7GABTCOLTG5QE7NWITX74D6YC3QZLN6Y5SZF23WZBQ",
+ "transaction_id": "U7BEN5KFHLXU45NWEDZCYOZGR3MAACTPJ3YNOPDWRRCBDCN2OARQ",
"content": {
- "amt": 2,
+ "type": "pay",
+ "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
"fv": 33652328,
- "gen": "testnet-v1.0",
- "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 33653328,
- "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "type": "pay"
+ "fee": 1000,
+ "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ "gen": "testnet-v1.0",
+ "amt": 2,
+ "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI="
}
},
{
- "transaction_id": "NEI3KU7ALQ6PFOSTYEN3LSJX2CUDEESDH2NH2XUJGYHNR3UVB3OQ",
+ "transaction_id": "XU2X2APELWEA5F5FJXRY3HY2HN2WZHZ5QXVB3KSWTII2GSFJGANQ",
"content": {
- "amt": 3,
+ "type": "pay",
+ "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
"fv": 33652328,
- "gen": "testnet-v1.0",
- "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 33653328,
- "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "type": "pay"
+ "fee": 1000,
+ "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ "gen": "testnet-v1.0",
+ "amt": 3,
+ "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI="
}
}
]
Would you like to proceed with signing the above? (y, n) [n]: y
[
{
- "transaction_id": "YGSOMX5QSASQALR5V4MH47L4GEHFJZVGSUETJAWUFM2I6PJAQL4Q",
- "content": "gqNzaWfEQHHuPbhkAADyq8eKU/NiDCuJ+cnW9MrHT3iAAEPm+okmoio/rmgctA7QUpqqd4eF5aYlUcgz9EbU+uUXS1rFOg2jdHhuiKNhbXQBomZ2zgIBfmijZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAgGCUKNyY3bEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCo3NuZMQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKkdHlwZaNwYXk="
+ "transaction_id": "FXAXUBFEV7TTXNDPNWDEVIPHP5FFILUBHLFZUU5ZUWO6PDBDHNBA",
+ "content": "gqNzaWfEQOQpODGqNgY91HdDDSGiDNaAa10DK3TTGBrDclzUpppvRkvxvQtB3GQWVVFXqIg4zsZn6a3xxT5dYmTFixo4gw+jdHhuiaNhbXQBo2ZlZc0D6KJmds4CAX5oo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgIBglCjcmN2xCBluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAqNzbmTEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCpHR5cGWjcGF5"
},
{
- "transaction_id": "MLS7IUJQVK7GABTCOLTG5QE7NWITX74D6YC3QZLN6Y5SZF23WZBQ",
- "content": "gqNzaWfEQMDbNg81bX8hvW+MHye1pJhtDxWvk/3Oec8lC8QZ5i0pn7LNnXTEniYzhECzjwxL11ENlTh6w66M2jl1f4YeZwijdHhuiKNhbXQComZ2zgIBfmijZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAgGCUKNyY3bEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCo3NuZMQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKkdHlwZaNwYXk="
+ "transaction_id": "U7BEN5KFHLXU45NWEDZCYOZGR3MAACTPJ3YNOPDWRRCBDCN2OARQ",
+ "content": "gqNzaWfEQKfuYSfeVHZOW7O2I388MWbjE1zRhp6zrZE7KJ4oV75XJpx8ExKByk9NIAYpyneekuoGDg4Ks+kVVcvT6X6J9wujdHhuiaNhbXQCo2ZlZc0D6KJmds4CAX5oo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgIBglCjcmN2xCBluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAqNzbmTEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCpHR5cGWjcGF5"
},
{
- "transaction_id": "NEI3KU7ALQ6PFOSTYEN3LSJX2CUDEESDH2NH2XUJGYHNR3UVB3OQ",
- "content": "gqNzaWfEQJPaDlnXKBkMacMv6SNJmDlRf2dBzVBZwhOelc/Q+uriONVXzP0pqmZqqCua/fo3DxH9tbKyCDcSYVmn9MsaLgqjdHhuiKNhbXQDomZ2zgIBfmijZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAgGCUKNyY3bEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCo3NuZMQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKkdHlwZaNwYXk="
+ "transaction_id": "XU2X2APELWEA5F5FJXRY3HY2HN2WZHZ5QXVB3KSWTII2GSFJGANQ",
+ "content": "gqNzaWfEQEsValgtAQZFPE1/iDUyIr58QNhNCjogIK72ckwM78kyUaEX3+PYPLZDkoVLvjx5ChMrbB71avpVt0onfrqSvQCjdHhuiaNhbXQDo2ZlZc0D6KJmds4CAX5oo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgIBglCjcmN2xCBluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAqNzbmTEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCpHR5cGWjcGF5"
}
]
diff --git a/tests/tasks/test_sign_transaction.test_sign_many_from_file_with_alias_successful.approved.txt b/tests/tasks/test_sign_transaction.test_sign_many_from_file_with_alias_successful.approved.txt
index ecd969451..43428e904 100644
--- a/tests/tasks/test_sign_transaction.test_sign_many_from_file_with_alias_successful.approved.txt
+++ b/tests/tasks/test_sign_transaction.test_sign_many_from_file_with_alias_successful.approved.txt
@@ -1,56 +1,59 @@
[
{
- "transaction_id": "YGSOMX5QSASQALR5V4MH47L4GEHFJZVGSUETJAWUFM2I6PJAQL4Q",
+ "transaction_id": "FXAXUBFEV7TTXNDPNWDEVIPHP5FFILUBHLFZUU5ZUWO6PDBDHNBA",
"content": {
- "amt": 1,
+ "type": "pay",
+ "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
"fv": 33652328,
- "gen": "testnet-v1.0",
- "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 33653328,
- "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "type": "pay"
+ "fee": 1000,
+ "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ "gen": "testnet-v1.0",
+ "amt": 1,
+ "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI="
}
},
{
- "transaction_id": "MLS7IUJQVK7GABTCOLTG5QE7NWITX74D6YC3QZLN6Y5SZF23WZBQ",
+ "transaction_id": "U7BEN5KFHLXU45NWEDZCYOZGR3MAACTPJ3YNOPDWRRCBDCN2OARQ",
"content": {
- "amt": 2,
+ "type": "pay",
+ "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
"fv": 33652328,
- "gen": "testnet-v1.0",
- "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 33653328,
- "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "type": "pay"
+ "fee": 1000,
+ "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ "gen": "testnet-v1.0",
+ "amt": 2,
+ "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI="
}
},
{
- "transaction_id": "NEI3KU7ALQ6PFOSTYEN3LSJX2CUDEESDH2NH2XUJGYHNR3UVB3OQ",
+ "transaction_id": "XU2X2APELWEA5F5FJXRY3HY2HN2WZHZ5QXVB3KSWTII2GSFJGANQ",
"content": {
- "amt": 3,
+ "type": "pay",
+ "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
"fv": 33652328,
- "gen": "testnet-v1.0",
- "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 33653328,
- "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "snd": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI=",
- "type": "pay"
+ "fee": 1000,
+ "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
+ "gen": "testnet-v1.0",
+ "amt": 3,
+ "rcv": "ZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQI="
}
}
]
Would you like to proceed with signing the above? (y, n) [n]: y
[
{
- "transaction_id": "YGSOMX5QSASQALR5V4MH47L4GEHFJZVGSUETJAWUFM2I6PJAQL4Q",
- "content": "gqNzaWfEQHHuPbhkAADyq8eKU/NiDCuJ+cnW9MrHT3iAAEPm+okmoio/rmgctA7QUpqqd4eF5aYlUcgz9EbU+uUXS1rFOg2jdHhuiKNhbXQBomZ2zgIBfmijZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAgGCUKNyY3bEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCo3NuZMQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKkdHlwZaNwYXk="
+ "transaction_id": "FXAXUBFEV7TTXNDPNWDEVIPHP5FFILUBHLFZUU5ZUWO6PDBDHNBA",
+ "content": "gqNzaWfEQOQpODGqNgY91HdDDSGiDNaAa10DK3TTGBrDclzUpppvRkvxvQtB3GQWVVFXqIg4zsZn6a3xxT5dYmTFixo4gw+jdHhuiaNhbXQBo2ZlZc0D6KJmds4CAX5oo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgIBglCjcmN2xCBluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAqNzbmTEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCpHR5cGWjcGF5"
},
{
- "transaction_id": "MLS7IUJQVK7GABTCOLTG5QE7NWITX74D6YC3QZLN6Y5SZF23WZBQ",
- "content": "gqNzaWfEQMDbNg81bX8hvW+MHye1pJhtDxWvk/3Oec8lC8QZ5i0pn7LNnXTEniYzhECzjwxL11ENlTh6w66M2jl1f4YeZwijdHhuiKNhbXQComZ2zgIBfmijZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAgGCUKNyY3bEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCo3NuZMQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKkdHlwZaNwYXk="
+ "transaction_id": "U7BEN5KFHLXU45NWEDZCYOZGR3MAACTPJ3YNOPDWRRCBDCN2OARQ",
+ "content": "gqNzaWfEQKfuYSfeVHZOW7O2I388MWbjE1zRhp6zrZE7KJ4oV75XJpx8ExKByk9NIAYpyneekuoGDg4Ks+kVVcvT6X6J9wujdHhuiaNhbXQCo2ZlZc0D6KJmds4CAX5oo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgIBglCjcmN2xCBluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAqNzbmTEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCpHR5cGWjcGF5"
},
{
- "transaction_id": "NEI3KU7ALQ6PFOSTYEN3LSJX2CUDEESDH2NH2XUJGYHNR3UVB3OQ",
- "content": "gqNzaWfEQJPaDlnXKBkMacMv6SNJmDlRf2dBzVBZwhOelc/Q+uriONVXzP0pqmZqqCua/fo3DxH9tbKyCDcSYVmn9MsaLgqjdHhuiKNhbXQDomZ2zgIBfmijZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOAgGCUKNyY3bEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCo3NuZMQgZbpO9Kb7j1+HWA9SYq/ObmT/gCJjP/EgZnT0aQUkxQKkdHlwZaNwYXk="
+ "transaction_id": "XU2X2APELWEA5F5FJXRY3HY2HN2WZHZ5QXVB3KSWTII2GSFJGANQ",
+ "content": "gqNzaWfEQEsValgtAQZFPE1/iDUyIr58QNhNCjogIK72ckwM78kyUaEX3+PYPLZDkoVLvjx5ChMrbB71avpVt0onfrqSvQCjdHhuiaNhbXQDo2ZlZc0D6KJmds4CAX5oo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgIBglCjcmN2xCBluk70pvuPX4dYD1Jir85uZP+AImM/8SBmdPRpBSTFAqNzbmTEIGW6TvSm+49fh1gPUmKvzm5k/4AiYz/xIGZ09GkFJMUCpHR5cGWjcGF5"
}
]
diff --git a/tests/tasks/test_transfer.py b/tests/tasks/test_transfer.py
index 502411b13..9eea83105 100644
--- a/tests/tasks/test_transfer.py
+++ b/tests/tasks/test_transfer.py
@@ -1,11 +1,11 @@
import json
import pytest
-from algokit_utils import SendAtomicTransactionComposerResults
-from algosdk import account, mnemonic
+from algokit_utils import SendTransactionComposerResults
from pytest_mock import MockerFixture
from algokit.core.tasks.wallet import WALLET_ALIASES_KEYRING_USERNAME
+from tests.conftest import generate_test_account
from tests.utils.approvals import verify
from tests.utils.click_invoker import invoke
@@ -15,15 +15,6 @@ def get_txid(self) -> str:
return "dummy_txid"
-def _generate_account() -> tuple[str, str]:
- pk, addr = account.generate_account() # type: ignore[no-untyped-call]
- return pk, addr
-
-
-def _get_mnemonic_from_private_key(private_key: str) -> str:
- return str(mnemonic.from_private_key(private_key)) # type: ignore[no-untyped-call]
-
-
def test_transfer_no_args() -> None:
result = invoke("task transfer")
@@ -34,7 +25,7 @@ def test_transfer_no_args() -> None:
@pytest.mark.usefixtures("mock_keyring")
def test_transfer_invalid_sender_account() -> None:
# Arrange
- dummy_receiver = _generate_account()[1]
+ _, dummy_receiver, _ = generate_test_account()
# Act
result = invoke(f"task transfer -s invalid-address -r {dummy_receiver} -a 1")
@@ -47,12 +38,12 @@ def test_transfer_invalid_sender_account() -> None:
@pytest.mark.usefixtures("mock_keyring")
def test_transfer_invalid_receiver_account() -> None:
# Arrange
- dummy_sender_pk, dummy_sender_address = _generate_account()
+ dummy_sender_pk, dummy_sender_address, dummy_sender_mnemonic = generate_test_account()
# Act
result = invoke(
f"task transfer -s {dummy_sender_address} -r invalid-address -a 1",
- input=_get_mnemonic_from_private_key(dummy_sender_pk),
+ input=dummy_sender_mnemonic,
)
# Assert
@@ -62,13 +53,13 @@ def test_transfer_invalid_receiver_account() -> None:
def test_transfer_no_amount() -> None:
# Arrange
- dummy_sender_pk, dummy_sender_address = _generate_account()
- dummy_receiver_address = _generate_account()[1]
+ dummy_sender_pk, dummy_sender_address, dummy_sender_mnemonic = generate_test_account()
+ _, dummy_receiver_address, _ = generate_test_account()
# Act
result = invoke(
f"task transfer -s {dummy_sender_address} -r {dummy_receiver_address}",
- input=_get_mnemonic_from_private_key(dummy_sender_pk),
+ input=dummy_sender_mnemonic,
)
# Assert
@@ -81,7 +72,7 @@ def test_transfer_algo_from_address_successful(mocker: MockerFixture) -> None:
algorand_mock = mocker.MagicMock()
composer_mock = mocker.MagicMock()
composer_mock.add_payment.return_value = composer_mock
- composer_mock.send.return_value = SendAtomicTransactionComposerResults(
+ composer_mock.send.return_value = SendTransactionComposerResults(
group_id="dummy_group_id",
confirmations=[],
tx_ids=["dummy_txid"],
@@ -92,13 +83,13 @@ def test_transfer_algo_from_address_successful(mocker: MockerFixture) -> None:
mocker.patch("algokit.cli.tasks.transfer.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.transfer.validate_address")
mocker.patch("algokit.cli.tasks.transfer.validate_balance")
- dummy_sender_pk, dummy_sender_address = _generate_account()
- dummy_receiver_address = _generate_account()[1]
+ dummy_sender_pk, dummy_sender_address, dummy_sender_mnemonic = generate_test_account()
+ _, dummy_receiver_address, _ = generate_test_account()
# Act
result = invoke(
f"task transfer -s {dummy_sender_address} -r {dummy_receiver_address} -a 1",
- input=_get_mnemonic_from_private_key(dummy_sender_pk),
+ input=dummy_sender_mnemonic,
)
# Assert
@@ -111,7 +102,7 @@ def test_transfer_algo_from_alias_successful(mocker: MockerFixture, mock_keyring
algorand_mock = mocker.MagicMock()
composer_mock = mocker.MagicMock()
composer_mock.add_payment.return_value = composer_mock
- composer_mock.send.return_value = SendAtomicTransactionComposerResults(
+ composer_mock.send.return_value = SendTransactionComposerResults(
group_id="dummy_group_id",
confirmations=[],
tx_ids=["dummy_txid"],
@@ -122,8 +113,8 @@ def test_transfer_algo_from_alias_successful(mocker: MockerFixture, mock_keyring
mocker.patch("algokit.cli.tasks.transfer.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.transfer.validate_address")
mocker.patch("algokit.cli.tasks.transfer.validate_balance")
- dummy_sender_pk, dummy_sender_address = _generate_account()
- dummy_receiver_address = _generate_account()[1]
+ dummy_sender_pk, dummy_sender_address, dummy_sender_mnemonic = generate_test_account()
+ _, dummy_receiver_address, _ = generate_test_account()
alias_name = "dummy_alias"
mock_keyring[alias_name] = json.dumps(
@@ -138,7 +129,7 @@ def test_transfer_algo_from_alias_successful(mocker: MockerFixture, mock_keyring
# Act
result = invoke(
f"task transfer -s {alias_name} -r {dummy_receiver_address} -a 1",
- input=_get_mnemonic_from_private_key(dummy_sender_pk),
+ input=dummy_sender_mnemonic,
)
# Assert
@@ -151,7 +142,7 @@ def test_transfer_asset_from_address_successful(mocker: MockerFixture) -> None:
algorand_mock = mocker.MagicMock()
composer_mock = mocker.MagicMock()
composer_mock.add_asset_transfer.return_value = composer_mock
- composer_mock.send.return_value = SendAtomicTransactionComposerResults(
+ composer_mock.send.return_value = SendTransactionComposerResults(
group_id="dummy_group_id",
confirmations=[],
tx_ids=["dummy_txid"],
@@ -162,13 +153,13 @@ def test_transfer_asset_from_address_successful(mocker: MockerFixture) -> None:
mocker.patch("algokit.cli.tasks.transfer.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.transfer.validate_address")
mocker.patch("algokit.cli.tasks.transfer.validate_balance")
- dummy_sender_pk, dummy_sender_address = _generate_account()
- dummy_receiver_address = _generate_account()[1]
+ dummy_sender_pk, dummy_sender_address, dummy_sender_mnemonic = generate_test_account()
+ _, dummy_receiver_address, _ = generate_test_account()
# Act
result = invoke(
f"task transfer -s {dummy_sender_address} -r {dummy_receiver_address} -a 1 --id 1234",
- input=_get_mnemonic_from_private_key(dummy_sender_pk),
+ input=dummy_sender_mnemonic,
)
# Assert
@@ -181,7 +172,7 @@ def test_transfer_asset_from_address_to_alias_successful(mocker: MockerFixture,
algorand_mock = mocker.MagicMock()
composer_mock = mocker.MagicMock()
composer_mock.add_asset_transfer.return_value = composer_mock
- composer_mock.send.return_value = SendAtomicTransactionComposerResults(
+ composer_mock.send.return_value = SendTransactionComposerResults(
group_id="dummy_group_id",
confirmations=[],
tx_ids=["dummy_txid"],
@@ -192,8 +183,7 @@ def test_transfer_asset_from_address_to_alias_successful(mocker: MockerFixture,
mocker.patch("algokit.cli.tasks.transfer.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.transfer.validate_address")
mocker.patch("algokit.cli.tasks.transfer.validate_balance")
- dummy_sender_pk, dummy_sender_address = _generate_account()
- _generate_account()[1]
+ dummy_sender_pk, dummy_sender_address, dummy_sender_mnemonic = generate_test_account()
dummy_receiver_alias = "dummy_receiver_alias"
mock_keyring[dummy_receiver_alias] = json.dumps(
@@ -208,7 +198,7 @@ def test_transfer_asset_from_address_to_alias_successful(mocker: MockerFixture,
# Act
result = invoke(
f"task transfer -s {dummy_sender_address} -r {dummy_receiver_alias} -a 1 --id 1234",
- input=_get_mnemonic_from_private_key(dummy_sender_pk),
+ input=dummy_sender_mnemonic,
)
# Assert
@@ -221,7 +211,7 @@ def test_transfer_asset_from_alias_successful(mocker: MockerFixture, mock_keyrin
algorand_mock = mocker.MagicMock()
composer_mock = mocker.MagicMock()
composer_mock.add_asset_transfer.return_value = composer_mock
- composer_mock.send.return_value = SendAtomicTransactionComposerResults(
+ composer_mock.send.return_value = SendTransactionComposerResults(
group_id="dummy_group_id",
confirmations=[],
tx_ids=["dummy_txid"],
@@ -232,8 +222,8 @@ def test_transfer_asset_from_alias_successful(mocker: MockerFixture, mock_keyrin
mocker.patch("algokit.cli.tasks.transfer.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.transfer.validate_address")
mocker.patch("algokit.cli.tasks.transfer.validate_balance")
- dummy_sender_pk, dummy_sender_address = _generate_account()
- dummy_receiver_address = _generate_account()[1]
+ dummy_sender_pk, dummy_sender_address, dummy_sender_mnemonic = generate_test_account()
+ _, dummy_receiver_address, _ = generate_test_account()
alias_name = "dummy_alias"
mock_keyring[alias_name] = json.dumps(
@@ -248,7 +238,7 @@ def test_transfer_asset_from_alias_successful(mocker: MockerFixture, mock_keyrin
# Act
result = invoke(
f"task transfer -s {alias_name} -r {dummy_receiver_address} -a 1 --id 1234",
- input=_get_mnemonic_from_private_key(dummy_sender_pk),
+ input=dummy_sender_mnemonic,
)
# Assert
@@ -265,8 +255,8 @@ def test_transfer_failed(mocker: MockerFixture, mock_keyring: dict[str, str]) ->
mocker.patch("algokit.cli.tasks.transfer.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.transfer.validate_address")
mocker.patch("algokit.cli.tasks.transfer.validate_balance")
- dummy_sender_pk, dummy_sender_address = _generate_account()
- dummy_receiver_address = _generate_account()[1]
+ dummy_sender_pk, dummy_sender_address, dummy_sender_mnemonic = generate_test_account()
+ _, dummy_receiver_address, _ = generate_test_account()
alias_name = "dummy_alias"
mock_keyring[alias_name] = json.dumps(
@@ -281,7 +271,7 @@ def test_transfer_failed(mocker: MockerFixture, mock_keyring: dict[str, str]) ->
# Act
result = invoke(
f"task transfer -s {alias_name} -r {dummy_receiver_address} -a 1",
- input=_get_mnemonic_from_private_key(dummy_sender_pk),
+ input=dummy_sender_mnemonic,
)
# Assert
@@ -294,7 +284,7 @@ def test_transfer_on_testnet(mocker: MockerFixture) -> None:
algorand_mock = mocker.MagicMock()
composer_mock = mocker.MagicMock()
composer_mock.add_payment.return_value = composer_mock
- composer_mock.send.return_value = SendAtomicTransactionComposerResults(
+ composer_mock.send.return_value = SendTransactionComposerResults(
group_id="dummy_group_id",
confirmations=[],
tx_ids=["dummy_txid"],
@@ -305,13 +295,13 @@ def test_transfer_on_testnet(mocker: MockerFixture) -> None:
mocker.patch("algokit.cli.tasks.transfer.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.transfer.validate_address")
mocker.patch("algokit.cli.tasks.transfer.validate_balance")
- dummy_sender_pk, dummy_sender_address = _generate_account()
- dummy_receiver_address = _generate_account()[1]
+ dummy_sender_pk, dummy_sender_address, dummy_sender_mnemonic = generate_test_account()
+ _, dummy_receiver_address, _ = generate_test_account()
# Act
result = invoke(
f"task transfer -s {dummy_sender_address} -r {dummy_receiver_address} -a 1 -n testnet",
- input=_get_mnemonic_from_private_key(dummy_sender_pk),
+ input=dummy_sender_mnemonic,
)
# Assert
@@ -324,7 +314,7 @@ def test_transfer_on_mainnet(mocker: MockerFixture) -> None:
algorand_mock = mocker.MagicMock()
composer_mock = mocker.MagicMock()
composer_mock.add_payment.return_value = composer_mock
- composer_mock.send.return_value = SendAtomicTransactionComposerResults(
+ composer_mock.send.return_value = SendTransactionComposerResults(
group_id="dummy_group_id",
confirmations=[],
tx_ids=["dummy_txid"],
@@ -335,13 +325,13 @@ def test_transfer_on_mainnet(mocker: MockerFixture) -> None:
mocker.patch("algokit.cli.tasks.transfer.get_algorand_client_for_network", return_value=algorand_mock)
mocker.patch("algokit.cli.tasks.transfer.validate_address")
mocker.patch("algokit.cli.tasks.transfer.validate_balance")
- dummy_sender_pk, dummy_sender_address = _generate_account()
- dummy_receiver_address = _generate_account()[1]
+ dummy_sender_pk, dummy_sender_address, dummy_sender_mnemonic = generate_test_account()
+ _, dummy_receiver_address, _ = generate_test_account()
# Act
result = invoke(
f"task transfer -s {dummy_sender_address} -r {dummy_receiver_address} -a 1 -n mainnet",
- input=_get_mnemonic_from_private_key(dummy_sender_pk),
+ input=dummy_sender_mnemonic,
)
# Assert
diff --git a/tests/tasks/test_wallet.py b/tests/tasks/test_wallet.py
index 45248117b..69bc35485 100644
--- a/tests/tasks/test_wallet.py
+++ b/tests/tasks/test_wallet.py
@@ -1,7 +1,10 @@
+import base64
import json
-import algosdk
import pytest
+from algokit_utils.algo25 import secret_key_to_mnemonic
+from algokit_utils.common import address_from_public_key
+from nacl.signing import SigningKey
from pytest_mock import MockerFixture
from algokit.core.tasks.wallet import WALLET_ALIASES_KEYRING_USERNAME
@@ -9,11 +12,25 @@
from tests.utils.click_invoker import invoke
+def generate_test_account() -> tuple[str, str]:
+ """Generate a test account for testing purposes.
+
+ Returns:
+ tuple[str, str]: A tuple of (private_key, address).
+ The private key is base64-encoded (64 bytes: 32 bytes secret + 32 bytes public key).
+ """
+ signing_key = SigningKey.generate()
+ private_key_bytes = signing_key.encode() + signing_key.verify_key.encode()
+ private_key = base64.b64encode(private_key_bytes).decode()
+ address = address_from_public_key(signing_key.verify_key.encode())
+ return private_key, address
+
+
class TestAddAlias:
def test_wallet_add_address_successful(self, mock_keyring: dict[str, str | None]) -> None:
# Arrange
alias_name = "test_alias"
- address = algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
+ address = generate_test_account()[1]
# Act
result = invoke(f"task wallet add {alias_name} -a {address}")
@@ -31,8 +48,8 @@ def test_wallet_add_address_successful(self, mock_keyring: dict[str, str | None]
def test_wallet_add_account_successful(self, mock_keyring: dict[str, str | None]) -> None:
# Arrange
alias_name = "test_alias"
- pk, address = algosdk.account.generate_account() # type: ignore[no-untyped-call]
- mnemonic = algosdk.mnemonic.from_private_key(pk) # type: ignore[no-untyped-call]
+ pk, address = generate_test_account()
+ mnemonic = secret_key_to_mnemonic(base64.b64decode(pk))
# Act
result = invoke(f"task wallet add {alias_name} -a {address} -m", input=f"{mnemonic}\n")
@@ -60,9 +77,9 @@ def test_wallet_add_invalid_address(self, mock_keyring: dict[str, str | None]) -
def test_wallet_add_alias_exists(self, mock_keyring: dict[str, str | None]) -> None:
# Arrange
bob_alias = "test_alias"
- bob_address = algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
+ bob_address = generate_test_account()[1]
mock_keyring[bob_alias] = json.dumps({"alias": bob_alias, "address": bob_address, "private_key": None})
- alice_address = algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
+ alice_address = generate_test_account()[1]
# Act
result = invoke(f"task wallet add {bob_alias} -a {alice_address}", input="y\n")
@@ -80,9 +97,9 @@ def test_wallet_add_alias_exists(self, mock_keyring: dict[str, str | None]) -> N
def test_wallet_add_alias_mnemonic_differs(self, mock_keyring: dict[str, str | None]) -> None:
# Arrange
alias_name = "test_alias"
- address = algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
- pk = algosdk.account.generate_account()[0] # type: ignore[no-untyped-call]
- mnemonic = algosdk.mnemonic.from_private_key(pk) # type: ignore[no-untyped-call]
+ address = generate_test_account()[1]
+ pk = generate_test_account()[0]
+ mnemonic = secret_key_to_mnemonic(base64.b64decode(pk))
# Act
result = invoke(f"task wallet add {alias_name} -a {address} -m", input=f"{mnemonic}\n")
@@ -99,12 +116,12 @@ def test_wallet_add_alias_limit_error(self, mock_keyring: dict[str, str | None])
for i in range(50):
alias_name = f"test_alias_{i}"
dummy_aliases.append(alias_name)
- address = algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
+ address = generate_test_account()[1]
mock_keyring[alias_name] = json.dumps({"alias": alias_name, "address": address, "private_key": None})
mock_keyring[WALLET_ALIASES_KEYRING_USERNAME] = json.dumps(dummy_aliases)
alias_name = "test_alias"
- address = algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
+ address = generate_test_account()[1]
# Act
result = invoke(f"task wallet add {alias_name} -a {address}")
@@ -118,7 +135,7 @@ def test_wallet_add_alias_limit_error(self, mock_keyring: dict[str, str | None])
def test_wallet_add_alias_generic_error(self, mocker: MockerFixture, mock_keyring: dict[str, str | None]) -> None:
# Arrange
alias_name = "test_alias"
- address = algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
+ address = generate_test_account()[1]
mocker.patch("algokit.cli.tasks.wallet.add_alias", side_effect=Exception("test error"))
# Act
@@ -135,7 +152,7 @@ class TestGetAlias:
def test_wallet_get_address_alias_successful(self, mock_keyring: dict[str, str | None]) -> None:
# Arrange
alias_name = "test_alias"
- address = algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
+ address = generate_test_account()[1]
mock_keyring[alias_name] = json.dumps({"alias": alias_name, "address": address, "private_key": None})
# Act
@@ -148,7 +165,7 @@ def test_wallet_get_address_alias_successful(self, mock_keyring: dict[str, str |
def test_wallet_get_account_alias_successful(self, mock_keyring: dict[str, str | None]) -> None:
# Arrange
alias_name = "test_alias"
- pk, address = algosdk.account.generate_account() # type: ignore[no-untyped-call]
+ pk, address = generate_test_account()
mock_keyring[alias_name] = json.dumps({"alias": alias_name, "address": address, "private_key": pk})
# Act
@@ -176,7 +193,6 @@ def test_wallet_get_alias_not_found(
class TestListAliases:
def test_wallet_list_aliases_successful(self, mock_keyring: dict[str, str | None]) -> None:
# Arrange
- algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
mock_keyring["test_alias_1"] = json.dumps(
{"alias": "test_alias_1", "address": "test_address_1", "private_key": None},
)
@@ -212,7 +228,7 @@ class TestRemoveAlias:
def test_wallet_remove_alias_successful(self, mock_keyring: dict[str, str | None]) -> None:
# Arrange
alias_name = "test_alias"
- address = algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
+ address = generate_test_account()[1]
mock_keyring[alias_name] = json.dumps({"alias": alias_name, "address": address, "private_key": None})
mock_keyring[WALLET_ALIASES_KEYRING_USERNAME] = json.dumps([alias_name])
@@ -254,7 +270,6 @@ def test_wallet_remove_alias_generic_error(self, mocker: MockerFixture) -> None:
class TestResetAliases:
def test_wallet_reset_aliases_successful(self, mock_keyring: dict[str, str | None]) -> None:
# Arrange
- algosdk.account.generate_account()[1] # type: ignore[no-untyped-call]
mock_keyring["test_alias_1"] = json.dumps(
{"alias": "test_alias_1", "address": "test_address_1", "private_key": None},
)
diff --git a/tests/test_utils_path_resolution.py b/tests/test_utils_path_resolution.py
new file mode 100644
index 000000000..a93ee0a46
--- /dev/null
+++ b/tests/test_utils_path_resolution.py
@@ -0,0 +1,68 @@
+import logging
+import os
+import stat
+import sys
+from pathlib import Path
+from typing import TYPE_CHECKING
+
+from pytest_mock import MockerFixture
+
+from algokit.cli import _check_binary_deprecation
+from algokit.core.utils import find_all_on_path
+
+if TYPE_CHECKING:
+ from _pytest.logging import LogCaptureFixture
+ from _pytest.monkeypatch import MonkeyPatch
+
+
+def _make_executable(path: Path) -> Path:
+ executable_path = path.with_suffix(".exe") if os.name == "nt" else path
+ executable_path.write_text("#!/usr/bin/env sh\n", encoding="utf-8")
+ executable_path.chmod(executable_path.stat().st_mode | stat.S_IXUSR)
+ return executable_path
+
+
+def test_find_all_on_path_returns_matches_in_path_order(tmp_path: Path, monkeypatch: "MonkeyPatch") -> None:
+ legacy_dir = tmp_path / "legacy-bin"
+ uv_dir = tmp_path / "uv-bin"
+ legacy_dir.mkdir()
+ uv_dir.mkdir()
+
+ legacy_algokit = _make_executable(legacy_dir / "algokit")
+ uv_algokit = _make_executable(uv_dir / "algokit")
+
+ monkeypatch.setenv("PATH", f"{legacy_dir}{os.pathsep}{uv_dir}")
+
+ paths = find_all_on_path("algokit")
+
+ assert [path.resolve() for path in paths] == [legacy_algokit.resolve(), uv_algokit.resolve()]
+
+
+def test_find_all_on_path_deduplicates_repeated_entries(tmp_path: Path, monkeypatch: "MonkeyPatch") -> None:
+ tools_dir = tmp_path / "tools"
+ tools_dir.mkdir()
+
+ algokit = _make_executable(tools_dir / "algokit")
+
+ monkeypatch.setenv("PATH", f"{tools_dir}{os.pathsep}{tools_dir}")
+
+ paths = find_all_on_path("algokit")
+
+ assert [path.resolve() for path in paths] == [algokit.resolve()]
+
+
+def test_check_binary_deprecation_warns_when_multiple_algokit_are_on_path(
+ caplog: "LogCaptureFixture", mocker: MockerFixture, monkeypatch: "MonkeyPatch"
+) -> None:
+ mocker.patch("algokit.cli.is_binary_mode", return_value=True)
+ first_algokit_path = Path("/usr/local/bin/algokit")
+ second_algokit_path = Path("/home/user/.local/bin/algokit")
+ mocker.patch("algokit.cli.find_all_on_path", return_value=[first_algokit_path, second_algokit_path])
+ monkeypatch.setattr(sys, "executable", str(first_algokit_path))
+
+ with caplog.at_level(logging.WARNING):
+ _check_binary_deprecation()
+
+ assert "Multiple `algokit` executables were found on PATH." in caplog.text
+ assert str(first_algokit_path) in caplog.text
+ assert str(second_algokit_path) in caplog.text
diff --git a/tests/utils/approvals.py b/tests/utils/approvals.py
index a5fa6e7c3..3ba31a2f7 100644
--- a/tests/utils/approvals.py
+++ b/tests/utils/approvals.py
@@ -23,7 +23,7 @@ def normalize_path(content: str, path: str, token: str) -> str:
)
-def _normalize_platform_differences(data: str, poetry_version: str = "99.99.99") -> str:
+def _normalize_platform_differences(data: str) -> str:
"""Normalize platform-specific and version-specific differences."""
result = data
@@ -39,10 +39,9 @@ def _normalize_platform_differences(data: str, poetry_version: str = "99.99.99")
r"DEBUG: git: Stopping at filesystem boundary \(GIT_DISCOVERY_ACROSS_FILESYSTEM not set\)\.\n", "", result
)
- # Normalize Poetry version output to avoid test failures on version updates
- result = re.sub(
- r"DEBUG: poetry: Poetry \(version \d+\.\d+\.\d+\)", f"DEBUG: poetry: Poetry (version {poetry_version})", result
- )
+ # Strip poetry version output entirely — poetry may or may not be installed
+ result = re.sub(r"DEBUG: poetry: Poetry \(version \d+\.\d+\.\d+\)\n?", "", result)
+ result = re.sub(r"DEBUG: Running 'poetry --version'[^\n]*\n?", "", result)
# Normalize msgpack/Python TypeError messages for 'in' operator
# C-extension msgpack (Python 3.10-3.13) says "is not a container or iterable"
@@ -78,7 +77,6 @@ def verify(
*,
options: approvaltests.Options | None = None,
scrubber: Scrubber | None = None,
- poetry_version: str = "99.99.99",
**kwargs: Any,
) -> None:
options = options or approvaltests.Options()
@@ -87,8 +85,7 @@ def verify(
kwargs.setdefault("encoding", "utf-8")
normalised_data = str(data).replace("\r\n", "\n")
- # Apply global platform/version normalization with configurable poetry version
- normalised_data = _normalize_platform_differences(normalised_data, poetry_version)
+ normalised_data = _normalize_platform_differences(normalised_data)
approvaltests.verify(
data=normalised_data,
diff --git a/tests/version_check/test_version_check.test_version_check_queries_github_when_cache_out_of_date.approved.txt b/tests/version_check/test_version_check.test_version_check_queries_github_when_cache_out_of_date.approved.txt
index 0405965f9..f17d9698e 100644
--- a/tests/version_check/test_version_check.test_version_check_queries_github_when_cache_out_of_date.approved.txt
+++ b/tests/version_check/test_version_check.test_version_check_queries_github_when_cache_out_of_date.approved.txt
@@ -2,7 +2,5 @@ DEBUG: 1234.56.78 found in cache {app_state}/last-version-check
HTTP Request: GET https://api.github.com/repos/algorandfoundation/algokit-cli/releases/latest "HTTP/1.1 200 OK"
DEBUG: Latest version tag: v{new_version}
You are using AlgoKit version {current_version}, however version {new_version} is available. Please update using the tool used to install AlgoKit.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
diff --git a/tests/version_check/test_version_check.test_version_check_queries_github_when_no_cache.approved.txt b/tests/version_check/test_version_check.test_version_check_queries_github_when_no_cache.approved.txt
index 2cbd0ad23..5a16229b3 100644
--- a/tests/version_check/test_version_check.test_version_check_queries_github_when_no_cache.approved.txt
+++ b/tests/version_check/test_version_check.test_version_check_queries_github_when_no_cache.approved.txt
@@ -2,7 +2,5 @@ DEBUG: {app_state}/last-version-check inaccessible
HTTP Request: GET https://api.github.com/repos/algorandfoundation/algokit-cli/releases/latest "HTTP/1.1 200 OK"
DEBUG: Latest version tag: v{new_version}
You are using AlgoKit version {current_version}, however version {new_version} is available. Please update using the tool used to install AlgoKit.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
diff --git a/tests/version_check/test_version_check.test_version_check_respects_disable_config.approved.txt b/tests/version_check/test_version_check.test_version_check_respects_disable_config.approved.txt
index ea96feeae..57893de50 100644
--- a/tests/version_check/test_version_check.test_version_check_respects_disable_config.approved.txt
+++ b/tests/version_check/test_version_check.test_version_check_respects_disable_config.approved.txt
@@ -1,5 +1,3 @@
DEBUG: Version prompt disabled
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
diff --git a/tests/version_check/test_version_check.test_version_check_respects_skip_option.approved.txt b/tests/version_check/test_version_check.test_version_check_respects_skip_option.approved.txt
index f1eeca807..4e14461c8 100644
--- a/tests/version_check/test_version_check.test_version_check_respects_skip_option.approved.txt
+++ b/tests/version_check/test_version_check.test_version_check_respects_skip_option.approved.txt
@@ -1,4 +1,2 @@
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
diff --git a/tests/version_check/test_version_check.test_version_check_uses_cache.approved.txt b/tests/version_check/test_version_check.test_version_check_uses_cache.approved.txt
index e0df934a3..ce57ae483 100644
--- a/tests/version_check/test_version_check.test_version_check_uses_cache.approved.txt
+++ b/tests/version_check/test_version_check.test_version_check_uses_cache.approved.txt
@@ -1,6 +1,4 @@
DEBUG: 1234.56.78 found in cache {app_state}/last-version-check
You are using AlgoKit version {current_version}, however version 1234.56.78 is available. Please update using the tool used to install AlgoKit.
-DEBUG: Running 'poetry --version' in '{current_working_directory}'
-DEBUG: poetry: Poetry (version 99.99.99)
DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml
DEBUG: No .algokit.toml file found in the project directory.
diff --git a/uv.lock b/uv.lock
new file mode 100644
index 000000000..9ff843137
--- /dev/null
+++ b/uv.lock
@@ -0,0 +1,2824 @@
+version = 1
+revision = 3
+requires-python = ">=3.10, <3.15"
+
+[[package]]
+name = "alabaster"
+version = "0.7.16"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c9/3e/13dd8e5ed9094e734ac430b5d0eb4f2bb001708a8b7856cbf8e084e001ba/alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", size = 23776, upload-time = "2024-01-10T00:56:10.189Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/32/34/d4e1c02d3bee589efb5dfa17f88ea08bdb3e3eac12bc475462aec52ed223/alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92", size = 13511, upload-time = "2024-01-10T00:56:08.388Z" },
+]
+
+[[package]]
+name = "algokit"
+version = "2.10.2"
+source = { editable = "." }
+dependencies = [
+ { name = "algokit-utils" },
+ { name = "click" },
+ { name = "copier" },
+ { name = "cryptography" },
+ { name = "httpx" },
+ { name = "jsondiff" },
+ { name = "keyring" },
+ { name = "mslex" },
+ { name = "multiformats" },
+ { name = "multiformats-config" },
+ { name = "prompt-toolkit" },
+ { name = "pyclip" },
+ { name = "pyjwt" },
+ { name = "python-dotenv" },
+ { name = "pywin32", marker = "sys_platform == 'win32'" },
+ { name = "questionary" },
+ { name = "requests" },
+ { name = "shellingham" },
+ { name = "textual" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+
+[package.dev-dependencies]
+dev = [
+ { name = "approvaltests" },
+ { name = "gfm-toc" },
+ { name = "mypy" },
+ { name = "pip-audit" },
+ { name = "poethepoet" },
+ { name = "pre-commit" },
+ { name = "pyinstaller" },
+ { name = "pytest" },
+ { name = "pytest-cov" },
+ { name = "pytest-httpx" },
+ { name = "pytest-mock" },
+ { name = "pytest-sugar" },
+ { name = "pytest-xdist" },
+ { name = "python-semantic-release" },
+ { name = "ruff" },
+ { name = "types-pyyaml" },
+]
+docs = [
+ { name = "sphinx" },
+ { name = "sphinx-click" },
+ { name = "sphinxnotes-markdown-builder" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "algokit-utils", specifier = ">=5.0.0a7,<6.0.0" },
+ { name = "click", specifier = "==8.1.8" },
+ { name = "copier", specifier = ">=9.11.3,<10.0.0" },
+ { name = "cryptography", specifier = ">=46.0.5,<47.0.0" },
+ { name = "httpx", specifier = ">=0.23.1,<=0.28.1" },
+ { name = "jsondiff", specifier = ">=2.0.0,<3.0.0" },
+ { name = "keyring", specifier = "==25.6.0" },
+ { name = "mslex", specifier = ">=1.1.0,<2.0.0" },
+ { name = "multiformats", specifier = "==0.3.1" },
+ { name = "multiformats-config", specifier = "==0.3.1" },
+ { name = "prompt-toolkit", specifier = "==3.0.51" },
+ { name = "pyclip", specifier = ">=0.7.0,<0.8.0" },
+ { name = "pyjwt", specifier = ">=2.10.1,<3.0.0" },
+ { name = "python-dotenv", specifier = ">=1.0.0,<2.0.0" },
+ { name = "pywin32", marker = "sys_platform == 'win32'", specifier = ">=311,<312" },
+ { name = "questionary", specifier = ">=1.10.0,<2.0.0" },
+ { name = "requests", specifier = ">=2.31.0,<3.0.0" },
+ { name = "shellingham", specifier = ">=1.5.4,<2.0.0" },
+ { name = "textual", specifier = ">=3.0.1,<4.0.0" },
+ { name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=2.0.1,<3.0.0" },
+]
+
+[package.metadata.requires-dev]
+dev = [
+ { name = "approvaltests", specifier = ">=7.2.0,<8.0.0" },
+ { name = "gfm-toc", specifier = ">=0.0.7,<0.0.8" },
+ { name = "mypy", specifier = ">=1.0.0,<2.0.0" },
+ { name = "pip-audit", specifier = ">=2.4.7,<3.0.0" },
+ { name = "poethepoet", specifier = ">=0.17.1,<0.37.0" },
+ { name = "pre-commit", specifier = ">=2.20,<4.0" },
+ { name = "pyinstaller", specifier = ">=6.10.0,<7.0.0" },
+ { name = "pytest", specifier = ">=8,<9" },
+ { name = "pytest-cov", specifier = ">=4.0.0,<5.0.0" },
+ { name = "pytest-httpx", specifier = ">=0.35.0,<0.36.0" },
+ { name = "pytest-mock", specifier = ">=3.10.0,<4.0.0" },
+ { name = "pytest-sugar", specifier = ">=1.0.0,<2.0.0" },
+ { name = "pytest-xdist", specifier = ">=3.4.0,<4.0.0" },
+ { name = "python-semantic-release", specifier = ">=7.32.2,<8.0.0" },
+ { name = "ruff", specifier = ">=0.1.6,<0.13.0" },
+ { name = "types-pyyaml", specifier = ">=6.0.12.20250402,<7.0.0" },
+]
+docs = [
+ { name = "sphinx", specifier = ">=6.0.0,<7.0.0" },
+ { name = "sphinx-click", specifier = ">=4.4.0,<5.0.0" },
+ { name = "sphinxnotes-markdown-builder", specifier = ">=0.5.6,<0.6.0" },
+]
+
+[[package]]
+name = "algokit-utils"
+version = "5.0.0a17"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "httpx" },
+ { name = "msgpack" },
+ { name = "msgpack-types" },
+ { name = "pycryptodomex" },
+ { name = "pynacl" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f1/06/dc995bfddff9bf64e67f9b74b6bced79e404f3f87a4948d85de7e6516045/algokit_utils-5.0.0a17.tar.gz", hash = "sha256:378773ec6d24a9838c7be90b79810359544848d9a7ddafd38655e9a468809bd3", size = 217266, upload-time = "2026-02-20T20:40:24.165Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9a/19/d4f4be3aae15294f8ab90e07be71abe82a10da862b4544878a005a6fcd68/algokit_utils-5.0.0a17-py3-none-any.whl", hash = "sha256:4c896e8cdfaedc32b67ff0bce6981d999e4da5319fe0aafcc749e16a820c0fdc", size = 337339, upload-time = "2026-02-20T20:40:22.708Z" },
+]
+
+[[package]]
+name = "allpairspy"
+version = "2.5.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ea/9e/a5a536c22f56cdbbb0236889cff33915e20fb93a0526887367b38e91122e/allpairspy-2.5.1.tar.gz", hash = "sha256:f69d31a3b56eee119d1ec6063e9c732dd44fbba352ef738cb22d9699fc4009fe", size = 14281, upload-time = "2023-07-08T09:08:54.049Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/1a/fedf0f2ff77ec65e599112b2d5402fee5c166d9378b51760b696bd8cde1d/allpairspy-2.5.1-py3-none-any.whl", hash = "sha256:3f97cbac2bbee86f4bfceffd0fd91dca740a120c78e9368af2bad81a2b3426e2", size = 8965, upload-time = "2023-07-08T09:08:51.994Z" },
+]
+
+[[package]]
+name = "altgraph"
+version = "0.17.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7e/f8/97fdf103f38fed6792a1601dbc16cc8aac56e7459a9fff08c812d8ae177a/altgraph-0.17.5.tar.gz", hash = "sha256:c87b395dd12fabde9c99573a9749d67da8d29ef9de0125c7f536699b4a9bc9e7", size = 48428, upload-time = "2025-11-21T20:35:50.583Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a9/ba/000a1996d4308bc65120167c21241a3b205464a2e0b58deda26ae8ac21d1/altgraph-0.17.5-py2.py3-none-any.whl", hash = "sha256:f3a22400bce1b0c701683820ac4f3b159cd301acab067c51c653e06961600597", size = 21228, upload-time = "2025-11-21T20:35:49.444Z" },
+]
+
+[[package]]
+name = "annotated-types"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
+]
+
+[[package]]
+name = "anyio"
+version = "4.12.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+ { name = "idna" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" },
+]
+
+[[package]]
+name = "approval-utilities"
+version = "7.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/60/4c/fcf3bbd765b99086cdd58ab93378363195f6ec985e542d52aedb41b101bb/approval_utilities-7.4.0.tar.gz", hash = "sha256:8e0b146716db2f7d95d01726947438904760a6cb005aa391cee6f7a623d627ee", size = 16445, upload-time = "2022-12-11T19:10:40.624Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/9c/01596fbd22d57f5b75f7a203c9a25a9f94753da6c85ede8fb97ed8d7232f/approval_utilities-7.4.0-py3-none-any.whl", hash = "sha256:d11f545ad318f3520e997657aaeb6511521a4d0b647a0868037ca817af7c73b3", size = 17136, upload-time = "2022-12-11T19:10:39.068Z" },
+]
+
+[[package]]
+name = "approvaltests"
+version = "7.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "allpairspy" },
+ { name = "approval-utilities" },
+ { name = "beautifulsoup4" },
+ { name = "empty-files" },
+ { name = "mrjob" },
+ { name = "pyperclip" },
+ { name = "pytest" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/44/c7/3a85d9a136b27922a51c4aba505cbca26ffdb9f860ea93e3f5ae4eda3e5c/approvaltests-7.4.0.tar.gz", hash = "sha256:e09b2f2af6cd049d71a3dcdc7b3bb4c2cd887cc5eb4b1294b557675360c5f90d", size = 35166, upload-time = "2022-12-11T19:10:44.306Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/86/34/58af7f3e316be630a1568ae40a1117a22d6298fb59a707c0470c7593bc26/approvaltests-7.4.0-py3-none-any.whl", hash = "sha256:64e8798f843f44ffd047935f18e8ec850caf9d4f924b9b24456008102cbb6aca", size = 59778, upload-time = "2022-12-11T19:10:42.67Z" },
+]
+
+[[package]]
+name = "babel"
+version = "2.18.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" },
+]
+
+[[package]]
+name = "backports-tarfile"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991", size = 86406, upload-time = "2024-05-28T17:01:54.731Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181, upload-time = "2024-05-28T17:01:53.112Z" },
+]
+
+[[package]]
+name = "bases"
+version = "0.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+ { name = "typing-validation" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/de/8d/105bca352e2fc5f1ee07f425ec296aa680525aac7f197ef135ea057902ac/bases-0.3.0.tar.gz", hash = "sha256:70f04a4a45d63245787f9e89095ca11042685b6b64b542ad916575ba3ccd1570", size = 789978, upload-time = "2023-12-18T16:57:17.898Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b4/15/7bcf28a3f971e1b0523fab46ae3ca935a589249544187558e5a8e70af393/bases-0.3.0-py3-none-any.whl", hash = "sha256:a2fef3366f3e522ff473d2e95c21523fe8e44251038d5c6150c01481585ebf5b", size = 36053, upload-time = "2023-12-18T16:57:14.253Z" },
+]
+
+[[package]]
+name = "beautifulsoup4"
+version = "4.14.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "soupsieve" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" },
+]
+
+[[package]]
+name = "boolean-py"
+version = "5.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c4/cf/85379f13b76f3a69bca86b60237978af17d6aa0bc5998978c3b8cf05abb2/boolean_py-5.0.tar.gz", hash = "sha256:60cbc4bad079753721d32649545505362c754e121570ada4658b852a3a318d95", size = 37047, upload-time = "2025-04-03T10:39:49.734Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e5/ca/78d423b324b8d77900030fa59c4aa9054261ef0925631cd2501dd015b7b7/boolean_py-5.0-py3-none-any.whl", hash = "sha256:ef28a70bd43115208441b53a045d1549e2f0ec6e3d08a9d142cbc41c1938e8d9", size = 26577, upload-time = "2025-04-03T10:39:48.449Z" },
+]
+
+[[package]]
+name = "cachecontrol"
+version = "0.14.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "msgpack" },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2d/f6/c972b32d80760fb79d6b9eeb0b3010a46b89c0b23cf6329417ff7886cd22/cachecontrol-0.14.4.tar.gz", hash = "sha256:e6220afafa4c22a47dd0badb319f84475d79108100d04e26e8542ef7d3ab05a1", size = 16150, upload-time = "2025-11-14T04:32:13.138Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ef/79/c45f2d53efe6ada1110cf6f9fca095e4ff47a0454444aefdde6ac4789179/cachecontrol-0.14.4-py3-none-any.whl", hash = "sha256:b7ac014ff72ee199b5f8af1de29d60239954f223e948196fa3d84adaffc71d2b", size = 22247, upload-time = "2025-11-14T04:32:11.733Z" },
+]
+
+[package.optional-dependencies]
+filecache = [
+ { name = "filelock" },
+]
+
+[[package]]
+name = "certifi"
+version = "2026.2.25"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
+]
+
+[[package]]
+name = "cffi"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pycparser", marker = "implementation_name != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" },
+ { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" },
+ { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" },
+ { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" },
+ { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" },
+ { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" },
+ { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" },
+ { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" },
+ { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" },
+ { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" },
+ { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" },
+ { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
+ { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
+ { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
+ { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
+ { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
+ { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
+ { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
+ { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
+ { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
+ { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
+ { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
+ { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
+ { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
+ { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
+]
+
+[[package]]
+name = "cfgv"
+version = "3.5.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" },
+]
+
+[[package]]
+name = "charset-normalizer"
+version = "3.4.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" },
+ { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" },
+ { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" },
+ { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" },
+ { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" },
+ { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" },
+ { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" },
+ { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" },
+ { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" },
+ { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" },
+ { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" },
+ { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" },
+ { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
+ { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" },
+ { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" },
+ { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" },
+ { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" },
+ { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" },
+ { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" },
+ { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" },
+ { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" },
+ { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" },
+ { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" },
+ { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" },
+ { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" },
+ { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" },
+ { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" },
+ { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" },
+ { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" },
+ { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" },
+ { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" },
+ { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" },
+ { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
+]
+
+[[package]]
+name = "click"
+version = "8.1.8"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" },
+]
+
+[[package]]
+name = "click-log"
+version = "0.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/32/32/228be4f971e4bd556c33d52a22682bfe318ffe57a1ddb7a546f347a90260/click-log-0.4.0.tar.gz", hash = "sha256:3970f8570ac54491237bcdb3d8ab5e3eef6c057df29f8c3d1151a51a9c23b975", size = 9985, upload-time = "2022-03-13T11:10:15.262Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ae/5a/4f025bc751087833686892e17e7564828e409c43b632878afeae554870cd/click_log-0.4.0-py2.py3-none-any.whl", hash = "sha256:a43e394b528d52112af599f2fc9e4b7cf3c15f94e53581f74fa6867e68c91756", size = 4273, upload-time = "2022-03-13T11:10:17.594Z" },
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple" }
+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" }
+wheels = [
+ { 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" },
+]
+
+[[package]]
+name = "copier"
+version = "9.12.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama" },
+ { name = "dunamai" },
+ { name = "funcy" },
+ { name = "jinja2" },
+ { name = "jinja2-ansible-filters" },
+ { name = "packaging" },
+ { name = "pathspec" },
+ { name = "platformdirs" },
+ { name = "plumbum" },
+ { name = "pydantic" },
+ { name = "pygments" },
+ { name = "pyyaml" },
+ { name = "questionary" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/6b/e0/5187c63a9020e84cfbb3cc52b52d7fc15aab73fd1e9106ae33167116a3f9/copier-9.12.0.tar.gz", hash = "sha256:87986637205a0443dbf7e5946502e5c71962a559c25f436642a08203cf61ef54", size = 611292, upload-time = "2026-02-21T13:32:40.37Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9c/22/6d9cfea622a064d17f406bbea1dd37f95ac75094d44e23447df934661add/copier-9.12.0-py3-none-any.whl", hash = "sha256:a1bc84dfd2a4b85dbe034999026c0e24ca02a6bc1574f45df07fd76d935c2ea9", size = 58805, upload-time = "2026-02-21T13:32:38.767Z" },
+]
+
+[[package]]
+name = "coverage"
+version = "7.13.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/44/d4/7827d9ffa34d5d4d752eec907022aa417120936282fc488306f5da08c292/coverage-7.13.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fc31c787a84f8cd6027eba44010517020e0d18487064cd3d8968941856d1415", size = 219152, upload-time = "2026-02-09T12:56:11.974Z" },
+ { url = "https://files.pythonhosted.org/packages/35/b0/d69df26607c64043292644dbb9dc54b0856fabaa2cbb1eeee3331cc9e280/coverage-7.13.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a32ebc02a1805adf637fc8dec324b5cdacd2e493515424f70ee33799573d661b", size = 219667, upload-time = "2026-02-09T12:56:13.33Z" },
+ { url = "https://files.pythonhosted.org/packages/82/a4/c1523f7c9e47b2271dbf8c2a097e7a1f89ef0d66f5840bb59b7e8814157b/coverage-7.13.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e24f9156097ff9dc286f2f913df3a7f63c0e333dcafa3c196f2c18b4175ca09a", size = 246425, upload-time = "2026-02-09T12:56:14.552Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/02/aa7ec01d1a5023c4b680ab7257f9bfde9defe8fdddfe40be096ac19e8177/coverage-7.13.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8041b6c5bfdc03257666e9881d33b1abc88daccaf73f7b6340fb7946655cd10f", size = 248229, upload-time = "2026-02-09T12:56:16.31Z" },
+ { url = "https://files.pythonhosted.org/packages/35/98/85aba0aed5126d896162087ef3f0e789a225697245256fc6181b95f47207/coverage-7.13.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a09cfa6a5862bc2fc6ca7c3def5b2926194a56b8ab78ffcf617d28911123012", size = 250106, upload-time = "2026-02-09T12:56:18.024Z" },
+ { url = "https://files.pythonhosted.org/packages/96/72/1db59bd67494bc162e3e4cd5fbc7edba2c7026b22f7c8ef1496d58c2b94c/coverage-7.13.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:296f8b0af861d3970c2a4d8c91d48eb4dd4771bcef9baedec6a9b515d7de3def", size = 252021, upload-time = "2026-02-09T12:56:19.272Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/97/72899c59c7066961de6e3daa142d459d47d104956db43e057e034f015c8a/coverage-7.13.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e101609bcbbfb04605ea1027b10dc3735c094d12d40826a60f897b98b1c30256", size = 247114, upload-time = "2026-02-09T12:56:21.051Z" },
+ { url = "https://files.pythonhosted.org/packages/39/1f/f1885573b5970235e908da4389176936c8933e86cb316b9620aab1585fa2/coverage-7.13.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa3feb8db2e87ff5e6d00d7e1480ae241876286691265657b500886c98f38bda", size = 248143, upload-time = "2026-02-09T12:56:22.585Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/cf/e80390c5b7480b722fa3e994f8202807799b85bc562aa4f1dde209fbb7be/coverage-7.13.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4fc7fa81bbaf5a02801b65346c8b3e657f1d93763e58c0abdf7c992addd81a92", size = 246152, upload-time = "2026-02-09T12:56:23.748Z" },
+ { url = "https://files.pythonhosted.org/packages/44/bf/f89a8350d85572f95412debb0fb9bb4795b1d5b5232bd652923c759e787b/coverage-7.13.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:33901f604424145c6e9c2398684b92e176c0b12df77d52db81c20abd48c3794c", size = 249959, upload-time = "2026-02-09T12:56:25.209Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/6e/612a02aece8178c818df273e8d1642190c4875402ca2ba74514394b27aba/coverage-7.13.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:bb28c0f2cf2782508a40cec377935829d5fcc3ad9a3681375af4e84eb34b6b58", size = 246416, upload-time = "2026-02-09T12:56:26.475Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/98/b5afc39af67c2fa6786b03c3a7091fc300947387ce8914b096db8a73d67a/coverage-7.13.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d107aff57a83222ddbd8d9ee705ede2af2cc926608b57abed8ef96b50b7e8f9", size = 247025, upload-time = "2026-02-09T12:56:27.727Z" },
+ { url = "https://files.pythonhosted.org/packages/51/30/2bba8ef0682d5bd210c38fe497e12a06c9f8d663f7025e9f5c2c31ce847d/coverage-7.13.4-cp310-cp310-win32.whl", hash = "sha256:a6f94a7d00eb18f1b6d403c91a88fd58cfc92d4b16080dfdb774afc8294469bf", size = 221758, upload-time = "2026-02-09T12:56:29.051Z" },
+ { url = "https://files.pythonhosted.org/packages/78/13/331f94934cf6c092b8ea59ff868eb587bc8fe0893f02c55bc6c0183a192e/coverage-7.13.4-cp310-cp310-win_amd64.whl", hash = "sha256:2cb0f1e000ebc419632bbe04366a8990b6e32c4e0b51543a6484ffe15eaeda95", size = 222693, upload-time = "2026-02-09T12:56:30.366Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/ad/b59e5b451cf7172b8d1043dc0fa718f23aab379bc1521ee13d4bd9bfa960/coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053", size = 219278, upload-time = "2026-02-09T12:56:31.673Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/17/0cb7ca3de72e5f4ef2ec2fa0089beafbcaaaead1844e8b8a63d35173d77d/coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11", size = 219783, upload-time = "2026-02-09T12:56:33.104Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/63/325d8e5b11e0eaf6d0f6a44fad444ae58820929a9b0de943fa377fe73e85/coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa", size = 250200, upload-time = "2026-02-09T12:56:34.474Z" },
+ { url = "https://files.pythonhosted.org/packages/76/53/c16972708cbb79f2942922571a687c52bd109a7bd51175aeb7558dff2236/coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7", size = 252114, upload-time = "2026-02-09T12:56:35.749Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/c2/7ab36d8b8cc412bec9ea2d07c83c48930eb4ba649634ba00cb7e4e0f9017/coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00", size = 254220, upload-time = "2026-02-09T12:56:37.796Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/4d/cf52c9a3322c89a0e6febdfbc83bb45c0ed3c64ad14081b9503adee702e7/coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef", size = 256164, upload-time = "2026-02-09T12:56:39.016Z" },
+ { url = "https://files.pythonhosted.org/packages/78/e9/eb1dd17bd6de8289df3580e967e78294f352a5df8a57ff4671ee5fc3dcd0/coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903", size = 250325, upload-time = "2026-02-09T12:56:40.668Z" },
+ { url = "https://files.pythonhosted.org/packages/71/07/8c1542aa873728f72267c07278c5cc0ec91356daf974df21335ccdb46368/coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f", size = 251913, upload-time = "2026-02-09T12:56:41.97Z" },
+ { url = "https://files.pythonhosted.org/packages/74/d7/c62e2c5e4483a748e27868e4c32ad3daa9bdddbba58e1bc7a15e252baa74/coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299", size = 249974, upload-time = "2026-02-09T12:56:43.323Z" },
+ { url = "https://files.pythonhosted.org/packages/98/9f/4c5c015a6e98ced54efd0f5cf8d31b88e5504ecb6857585fc0161bb1e600/coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505", size = 253741, upload-time = "2026-02-09T12:56:45.155Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/59/0f4eef89b9f0fcd9633b5d350016f54126ab49426a70ff4c4e87446cabdc/coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6", size = 249695, upload-time = "2026-02-09T12:56:46.636Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/2c/b7476f938deb07166f3eb281a385c262675d688ff4659ad56c6c6b8e2e70/coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9", size = 250599, upload-time = "2026-02-09T12:56:48.13Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/34/c3420709d9846ee3785b9f2831b4d94f276f38884032dca1457fa83f7476/coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9", size = 221780, upload-time = "2026-02-09T12:56:50.479Z" },
+ { url = "https://files.pythonhosted.org/packages/61/08/3d9c8613079d2b11c185b865de9a4c1a68850cfda2b357fae365cf609f29/coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f", size = 222715, upload-time = "2026-02-09T12:56:51.815Z" },
+ { url = "https://files.pythonhosted.org/packages/18/1a/54c3c80b2f056164cc0a6cdcb040733760c7c4be9d780fe655f356f433e4/coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f", size = 221385, upload-time = "2026-02-09T12:56:53.194Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/81/4ce2fdd909c5a0ed1f6dedb88aa57ab79b6d1fbd9b588c1ac7ef45659566/coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459", size = 219449, upload-time = "2026-02-09T12:56:54.889Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/96/5238b1efc5922ddbdc9b0db9243152c09777804fb7c02ad1741eb18a11c0/coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3", size = 219810, upload-time = "2026-02-09T12:56:56.33Z" },
+ { url = "https://files.pythonhosted.org/packages/78/72/2f372b726d433c9c35e56377cf1d513b4c16fe51841060d826b95caacec1/coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634", size = 251308, upload-time = "2026-02-09T12:56:57.858Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/a0/2ea570925524ef4e00bb6c82649f5682a77fac5ab910a65c9284de422600/coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3", size = 254052, upload-time = "2026-02-09T12:56:59.754Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/ac/45dc2e19a1939098d783c846e130b8f862fbb50d09e0af663988f2f21973/coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa", size = 255165, upload-time = "2026-02-09T12:57:01.287Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/4d/26d236ff35abc3b5e63540d3386e4c3b192168c1d96da5cb2f43c640970f/coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3", size = 257432, upload-time = "2026-02-09T12:57:02.637Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/55/14a966c757d1348b2e19caf699415a2a4c4f7feaa4bbc6326a51f5c7dd1b/coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a", size = 251716, upload-time = "2026-02-09T12:57:04.056Z" },
+ { url = "https://files.pythonhosted.org/packages/77/33/50116647905837c66d28b2af1321b845d5f5d19be9655cb84d4a0ea806b4/coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7", size = 253089, upload-time = "2026-02-09T12:57:05.503Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/b4/8efb11a46e3665d92635a56e4f2d4529de6d33f2cb38afd47d779d15fc99/coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc", size = 251232, upload-time = "2026-02-09T12:57:06.879Z" },
+ { url = "https://files.pythonhosted.org/packages/51/24/8cd73dd399b812cc76bb0ac260e671c4163093441847ffe058ac9fda1e32/coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47", size = 255299, upload-time = "2026-02-09T12:57:08.245Z" },
+ { url = "https://files.pythonhosted.org/packages/03/94/0a4b12f1d0e029ce1ccc1c800944a9984cbe7d678e470bb6d3c6bc38a0da/coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985", size = 250796, upload-time = "2026-02-09T12:57:10.142Z" },
+ { url = "https://files.pythonhosted.org/packages/73/44/6002fbf88f6698ca034360ce474c406be6d5a985b3fdb3401128031eef6b/coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0", size = 252673, upload-time = "2026-02-09T12:57:12.197Z" },
+ { url = "https://files.pythonhosted.org/packages/de/c6/a0279f7c00e786be75a749a5674e6fa267bcbd8209cd10c9a450c655dfa7/coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246", size = 221990, upload-time = "2026-02-09T12:57:14.085Z" },
+ { url = "https://files.pythonhosted.org/packages/77/4e/c0a25a425fcf5557d9abd18419c95b63922e897bc86c1f327f155ef234a9/coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126", size = 222800, upload-time = "2026-02-09T12:57:15.944Z" },
+ { url = "https://files.pythonhosted.org/packages/47/ac/92da44ad9a6f4e3a7debd178949d6f3769bedca33830ce9b1dcdab589a37/coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d", size = 221415, upload-time = "2026-02-09T12:57:17.497Z" },
+ { url = "https://files.pythonhosted.org/packages/db/23/aad45061a31677d68e47499197a131eea55da4875d16c1f42021ab963503/coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9", size = 219474, upload-time = "2026-02-09T12:57:19.332Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/70/9b8b67a0945f3dfec1fd896c5cefb7c19d5a3a6d74630b99a895170999ae/coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac", size = 219844, upload-time = "2026-02-09T12:57:20.66Z" },
+ { url = "https://files.pythonhosted.org/packages/97/fd/7e859f8fab324cef6c4ad7cff156ca7c489fef9179d5749b0c8d321281c2/coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea", size = 250832, upload-time = "2026-02-09T12:57:22.007Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/dc/b2442d10020c2f52617828862d8b6ee337859cd8f3a1f13d607dddda9cf7/coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b", size = 253434, upload-time = "2026-02-09T12:57:23.339Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/88/6728a7ad17428b18d836540630487231f5470fb82454871149502f5e5aa2/coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525", size = 254676, upload-time = "2026-02-09T12:57:24.774Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/bc/21244b1b8cedf0dff0a2b53b208015fe798d5f2a8d5348dbfece04224fff/coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242", size = 256807, upload-time = "2026-02-09T12:57:26.125Z" },
+ { url = "https://files.pythonhosted.org/packages/97/a0/ddba7ed3251cff51006737a727d84e05b61517d1784a9988a846ba508877/coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148", size = 251058, upload-time = "2026-02-09T12:57:27.614Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/55/e289addf7ff54d3a540526f33751951bf0878f3809b47f6dfb3def69c6f7/coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a", size = 252805, upload-time = "2026-02-09T12:57:29.066Z" },
+ { url = "https://files.pythonhosted.org/packages/13/4e/cc276b1fa4a59be56d96f1dabddbdc30f4ba22e3b1cd42504c37b3313255/coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23", size = 250766, upload-time = "2026-02-09T12:57:30.522Z" },
+ { url = "https://files.pythonhosted.org/packages/94/44/1093b8f93018f8b41a8cf29636c9292502f05e4a113d4d107d14a3acd044/coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80", size = 254923, upload-time = "2026-02-09T12:57:31.946Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/55/ea2796da2d42257f37dbea1aab239ba9263b31bd91d5527cdd6db5efe174/coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea", size = 250591, upload-time = "2026-02-09T12:57:33.842Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/fa/7c4bb72aacf8af5020675aa633e59c1fbe296d22aed191b6a5b711eb2bc7/coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a", size = 252364, upload-time = "2026-02-09T12:57:35.743Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/38/a8d2ec0146479c20bbaa7181b5b455a0c41101eed57f10dd19a78ab44c80/coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d", size = 222010, upload-time = "2026-02-09T12:57:37.25Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/0c/dbfafbe90a185943dcfbc766fe0e1909f658811492d79b741523a414a6cc/coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd", size = 222818, upload-time = "2026-02-09T12:57:38.734Z" },
+ { url = "https://files.pythonhosted.org/packages/04/d1/934918a138c932c90d78301f45f677fb05c39a3112b96fd2c8e60503cdc7/coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af", size = 221438, upload-time = "2026-02-09T12:57:40.223Z" },
+ { url = "https://files.pythonhosted.org/packages/52/57/ee93ced533bcb3e6df961c0c6e42da2fc6addae53fb95b94a89b1e33ebd7/coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d", size = 220165, upload-time = "2026-02-09T12:57:41.639Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/e0/969fc285a6fbdda49d91af278488d904dcd7651b2693872f0ff94e40e84a/coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12", size = 220516, upload-time = "2026-02-09T12:57:44.215Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/b8/9531944e16267e2735a30a9641ff49671f07e8138ecf1ca13db9fd2560c7/coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b", size = 261804, upload-time = "2026-02-09T12:57:45.989Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/f3/e63df6d500314a2a60390d1989240d5f27318a7a68fa30ad3806e2a9323e/coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9", size = 263885, upload-time = "2026-02-09T12:57:47.42Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/67/7654810de580e14b37670b60a09c599fa348e48312db5b216d730857ffe6/coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092", size = 266308, upload-time = "2026-02-09T12:57:49.345Z" },
+ { url = "https://files.pythonhosted.org/packages/37/6f/39d41eca0eab3cc82115953ad41c4e77935286c930e8fad15eaed1389d83/coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9", size = 267452, upload-time = "2026-02-09T12:57:50.811Z" },
+ { url = "https://files.pythonhosted.org/packages/50/6d/39c0fbb8fc5cd4d2090811e553c2108cf5112e882f82505ee7495349a6bf/coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26", size = 261057, upload-time = "2026-02-09T12:57:52.447Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/a2/60010c669df5fa603bb5a97fb75407e191a846510da70ac657eb696b7fce/coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2", size = 263875, upload-time = "2026-02-09T12:57:53.938Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/d9/63b22a6bdbd17f1f96e9ed58604c2a6b0e72a9133e37d663bef185877cf6/coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940", size = 261500, upload-time = "2026-02-09T12:57:56.012Z" },
+ { url = "https://files.pythonhosted.org/packages/70/bf/69f86ba1ad85bc3ad240e4c0e57a2e620fbc0e1645a47b5c62f0e941ad7f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c", size = 265212, upload-time = "2026-02-09T12:57:57.5Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/f2/5f65a278a8c2148731831574c73e42f57204243d33bedaaf18fa79c5958f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0", size = 260398, upload-time = "2026-02-09T12:57:59.027Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/80/6e8280a350ee9fea92f14b8357448a242dcaa243cb2c72ab0ca591f66c8c/coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b", size = 262584, upload-time = "2026-02-09T12:58:01.129Z" },
+ { url = "https://files.pythonhosted.org/packages/22/63/01ff182fc95f260b539590fb12c11ad3e21332c15f9799cb5e2386f71d9f/coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9", size = 222688, upload-time = "2026-02-09T12:58:02.736Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/43/89de4ef5d3cd53b886afa114065f7e9d3707bdb3e5efae13535b46ae483d/coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd", size = 223746, upload-time = "2026-02-09T12:58:05.362Z" },
+ { url = "https://files.pythonhosted.org/packages/35/39/7cf0aa9a10d470a5309b38b289b9bb07ddeac5d61af9b664fe9775a4cb3e/coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997", size = 222003, upload-time = "2026-02-09T12:58:06.952Z" },
+ { url = "https://files.pythonhosted.org/packages/92/11/a9cf762bb83386467737d32187756a42094927150c3e107df4cb078e8590/coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601", size = 219522, upload-time = "2026-02-09T12:58:08.623Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/28/56e6d892b7b052236d67c95f1936b6a7cf7c3e2634bf27610b8cbd7f9c60/coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689", size = 219855, upload-time = "2026-02-09T12:58:10.176Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/69/233459ee9eb0c0d10fcc2fe425a029b3fa5ce0f040c966ebce851d030c70/coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c", size = 250887, upload-time = "2026-02-09T12:58:12.503Z" },
+ { url = "https://files.pythonhosted.org/packages/06/90/2cdab0974b9b5bbc1623f7876b73603aecac11b8d95b85b5b86b32de5eab/coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129", size = 253396, upload-time = "2026-02-09T12:58:14.615Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/15/ea4da0f85bf7d7b27635039e649e99deb8173fe551096ea15017f7053537/coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552", size = 254745, upload-time = "2026-02-09T12:58:16.162Z" },
+ { url = "https://files.pythonhosted.org/packages/99/11/bb356e86920c655ca4d61daee4e2bbc7258f0a37de0be32d233b561134ff/coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a", size = 257055, upload-time = "2026-02-09T12:58:17.892Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/0f/9ae1f8cb17029e09da06ca4e28c9e1d5c1c0a511c7074592e37e0836c915/coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356", size = 250911, upload-time = "2026-02-09T12:58:19.495Z" },
+ { url = "https://files.pythonhosted.org/packages/89/3a/adfb68558fa815cbc29747b553bc833d2150228f251b127f1ce97e48547c/coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71", size = 252754, upload-time = "2026-02-09T12:58:21.064Z" },
+ { url = "https://files.pythonhosted.org/packages/32/b1/540d0c27c4e748bd3cd0bd001076ee416eda993c2bae47a73b7cc9357931/coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5", size = 250720, upload-time = "2026-02-09T12:58:22.622Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/95/383609462b3ffb1fe133014a7c84fc0dd01ed55ac6140fa1093b5af7ebb1/coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98", size = 254994, upload-time = "2026-02-09T12:58:24.548Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/ba/1761138e86c81680bfc3c49579d66312865457f9fe405b033184e5793cb3/coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5", size = 250531, upload-time = "2026-02-09T12:58:26.271Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/8e/05900df797a9c11837ab59c4d6fe94094e029582aab75c3309a93e6fb4e3/coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0", size = 252189, upload-time = "2026-02-09T12:58:27.807Z" },
+ { url = "https://files.pythonhosted.org/packages/00/bd/29c9f2db9ea4ed2738b8a9508c35626eb205d51af4ab7bf56a21a2e49926/coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb", size = 222258, upload-time = "2026-02-09T12:58:29.441Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/4d/1f8e723f6829977410efeb88f73673d794075091c8c7c18848d273dc9d73/coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505", size = 223073, upload-time = "2026-02-09T12:58:31.026Z" },
+ { url = "https://files.pythonhosted.org/packages/51/5b/84100025be913b44e082ea32abcf1afbf4e872f5120b7a1cab1d331b1e13/coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2", size = 221638, upload-time = "2026-02-09T12:58:32.599Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/e4/c884a405d6ead1370433dad1e3720216b4f9fd8ef5b64bfd984a2a60a11a/coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056", size = 220246, upload-time = "2026-02-09T12:58:34.181Z" },
+ { url = "https://files.pythonhosted.org/packages/81/5c/4d7ed8b23b233b0fffbc9dfec53c232be2e695468523242ea9fd30f97ad2/coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc", size = 220514, upload-time = "2026-02-09T12:58:35.704Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/6f/3284d4203fd2f28edd73034968398cd2d4cb04ab192abc8cff007ea35679/coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9", size = 261877, upload-time = "2026-02-09T12:58:37.864Z" },
+ { url = "https://files.pythonhosted.org/packages/09/aa/b672a647bbe1556a85337dc95bfd40d146e9965ead9cc2fe81bde1e5cbce/coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf", size = 264004, upload-time = "2026-02-09T12:58:39.492Z" },
+ { url = "https://files.pythonhosted.org/packages/79/a1/aa384dbe9181f98bba87dd23dda436f0c6cf2e148aecbb4e50fc51c1a656/coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55", size = 266408, upload-time = "2026-02-09T12:58:41.852Z" },
+ { url = "https://files.pythonhosted.org/packages/53/5e/5150bf17b4019bc600799f376bb9606941e55bd5a775dc1e096b6ffea952/coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72", size = 267544, upload-time = "2026-02-09T12:58:44.093Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/ed/f1de5c675987a4a7a672250d2c5c9d73d289dbf13410f00ed7181d8017dd/coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a", size = 260980, upload-time = "2026-02-09T12:58:45.721Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/e3/fe758d01850aa172419a6743fe76ba8b92c29d181d4f676ffe2dae2ba631/coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6", size = 263871, upload-time = "2026-02-09T12:58:47.334Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/76/b829869d464115e22499541def9796b25312b8cf235d3bb00b39f1675395/coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3", size = 261472, upload-time = "2026-02-09T12:58:48.995Z" },
+ { url = "https://files.pythonhosted.org/packages/14/9e/caedb1679e73e2f6ad240173f55218488bfe043e38da577c4ec977489915/coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750", size = 265210, upload-time = "2026-02-09T12:58:51.178Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/10/0dd02cb009b16ede425b49ec344aba13a6ae1dc39600840ea6abcb085ac4/coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39", size = 260319, upload-time = "2026-02-09T12:58:53.081Z" },
+ { url = "https://files.pythonhosted.org/packages/92/8e/234d2c927af27c6d7a5ffad5bd2cf31634c46a477b4c7adfbfa66baf7ebb/coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0", size = 262638, upload-time = "2026-02-09T12:58:55.258Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/64/e5547c8ff6964e5965c35a480855911b61509cce544f4d442caa759a0702/coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea", size = 223040, upload-time = "2026-02-09T12:58:56.936Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/96/38086d58a181aac86d503dfa9c47eb20715a79c3e3acbdf786e92e5c09a8/coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932", size = 224148, upload-time = "2026-02-09T12:58:58.645Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/72/8d10abd3740a0beb98c305e0c3faf454366221c0f37a8bcf8f60020bb65a/coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b", size = 222172, upload-time = "2026-02-09T12:59:00.396Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" },
+]
+
+[package.optional-dependencies]
+toml = [
+ { name = "tomli", marker = "python_full_version <= '3.11'" },
+]
+
+[[package]]
+name = "cryptography"
+version = "46.0.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" },
+ { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" },
+ { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" },
+ { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" },
+ { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" },
+ { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload-time = "2026-02-10T19:17:33.801Z" },
+ { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" },
+ { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" },
+ { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload-time = "2026-02-10T19:17:52.997Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload-time = "2026-02-10T19:17:54.549Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" },
+ { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" },
+ { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" },
+ { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" },
+ { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" },
+ { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" },
+ { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" },
+ { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" },
+ { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" },
+ { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/dd/2d9fdb07cebdf3d51179730afb7d5e576153c6744c3ff8fded23030c204e/cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c", size = 3476964, upload-time = "2026-02-10T19:18:20.687Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/6f/6cc6cc9955caa6eaf83660b0da2b077c7fe8ff9950a3c5e45d605038d439/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a", size = 4218321, upload-time = "2026-02-10T19:18:22.349Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/5d/c4da701939eeee699566a6c1367427ab91a8b7088cc2328c09dbee940415/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356", size = 4381786, upload-time = "2026-02-10T19:18:24.529Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/97/a538654732974a94ff96c1db621fa464f455c02d4bb7d2652f4edc21d600/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da", size = 4217990, upload-time = "2026-02-10T19:18:25.957Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/11/7e500d2dd3ba891197b9efd2da5454b74336d64a7cc419aa7327ab74e5f6/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257", size = 4381252, upload-time = "2026-02-10T19:18:27.496Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/58/6b3d24e6b9bc474a2dcdee65dfd1f008867015408a271562e4b690561a4d/cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7", size = 3407605, upload-time = "2026-02-10T19:18:29.233Z" },
+]
+
+[[package]]
+name = "cyclonedx-python-lib"
+version = "11.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "license-expression" },
+ { name = "packageurl-python" },
+ { name = "py-serializable" },
+ { name = "sortedcontainers" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/89/ed/54ecfa25fc145c58bf4f98090f7b6ffe5188d0759248c57dde44427ea239/cyclonedx_python_lib-11.6.0.tar.gz", hash = "sha256:7fb85a4371fa3a203e5be577ac22b7e9a7157f8b0058b7448731474d6dea7bf0", size = 1408147, upload-time = "2025-12-02T12:28:46.446Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/1b/534ad8a5e0f9470522811a8e5a9bc5d328fb7738ba29faf357467a4ef6d0/cyclonedx_python_lib-11.6.0-py3-none-any.whl", hash = "sha256:94f4aae97db42a452134dafdddcfab9745324198201c4777ed131e64c8380759", size = 511157, upload-time = "2025-12-02T12:28:44.158Z" },
+]
+
+[[package]]
+name = "defusedxml"
+version = "0.7.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" },
+]
+
+[[package]]
+name = "distlib"
+version = "0.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" },
+]
+
+[[package]]
+name = "docutils"
+version = "0.19"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/330ea8d383eb2ce973df34d1239b3b21e91cd8c865d21ff82902d952f91f/docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6", size = 2056383, upload-time = "2022-07-05T20:17:31.045Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/93/69/e391bd51bc08ed9141ecd899a0ddb61ab6465309f1eb470905c0c8868081/docutils-0.19-py3-none-any.whl", hash = "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc", size = 570472, upload-time = "2022-07-05T20:17:26.388Z" },
+]
+
+[[package]]
+name = "dotty-dict"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6a/ab/88d67f02024700b48cd8232579ad1316aa9df2272c63049c27cc094229d6/dotty_dict-1.3.1.tar.gz", hash = "sha256:4b016e03b8ae265539757a53eba24b9bfda506fb94fbce0bee843c6f05541a15", size = 7699, upload-time = "2022-07-09T18:50:57.727Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1a/91/e0d457ee03ec33d79ee2cd8d212debb1bc21dfb99728ae35efdb5832dc22/dotty_dict-1.3.1-py3-none-any.whl", hash = "sha256:5022d234d9922f13aa711b4950372a06a6d64cb6d6db9ba43d0ba133ebfce31f", size = 7014, upload-time = "2022-07-09T18:50:55.058Z" },
+]
+
+[[package]]
+name = "dunamai"
+version = "1.26.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "packaging" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1c/c4/346cef905782df6152f29f02d9c8ed4acf7ae66b0e66210b7156c5575ccb/dunamai-1.26.0.tar.gz", hash = "sha256:5396ac43aa20ed059040034e9f9798c7464cf4334c6fc3da3732e29273a2f97d", size = 45500, upload-time = "2026-02-15T02:58:55.534Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl", hash = "sha256:f584edf0fda0d308cce0961f807bc90a8fe3d9ff4d62f94e72eca7b43f0ed5f6", size = 27322, upload-time = "2026-02-15T02:58:54.143Z" },
+]
+
+[[package]]
+name = "empty-files"
+version = "0.0.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0e/19/ac55ab18403da2885b3fd5baa7974b12d8a3c59ee56ea185a9a80632839b/empty-files-0.0.9.tar.gz", hash = "sha256:22e74de327271ef9592a661aaa53bb1d5fa6cfd539dac7315625c8b30b7292ae", size = 6812, upload-time = "2023-07-30T19:40:44.035Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3c/4c/d5b6973c9f10992a2aee9c4cb542b25ebdabe907243d6c9650c89dbf578b/empty_files-0.0.9-py3-none-any.whl", hash = "sha256:9af04feacd5858d1255a00e76926a2d760f6d05c3c5a8df58abd6be21da742c2", size = 7165, upload-time = "2023-07-30T19:40:42.657Z" },
+]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
+]
+
+[[package]]
+name = "execnet"
+version = "2.1.2"
+source = { registry = "https://pypi.org/simple" }
+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" }
+wheels = [
+ { 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" },
+]
+
+[[package]]
+name = "filelock"
+version = "3.25.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/77/18/a1fd2231c679dcb9726204645721b12498aeac28e1ad0601038f94b42556/filelock-3.25.0.tar.gz", hash = "sha256:8f00faf3abf9dc730a1ffe9c354ae5c04e079ab7d3a683b7c32da5dd05f26af3", size = 40158, upload-time = "2026-03-01T15:08:45.916Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f9/0b/de6f54d4a8bedfe8645c41497f3c18d749f0bd3218170c667bf4b81d0cdd/filelock-3.25.0-py3-none-any.whl", hash = "sha256:5ccf8069f7948f494968fc0713c10e5c182a9c9d9eef3a636307a20c2490f047", size = 26427, upload-time = "2026-03-01T15:08:44.593Z" },
+]
+
+[[package]]
+name = "funcy"
+version = "2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/70/b8/c6081521ff70afdff55cd9512b2220bbf4fa88804dae51d1b57b4b58ef32/funcy-2.0.tar.gz", hash = "sha256:3963315d59d41c6f30c04bc910e10ab50a3ac4a225868bfa96feed133df075cb", size = 537931, upload-time = "2023-03-28T06:22:46.764Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl", hash = "sha256:53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0", size = 30891, upload-time = "2023-03-28T06:22:42.576Z" },
+]
+
+[[package]]
+name = "gfm-toc"
+version = "0.0.7"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c9/11/ebcf4b0f261f886d06ba81c6055fad17eb64ba259f2d20e259b67913b7f1/gfm-toc-0.0.7.tar.gz", hash = "sha256:c53ed0e2cd400e89051377017ca98c11c9cef628b2effddf787db4fc19ff343d", size = 6018, upload-time = "2019-04-07T07:56:58.35Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5d/93/5af84cd3a2f818d5a68d154796b0e6a25cd490b82ee26071d6d43d883dc8/gfm_toc-0.0.7-py3-none-any.whl", hash = "sha256:247af7267a6cbbdd4213f8383157997bcb07e39e819db737bd2dbfbdb94ee7ae", size = 6781, upload-time = "2019-04-07T07:56:56.814Z" },
+]
+
+[[package]]
+name = "gitdb"
+version = "4.0.12"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "smmap" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" },
+]
+
+[[package]]
+name = "gitpython"
+version = "3.1.46"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "gitdb" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz", hash = "sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", size = 215371, upload-time = "2026-01-01T15:37:32.073Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl", hash = "sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", size = 208620, upload-time = "2026-01-01T15:37:30.574Z" },
+]
+
+[[package]]
+name = "h11"
+version = "0.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
+]
+
+[[package]]
+name = "html2text"
+version = "2025.4.15"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f8/27/e158d86ba1e82967cc2f790b0cb02030d4a8bef58e0c79a8590e9678107f/html2text-2025.4.15.tar.gz", hash = "sha256:948a645f8f0bc3abe7fd587019a2197a12436cd73d0d4908af95bfc8da337588", size = 64316, upload-time = "2025-04-15T04:02:30.045Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1d/84/1a0f9555fd5f2b1c924ff932d99b40a0f8a6b12f6dd625e2a47f415b00ea/html2text-2025.4.15-py3-none-any.whl", hash = "sha256:00569167ffdab3d7767a4cdf589b7f57e777a5ed28d12907d8c58769ec734acc", size = 34656, upload-time = "2025-04-15T04:02:28.44Z" },
+]
+
+[[package]]
+name = "httpcore"
+version = "1.0.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
+]
+
+[[package]]
+name = "httpx"
+version = "0.28.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "certifi" },
+ { name = "httpcore" },
+ { name = "idna" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
+]
+
+[[package]]
+name = "identify"
+version = "2.6.17"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/57/84/376a3b96e5a8d33a7aa2c5b3b31a4b3c364117184bf0b17418055f6ace66/identify-2.6.17.tar.gz", hash = "sha256:f816b0b596b204c9fdf076ded172322f2723cf958d02f9c3587504834c8ff04d", size = 99579, upload-time = "2026-03-01T20:04:12.702Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/40/66/71c1227dff78aaeb942fed29dd5651f2aec166cc7c9aeea3e8b26a539b7d/identify-2.6.17-py2.py3-none-any.whl", hash = "sha256:be5f8412d5ed4b20f2bd41a65f920990bdccaa6a4a18a08f1eefdcd0bdd885f0", size = 99382, upload-time = "2026-03-01T20:04:11.439Z" },
+]
+
+[[package]]
+name = "idna"
+version = "3.11"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
+]
+
+[[package]]
+name = "imagesize"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6c/e6/7bf14eeb8f8b7251141944835abd42eb20a658d89084b7e1f3e5fe394090/imagesize-2.0.0.tar.gz", hash = "sha256:8e8358c4a05c304f1fccf7ff96f036e7243a189e9e42e90851993c558cfe9ee3", size = 1773045, upload-time = "2026-03-03T14:18:29.941Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5f/53/fb7122b71361a0d121b669dcf3d31244ef75badbbb724af388948de543e2/imagesize-2.0.0-py2.py3-none-any.whl", hash = "sha256:5667c5bbb57ab3f1fa4bc366f4fbc971db3d5ed011fd2715fd8001f782718d96", size = 9441, upload-time = "2026-03-03T14:18:27.892Z" },
+]
+
+[[package]]
+name = "importlib-metadata"
+version = "8.7.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "zipp" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" },
+]
+
+[[package]]
+name = "iniconfig"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+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" }
+wheels = [
+ { 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" },
+]
+
+[[package]]
+name = "invoke"
+version = "2.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/de/bd/b461d3424a24c80490313fd77feeb666ca4f6a28c7e72713e3d9095719b4/invoke-2.2.1.tar.gz", hash = "sha256:515bf49b4a48932b79b024590348da22f39c4942dff991ad1fb8b8baea1be707", size = 304762, upload-time = "2025-10-11T00:36:35.172Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/32/4b/b99e37f88336009971405cbb7630610322ed6fbfa31e1d7ab3fbf3049a2d/invoke-2.2.1-py3-none-any.whl", hash = "sha256:2413bc441b376e5cd3f55bb5d364f973ad8bdd7bf87e53c79de3c11bf3feecc8", size = 160287, upload-time = "2025-10-11T00:36:33.703Z" },
+]
+
+[[package]]
+name = "jaraco-classes"
+version = "3.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "more-itertools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" },
+]
+
+[[package]]
+name = "jaraco-context"
+version = "6.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "backports-tarfile", marker = "python_full_version < '3.12'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cb/9c/a788f5bb29c61e456b8ee52ce76dbdd32fd72cd73dd67bc95f42c7a8d13c/jaraco_context-6.1.0.tar.gz", hash = "sha256:129a341b0a85a7db7879e22acd66902fda67882db771754574338898b2d5d86f", size = 15850, upload-time = "2026-01-13T02:53:53.847Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8d/48/aa685dbf1024c7bd82bede569e3a85f82c32fd3d79ba5fea578f0159571a/jaraco_context-6.1.0-py3-none-any.whl", hash = "sha256:a43b5ed85815223d0d3cfdb6d7ca0d2bc8946f28f30b6f3216bda070f68badda", size = 7065, upload-time = "2026-01-13T02:53:53.031Z" },
+]
+
+[[package]]
+name = "jaraco-functools"
+version = "4.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "more-itertools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0f/27/056e0638a86749374d6f57d0b0db39f29509cce9313cf91bdc0ac4d91084/jaraco_functools-4.4.0.tar.gz", hash = "sha256:da21933b0417b89515562656547a77b4931f98176eb173644c0d35032a33d6bb", size = 19943, upload-time = "2025-12-21T09:29:43.6Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl", hash = "sha256:9eec1e36f45c818d9bf307c8948eb03b2b56cd44087b3cdc989abca1f20b9176", size = 10481, upload-time = "2025-12-21T09:29:42.27Z" },
+]
+
+[[package]]
+name = "jeepney"
+version = "0.9.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" },
+]
+
+[[package]]
+name = "jinja2"
+version = "3.1.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markupsafe" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
+]
+
+[[package]]
+name = "jinja2-ansible-filters"
+version = "1.3.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "jinja2" },
+ { name = "pyyaml" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1a/27/fa186af4b246eb869ffca8ffa42d92b05abaec08c99329e74d88b2c46ec7/jinja2-ansible-filters-1.3.2.tar.gz", hash = "sha256:07c10cf44d7073f4f01102ca12d9a2dc31b41d47e4c61ed92ef6a6d2669b356b", size = 16945, upload-time = "2022-06-30T14:08:50.775Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl", hash = "sha256:e1082f5564917649c76fed239117820610516ec10f87735d0338688800a55b34", size = 18975, upload-time = "2022-06-30T14:08:49.571Z" },
+]
+
+[[package]]
+name = "jsondiff"
+version = "2.2.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyyaml" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/35/48/841137f1843fa215ea284834d1514b8e9e20962bda63a636c7417e02f8fb/jsondiff-2.2.1.tar.gz", hash = "sha256:658d162c8a86ba86de26303cd86a7b37e1b2c1ec98b569a60e2ca6180545f7fe", size = 26649, upload-time = "2024-08-29T04:09:06.201Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/63/94/a8066f84d62ab666d61ef97deba1a33126e3e5c0c0da2c458ada17053ed6/jsondiff-2.2.1-py3-none-any.whl", hash = "sha256:b1f0f7e2421881848b1d556d541ac01a91680cfcc14f51a9b62cdf4da0e56722", size = 13440, upload-time = "2024-08-29T04:09:04.955Z" },
+]
+
+[[package]]
+name = "keyring"
+version = "25.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "importlib-metadata", marker = "python_full_version < '3.12'" },
+ { name = "jaraco-classes" },
+ { name = "jaraco-context" },
+ { name = "jaraco-functools" },
+ { name = "jeepney", marker = "sys_platform == 'linux'" },
+ { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" },
+ { name = "secretstorage", marker = "sys_platform == 'linux'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/70/09/d904a6e96f76ff214be59e7aa6ef7190008f52a0ab6689760a98de0bf37d/keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66", size = 62750, upload-time = "2024-12-25T15:26:45.782Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd", size = 39085, upload-time = "2024-12-25T15:26:44.377Z" },
+]
+
+[[package]]
+name = "librt"
+version = "0.8.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/56/9c/b4b0c54d84da4a94b37bd44151e46d5e583c9534c7e02250b961b1b6d8a8/librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73", size = 177471, upload-time = "2026-02-17T16:13:06.101Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7c/5f/63f5fa395c7a8a93558c0904ba8f1c8d1b997ca6a3de61bc7659970d66bf/librt-0.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:81fd938344fecb9373ba1b155968c8a329491d2ce38e7ddb76f30ffb938f12dc", size = 65697, upload-time = "2026-02-17T16:11:06.903Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/e0/0472cf37267b5920eff2f292ccfaede1886288ce35b7f3203d8de00abfe6/librt-0.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5db05697c82b3a2ec53f6e72b2ed373132b0c2e05135f0696784e97d7f5d48e7", size = 68376, upload-time = "2026-02-17T16:11:08.395Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/be/8bd1359fdcd27ab897cd5963294fa4a7c83b20a8564678e4fd12157e56a5/librt-0.8.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d56bc4011975f7460bea7b33e1ff425d2f1adf419935ff6707273c77f8a4ada6", size = 197084, upload-time = "2026-02-17T16:11:09.774Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/fe/163e33fdd091d0c2b102f8a60cc0a61fd730ad44e32617cd161e7cd67a01/librt-0.8.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdc0f588ff4b663ea96c26d2a230c525c6fc62b28314edaaaca8ed5af931ad0", size = 207337, upload-time = "2026-02-17T16:11:11.311Z" },
+ { url = "https://files.pythonhosted.org/packages/01/99/f85130582f05dcf0c8902f3d629270231d2f4afdfc567f8305a952ac7f14/librt-0.8.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:97c2b54ff6717a7a563b72627990bec60d8029df17df423f0ed37d56a17a176b", size = 219980, upload-time = "2026-02-17T16:11:12.499Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/54/cb5e4d03659e043a26c74e08206412ac9a3742f0477d96f9761a55313b5f/librt-0.8.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f1125e6bbf2f1657d9a2f3ccc4a2c9b0c8b176965bb565dd4d86be67eddb4b6", size = 212921, upload-time = "2026-02-17T16:11:14.484Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/81/a3a01e4240579c30f3487f6fed01eb4bc8ef0616da5b4ebac27ca19775f3/librt-0.8.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8f4bb453f408137d7581be309b2fbc6868a80e7ef60c88e689078ee3a296ae71", size = 221381, upload-time = "2026-02-17T16:11:17.459Z" },
+ { url = "https://files.pythonhosted.org/packages/08/b0/fc2d54b4b1c6fb81e77288ff31ff25a2c1e62eaef4424a984f228839717b/librt-0.8.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c336d61d2fe74a3195edc1646d53ff1cddd3a9600b09fa6ab75e5514ba4862a7", size = 216714, upload-time = "2026-02-17T16:11:19.197Z" },
+ { url = "https://files.pythonhosted.org/packages/96/96/85daa73ffbd87e1fb287d7af6553ada66bf25a2a6b0de4764344a05469f6/librt-0.8.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:eb5656019db7c4deacf0c1a55a898c5bb8f989be904597fcb5232a2f4828fa05", size = 214777, upload-time = "2026-02-17T16:11:20.443Z" },
+ { url = "https://files.pythonhosted.org/packages/12/9c/c3aa7a2360383f4bf4f04d98195f2739a579128720c603f4807f006a4225/librt-0.8.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c25d9e338d5bed46c1632f851babf3d13c78f49a225462017cf5e11e845c5891", size = 237398, upload-time = "2026-02-17T16:11:22.083Z" },
+ { url = "https://files.pythonhosted.org/packages/61/19/d350ea89e5274665185dabc4bbb9c3536c3411f862881d316c8b8e00eb66/librt-0.8.1-cp310-cp310-win32.whl", hash = "sha256:aaab0e307e344cb28d800957ef3ec16605146ef0e59e059a60a176d19543d1b7", size = 54285, upload-time = "2026-02-17T16:11:23.27Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/d6/45d587d3d41c112e9543a0093d883eb57a24a03e41561c127818aa2a6bcc/librt-0.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:56e04c14b696300d47b3bc5f1d10a00e86ae978886d0cee14e5714fafb5df5d2", size = 61352, upload-time = "2026-02-17T16:11:24.207Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/01/0e748af5e4fee180cf7cd12bd12b0513ad23b045dccb2a83191bde82d168/librt-0.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:681dc2451d6d846794a828c16c22dc452d924e9f700a485b7ecb887a30aad1fd", size = 65315, upload-time = "2026-02-17T16:11:25.152Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/4d/7184806efda571887c798d573ca4134c80ac8642dcdd32f12c31b939c595/librt-0.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3b4350b13cc0e6f5bec8fa7caf29a8fb8cdc051a3bae45cfbfd7ce64f009965", size = 68021, upload-time = "2026-02-17T16:11:26.129Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/88/c3c52d2a5d5101f28d3dc89298444626e7874aa904eed498464c2af17627/librt-0.8.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ac1e7817fd0ed3d14fd7c5df91daed84c48e4c2a11ee99c0547f9f62fdae13da", size = 194500, upload-time = "2026-02-17T16:11:27.177Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/5d/6fb0a25b6a8906e85b2c3b87bee1d6ed31510be7605b06772f9374ca5cb3/librt-0.8.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:747328be0c5b7075cde86a0e09d7a9196029800ba75a1689332348e998fb85c0", size = 205622, upload-time = "2026-02-17T16:11:28.242Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/a6/8006ae81227105476a45691f5831499e4d936b1c049b0c1feb17c11b02d1/librt-0.8.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0af2bd2bc204fa27f3d6711d0f360e6b8c684a035206257a81673ab924aa11e", size = 218304, upload-time = "2026-02-17T16:11:29.344Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/19/60e07886ad16670aae57ef44dada41912c90906a6fe9f2b9abac21374748/librt-0.8.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d480de377f5b687b6b1bc0c0407426da556e2a757633cc7e4d2e1a057aa688f3", size = 211493, upload-time = "2026-02-17T16:11:30.445Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/cf/f666c89d0e861d05600438213feeb818c7514d3315bae3648b1fc145d2b6/librt-0.8.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d0ee06b5b5291f609ddb37b9750985b27bc567791bc87c76a569b3feed8481ac", size = 219129, upload-time = "2026-02-17T16:11:32.021Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/ef/f1bea01e40b4a879364c031476c82a0dc69ce068daad67ab96302fed2d45/librt-0.8.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9e2c6f77b9ad48ce5603b83b7da9ee3e36b3ab425353f695cba13200c5d96596", size = 213113, upload-time = "2026-02-17T16:11:33.192Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/80/cdab544370cc6bc1b72ea369525f547a59e6938ef6863a11ab3cd24759af/librt-0.8.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:439352ba9373f11cb8e1933da194dcc6206daf779ff8df0ed69c5e39113e6a99", size = 212269, upload-time = "2026-02-17T16:11:34.373Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/9c/48d6ed8dac595654f15eceab2035131c136d1ae9a1e3548e777bb6dbb95d/librt-0.8.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:82210adabbc331dbb65d7868b105185464ef13f56f7f76688565ad79f648b0fe", size = 234673, upload-time = "2026-02-17T16:11:36.063Z" },
+ { url = "https://files.pythonhosted.org/packages/16/01/35b68b1db517f27a01be4467593292eb5315def8900afad29fabf56304ba/librt-0.8.1-cp311-cp311-win32.whl", hash = "sha256:52c224e14614b750c0a6d97368e16804a98c684657c7518752c356834fff83bb", size = 54597, upload-time = "2026-02-17T16:11:37.544Z" },
+ { url = "https://files.pythonhosted.org/packages/71/02/796fe8f02822235966693f257bf2c79f40e11337337a657a8cfebba5febc/librt-0.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:c00e5c884f528c9932d278d5c9cbbea38a6b81eb62c02e06ae53751a83a4d52b", size = 61733, upload-time = "2026-02-17T16:11:38.691Z" },
+ { url = "https://files.pythonhosted.org/packages/28/ad/232e13d61f879a42a4e7117d65e4984bb28371a34bb6fb9ca54ec2c8f54e/librt-0.8.1-cp311-cp311-win_arm64.whl", hash = "sha256:f7cdf7f26c2286ffb02e46d7bac56c94655540b26347673bea15fa52a6af17e9", size = 52273, upload-time = "2026-02-17T16:11:40.308Z" },
+ { url = "https://files.pythonhosted.org/packages/95/21/d39b0a87ac52fc98f621fb6f8060efb017a767ebbbac2f99fbcbc9ddc0d7/librt-0.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a28f2612ab566b17f3698b0da021ff9960610301607c9a5e8eaca62f5e1c350a", size = 66516, upload-time = "2026-02-17T16:11:41.604Z" },
+ { url = "https://files.pythonhosted.org/packages/69/f1/46375e71441c43e8ae335905e069f1c54febee63a146278bcee8782c84fd/librt-0.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60a78b694c9aee2a0f1aaeaa7d101cf713e92e8423a941d2897f4fa37908dab9", size = 68634, upload-time = "2026-02-17T16:11:43.268Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/33/c510de7f93bf1fa19e13423a606d8189a02624a800710f6e6a0a0f0784b3/librt-0.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:758509ea3f1eba2a57558e7e98f4659d0ea7670bff49673b0dde18a3c7e6c0eb", size = 198941, upload-time = "2026-02-17T16:11:44.28Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/36/e725903416409a533d92398e88ce665476f275081d0d7d42f9c4951999e5/librt-0.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:039b9f2c506bd0ab0f8725aa5ba339c6f0cd19d3b514b50d134789809c24285d", size = 209991, upload-time = "2026-02-17T16:11:45.462Z" },
+ { url = "https://files.pythonhosted.org/packages/30/7a/8d908a152e1875c9f8eac96c97a480df425e657cdb47854b9efaa4998889/librt-0.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bb54f1205a3a6ab41a6fd71dfcdcbd278670d3a90ca502a30d9da583105b6f7", size = 224476, upload-time = "2026-02-17T16:11:46.542Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/b8/a22c34f2c485b8903a06f3fe3315341fe6876ef3599792344669db98fcff/librt-0.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:05bd41cdee35b0c59c259f870f6da532a2c5ca57db95b5f23689fcb5c9e42440", size = 217518, upload-time = "2026-02-17T16:11:47.746Z" },
+ { url = "https://files.pythonhosted.org/packages/79/6f/5c6fea00357e4f82ba44f81dbfb027921f1ab10e320d4a64e1c408d035d9/librt-0.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adfab487facf03f0d0857b8710cf82d0704a309d8ffc33b03d9302b4c64e91a9", size = 225116, upload-time = "2026-02-17T16:11:49.298Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/a0/95ced4e7b1267fe1e2720a111685bcddf0e781f7e9e0ce59d751c44dcfe5/librt-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:153188fe98a72f206042be10a2c6026139852805215ed9539186312d50a8e972", size = 217751, upload-time = "2026-02-17T16:11:50.49Z" },
+ { url = "https://files.pythonhosted.org/packages/93/c2/0517281cb4d4101c27ab59472924e67f55e375bc46bedae94ac6dc6e1902/librt-0.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dd3c41254ee98604b08bd5b3af5bf0a89740d4ee0711de95b65166bf44091921", size = 218378, upload-time = "2026-02-17T16:11:51.783Z" },
+ { url = "https://files.pythonhosted.org/packages/43/e8/37b3ac108e8976888e559a7b227d0ceac03c384cfd3e7a1c2ee248dbae79/librt-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e0d138c7ae532908cbb342162b2611dbd4d90c941cd25ab82084aaf71d2c0bd0", size = 241199, upload-time = "2026-02-17T16:11:53.561Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/5b/35812d041c53967fedf551a39399271bbe4257e681236a2cf1a69c8e7fa1/librt-0.8.1-cp312-cp312-win32.whl", hash = "sha256:43353b943613c5d9c49a25aaffdba46f888ec354e71e3529a00cca3f04d66a7a", size = 54917, upload-time = "2026-02-17T16:11:54.758Z" },
+ { url = "https://files.pythonhosted.org/packages/de/d1/fa5d5331b862b9775aaf2a100f5ef86854e5d4407f71bddf102f4421e034/librt-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff8baf1f8d3f4b6b7257fcb75a501f2a5499d0dda57645baa09d4d0d34b19444", size = 62017, upload-time = "2026-02-17T16:11:55.748Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/7c/c614252f9acda59b01a66e2ddfd243ed1c7e1deab0293332dfbccf862808/librt-0.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f2ae3725904f7377e11cc37722d5d401e8b3d5851fb9273d7f4fe04f6b3d37d", size = 52441, upload-time = "2026-02-17T16:11:56.801Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/3c/f614c8e4eaac7cbf2bbdf9528790b21d89e277ee20d57dc6e559c626105f/librt-0.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e6bad1cd94f6764e1e21950542f818a09316645337fd5ab9a7acc45d99a8f35", size = 66529, upload-time = "2026-02-17T16:11:57.809Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/96/5836544a45100ae411eda07d29e3d99448e5258b6e9c8059deb92945f5c2/librt-0.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf450f498c30af55551ba4f66b9123b7185362ec8b625a773b3d39aa1a717583", size = 68669, upload-time = "2026-02-17T16:11:58.843Z" },
+ { url = "https://files.pythonhosted.org/packages/06/53/f0b992b57af6d5531bf4677d75c44f095f2366a1741fb695ee462ae04b05/librt-0.8.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eca45e982fa074090057132e30585a7e8674e9e885d402eae85633e9f449ce6c", size = 199279, upload-time = "2026-02-17T16:11:59.862Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/ad/4848cc16e268d14280d8168aee4f31cea92bbd2b79ce33d3e166f2b4e4fc/librt-0.8.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3811485fccfda840861905b8c70bba5ec094e02825598bb9d4ca3936857a04", size = 210288, upload-time = "2026-02-17T16:12:00.954Z" },
+ { url = "https://files.pythonhosted.org/packages/52/05/27fdc2e95de26273d83b96742d8d3b7345f2ea2bdbd2405cc504644f2096/librt-0.8.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e4af413908f77294605e28cfd98063f54b2c790561383971d2f52d113d9c363", size = 224809, upload-time = "2026-02-17T16:12:02.108Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/d0/78200a45ba3240cb042bc597d6f2accba9193a2c57d0356268cbbe2d0925/librt-0.8.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5212a5bd7fae98dae95710032902edcd2ec4dc994e883294f75c857b83f9aba0", size = 218075, upload-time = "2026-02-17T16:12:03.631Z" },
+ { url = "https://files.pythonhosted.org/packages/af/72/a210839fa74c90474897124c064ffca07f8d4b347b6574d309686aae7ca6/librt-0.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e692aa2d1d604e6ca12d35e51fdc36f4cda6345e28e36374579f7ef3611b3012", size = 225486, upload-time = "2026-02-17T16:12:04.725Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/c1/a03cc63722339ddbf087485f253493e2b013039f5b707e8e6016141130fa/librt-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4be2a5c926b9770c9e08e717f05737a269b9d0ebc5d2f0060f0fe3fe9ce47acb", size = 218219, upload-time = "2026-02-17T16:12:05.828Z" },
+ { url = "https://files.pythonhosted.org/packages/58/f5/fff6108af0acf941c6f274a946aea0e484bd10cd2dc37610287ce49388c5/librt-0.8.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fd1a720332ea335ceb544cf0a03f81df92abd4bb887679fd1e460976b0e6214b", size = 218750, upload-time = "2026-02-17T16:12:07.09Z" },
+ { url = "https://files.pythonhosted.org/packages/71/67/5a387bfef30ec1e4b4f30562c8586566faf87e47d696768c19feb49e3646/librt-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2af9e01e0ef80d95ae3c720be101227edae5f2fe7e3dc63d8857fadfc5a1d", size = 241624, upload-time = "2026-02-17T16:12:08.43Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/be/24f8502db11d405232ac1162eb98069ca49c3306c1d75c6ccc61d9af8789/librt-0.8.1-cp313-cp313-win32.whl", hash = "sha256:086a32dbb71336627e78cc1d6ee305a68d038ef7d4c39aaff41ae8c9aa46e91a", size = 54969, upload-time = "2026-02-17T16:12:09.633Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/73/c9fdf6cb2a529c1a092ce769a12d88c8cca991194dfe641b6af12fa964d2/librt-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:e11769a1dbda4da7b00a76cfffa67aa47cfa66921d2724539eee4b9ede780b79", size = 62000, upload-time = "2026-02-17T16:12:10.632Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/97/68f80ca3ac4924f250cdfa6e20142a803e5e50fca96ef5148c52ee8c10ea/librt-0.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:924817ab3141aca17893386ee13261f1d100d1ef410d70afe4389f2359fea4f0", size = 52495, upload-time = "2026-02-17T16:12:11.633Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/6a/907ef6800f7bca71b525a05f1839b21f708c09043b1c6aa77b6b827b3996/librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f", size = 66081, upload-time = "2026-02-17T16:12:12.766Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/18/25e991cd5640c9fb0f8d91b18797b29066b792f17bf8493da183bf5caabe/librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c", size = 68309, upload-time = "2026-02-17T16:12:13.756Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/36/46820d03f058cfb5a9de5940640ba03165ed8aded69e0733c417bb04df34/librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc", size = 196804, upload-time = "2026-02-17T16:12:14.818Z" },
+ { url = "https://files.pythonhosted.org/packages/59/18/5dd0d3b87b8ff9c061849fbdb347758d1f724b9a82241aa908e0ec54ccd0/librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c", size = 206907, upload-time = "2026-02-17T16:12:16.513Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/96/ef04902aad1424fd7299b62d1890e803e6ab4018c3044dca5922319c4b97/librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3", size = 221217, upload-time = "2026-02-17T16:12:17.906Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/ff/7e01f2dda84a8f5d280637a2e5827210a8acca9a567a54507ef1c75b342d/librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14", size = 214622, upload-time = "2026-02-17T16:12:19.108Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/8c/5b093d08a13946034fed57619742f790faf77058558b14ca36a6e331161e/librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7", size = 221987, upload-time = "2026-02-17T16:12:20.331Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/cc/86b0b3b151d40920ad45a94ce0171dec1aebba8a9d72bb3fa00c73ab25dd/librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6", size = 215132, upload-time = "2026-02-17T16:12:21.54Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/be/8588164a46edf1e69858d952654e216a9a91174688eeefb9efbb38a9c799/librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071", size = 215195, upload-time = "2026-02-17T16:12:23.073Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/f2/0b9279bea735c734d69344ecfe056c1ba211694a72df10f568745c899c76/librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78", size = 237946, upload-time = "2026-02-17T16:12:24.275Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/cc/5f2a34fbc8aeb35314a3641f9956fa9051a947424652fad9882be7a97949/librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023", size = 50689, upload-time = "2026-02-17T16:12:25.766Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/76/cd4d010ab2147339ca2b93e959c3686e964edc6de66ddacc935c325883d7/librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730", size = 57875, upload-time = "2026-02-17T16:12:27.465Z" },
+ { url = "https://files.pythonhosted.org/packages/84/0f/2143cb3c3ca48bd3379dcd11817163ca50781927c4537345d608b5045998/librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3", size = 48058, upload-time = "2026-02-17T16:12:28.556Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/0e/9b23a87e37baf00311c3efe6b48d6b6c168c29902dfc3f04c338372fd7db/librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1", size = 68313, upload-time = "2026-02-17T16:12:29.659Z" },
+ { url = "https://files.pythonhosted.org/packages/db/9a/859c41e5a4f1c84200a7d2b92f586aa27133c8243b6cac9926f6e54d01b9/librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee", size = 70994, upload-time = "2026-02-17T16:12:31.516Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/28/10605366ee599ed34223ac2bf66404c6fb59399f47108215d16d5ad751a8/librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7", size = 220770, upload-time = "2026-02-17T16:12:33.294Z" },
+ { url = "https://files.pythonhosted.org/packages/af/8d/16ed8fd452dafae9c48d17a6bc1ee3e818fd40ef718d149a8eff2c9f4ea2/librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040", size = 235409, upload-time = "2026-02-17T16:12:35.443Z" },
+ { url = "https://files.pythonhosted.org/packages/89/1b/7bdf3e49349c134b25db816e4a3db6b94a47ac69d7d46b1e682c2c4949be/librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e", size = 246473, upload-time = "2026-02-17T16:12:36.656Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/8a/91fab8e4fd2a24930a17188c7af5380eb27b203d72101c9cc000dbdfd95a/librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732", size = 238866, upload-time = "2026-02-17T16:12:37.849Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/e0/c45a098843fc7c07e18a7f8a24ca8496aecbf7bdcd54980c6ca1aaa79a8e/librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624", size = 250248, upload-time = "2026-02-17T16:12:39.445Z" },
+ { url = "https://files.pythonhosted.org/packages/82/30/07627de23036640c952cce0c1fe78972e77d7d2f8fd54fa5ef4554ff4a56/librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4", size = 240629, upload-time = "2026-02-17T16:12:40.889Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/c1/55bfe1ee3542eba055616f9098eaf6eddb966efb0ca0f44eaa4aba327307/librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382", size = 239615, upload-time = "2026-02-17T16:12:42.446Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/39/191d3d28abc26c9099b19852e6c99f7f6d400b82fa5a4e80291bd3803e19/librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994", size = 263001, upload-time = "2026-02-17T16:12:43.627Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/eb/7697f60fbe7042ab4e88f4ee6af496b7f222fffb0a4e3593ef1f29f81652/librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a", size = 51328, upload-time = "2026-02-17T16:12:45.148Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/72/34bf2eb7a15414a23e5e70ecb9440c1d3179f393d9349338a91e2781c0fb/librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4", size = 58722, upload-time = "2026-02-17T16:12:46.85Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/c8/d148e041732d631fc76036f8b30fae4e77b027a1e95b7a84bb522481a940/librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61", size = 48755, upload-time = "2026-02-17T16:12:47.943Z" },
+]
+
+[[package]]
+name = "license-expression"
+version = "30.4.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "boolean-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/40/71/d89bb0e71b1415453980fd32315f2a037aad9f7f70f695c7cec7035feb13/license_expression-30.4.4.tar.gz", hash = "sha256:73448f0aacd8d0808895bdc4b2c8e01a8d67646e4188f887375398c761f340fd", size = 186402, upload-time = "2025-07-22T11:13:32.17Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/af/40/791891d4c0c4dab4c5e187c17261cedc26285fd41541577f900470a45a4d/license_expression-30.4.4-py3-none-any.whl", hash = "sha256:421788fdcadb41f049d2dc934ce666626265aeccefddd25e162a26f23bcbf8a4", size = 120615, upload-time = "2025-07-22T11:13:31.217Z" },
+]
+
+[[package]]
+name = "linkify-it-py"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "uc-micro-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2e/c9/06ea13676ef354f0af6169587ae292d3e2406e212876a413bf9eece4eb23/linkify_it_py-2.1.0.tar.gz", hash = "sha256:43360231720999c10e9328dc3691160e27a718e280673d444c38d7d3aaa3b98b", size = 29158, upload-time = "2026-03-01T07:48:47.683Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b4/de/88b3be5c31b22333b3ca2f6ff1de4e863d8fe45aaea7485f591970ec1d3e/linkify_it_py-2.1.0-py3-none-any.whl", hash = "sha256:0d252c1594ecba2ecedc444053db5d3a9b7ec1b0dd929c8f1d74dce89f86c05e", size = 19878, upload-time = "2026-03-01T07:48:46.098Z" },
+]
+
+[[package]]
+name = "macholib"
+version = "1.16.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "altgraph" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/10/2f/97589876ea967487978071c9042518d28b958d87b17dceb7cdc1d881f963/macholib-1.16.4.tar.gz", hash = "sha256:f408c93ab2e995cd2c46e34fe328b130404be143469e41bc366c807448979362", size = 59427, upload-time = "2025-11-22T08:28:38.373Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/d1/a9f36f8ecdf0fb7c9b1e78c8d7af12b8c8754e74851ac7b94a8305540fc7/macholib-1.16.4-py2.py3-none-any.whl", hash = "sha256:da1a3fa8266e30f0ce7e97c6a54eefaae8edd1e5f86f3eb8b95457cae90265ea", size = 38117, upload-time = "2025-11-22T08:28:36.939Z" },
+]
+
+[[package]]
+name = "markdown-it-py"
+version = "4.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mdurl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
+]
+
+[package.optional-dependencies]
+linkify = [
+ { name = "linkify-it-py" },
+]
+plugins = [
+ { name = "mdit-py-plugins" },
+]
+
+[[package]]
+name = "markupsafe"
+version = "3.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" },
+ { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" },
+ { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" },
+ { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" },
+ { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" },
+ { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" },
+ { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" },
+ { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" },
+ { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" },
+ { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" },
+ { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" },
+ { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" },
+ { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" },
+ { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" },
+ { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" },
+ { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" },
+ { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" },
+ { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" },
+ { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" },
+ { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" },
+ { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" },
+ { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" },
+ { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" },
+ { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" },
+ { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" },
+ { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" },
+ { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" },
+ { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" },
+ { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" },
+ { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" },
+ { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" },
+ { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" },
+ { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" },
+ { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" },
+]
+
+[[package]]
+name = "mdit-py-plugins"
+version = "0.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b2/fd/a756d36c0bfba5f6e39a1cdbdbfdd448dc02692467d83816dff4592a1ebc/mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6", size = 44655, upload-time = "2025-08-11T07:25:49.083Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/86/dd6e5db36df29e76c7a7699123569a4a18c1623ce68d826ed96c62643cae/mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f", size = 57205, upload-time = "2025-08-11T07:25:47.597Z" },
+]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
+]
+
+[[package]]
+name = "more-itertools"
+version = "10.8.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" },
+]
+
+[[package]]
+name = "mrjob"
+version = "0.7.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyyaml" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2c/ed/207853d1ebc6b549551d12db35e471289d26cac2cdae363419357294d3c5/mrjob-0.7.4.tar.gz", hash = "sha256:2c8d8dc8aa4b354a97de18d0260f551f018693af74af104b3d41daf165eebdd4", size = 652429, upload-time = "2020-09-17T22:26:04.518Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8e/58/fc28ab743aba16e90736ad4e29694bd2adaf7b879376ff149306d50c4e90/mrjob-0.7.4-py2.py3-none-any.whl", hash = "sha256:d8fa1bafcada0ffe3e7166896a27e996815e2cb835088aec025e3dd12c7146ce", size = 439592, upload-time = "2020-09-17T22:26:01.029Z" },
+]
+
+[[package]]
+name = "msgpack"
+version = "1.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f5/a2/3b68a9e769db68668b25c6108444a35f9bd163bb848c0650d516761a59c0/msgpack-1.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0051fffef5a37ca2cd16978ae4f0aef92f164df86823871b5162812bebecd8e2", size = 81318, upload-time = "2025-10-08T09:14:38.722Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/e1/2b720cc341325c00be44e1ed59e7cfeae2678329fbf5aa68f5bda57fe728/msgpack-1.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a605409040f2da88676e9c9e5853b3449ba8011973616189ea5ee55ddbc5bc87", size = 83786, upload-time = "2025-10-08T09:14:40.082Z" },
+ { url = "https://files.pythonhosted.org/packages/71/e5/c2241de64bfceac456b140737812a2ab310b10538a7b34a1d393b748e095/msgpack-1.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b696e83c9f1532b4af884045ba7f3aa741a63b2bc22617293a2c6a7c645f251", size = 398240, upload-time = "2025-10-08T09:14:41.151Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/09/2a06956383c0fdebaef5aa9246e2356776f12ea6f2a44bd1368abf0e46c4/msgpack-1.1.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:365c0bbe981a27d8932da71af63ef86acc59ed5c01ad929e09a0b88c6294e28a", size = 406070, upload-time = "2025-10-08T09:14:42.821Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/74/2957703f0e1ef20637d6aead4fbb314330c26f39aa046b348c7edcf6ca6b/msgpack-1.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:41d1a5d875680166d3ac5c38573896453bbbea7092936d2e107214daf43b1d4f", size = 393403, upload-time = "2025-10-08T09:14:44.38Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/09/3bfc12aa90f77b37322fc33e7a8a7c29ba7c8edeadfa27664451801b9860/msgpack-1.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:354e81bcdebaab427c3df4281187edc765d5d76bfb3a7c125af9da7a27e8458f", size = 398947, upload-time = "2025-10-08T09:14:45.56Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/4f/05fcebd3b4977cb3d840f7ef6b77c51f8582086de5e642f3fefee35c86fc/msgpack-1.1.2-cp310-cp310-win32.whl", hash = "sha256:e64c8d2f5e5d5fda7b842f55dec6133260ea8f53c4257d64494c534f306bf7a9", size = 64769, upload-time = "2025-10-08T09:14:47.334Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/3e/b4547e3a34210956382eed1c85935fff7e0f9b98be3106b3745d7dec9c5e/msgpack-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:db6192777d943bdaaafb6ba66d44bf65aa0e9c5616fa1d2da9bb08828c6b39aa", size = 71293, upload-time = "2025-10-08T09:14:48.665Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/97/560d11202bcd537abca693fd85d81cebe2107ba17301de42b01ac1677b69/msgpack-1.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e86a607e558d22985d856948c12a3fa7b42efad264dca8a3ebbcfa2735d786c", size = 82271, upload-time = "2025-10-08T09:14:49.967Z" },
+ { url = "https://files.pythonhosted.org/packages/83/04/28a41024ccbd67467380b6fb440ae916c1e4f25e2cd4c63abe6835ac566e/msgpack-1.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:283ae72fc89da59aa004ba147e8fc2f766647b1251500182fac0350d8af299c0", size = 84914, upload-time = "2025-10-08T09:14:50.958Z" },
+ { url = "https://files.pythonhosted.org/packages/71/46/b817349db6886d79e57a966346cf0902a426375aadc1e8e7a86a75e22f19/msgpack-1.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61c8aa3bd513d87c72ed0b37b53dd5c5a0f58f2ff9f26e1555d3bd7948fb7296", size = 416962, upload-time = "2025-10-08T09:14:51.997Z" },
+ { url = "https://files.pythonhosted.org/packages/da/e0/6cc2e852837cd6086fe7d8406af4294e66827a60a4cf60b86575a4a65ca8/msgpack-1.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:454e29e186285d2ebe65be34629fa0e8605202c60fbc7c4c650ccd41870896ef", size = 426183, upload-time = "2025-10-08T09:14:53.477Z" },
+ { url = "https://files.pythonhosted.org/packages/25/98/6a19f030b3d2ea906696cedd1eb251708e50a5891d0978b012cb6107234c/msgpack-1.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7bc8813f88417599564fafa59fd6f95be417179f76b40325b500b3c98409757c", size = 411454, upload-time = "2025-10-08T09:14:54.648Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/cd/9098fcb6adb32187a70b7ecaabf6339da50553351558f37600e53a4a2a23/msgpack-1.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bafca952dc13907bdfdedfc6a5f579bf4f292bdd506fadb38389afa3ac5b208e", size = 422341, upload-time = "2025-10-08T09:14:56.328Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/ae/270cecbcf36c1dc85ec086b33a51a4d7d08fc4f404bdbc15b582255d05ff/msgpack-1.1.2-cp311-cp311-win32.whl", hash = "sha256:602b6740e95ffc55bfb078172d279de3773d7b7db1f703b2f1323566b878b90e", size = 64747, upload-time = "2025-10-08T09:14:57.882Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/79/309d0e637f6f37e83c711f547308b91af02b72d2326ddd860b966080ef29/msgpack-1.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:d198d275222dc54244bf3327eb8cbe00307d220241d9cec4d306d49a44e85f68", size = 71633, upload-time = "2025-10-08T09:14:59.177Z" },
+ { url = "https://files.pythonhosted.org/packages/73/4d/7c4e2b3d9b1106cd0aa6cb56cc57c6267f59fa8bfab7d91df5adc802c847/msgpack-1.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:86f8136dfa5c116365a8a651a7d7484b65b13339731dd6faebb9a0242151c406", size = 64755, upload-time = "2025-10-08T09:15:00.48Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/bd/8b0d01c756203fbab65d265859749860682ccd2a59594609aeec3a144efa/msgpack-1.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:70a0dff9d1f8da25179ffcf880e10cf1aad55fdb63cd59c9a49a1b82290062aa", size = 81939, upload-time = "2025-10-08T09:15:01.472Z" },
+ { url = "https://files.pythonhosted.org/packages/34/68/ba4f155f793a74c1483d4bdef136e1023f7bcba557f0db4ef3db3c665cf1/msgpack-1.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:446abdd8b94b55c800ac34b102dffd2f6aa0ce643c55dfc017ad89347db3dbdb", size = 85064, upload-time = "2025-10-08T09:15:03.764Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/60/a064b0345fc36c4c3d2c743c82d9100c40388d77f0b48b2f04d6041dbec1/msgpack-1.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c63eea553c69ab05b6747901b97d620bb2a690633c77f23feb0c6a947a8a7b8f", size = 417131, upload-time = "2025-10-08T09:15:05.136Z" },
+ { url = "https://files.pythonhosted.org/packages/65/92/a5100f7185a800a5d29f8d14041f61475b9de465ffcc0f3b9fba606e4505/msgpack-1.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:372839311ccf6bdaf39b00b61288e0557916c3729529b301c52c2d88842add42", size = 427556, upload-time = "2025-10-08T09:15:06.837Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/87/ffe21d1bf7d9991354ad93949286f643b2bb6ddbeab66373922b44c3b8cc/msgpack-1.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2929af52106ca73fcb28576218476ffbb531a036c2adbcf54a3664de124303e9", size = 404920, upload-time = "2025-10-08T09:15:08.179Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/41/8543ed2b8604f7c0d89ce066f42007faac1eaa7d79a81555f206a5cdb889/msgpack-1.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be52a8fc79e45b0364210eef5234a7cf8d330836d0a64dfbb878efa903d84620", size = 415013, upload-time = "2025-10-08T09:15:09.83Z" },
+ { url = "https://files.pythonhosted.org/packages/41/0d/2ddfaa8b7e1cee6c490d46cb0a39742b19e2481600a7a0e96537e9c22f43/msgpack-1.1.2-cp312-cp312-win32.whl", hash = "sha256:1fff3d825d7859ac888b0fbda39a42d59193543920eda9d9bea44d958a878029", size = 65096, upload-time = "2025-10-08T09:15:11.11Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/ec/d431eb7941fb55a31dd6ca3404d41fbb52d99172df2e7707754488390910/msgpack-1.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1de460f0403172cff81169a30b9a92b260cb809c4cb7e2fc79ae8d0510c78b6b", size = 72708, upload-time = "2025-10-08T09:15:12.554Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/31/5b1a1f70eb0e87d1678e9624908f86317787b536060641d6798e3cf70ace/msgpack-1.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:be5980f3ee0e6bd44f3a9e9dea01054f175b50c3e6cdb692bc9424c0bbb8bf69", size = 64119, upload-time = "2025-10-08T09:15:13.589Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212, upload-time = "2025-10-08T09:15:14.552Z" },
+ { url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315, upload-time = "2025-10-08T09:15:15.543Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721, upload-time = "2025-10-08T09:15:16.567Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657, upload-time = "2025-10-08T09:15:17.825Z" },
+ { url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668, upload-time = "2025-10-08T09:15:19.003Z" },
+ { url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040, upload-time = "2025-10-08T09:15:20.183Z" },
+ { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" },
+ { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" },
+ { url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127, upload-time = "2025-10-08T09:15:24.408Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981, upload-time = "2025-10-08T09:15:25.812Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885, upload-time = "2025-10-08T09:15:27.22Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658, upload-time = "2025-10-08T09:15:28.4Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290, upload-time = "2025-10-08T09:15:29.764Z" },
+ { url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234, upload-time = "2025-10-08T09:15:31.022Z" },
+ { url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391, upload-time = "2025-10-08T09:15:32.265Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787, upload-time = "2025-10-08T09:15:33.219Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453, upload-time = "2025-10-08T09:15:34.225Z" },
+ { url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264, upload-time = "2025-10-08T09:15:35.61Z" },
+ { url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076, upload-time = "2025-10-08T09:15:36.619Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242, upload-time = "2025-10-08T09:15:37.647Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509, upload-time = "2025-10-08T09:15:38.794Z" },
+ { url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957, upload-time = "2025-10-08T09:15:40.238Z" },
+ { url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910, upload-time = "2025-10-08T09:15:41.505Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197, upload-time = "2025-10-08T09:15:42.954Z" },
+ { url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772, upload-time = "2025-10-08T09:15:43.954Z" },
+ { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" },
+]
+
+[[package]]
+name = "msgpack-types"
+version = "0.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "msgpack" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7f/26/a15707f2af5681333cd598724bedd1948844ac2af45eafc4175af0671a8d/msgpack_types-0.5.0.tar.gz", hash = "sha256:aebd1b8da23f8f9966d66ebb1a43bd261b95751c6a267bd21a124d2ccac84201", size = 6702, upload-time = "2024-09-21T13:55:05.587Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/19/dd/cd9d2b0ef506f6164cd81d4e92e408095041f28523d751b9f7dabdc244eb/msgpack_types-0.5.0-py3-none-any.whl", hash = "sha256:8b633ed75e495a555fa0615843de559a74b1d176828d59bb393d266e51f6bda7", size = 8182, upload-time = "2024-09-21T13:55:04.232Z" },
+]
+
+[[package]]
+name = "mslex"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e0/97/7022667073c99a0fe028f2e34b9bf76b49a611afd21b02527fbfd92d4cd5/mslex-1.3.0.tar.gz", hash = "sha256:641c887d1d3db610eee2af37a8e5abda3f70b3006cdfd2d0d29dc0d1ae28a85d", size = 11583, upload-time = "2024-10-16T13:16:18.523Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/64/f2/66bd65ca0139675a0d7b18f0bada6e12b51a984e41a76dbe44761bf1b3ee/mslex-1.3.0-py3-none-any.whl", hash = "sha256:c7074b347201b3466fc077c5692fbce9b5f62a63a51f537a53fbbd02eff2eea4", size = 7820, upload-time = "2024-10-16T13:16:17.566Z" },
+]
+
+[[package]]
+name = "multiformats"
+version = "0.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "bases" },
+ { name = "multiformats-config" },
+ { name = "typing-extensions" },
+ { name = "typing-validation" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0a/a8/5b341c3ca0dd651b6276430651b7a6943625a2df419427bcae11b6e32267/multiformats-0.3.1.tar.gz", hash = "sha256:6b011e780d8283395c3062e16def6a61636ee265a3a8c94cc83d7a80293e70e5", size = 825880, upload-time = "2023-12-18T22:08:46.984Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/82/a3/7f2566a11d72502eacbeaedad95fa156a292862b9220483aea522a76ddb5/multiformats-0.3.1-py3-none-any.whl", hash = "sha256:e194bae88004cb41ca8df83cd330d97e0a566c46db99e915831761cbf0a319a4", size = 57218, upload-time = "2023-12-18T22:08:44.616Z" },
+]
+
+[[package]]
+name = "multiformats-config"
+version = "0.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "multiformats" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c6/09/ccb6867c2d6c6de98d1d285d8a3a2103fdf452c2fef5019bb3d8ac9938d9/multiformats-config-0.3.1.tar.gz", hash = "sha256:7eaa80ef5d9c5ee9b86612d21f93a087c4a655cbcb68960457e61adbc62b47a7", size = 28345, upload-time = "2023-12-18T21:35:23.972Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f3/9b/c21a9c1d5ea4847989f1eb00e3147e38e79aaea7c4b4d1cbd4f1afae9740/multiformats_config-0.3.1-py3-none-any.whl", hash = "sha256:dec4c9d42ed0d9305889b67440f72e8e8d74b82b80abd7219667764b5b0a8e1d", size = 17153, upload-time = "2023-12-18T21:35:21.171Z" },
+]
+
+[[package]]
+name = "mypy"
+version = "1.19.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "librt", marker = "platform_python_implementation != 'PyPy'" },
+ { name = "mypy-extensions" },
+ { name = "pathspec" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2f/63/e499890d8e39b1ff2df4c0c6ce5d371b6844ee22b8250687a99fd2f657a8/mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec", size = 13101333, upload-time = "2025-12-15T05:03:03.28Z" },
+ { url = "https://files.pythonhosted.org/packages/72/4b/095626fc136fba96effc4fd4a82b41d688ab92124f8c4f7564bffe5cf1b0/mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b", size = 12164102, upload-time = "2025-12-15T05:02:33.611Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/5b/952928dd081bf88a83a5ccd49aaecfcd18fd0d2710c7ff07b8fb6f7032b9/mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6", size = 12765799, upload-time = "2025-12-15T05:03:28.44Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/0d/93c2e4a287f74ef11a66fb6d49c7a9f05e47b0a4399040e6719b57f500d2/mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74", size = 13522149, upload-time = "2025-12-15T05:02:36.011Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/0e/33a294b56aaad2b338d203e3a1d8b453637ac36cb278b45005e0901cf148/mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1", size = 13810105, upload-time = "2025-12-15T05:02:40.327Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/fd/3e82603a0cb66b67c5e7abababce6bf1a929ddf67bf445e652684af5c5a0/mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac", size = 10057200, upload-time = "2025-12-15T05:02:51.012Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/47/6b3ebabd5474d9cdc170d1342fbf9dddc1b0ec13ec90bf9004ee6f391c31/mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288", size = 13028539, upload-time = "2025-12-15T05:03:44.129Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/a6/ac7c7a88a3c9c54334f53a941b765e6ec6c4ebd65d3fe8cdcfbe0d0fd7db/mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab", size = 12083163, upload-time = "2025-12-15T05:03:37.679Z" },
+ { url = "https://files.pythonhosted.org/packages/67/af/3afa9cf880aa4a2c803798ac24f1d11ef72a0c8079689fac5cfd815e2830/mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6", size = 12687629, upload-time = "2025-12-15T05:02:31.526Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/46/20f8a7114a56484ab268b0ab372461cb3a8f7deed31ea96b83a4e4cfcfca/mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331", size = 13436933, upload-time = "2025-12-15T05:03:15.606Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/f8/33b291ea85050a21f15da910002460f1f445f8007adb29230f0adea279cb/mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925", size = 13661754, upload-time = "2025-12-15T05:02:26.731Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/a3/47cbd4e85bec4335a9cd80cf67dbc02be21b5d4c9c23ad6b95d6c5196bac/mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042", size = 10055772, upload-time = "2025-12-15T05:03:26.179Z" },
+ { url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" },
+ { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" },
+ { url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/63/e7493e5f90e1e085c562bb06e2eb32cae27c5057b9653348d38b47daaecc/mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13", size = 10118104, upload-time = "2025-12-15T05:03:10.834Z" },
+ { url = "https://files.pythonhosted.org/packages/de/9f/a6abae693f7a0c697dbb435aac52e958dc8da44e92e08ba88d2e42326176/mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250", size = 13201927, upload-time = "2025-12-15T05:02:29.138Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/a4/45c35ccf6e1c65afc23a069f50e2c66f46bd3798cbe0d680c12d12935caa/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b", size = 12206730, upload-time = "2025-12-15T05:03:01.325Z" },
+ { url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" },
+ { url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" },
+ { url = "https://files.pythonhosted.org/packages/98/76/d32051fa65ecf6cc8c6610956473abdc9b4c43301107476ac03559507843/mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd", size = 10135510, upload-time = "2025-12-15T05:02:58.438Z" },
+ { url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" },
+ { url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" },
+ { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" },
+]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+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" }
+wheels = [
+ { 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" },
+]
+
+[[package]]
+name = "nh3"
+version = "0.3.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cc/37/ab55eb2b05e334ff9a1ad52c556ace1f9c20a3f63613a165d384d5387657/nh3-0.3.3.tar.gz", hash = "sha256:185ed41b88c910b9ca8edc89ca3b4be688a12cb9de129d84befa2f74a0039fee", size = 18968, upload-time = "2026-02-14T09:35:15.664Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/a4/834f0ebd80844ce67e1bdb011d6f844f61cdb4c1d7cdc56a982bc054cc00/nh3-0.3.3-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:21b058cd20d9f0919421a820a2843fdb5e1749c0bf57a6247ab8f4ba6723c9fc", size = 1428680, upload-time = "2026-02-14T09:34:33.015Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/1a/a7d72e750f74c6b71befbeebc4489579fe783466889d41f32e34acde0b6b/nh3-0.3.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4400a73c2a62859e769f9d36d1b5a7a5c65c4179d1dddd2f6f3095b2db0cbfc", size = 799003, upload-time = "2026-02-14T09:34:35.108Z" },
+ { url = "https://files.pythonhosted.org/packages/58/d5/089eb6d65da139dc2223b83b2627e00872eccb5e1afdf5b1d76eb6ad3fcc/nh3-0.3.3-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ef87f8e916321a88b45f2d597f29bd56e560ed4568a50f0f1305afab86b7189", size = 846818, upload-time = "2026-02-14T09:34:37Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/c6/44a0b65fc7b213a3a725f041ef986534b100e58cd1a2e00f0fd3c9603893/nh3-0.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a446eae598987f49ee97ac2f18eafcce4e62e7574bd1eb23782e4702e54e217d", size = 1012537, upload-time = "2026-02-14T09:34:38.515Z" },
+ { url = "https://files.pythonhosted.org/packages/94/3a/91bcfcc0a61b286b8b25d39e288b9c0ba91c3290d402867d1cd705169844/nh3-0.3.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:0d5eb734a78ac364af1797fef718340a373f626a9ff6b4fb0b4badf7927e7b81", size = 1095435, upload-time = "2026-02-14T09:34:40.022Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/fd/4617a19d80cf9f958e65724ff5e97bc2f76f2f4c5194c740016606c87bd1/nh3-0.3.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:92a958e6f6d0100e025a5686aafd67e3c98eac67495728f8bb64fbeb3e474493", size = 1056344, upload-time = "2026-02-14T09:34:41.469Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/7d/5bcbbc56e71b7dda7ef1d6008098da9c5426d6334137ef32bb2b9c496984/nh3-0.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9ed40cf8449a59a03aa465114fedce1ff7ac52561688811d047917cc878b19ca", size = 1034533, upload-time = "2026-02-14T09:34:43.313Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/9c/054eff8a59a8b23b37f0f4ac84cdd688ee84cf5251664c0e14e5d30a8a67/nh3-0.3.3-cp314-cp314t-win32.whl", hash = "sha256:b50c3770299fb2a7c1113751501e8878d525d15160a4c05194d7fe62b758aad8", size = 608305, upload-time = "2026-02-14T09:34:44.622Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/b0/64667b8d522c7b859717a02b1a66ba03b529ca1df623964e598af8db1ed5/nh3-0.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:21a63ccb18ddad3f784bb775955839b8b80e347e597726f01e43ca1abcc5c808", size = 620633, upload-time = "2026-02-14T09:34:46.069Z" },
+ { url = "https://files.pythonhosted.org/packages/91/b5/ae9909e4ddfd86ee076c4d6d62ba69e9b31061da9d2f722936c52df8d556/nh3-0.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f508ddd4e2433fdcb78c790fc2d24e3a349ba775e5fa904af89891321d4844a3", size = 607027, upload-time = "2026-02-14T09:34:47.91Z" },
+ { url = "https://files.pythonhosted.org/packages/13/3e/aef8cf8e0419b530c95e96ae93a5078e9b36c1e6613eeb1df03a80d5194e/nh3-0.3.3-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e8ee96156f7dfc6e30ecda650e480c5ae0a7d38f0c6fafc3c1c655e2500421d9", size = 1448640, upload-time = "2026-02-14T09:34:49.316Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/43/d2011a4f6c0272cb122eeff40062ee06bb2b6e57eabc3a5e057df0d582df/nh3-0.3.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45fe0d6a607264910daec30360c8a3b5b1500fd832d21b2da608256287bcb92d", size = 839405, upload-time = "2026-02-14T09:34:50.779Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/f3/965048510c1caf2a34ed04411a46a04a06eb05563cd06f1aa57b71eb2bc8/nh3-0.3.3-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5bc1d4b30ba1ba896669d944b6003630592665974bd11a3dc2f661bde92798a7", size = 825849, upload-time = "2026-02-14T09:34:52.622Z" },
+ { url = "https://files.pythonhosted.org/packages/78/99/b4bbc6ad16329d8db2c2c320423f00b549ca3b129c2b2f9136be2606dbb0/nh3-0.3.3-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f433a2dd66545aad4a720ad1b2150edcdca75bfff6f4e6f378ade1ec138d5e77", size = 1068303, upload-time = "2026-02-14T09:34:54.179Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/34/3420d97065aab1b35f3e93ce9c96c8ebd423ce86fe84dee3126790421a2a/nh3-0.3.3-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52e973cb742e95b9ae1b35822ce23992428750f4b46b619fe86eba4205255b30", size = 1029316, upload-time = "2026-02-14T09:34:56.186Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/9a/99eda757b14e596fdb2ca5f599a849d9554181aa899274d0d183faef4493/nh3-0.3.3-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c730617bdc15d7092dcc0469dc2826b914c8f874996d105b4bc3842a41c1cd9", size = 919944, upload-time = "2026-02-14T09:34:57.886Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/84/c0dc75c7fb596135f999e59a410d9f45bdabb989f1cb911f0016d22b747b/nh3-0.3.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e98fa3dbfd54e25487e36ba500bc29bca3a4cab4ffba18cfb1a35a2d02624297", size = 811461, upload-time = "2026-02-14T09:34:59.65Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/ec/b1bf57cab6230eec910e4863528dc51dcf21b57aaf7c88ee9190d62c9185/nh3-0.3.3-cp38-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:3a62b8ae7c235481715055222e54c682422d0495a5c73326807d4e44c5d14691", size = 840360, upload-time = "2026-02-14T09:35:01.444Z" },
+ { url = "https://files.pythonhosted.org/packages/37/5e/326ae34e904dde09af1de51219a611ae914111f0970f2f111f4f0188f57e/nh3-0.3.3-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc305a2264868ec8fa16548296f803d8fd9c1fa66cd28b88b605b1bd06667c0b", size = 859872, upload-time = "2026-02-14T09:35:03.348Z" },
+ { url = "https://files.pythonhosted.org/packages/09/38/7eba529ce17ab4d3790205da37deabb4cb6edcba15f27b8562e467f2fc97/nh3-0.3.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:90126a834c18af03bfd6ff9a027bfa6bbf0e238527bc780a24de6bd7cc1041e2", size = 1023550, upload-time = "2026-02-14T09:35:04.829Z" },
+ { url = "https://files.pythonhosted.org/packages/05/a2/556fdecd37c3681b1edee2cf795a6799c6ed0a5551b2822636960d7e7651/nh3-0.3.3-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:24769a428e9e971e4ccfb24628f83aaa7dc3c8b41b130c8ddc1835fa1c924489", size = 1105212, upload-time = "2026-02-14T09:35:06.821Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/e3/5db0b0ad663234967d83702277094687baf7c498831a2d3ad3451c11770f/nh3-0.3.3-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:b7a18ee057761e455d58b9d31445c3e4b2594cff4ddb84d2e331c011ef46f462", size = 1069970, upload-time = "2026-02-14T09:35:08.504Z" },
+ { url = "https://files.pythonhosted.org/packages/79/b2/2ea21b79c6e869581ce5f51549b6e185c4762233591455bf2a326fb07f3b/nh3-0.3.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5a4b2c1f3e6f3cbe7048e17f4fefad3f8d3e14cc0fd08fb8599e0d5653f6b181", size = 1047588, upload-time = "2026-02-14T09:35:09.911Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/92/2e434619e658c806d9c096eed2cdff9a883084299b7b19a3f0824eb8e63d/nh3-0.3.3-cp38-abi3-win32.whl", hash = "sha256:e974850b131fdffa75e7ad8e0d9c7a855b96227b093417fdf1bd61656e530f37", size = 616179, upload-time = "2026-02-14T09:35:11.366Z" },
+ { url = "https://files.pythonhosted.org/packages/73/88/1ce287ef8649dc51365b5094bd3713b76454838140a32ab4f8349973883c/nh3-0.3.3-cp38-abi3-win_amd64.whl", hash = "sha256:2efd17c0355d04d39e6d79122b42662277ac10a17ea48831d90b46e5ef7e4fc0", size = 631159, upload-time = "2026-02-14T09:35:12.77Z" },
+ { url = "https://files.pythonhosted.org/packages/31/f1/b4835dbde4fb06f29db89db027576d6014081cd278d9b6751facc3e69e43/nh3-0.3.3-cp38-abi3-win_arm64.whl", hash = "sha256:b838e619f483531483d26d889438e53a880510e832d2aafe73f93b7b1ac2bce2", size = 616645, upload-time = "2026-02-14T09:35:14.062Z" },
+]
+
+[[package]]
+name = "nodeenv"
+version = "1.10.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" },
+]
+
+[[package]]
+name = "packageurl-python"
+version = "0.17.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f5/d6/3b5a4e3cfaef7a53869a26ceb034d1ff5e5c27c814ce77260a96d50ab7bb/packageurl_python-0.17.6.tar.gz", hash = "sha256:1252ce3a102372ca6f86eb968e16f9014c4ba511c5c37d95a7f023e2ca6e5c25", size = 50618, upload-time = "2025-11-24T15:20:17.998Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b1/2f/c7277b7615a93f51b5fbc1eacfc1b75e8103370e786fd8ce2abf6e5c04ab/packageurl_python-0.17.6-py3-none-any.whl", hash = "sha256:31a85c2717bc41dd818f3c62908685ff9eebcb68588213745b14a6ee9e7df7c9", size = 36776, upload-time = "2025-11-24T15:20:16.962Z" },
+]
+
+[[package]]
+name = "packaging"
+version = "26.0"
+source = { registry = "https://pypi.org/simple" }
+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" }
+wheels = [
+ { 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" },
+]
+
+[[package]]
+name = "pasteboard"
+version = "0.3.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/06/43/adc39246de74e9c482c11fbe6a50e8bc7f9dc367fdc261f6f767de5b1419/pasteboard-0.3.3.tar.gz", hash = "sha256:d80275e76ff1eaaa5ca3d0e0fd8aecd5ea1298523dfd51f3774b5aaebdde02cf", size = 13540, upload-time = "2021-01-29T08:10:43.131Z" }
+
+[[package]]
+name = "pastel"
+version = "0.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555, upload-time = "2020-09-16T19:21:12.43Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955, upload-time = "2020-09-16T19:21:11.409Z" },
+]
+
+[[package]]
+name = "pathspec"
+version = "1.0.4"
+source = { registry = "https://pypi.org/simple" }
+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" }
+wheels = [
+ { 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" },
+]
+
+[[package]]
+name = "pefile"
+version = "2024.8.26"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/03/4f/2750f7f6f025a1507cd3b7218691671eecfd0bbebebe8b39aa0fe1d360b8/pefile-2024.8.26.tar.gz", hash = "sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632", size = 76008, upload-time = "2024-08-26T20:58:38.155Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl", hash = "sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f", size = 74766, upload-time = "2024-08-26T21:01:02.632Z" },
+]
+
+[[package]]
+name = "pip"
+version = "26.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/48/83/0d7d4e9efe3344b8e2fe25d93be44f64b65364d3c8d7bc6dc90198d5422e/pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8", size = 1812747, upload-time = "2026-02-05T02:20:18.702Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b", size = 1787723, upload-time = "2026-02-05T02:20:16.416Z" },
+]
+
+[[package]]
+name = "pip-api"
+version = "0.0.34"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pip" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b9/f1/ee85f8c7e82bccf90a3c7aad22863cc6e20057860a1361083cd2adacb92e/pip_api-0.0.34.tar.gz", hash = "sha256:9b75e958f14c5a2614bae415f2adf7eeb54d50a2cfbe7e24fd4826471bac3625", size = 123017, upload-time = "2024-07-09T20:32:30.641Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/91/f7/ebf5003e1065fd00b4cbef53bf0a65c3d3e1b599b676d5383ccb7a8b88ba/pip_api-0.0.34-py3-none-any.whl", hash = "sha256:8b2d7d7c37f2447373aa2cf8b1f60a2f2b27a84e1e9e0294a3f6ef10eb3ba6bb", size = 120369, upload-time = "2024-07-09T20:32:29.099Z" },
+]
+
+[[package]]
+name = "pip-audit"
+version = "2.10.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cachecontrol", extra = ["filecache"] },
+ { name = "cyclonedx-python-lib" },
+ { name = "packaging" },
+ { name = "pip-api" },
+ { name = "pip-requirements-parser" },
+ { name = "platformdirs" },
+ { name = "requests" },
+ { name = "rich" },
+ { name = "tomli" },
+ { name = "tomli-w" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bd/89/0e999b413facab81c33d118f3ac3739fd02c0622ccf7c4e82e37cebd8447/pip_audit-2.10.0.tar.gz", hash = "sha256:427ea5bf61d1d06b98b1ae29b7feacc00288a2eced52c9c58ceed5253ef6c2a4", size = 53776, upload-time = "2025-12-01T23:42:40.612Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/be/f3/4888f895c02afa085630a3a3329d1b18b998874642ad4c530e9a4d7851fe/pip_audit-2.10.0-py3-none-any.whl", hash = "sha256:16e02093872fac97580303f0848fa3ad64f7ecf600736ea7835a2b24de49613f", size = 61518, upload-time = "2025-12-01T23:42:39.193Z" },
+]
+
+[[package]]
+name = "pip-requirements-parser"
+version = "32.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "packaging" },
+ { name = "pyparsing" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/5e/2a/63b574101850e7f7b306ddbdb02cb294380d37948140eecd468fae392b54/pip-requirements-parser-32.0.1.tar.gz", hash = "sha256:b4fa3a7a0be38243123cf9d1f3518da10c51bdb165a2b2985566247f9155a7d3", size = 209359, upload-time = "2022-12-21T15:25:22.732Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/54/d0/d04f1d1e064ac901439699ee097f58688caadea42498ec9c4b4ad2ef84ab/pip_requirements_parser-32.0.1-py3-none-any.whl", hash = "sha256:4659bc2a667783e7a15d190f6fccf8b2486685b6dba4c19c3876314769c57526", size = 35648, upload-time = "2022-12-21T15:25:21.046Z" },
+]
+
+[[package]]
+name = "pkginfo"
+version = "1.12.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/24/03/e26bf3d6453b7fda5bd2b84029a426553bb373d6277ef6b5ac8863421f87/pkginfo-1.12.1.2.tar.gz", hash = "sha256:5cd957824ac36f140260964eba3c6be6442a8359b8c48f4adf90210f33a04b7b", size = 451828, upload-time = "2025-02-19T15:27:37.188Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fa/3d/f4f2ba829efb54b6cd2d91349c7463316a9cc55a43fc980447416c88540f/pkginfo-1.12.1.2-py3-none-any.whl", hash = "sha256:c783ac885519cab2c34927ccfa6bf64b5a704d7c69afaea583dd9b7afe969343", size = 32717, upload-time = "2025-02-19T15:27:33.071Z" },
+]
+
+[[package]]
+name = "platformdirs"
+version = "4.9.2"
+source = { registry = "https://pypi.org/simple" }
+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" }
+wheels = [
+ { 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" },
+]
+
+[[package]]
+name = "pluggy"
+version = "1.6.0"
+source = { registry = "https://pypi.org/simple" }
+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" }
+wheels = [
+ { 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" },
+]
+
+[[package]]
+name = "plumbum"
+version = "1.10.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/dc/c8/11a5f792704b70f071a3dbc329105a98e9cc8d25daaf09f733c44eb0ef8e/plumbum-1.10.0.tar.gz", hash = "sha256:f8cbf0ecec0b73ff4e349398b65112a9e3f9300e7dc019001217dcc148d5c97c", size = 320039, upload-time = "2025-10-31T05:02:48.697Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/79/ad/45312df6b63ba64ea35b8d8f5f0c577aac16e6b416eafe8e1cb34e03f9a7/plumbum-1.10.0-py3-none-any.whl", hash = "sha256:9583d737ac901c474d99d030e4d5eec4c4e6d2d7417b1cf49728cf3be34f6dc8", size = 127383, upload-time = "2025-10-31T05:02:47.002Z" },
+]
+
+[[package]]
+name = "poethepoet"
+version = "0.36.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pastel" },
+ { name = "pyyaml" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cf/ac/311c8a492dc887f0b7a54d0ec3324cb2f9538b7b78ea06e5f7ae1f167e52/poethepoet-0.36.0.tar.gz", hash = "sha256:2217b49cb4e4c64af0b42ff8c4814b17f02e107d38bc461542517348ede25663", size = 66854, upload-time = "2025-06-29T19:54:50.444Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/03/29/dedb3a6b7e17ea723143b834a2da428a7d743c80d5cd4d22ed28b5e8c441/poethepoet-0.36.0-py3-none-any.whl", hash = "sha256:693e3c1eae9f6731d3613c3c0c40f747d3c5c68a375beda42e590a63c5623308", size = 88031, upload-time = "2025-06-29T19:54:48.884Z" },
+]
+
+[[package]]
+name = "pre-commit"
+version = "3.8.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cfgv" },
+ { name = "identify" },
+ { name = "nodeenv" },
+ { name = "pyyaml" },
+ { name = "virtualenv" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/64/10/97ee2fa54dff1e9da9badbc5e35d0bbaef0776271ea5907eccf64140f72f/pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", size = 177815, upload-time = "2024-07-28T19:59:01.538Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/07/92/caae8c86e94681b42c246f0bca35c059a2f0529e5b92619f6aba4cf7e7b6/pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f", size = 204643, upload-time = "2024-07-28T19:58:59.335Z" },
+]
+
+[[package]]
+name = "prompt-toolkit"
+version = "3.0.51"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "wcwidth" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940, upload-time = "2025-04-15T09:18:47.731Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" },
+]
+
+[[package]]
+name = "py-serializable"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "defusedxml" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/73/21/d250cfca8ff30c2e5a7447bc13861541126ce9bd4426cd5d0c9f08b5547d/py_serializable-2.1.0.tar.gz", hash = "sha256:9d5db56154a867a9b897c0163b33a793c804c80cee984116d02d49e4578fc103", size = 52368, upload-time = "2025-07-21T09:56:48.07Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9b/bf/7595e817906a29453ba4d99394e781b6fabe55d21f3c15d240f85dd06bb1/py_serializable-2.1.0-py3-none-any.whl", hash = "sha256:b56d5d686b5a03ba4f4db5e769dc32336e142fc3bd4d68a8c25579ebb0a67304", size = 23045, upload-time = "2025-07-21T09:56:46.848Z" },
+]
+
+[[package]]
+name = "pyclip"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pasteboard", marker = "sys_platform == 'darwin'" },
+ { name = "pywin32", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/65/8a/98ed02d81dea4b2211a4746724d7a271264b701c991fed503c246de52864/pyclip-0.7.0.tar.gz", hash = "sha256:57602047a4ceab709bdcd42f3dde6449a3349b95c16154cfdce27376a2072491", size = 13639, upload-time = "2022-10-31T21:13:34.952Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7d/4f/4b02e2c232ddf694bca0baea3049b886eeb80ee3d89c415067f5191596c1/pyclip-0.7.0-py3-none-any.whl", hash = "sha256:a7b7ea2cfad2dd61e86a529af588d006070d3eb0bd32981afaee5215f4604fec", size = 18864, upload-time = "2022-10-31T21:13:33.459Z" },
+]
+
+[[package]]
+name = "pycparser"
+version = "3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
+]
+
+[[package]]
+name = "pycryptodomex"
+version = "3.23.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" },
+ { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" },
+ { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" },
+ { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" },
+ { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" },
+ { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" },
+ { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" },
+ { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" },
+ { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" },
+ { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" },
+ { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" },
+]
+
+[[package]]
+name = "pydantic"
+version = "2.12.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-types" },
+ { name = "pydantic-core" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" },
+]
+
+[[package]]
+name = "pydantic-core"
+version = "2.41.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" },
+ { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" },
+ { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" },
+ { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" },
+ { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" },
+ { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" },
+ { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" },
+ { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" },
+ { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" },
+ { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" },
+ { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" },
+ { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" },
+ { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" },
+ { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" },
+ { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" },
+ { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" },
+ { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" },
+ { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" },
+ { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" },
+ { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" },
+ { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" },
+ { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" },
+ { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" },
+ { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" },
+ { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" },
+ { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" },
+ { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" },
+ { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" },
+ { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" },
+ { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" },
+ { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" },
+ { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" },
+ { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
+ { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
+ { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" },
+ { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" },
+ { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" },
+ { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" },
+ { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" },
+ { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" },
+ { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" },
+ { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" },
+ { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" },
+]
+
+[[package]]
+name = "pydash"
+version = "8.0.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/75/c1/1c55272f49d761cec38ddb80be9817935b9c91ebd6a8988e10f532868d56/pydash-8.0.6.tar.gz", hash = "sha256:b2821547e9723f69cf3a986be4db64de41730be149b2641947ecd12e1e11025a", size = 164338, upload-time = "2026-01-17T16:42:56.576Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a5/b7/cc5e7974699db40014d58c7dd7c4ad4ffc244d36930dc9ec7d06ee67d7a9/pydash-8.0.6-py3-none-any.whl", hash = "sha256:ee70a81a5b292c007f28f03a4ee8e75c1f5d7576df5457b836ec7ab2839cc5d0", size = 101561, upload-time = "2026-01-17T16:42:55.448Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.19.2"
+source = { registry = "https://pypi.org/simple" }
+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" }
+wheels = [
+ { 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" },
+]
+
+[[package]]
+name = "pyinstaller"
+version = "6.19.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "altgraph" },
+ { name = "macholib", marker = "sys_platform == 'darwin'" },
+ { name = "packaging" },
+ { name = "pefile", marker = "sys_platform == 'win32'" },
+ { name = "pyinstaller-hooks-contrib" },
+ { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" },
+ { name = "setuptools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c8/63/fd62472b6371d89dc138d40c36d87a50dc2de18a035803bbdc376b4ffac4/pyinstaller-6.19.0.tar.gz", hash = "sha256:ec73aeb8bd9b7f2f1240d328a4542e90b3c6e6fbc106014778431c616592a865", size = 4036072, upload-time = "2026-02-14T18:06:28.718Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e3/eb/23374721fecfa72677e79800921cb6aceefa6ba48574dc404f3f6c6c3be7/pyinstaller-6.19.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:4190e76b74f0c4b5c5f11ac360928cd2e36ec8e3194d437bf6b8648c7bc0c134", size = 1040563, upload-time = "2026-02-14T18:05:22.436Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/7e/dfd724b0b533f5aaec0ee5df406fe2319987ed6964480a706f85478b12ea/pyinstaller-6.19.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8bd68abd812d8a6ba33b9f1810e91fee0f325969733721b78151f0065319ca11", size = 735477, upload-time = "2026-02-14T18:05:27.143Z" },
+ { url = "https://files.pythonhosted.org/packages/88/c9/ee3a4101c31f26344e66896c73c1fd6ed8282bf871473365b7f8674af406/pyinstaller-6.19.0-py3-none-manylinux2014_i686.whl", hash = "sha256:1ec54ef967996ca61dacba676227e2b23219878ccce5ee9d6f3aada7b8ed8abf", size = 747143, upload-time = "2026-02-14T18:05:31.488Z" },
+ { url = "https://files.pythonhosted.org/packages/da/0a/fc77e9f861be8cf300ac37155f59cc92aff99b29f2ddd78546f563a5b5a6/pyinstaller-6.19.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:4ab2bb52e58448e14ddf9450601bdedd66800465043501c1d8f1cab87b60b122", size = 744849, upload-time = "2026-02-14T18:05:35.492Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/e3/6872e020ee758afe0b821663858492c10745608b07150e5e2c824a5b3e1c/pyinstaller-6.19.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:da6d5c6391ccefe73554b9fa29b86001c8e378e0f20c2a4004f836ba537eff63", size = 741590, upload-time = "2026-02-14T18:05:39.59Z" },
+ { url = "https://files.pythonhosted.org/packages/53/60/b8db5f1a4b0fb228175f2ea0aa33f949adcc097fbe981cc524f9faf85777/pyinstaller-6.19.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a0fc5f6b3c55aa54353f0c74ffa59b1115433c1850c6f655d62b461a2ed6cbbe", size = 741448, upload-time = "2026-02-14T18:05:45.636Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/4d/63b0600f2694e9141b83129fbc1c488ec84d5a0770b1448ec154dcd0fee9/pyinstaller-6.19.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:e649ba6bd1b0b89b210ad92adb5fbdc8a42dd2c5ca4f72ef3a0bfec83a424b83", size = 740613, upload-time = "2026-02-14T18:05:49.726Z" },
+ { url = "https://files.pythonhosted.org/packages/01/d4/e812ad36178093a0e9fd4b8127577748dd85b0cb71de912229dca21fd741/pyinstaller-6.19.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:481a909c8e60c8692fc60fcb1344d984b44b943f8bc9682f2fcdae305ad297e6", size = 740350, upload-time = "2026-02-14T18:05:54.093Z" },
+ { url = "https://files.pythonhosted.org/packages/52/03/b2c2ee41fb8e10fd2a45d21f5ec2ef25852cfb978dbf762972eed59e3d63/pyinstaller-6.19.0-py3-none-win32.whl", hash = "sha256:3c5c251054fe4cfaa04c34a363dcfbf811545438cb7198304cd444756bc2edd2", size = 1324317, upload-time = "2026-02-14T18:06:00.085Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/d3/6d5e62b8270e2b53a6065e281b3a7785079b00e9019c8019952828dd1669/pyinstaller-6.19.0-py3-none-win_amd64.whl", hash = "sha256:b5bb6536c6560330d364d91522250f254b107cf69129d9cbcd0e6727c570be33", size = 1384894, upload-time = "2026-02-14T18:06:06.425Z" },
+ { url = "https://files.pythonhosted.org/packages/81/65/458cd523308a101a22fd2742893405030cc24994cc74b1b767cecf137160/pyinstaller-6.19.0-py3-none-win_arm64.whl", hash = "sha256:c2d5a539b0bfe6159d5522c8c70e1c0e487f22c2badae0f97d45246223b798ea", size = 1325374, upload-time = "2026-02-14T18:06:12.804Z" },
+]
+
+[[package]]
+name = "pyinstaller-hooks-contrib"
+version = "2026.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "packaging" },
+ { name = "setuptools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/6b/90/f3b30d72b89ab5b8f3ef714db94d09c7c263cce6562b4c7c636d99630695/pyinstaller_hooks_contrib-2026.2.tar.gz", hash = "sha256:cbd1eb00b5d13301b1cce602e1fffb17f0c531c0391f0a87a383d376be68a186", size = 171884, upload-time = "2026-03-02T23:07:01.221Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/34/3b/1efef5ff4d4d150f646b873e963437c0b800cb375a37df01fefab149f4d9/pyinstaller_hooks_contrib-2026.2-py3-none-any.whl", hash = "sha256:fc29f0481b58adf78ce9c1d9cf135fe96f38c708f74b2aa0670ef93e59578ab9", size = 453939, upload-time = "2026-03-02T23:06:59.469Z" },
+]
+
+[[package]]
+name = "pyjwt"
+version = "2.12.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" },
+]
+
+[[package]]
+name = "pynacl"
+version = "1.6.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" },
+ { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" },
+ { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" },
+ { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" },
+ { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" },
+ { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" },
+ { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" },
+ { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" },
+ { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" },
+ { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" },
+ { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" },
+ { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" },
+]
+
+[[package]]
+name = "pyparsing"
+version = "3.3.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" },
+]
+
+[[package]]
+name = "pyperclip"
+version = "1.11.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e8/52/d87eba7cb129b81563019d1679026e7a112ef76855d6159d24754dbd2a51/pyperclip-1.11.0.tar.gz", hash = "sha256:244035963e4428530d9e3a6101a1ef97209c6825edab1567beac148ccc1db1b6", size = 12185, upload-time = "2025-09-26T14:40:37.245Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl", hash = "sha256:299403e9ff44581cb9ba2ffeed69c7aa96a008622ad0c46cb575ca75b5b84273", size = 11063, upload-time = "2025-09-26T14:40:36.069Z" },
+]
+
+[[package]]
+name = "pytest"
+version = "8.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+ { name = "iniconfig" },
+ { name = "packaging" },
+ { name = "pluggy" },
+ { name = "pygments" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" },
+]
+
+[[package]]
+name = "pytest-cov"
+version = "4.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "coverage", extra = ["toml"] },
+ { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7a/15/da3df99fd551507694a9b01f512a2f6cf1254f33601605843c3775f39460/pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6", size = 63245, upload-time = "2023-05-24T18:44:56.845Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a7/4b/8b78d126e275efa2379b1c2e09dc52cf70df16fc3b90613ef82531499d73/pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a", size = 21949, upload-time = "2023-05-24T18:44:54.079Z" },
+]
+
+[[package]]
+name = "pytest-httpx"
+version = "0.35.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "httpx" },
+ { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1f/89/5b12b7b29e3d0af3a4b9c071ee92fa25a9017453731a38f08ba01c280f4c/pytest_httpx-0.35.0.tar.gz", hash = "sha256:d619ad5d2e67734abfbb224c3d9025d64795d4b8711116b1a13f72a251ae511f", size = 54146, upload-time = "2024-11-28T19:16:54.237Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b0/ed/026d467c1853dd83102411a78126b4842618e86c895f93528b0528c7a620/pytest_httpx-0.35.0-py3-none-any.whl", hash = "sha256:ee11a00ffcea94a5cbff47af2114d34c5b231c326902458deed73f9c459fd744", size = 19442, upload-time = "2024-11-28T19:16:52.787Z" },
+]
+
+[[package]]
+name = "pytest-mock"
+version = "3.15.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", size = 34036, upload-time = "2025-09-16T16:37:27.081Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", size = 10095, upload-time = "2025-09-16T16:37:25.734Z" },
+]
+
+[[package]]
+name = "pytest-sugar"
+version = "1.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pytest" },
+ { name = "termcolor" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0b/4e/60fed105549297ba1a700e1ea7b828044842ea27d72c898990510b79b0e2/pytest-sugar-1.1.1.tar.gz", hash = "sha256:73b8b65163ebf10f9f671efab9eed3d56f20d2ca68bda83fa64740a92c08f65d", size = 16533, upload-time = "2025-08-23T12:19:35.737Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/87/d5/81d38a91c1fdafb6711f053f5a9b92ff788013b19821257c2c38c1e132df/pytest_sugar-1.1.1-py3-none-any.whl", hash = "sha256:2f8319b907548d5b9d03a171515c1d43d2e38e32bd8182a1781eb20b43344cc8", size = 11440, upload-time = "2025-08-23T12:19:34.894Z" },
+]
+
+[[package]]
+name = "pytest-xdist"
+version = "3.8.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "execnet" },
+ { name = "pytest" },
+]
+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" }
+wheels = [
+ { 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" },
+]
+
+[[package]]
+name = "python-discovery"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "filelock" },
+ { name = "platformdirs" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/82/bb/93a3e83bdf9322c7e21cafd092e56a4a17c4d8ef4277b6eb01af1a540a6f/python_discovery-1.1.0.tar.gz", hash = "sha256:447941ba1aed8cc2ab7ee3cb91be5fc137c5bdbb05b7e6ea62fbdcb66e50b268", size = 55674, upload-time = "2026-02-26T09:42:49.668Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/06/54/82a6e2ef37f0f23dccac604b9585bdcbd0698604feb64807dcb72853693e/python_discovery-1.1.0-py3-none-any.whl", hash = "sha256:a162893b8809727f54594a99ad2179d2ede4bf953e12d4c7abc3cc9cdbd1437b", size = 30687, upload-time = "2026-02-26T09:42:48.548Z" },
+]
+
+[[package]]
+name = "python-dotenv"
+version = "1.2.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
+]
+
+[[package]]
+name = "python-gitlab"
+version = "3.15.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "requests" },
+ { name = "requests-toolbelt" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/22/53/248b87282df591d74ba3d38c3c3ced2b5087248c0ccfb6b3a947bb1034c3/python-gitlab-3.15.0.tar.gz", hash = "sha256:c9e65eb7612a9fbb8abf0339972eca7fd7a73d4da66c9b446ffe528930aff534", size = 273270, upload-time = "2023-06-09T09:51:31.92Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/38/51/3c7dd08272658e5490d0c0b6c94af15bd0c0649e7ad23c9ed0db1d276143/python_gitlab-3.15.0-py3-none-any.whl", hash = "sha256:8f8d1c0d387f642eb1ac7bf5e8e0cd8b3dd49c6f34170cee3c7deb7d384611f3", size = 135865, upload-time = "2023-06-09T09:51:29.996Z" },
+]
+
+[[package]]
+name = "python-semantic-release"
+version = "7.34.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "click-log" },
+ { name = "dotty-dict" },
+ { name = "gitpython" },
+ { name = "invoke" },
+ { name = "packaging" },
+ { name = "python-gitlab" },
+ { name = "requests" },
+ { name = "semver" },
+ { name = "tomlkit" },
+ { name = "twine" },
+ { name = "wheel" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/04/67/abf0ed527dafc5545b2ae264ec090b9849fac7775c319f0f6da95a50e9b7/python-semantic-release-7.34.6.tar.gz", hash = "sha256:e9b8fb788024ae9510a924136d573588415a16eeca31cc5240f2754a80a2e831", size = 41885, upload-time = "2023-06-17T14:12:17.089Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/53/d9b4c4a811a946489f89b62b02b01e9e456dc8c3bde154a18eac4f1dcbe4/python_semantic_release-7.34.6-py3-none-any.whl", hash = "sha256:7e3969ba4663d9b2087b02bf3ac140e202551377bf045c34e09bfe19753e19ab", size = 55637, upload-time = "2023-06-17T14:12:14.975Z" },
+]
+
+[[package]]
+name = "pywin32"
+version = "311"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" },
+ { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" },
+ { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" },
+ { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" },
+ { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" },
+ { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
+]
+
+[[package]]
+name = "pywin32-ctypes"
+version = "0.2.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" },
+]
+
+[[package]]
+name = "pyyaml"
+version = "6.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" },
+ { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" },
+ { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" },
+ { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" },
+ { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" },
+ { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" },
+ { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" },
+ { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
+ { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
+ { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
+ { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
+ { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
+ { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
+ { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
+ { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
+ { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
+ { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
+ { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
+ { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
+ { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
+ { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
+ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
+]
+
+[[package]]
+name = "questionary"
+version = "1.10.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "prompt-toolkit" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/04/c6/a8dbf1edcbc236d93348f6e7c437cf09c7356dd27119fcc3be9d70c93bb1/questionary-1.10.0.tar.gz", hash = "sha256:600d3aefecce26d48d97eee936fdb66e4bc27f934c3ab6dd1e292c4f43946d90", size = 23530, upload-time = "2021-07-15T10:11:01.435Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/49/00/151ff8314078efa3087c23b4b7c473f08f601dff7c62bfb894dd462e0fc9/questionary-1.10.0-py3-none-any.whl", hash = "sha256:fecfcc8cca110fda9d561cb83f1e97ecbb93c613ff857f655818839dac74ce90", size = 31443, upload-time = "2021-07-15T10:11:00.246Z" },
+]
+
+[[package]]
+name = "readme-renderer"
+version = "43.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "docutils" },
+ { name = "nh3" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fe/b5/536c775084d239df6345dccf9b043419c7e3308bc31be4c7882196abc62e/readme_renderer-43.0.tar.gz", hash = "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311", size = 31768, upload-time = "2024-02-26T16:10:59.415Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/45/be/3ea20dc38b9db08387cf97997a85a7d51527ea2057d71118feb0aa8afa55/readme_renderer-43.0-py3-none-any.whl", hash = "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9", size = 13301, upload-time = "2024-02-26T16:10:57.945Z" },
+]
+
+[[package]]
+name = "requests"
+version = "2.32.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "charset-normalizer" },
+ { name = "idna" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
+]
+
+[[package]]
+name = "requests-toolbelt"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" },
+]
+
+[[package]]
+name = "rfc3986"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/85/40/1520d68bfa07ab5a6f065a186815fb6610c86fe957bc065754e47f7b0840/rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c", size = 49026, upload-time = "2022-01-10T00:52:30.832Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", size = 31326, upload-time = "2022-01-10T00:52:29.594Z" },
+]
+
+[[package]]
+name = "rich"
+version = "14.3.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" },
+]
+
+[[package]]
+name = "ruff"
+version = "0.12.12"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a8/f0/e0965dd709b8cabe6356811c0ee8c096806bb57d20b5019eb4e48a117410/ruff-0.12.12.tar.gz", hash = "sha256:b86cd3415dbe31b3b46a71c598f4c4b2f550346d1ccf6326b347cc0c8fd063d6", size = 5359915, upload-time = "2025-09-04T16:50:18.273Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/09/79/8d3d687224d88367b51c7974cec1040c4b015772bfbeffac95face14c04a/ruff-0.12.12-py3-none-linux_armv6l.whl", hash = "sha256:de1c4b916d98ab289818e55ce481e2cacfaad7710b01d1f990c497edf217dafc", size = 12116602, upload-time = "2025-09-04T16:49:18.892Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/c3/6e599657fe192462f94861a09aae935b869aea8a1da07f47d6eae471397c/ruff-0.12.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7acd6045e87fac75a0b0cdedacf9ab3e1ad9d929d149785903cff9bb69ad9727", size = 12868393, upload-time = "2025-09-04T16:49:23.043Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/d2/9e3e40d399abc95336b1843f52fc0daaceb672d0e3c9290a28ff1a96f79d/ruff-0.12.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:abf4073688d7d6da16611f2f126be86523a8ec4343d15d276c614bda8ec44edb", size = 12036967, upload-time = "2025-09-04T16:49:26.04Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/03/6816b2ed08836be272e87107d905f0908be5b4a40c14bfc91043e76631b8/ruff-0.12.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:968e77094b1d7a576992ac078557d1439df678a34c6fe02fd979f973af167577", size = 12276038, upload-time = "2025-09-04T16:49:29.056Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/d5/707b92a61310edf358a389477eabd8af68f375c0ef858194be97ca5b6069/ruff-0.12.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42a67d16e5b1ffc6d21c5f67851e0e769517fb57a8ebad1d0781b30888aa704e", size = 11901110, upload-time = "2025-09-04T16:49:32.07Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/3d/f8b1038f4b9822e26ec3d5b49cf2bc313e3c1564cceb4c1a42820bf74853/ruff-0.12.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b216ec0a0674e4b1214dcc998a5088e54eaf39417327b19ffefba1c4a1e4971e", size = 13668352, upload-time = "2025-09-04T16:49:35.148Z" },
+ { url = "https://files.pythonhosted.org/packages/98/0e/91421368ae6c4f3765dd41a150f760c5f725516028a6be30e58255e3c668/ruff-0.12.12-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:59f909c0fdd8f1dcdbfed0b9569b8bf428cf144bec87d9de298dcd4723f5bee8", size = 14638365, upload-time = "2025-09-04T16:49:38.892Z" },
+ { url = "https://files.pythonhosted.org/packages/74/5d/88f3f06a142f58ecc8ecb0c2fe0b82343e2a2b04dcd098809f717cf74b6c/ruff-0.12.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ac93d87047e765336f0c18eacad51dad0c1c33c9df7484c40f98e1d773876f5", size = 14060812, upload-time = "2025-09-04T16:49:42.732Z" },
+ { url = "https://files.pythonhosted.org/packages/13/fc/8962e7ddd2e81863d5c92400820f650b86f97ff919c59836fbc4c1a6d84c/ruff-0.12.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01543c137fd3650d322922e8b14cc133b8ea734617c4891c5a9fccf4bfc9aa92", size = 13050208, upload-time = "2025-09-04T16:49:46.434Z" },
+ { url = "https://files.pythonhosted.org/packages/53/06/8deb52d48a9a624fd37390555d9589e719eac568c020b27e96eed671f25f/ruff-0.12.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afc2fa864197634e549d87fb1e7b6feb01df0a80fd510d6489e1ce8c0b1cc45", size = 13311444, upload-time = "2025-09-04T16:49:49.931Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/81/de5a29af7eb8f341f8140867ffb93f82e4fde7256dadee79016ac87c2716/ruff-0.12.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0c0945246f5ad776cb8925e36af2438e66188d2b57d9cf2eed2c382c58b371e5", size = 13279474, upload-time = "2025-09-04T16:49:53.465Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/14/d9577fdeaf791737ada1b4f5c6b59c21c3326f3f683229096cccd7674e0c/ruff-0.12.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a0fbafe8c58e37aae28b84a80ba1817f2ea552e9450156018a478bf1fa80f4e4", size = 12070204, upload-time = "2025-09-04T16:49:56.882Z" },
+ { url = "https://files.pythonhosted.org/packages/77/04/a910078284b47fad54506dc0af13839c418ff704e341c176f64e1127e461/ruff-0.12.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b9c456fb2fc8e1282affa932c9e40f5ec31ec9cbb66751a316bd131273b57c23", size = 11880347, upload-time = "2025-09-04T16:49:59.729Z" },
+ { url = "https://files.pythonhosted.org/packages/df/58/30185fcb0e89f05e7ea82e5817b47798f7fa7179863f9d9ba6fd4fe1b098/ruff-0.12.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f12856123b0ad0147d90b3961f5c90e7427f9acd4b40050705499c98983f489", size = 12891844, upload-time = "2025-09-04T16:50:02.591Z" },
+ { url = "https://files.pythonhosted.org/packages/21/9c/28a8dacce4855e6703dcb8cdf6c1705d0b23dd01d60150786cd55aa93b16/ruff-0.12.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:26a1b5a2bf7dd2c47e3b46d077cd9c0fc3b93e6c6cc9ed750bd312ae9dc302ee", size = 13360687, upload-time = "2025-09-04T16:50:05.8Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/fa/05b6428a008e60f79546c943e54068316f32ec8ab5c4f73e4563934fbdc7/ruff-0.12.12-py3-none-win32.whl", hash = "sha256:173be2bfc142af07a01e3a759aba6f7791aa47acf3604f610b1c36db888df7b1", size = 12052870, upload-time = "2025-09-04T16:50:09.121Z" },
+ { url = "https://files.pythonhosted.org/packages/85/60/d1e335417804df452589271818749d061b22772b87efda88354cf35cdb7a/ruff-0.12.12-py3-none-win_amd64.whl", hash = "sha256:e99620bf01884e5f38611934c09dd194eb665b0109104acae3ba6102b600fd0d", size = 13178016, upload-time = "2025-09-04T16:50:12.559Z" },
+ { url = "https://files.pythonhosted.org/packages/28/7e/61c42657f6e4614a4258f1c3b0c5b93adc4d1f8575f5229d1906b483099b/ruff-0.12.12-py3-none-win_arm64.whl", hash = "sha256:2a8199cab4ce4d72d158319b63370abf60991495fb733db96cd923a34c52d093", size = 12256762, upload-time = "2025-09-04T16:50:15.737Z" },
+]
+
+[[package]]
+name = "secretstorage"
+version = "3.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cryptography" },
+ { name = "jeepney" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137", size = 15554, upload-time = "2025-11-23T19:02:51.545Z" },
+]
+
+[[package]]
+name = "semver"
+version = "2.13.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/31/a9/b61190916030ee9af83de342e101f192bbb436c59be20a4cb0cdb7256ece/semver-2.13.0.tar.gz", hash = "sha256:fa0fe2722ee1c3f57eac478820c3a5ae2f624af8264cbdf9000c980ff7f75e3f", size = 45816, upload-time = "2020-10-20T20:16:54.454Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0b/70/b84f9944a03964a88031ef6ac219b6c91e8ba2f373362329d8770ef36f02/semver-2.13.0-py2.py3-none-any.whl", hash = "sha256:ced8b23dceb22134307c1b8abfa523da14198793d9787ac838e70e29e77458d4", size = 12901, upload-time = "2020-10-20T20:16:52.583Z" },
+]
+
+[[package]]
+name = "setuptools"
+version = "82.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/82/f3/748f4d6f65d1756b9ae577f329c951cda23fb900e4de9f70900ced962085/setuptools-82.0.0.tar.gz", hash = "sha256:22e0a2d69474c6ae4feb01951cb69d515ed23728cf96d05513d36e42b62b37cb", size = 1144893, upload-time = "2026-02-08T15:08:40.206Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e1/c6/76dc613121b793286a3f91621d7b75a2b493e0390ddca50f11993eadf192/setuptools-82.0.0-py3-none-any.whl", hash = "sha256:70b18734b607bd1da571d097d236cfcfacaf01de45717d59e6e04b96877532e0", size = 1003468, upload-time = "2026-02-08T15:08:38.723Z" },
+]
+
+[[package]]
+name = "shellingham"
+version = "1.5.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
+]
+
+[[package]]
+name = "smmap"
+version = "5.0.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" },
+]
+
+[[package]]
+name = "snowballstemmer"
+version = "3.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" },
+]
+
+[[package]]
+name = "sortedcontainers"
+version = "2.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" },
+]
+
+[[package]]
+name = "soupsieve"
+version = "2.8.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627, upload-time = "2026-01-20T04:27:02.457Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" },
+]
+
+[[package]]
+name = "sphinx"
+version = "6.2.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "alabaster" },
+ { name = "babel" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "docutils" },
+ { name = "imagesize" },
+ { name = "jinja2" },
+ { name = "packaging" },
+ { name = "pygments" },
+ { name = "requests" },
+ { name = "snowballstemmer" },
+ { name = "sphinxcontrib-applehelp" },
+ { name = "sphinxcontrib-devhelp" },
+ { name = "sphinxcontrib-htmlhelp" },
+ { name = "sphinxcontrib-jsmath" },
+ { name = "sphinxcontrib-qthelp" },
+ { name = "sphinxcontrib-serializinghtml" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0f/6d/392defcc95ca48daf62aecb89550143e97a4651275e62a3d7755efe35a3a/Sphinx-6.2.1.tar.gz", hash = "sha256:6d56a34697bb749ffa0152feafc4b19836c755d90a7c59b72bc7dfd371b9cc6b", size = 6681092, upload-time = "2023-04-25T11:01:40.914Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5f/d8/45ba6097c39ba44d9f0e1462fb232e13ca4ddb5aea93a385dcfa964687da/sphinx-6.2.1-py3-none-any.whl", hash = "sha256:97787ff1fa3256a3eef9eda523a63dbf299f7b47e053cfcf684a1c2a8380c912", size = 3024615, upload-time = "2023-04-25T11:01:08.562Z" },
+]
+
+[[package]]
+name = "sphinx-click"
+version = "4.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "docutils" },
+ { name = "sphinx" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/48/bf/8e5c3e7865d909a64ed2bd89dcc835f3c542fec857c8bdf38ee8b682af14/sphinx-click-4.4.0.tar.gz", hash = "sha256:cc67692bd28f482c7f01531c61b64e9d2f069bfcf3d24cbbb51d4a84a749fa48", size = 25564, upload-time = "2022-12-06T13:00:57.766Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ce/cd/00689d6d6e20159509499c79b76c143a2ac5fdcd5c44089119e47e3d674d/sphinx_click-4.4.0-py3-none-any.whl", hash = "sha256:2821c10a68fc9ee6ce7c92fad26540d8d8c8f45e6d7258f0e4fb7529ae8fab49", size = 9289, upload-time = "2022-12-06T13:00:56.496Z" },
+]
+
+[[package]]
+name = "sphinxcontrib-applehelp"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" },
+]
+
+[[package]]
+name = "sphinxcontrib-devhelp"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" },
+]
+
+[[package]]
+name = "sphinxcontrib-htmlhelp"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" },
+]
+
+[[package]]
+name = "sphinxcontrib-jsmath"
+version = "1.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" },
+]
+
+[[package]]
+name = "sphinxcontrib-qthelp"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" },
+]
+
+[[package]]
+name = "sphinxcontrib-serializinghtml"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" },
+]
+
+[[package]]
+name = "sphinxnotes-markdown-builder"
+version = "0.5.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "html2text" },
+ { name = "pydash" },
+ { name = "sphinx" },
+ { name = "unify" },
+ { name = "yapf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fe/75/cb8db5a62f39dd5d05210dafea1364fdbe49750839e10cdc9c122b34bfca/sphinxnotes-markdown-builder-0.5.7.tar.gz", hash = "sha256:ad3e88fa1052d1a9bc4b75d7ae389ce51ffa896963bb19643e01b9120ca17ee9", size = 17901, upload-time = "2023-12-24T03:37:44.053Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/1a/379ffb196cb026c7d7bbe459f462bf12b482b75abe9405f81dea16c1d612/sphinxnotes_markdown_builder-0.5.7-py2.py3-none-any.whl", hash = "sha256:e1c49c31f72c36b29defc69fb05b7087b736355474b8806c814306ad3b42e2b8", size = 18606, upload-time = "2023-12-24T03:37:42.292Z" },
+]
+
+[[package]]
+name = "termcolor"
+version = "3.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" },
+]
+
+[[package]]
+name = "textual"
+version = "3.7.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py", extra = ["linkify", "plugins"] },
+ { name = "platformdirs" },
+ { name = "rich" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/af/83/c99c252c3fad2f7010ceb476a31af042eec71da441ffeef75bb590bc2e9e/textual-3.7.1.tar.gz", hash = "sha256:a76ba0c8a6c194ef24fd5c3681ebfddca55e7127c064a014128c84fbd7f5d271", size = 1604038, upload-time = "2025-07-09T09:04:45.477Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/15/f1/8929fcce6dc983f7a260d0f3ddd2a69b74ba17383dbe57a7e0a9e085e8be/textual-3.7.1-py3-none-any.whl", hash = "sha256:ab5d153f4f65e77017977fa150d0376409e0acf5f1d2e25e2e4ab9de6c0d61ff", size = 691472, upload-time = "2025-07-09T09:04:43.626Z" },
+]
+
+[[package]]
+name = "tomli"
+version = "2.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" },
+ { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" },
+ { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" },
+ { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" },
+ { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" },
+ { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" },
+ { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" },
+ { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" },
+ { url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" },
+ { url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" },
+ { url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" },
+ { url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" },
+ { url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" },
+ { url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" },
+ { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" },
+]
+
+[[package]]
+name = "tomli-w"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" },
+]
+
+[[package]]
+name = "tomlkit"
+version = "0.14.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c3/af/14b24e41977adb296d6bd1fb59402cf7d60ce364f90c890bd2ec65c43b5a/tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064", size = 187167, upload-time = "2026-01-13T01:14:53.304Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b5/11/87d6d29fb5d237229d67973a6c9e06e048f01cf4994dee194ab0ea841814/tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680", size = 39310, upload-time = "2026-01-13T01:14:51.965Z" },
+]
+
+[[package]]
+name = "tqdm"
+version = "4.67.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" },
+]
+
+[[package]]
+name = "twine"
+version = "3.8.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama" },
+ { name = "importlib-metadata" },
+ { name = "keyring" },
+ { name = "pkginfo" },
+ { name = "readme-renderer" },
+ { name = "requests" },
+ { name = "requests-toolbelt" },
+ { name = "rfc3986" },
+ { name = "tqdm" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d1/3e/ce331d7e215abdc16c53e65f8506bfccf4840ce191b709a37b8c83cc32c7/twine-3.8.0.tar.gz", hash = "sha256:8efa52658e0ae770686a13b675569328f1fba9837e5de1867bfe5f46a9aefe19", size = 214568, upload-time = "2022-02-02T18:50:23.428Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5e/74/ea7dfb86223695fd8efa256a24d1520729dde79a4e628ee6879f0f136d40/twine-3.8.0-py3-none-any.whl", hash = "sha256:d0550fca9dc19f3d5e8eadfce0c227294df0a2a951251a4385797c8a6198b7c8", size = 36057, upload-time = "2022-02-02T18:50:21.723Z" },
+]
+
+[[package]]
+name = "types-pyyaml"
+version = "6.0.12.20250915"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7e/69/3c51b36d04da19b92f9e815be12753125bd8bc247ba0470a982e6979e71c/types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3", size = 17522, upload-time = "2025-09-15T03:01:00.728Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338, upload-time = "2025-09-15T03:00:59.218Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
+]
+
+[[package]]
+name = "typing-inspection"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
+]
+
+[[package]]
+name = "typing-validation"
+version = "1.2.12"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ba/c0/374639373a99b62f51c3204521235906dca1ed1886e73f65d6664465b187/typing_validation-1.2.12.tar.gz", hash = "sha256:7ea9463a18bd04922e799cac1954f687e68e9564773f81db491536852ffe1d54", size = 774523, upload-time = "2025-03-18T14:54:49.4Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/59/7b/29a088c5be56f40e0b1e611c460681f411ce79f0083d2cd3b233a35b7c4d/typing_validation-1.2.12-py3-none-any.whl", hash = "sha256:d68e22a41bf2b98ae91e5d6407db56e9ef83e9e5600164a7aff64aaa082fc232", size = 20657, upload-time = "2025-03-18T14:54:47.529Z" },
+]
+
+[[package]]
+name = "uc-micro-py"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/78/67/9a363818028526e2d4579334460df777115bdec1bb77c08f9db88f6389f2/uc_micro_py-2.0.0.tar.gz", hash = "sha256:c53691e495c8db60e16ffc4861a35469b0ba0821fe409a8a7a0a71864d33a811", size = 6611, upload-time = "2026-03-01T06:31:27.526Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/61/73/d21edf5b204d1467e06500080a50f79d49ef2b997c79123a536d4a17d97c/uc_micro_py-2.0.0-py3-none-any.whl", hash = "sha256:3603a3859af53e5a39bc7677713c78ea6589ff188d70f4fee165db88e22b242c", size = 6383, upload-time = "2026-03-01T06:31:26.257Z" },
+]
+
+[[package]]
+name = "unify"
+version = "0.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "untokenize" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e9/92/f7ab4a788a3efbf83cddeb0f78595fcddd690ef0f55371a525d0f7c237ad/unify-0.5.tar.gz", hash = "sha256:8ddce812b2457212b7598fe574c9e6eb3ad69710f445391338270c7f8a71723c", size = 4363, upload-time = "2019-08-07T13:46:09.142Z" }
+
+[[package]]
+name = "untokenize"
+version = "0.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz", hash = "sha256:3865dbbbb8efb4bb5eaa72f1be7f3e0be00ea8b7f125c69cbd1f5fda926f37a2", size = 3099, upload-time = "2014-02-08T16:30:40.631Z" }
+
+[[package]]
+name = "urllib3"
+version = "2.6.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
+]
+
+[[package]]
+name = "virtualenv"
+version = "21.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "distlib" },
+ { name = "filelock" },
+ { name = "platformdirs" },
+ { name = "python-discovery" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2f/c9/18d4b36606d6091844daa3bd93cf7dc78e6f5da21d9f21d06c221104b684/virtualenv-21.1.0.tar.gz", hash = "sha256:1990a0188c8f16b6b9cf65c9183049007375b26aad415514d377ccacf1e4fb44", size = 5840471, upload-time = "2026-02-27T08:49:29.702Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/55/896b06bf93a49bec0f4ae2a6f1ed12bd05c8860744ac3a70eda041064e4d/virtualenv-21.1.0-py3-none-any.whl", hash = "sha256:164f5e14c5587d170cf98e60378eb91ea35bf037be313811905d3a24ea33cc07", size = 5825072, upload-time = "2026-02-27T08:49:27.516Z" },
+]
+
+[[package]]
+name = "wcwidth"
+version = "0.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", size = 159684, upload-time = "2026-02-06T19:19:40.919Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" },
+]
+
+[[package]]
+name = "wheel"
+version = "0.46.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "packaging" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/89/24/a2eb353a6edac9a0303977c4cb048134959dd2a51b48a269dfc9dde00c8a/wheel-0.46.3.tar.gz", hash = "sha256:e3e79874b07d776c40bd6033f8ddf76a7dad46a7b8aa1b2787a83083519a1803", size = 60605, upload-time = "2026-01-22T12:39:49.136Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/87/22/b76d483683216dde3d67cba61fb2444be8d5be289bf628c13fc0fd90e5f9/wheel-0.46.3-py3-none-any.whl", hash = "sha256:4b399d56c9d9338230118d705d9737a2a468ccca63d5e813e2a4fc7815d8bc4d", size = 30557, upload-time = "2026-01-22T12:39:48.099Z" },
+]
+
+[[package]]
+name = "yapf"
+version = "0.43.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "platformdirs" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/23/97/b6f296d1e9cc1ec25c7604178b48532fa5901f721bcf1b8d8148b13e5588/yapf-0.43.0.tar.gz", hash = "sha256:00d3aa24bfedff9420b2e0d5d9f5ab6d9d4268e72afbf59bb3fa542781d5218e", size = 254907, upload-time = "2024-11-14T00:11:41.584Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/37/81/6acd6601f61e31cfb8729d3da6d5df966f80f374b78eff83760714487338/yapf-0.43.0-py3-none-any.whl", hash = "sha256:224faffbc39c428cb095818cf6ef5511fdab6f7430a10783fdfb292ccf2852ca", size = 256158, upload-time = "2024-11-14T00:11:39.37Z" },
+]
+
+[[package]]
+name = "zipp"
+version = "3.23.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" },
+]