aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yml21
-rw-r--r--.github/workflows/rust.yml24
-rw-r--r--AGENTS.md0
-rw-r--r--CHANGELOG.md49
-rw-r--r--Cargo.lock1937
-rw-r--r--Cargo.toml10
-rw-r--r--Dockerfile4
-rw-r--r--README.md1
-rw-r--r--crates/atuin-client/Cargo.toml2
-rw-r--r--crates/atuin-client/config.toml49
-rw-r--r--crates/atuin-client/src/import/replxx.rs19
-rw-r--r--crates/atuin-client/src/import/zsh.rs4
-rw-r--r--crates/atuin-client/src/secrets.rs2
-rw-r--r--crates/atuin-client/src/settings.rs252
-rw-r--r--crates/atuin-common/src/api.rs1
-rw-r--r--crates/atuin-daemon/Cargo.toml6
-rw-r--r--crates/atuin-dotfiles/Cargo.toml4
-rw-r--r--crates/atuin-history/Cargo.toml2
-rw-r--r--crates/atuin-kv/Cargo.toml4
-rw-r--r--crates/atuin-scripts/Cargo.toml4
-rw-r--r--crates/atuin-server-database/Cargo.toml2
-rw-r--r--crates/atuin-server-database/src/lib.rs22
-rw-r--r--crates/atuin-server-postgres/Cargo.toml6
-rw-r--r--crates/atuin-server-postgres/src/lib.rs98
-rw-r--r--crates/atuin-server-sqlite/Cargo.toml6
-rw-r--r--crates/atuin-server-sqlite/src/lib.rs11
-rw-r--r--crates/atuin-server/Cargo.toml10
-rw-r--r--crates/atuin-server/server.toml11
-rw-r--r--crates/atuin-server/src/handlers/history.rs8
-rw-r--r--crates/atuin-server/src/handlers/mod.rs5
-rw-r--r--crates/atuin-server/src/handlers/user.rs4
-rw-r--r--crates/atuin-server/src/handlers/v0/record.rs6
-rw-r--r--crates/atuin-server/src/handlers/v0/store.rs4
-rw-r--r--crates/atuin-server/src/lib.rs61
-rw-r--r--crates/atuin-server/src/metrics.rs4
-rw-r--r--crates/atuin-server/src/router.rs23
-rw-r--r--crates/atuin-server/src/settings.rs18
-rw-r--r--crates/atuin/Cargo.toml22
-rw-r--r--crates/atuin/src/command/client.rs2
-rw-r--r--crates/atuin/src/command/client/account/verify.rs2
-rw-r--r--crates/atuin/src/command/client/history.rs11
-rw-r--r--crates/atuin/src/command/client/scripts.rs2
-rw-r--r--crates/atuin/src/command/client/search.rs2
-rw-r--r--crates/atuin/src/command/client/search/engines/skim.rs2
-rw-r--r--crates/atuin/src/command/client/search/history_list.rs175
-rw-r--r--crates/atuin/src/command/client/search/inspector.rs4
-rw-r--r--crates/atuin/src/command/client/search/interactive.rs594
-rw-r--r--crates/atuin/src/command/client/wrapped.rs54
-rw-r--r--crates/atuin/src/main.rs9
-rw-r--r--crates/atuin/src/shell/atuin.bash66
-rw-r--r--crates/atuin/src/shell/atuin.ps171
-rw-r--r--crates/atuin/tests/common/mod.rs7
-rw-r--r--dist-workspace.toml6
-rw-r--r--docs-i18n/.gitignore (renamed from docs/.gitignore)0
-rw-r--r--docs-i18n/ru/config_ru.md (renamed from docs/ru/config_ru.md)0
-rw-r--r--docs-i18n/ru/import_ru.md (renamed from docs/ru/import_ru.md)0
-rw-r--r--docs-i18n/ru/key-binding_ru.md (renamed from docs/ru/key-binding_ru.md)0
-rw-r--r--docs-i18n/ru/list_ru.md (renamed from docs/ru/list_ru.md)0
-rw-r--r--docs-i18n/ru/search_ru.md (renamed from docs/ru/search_ru.md)0
-rw-r--r--docs-i18n/ru/server_ru.md (renamed from docs/ru/server_ru.md)0
-rw-r--r--docs-i18n/ru/shell-completions_ru.md (renamed from docs/ru/shell-completions_ru.md)0
-rw-r--r--docs-i18n/ru/stats_ru.md (renamed from docs/ru/stats_ru.md)0
-rw-r--r--docs-i18n/ru/sync_ru.md (renamed from docs/ru/sync_ru.md)0
-rw-r--r--docs-i18n/zh-CN/README.md (renamed from docs/zh-CN/README.md)0
-rw-r--r--docs-i18n/zh-CN/config.md (renamed from docs/zh-CN/config.md)0
-rw-r--r--docs-i18n/zh-CN/docker.md (renamed from docs/zh-CN/docker.md)0
-rw-r--r--docs-i18n/zh-CN/import.md (renamed from docs/zh-CN/import.md)0
-rw-r--r--docs-i18n/zh-CN/k8s.md (renamed from docs/zh-CN/k8s.md)0
-rw-r--r--docs-i18n/zh-CN/key-binding.md (renamed from docs/zh-CN/key-binding.md)0
-rw-r--r--docs-i18n/zh-CN/list.md (renamed from docs/zh-CN/list.md)0
-rw-r--r--docs-i18n/zh-CN/search.md (renamed from docs/zh-CN/search.md)0
-rw-r--r--docs-i18n/zh-CN/server.md (renamed from docs/zh-CN/server.md)0
-rw-r--r--docs-i18n/zh-CN/shell-completions.md (renamed from docs/zh-CN/shell-completions.md)0
-rw-r--r--docs-i18n/zh-CN/stats.md (renamed from docs/zh-CN/stats.md)0
-rw-r--r--docs-i18n/zh-CN/sync.md (renamed from docs/zh-CN/sync.md)0
-rw-r--r--docs/docs/configuration/config.md820
-rw-r--r--docs/docs/configuration/key-binding.md271
-rw-r--r--docs/docs/faq.md58
-rw-r--r--docs/docs/guide/basic-usage.md63
-rw-r--r--docs/docs/guide/dotfiles.md141
-rw-r--r--docs/docs/guide/getting-started.md54
-rw-r--r--docs/docs/guide/import.md18
-rw-r--r--docs/docs/guide/installation.md276
-rw-r--r--docs/docs/guide/sync.md78
-rw-r--r--docs/docs/guide/theming.md138
-rw-r--r--docs/docs/index.md48
-rw-r--r--docs/docs/integrations.md33
-rw-r--r--docs/docs/known-issues.md4
-rw-r--r--docs/docs/reference/daemon.md29
-rw-r--r--docs/docs/reference/doctor.md38
-rw-r--r--docs/docs/reference/gen-completions.md20
-rw-r--r--docs/docs/reference/import.md109
-rw-r--r--docs/docs/reference/info.md22
-rw-r--r--docs/docs/reference/list.md31
-rw-r--r--docs/docs/reference/prune.md15
-rw-r--r--docs/docs/reference/search.md65
-rw-r--r--docs/docs/reference/stats.md50
-rw-r--r--docs/docs/reference/sync.md77
-rw-r--r--docs/docs/self-hosting/docker.md130
-rw-r--r--docs/docs/self-hosting/kubernetes.md290
-rw-r--r--docs/docs/self-hosting/server-setup.md61
-rw-r--r--docs/docs/self-hosting/systemd.md65
-rw-r--r--docs/docs/self-hosting/usage.md14
-rw-r--r--docs/docs/sync-v2.md27
-rw-r--r--docs/docs/uninstall.md20
-rw-r--r--docs/mkdocs.yml92
-rw-r--r--docs/pyproject.toml15
-rw-r--r--docs/uv.lock750
-rw-r--r--flake.nix4
-rwxr-xr-xinstall.sh8
-rw-r--r--rust-toolchain.toml2
111 files changed, 6219 insertions, 1440 deletions
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ca92fbd3..6ea71524 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,6 +1,6 @@
-# This file was autogenerated by dist: https://github.com/astral-sh/cargo-dist
+# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist
#
-# Copyright 2025 Astral Software Inc.
+# Copyright 2022-2024, axodotdev
# SPDX-License-Identifier: MIT or Apache-2.0
#
# CI that:
@@ -15,9 +15,7 @@
name: Release
permissions:
- "attestations": "write"
"contents": "write"
- "id-token": "write"
# This task will run whenever you push a git tag that looks like a version
# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc.
@@ -60,12 +58,13 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
+ persist-credentials: false
submodules: recursive
- name: Install dist
# we specify bash to get pipefail; it guards against the `curl` command
# failing. otherwise `sh` won't catch that `curl` returned non-0
shell: bash
- run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/cargo-dist/releases/download/v0.28.3/cargo-dist-installer.sh | sh"
+ run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.30.3/cargo-dist-installer.sh | sh"
- name: Cache dist
uses: actions/upload-artifact@v4
with:
@@ -113,12 +112,17 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
+ permissions:
+ "attestations": "write"
+ "contents": "read"
+ "id-token": "write"
steps:
- name: enable windows longpaths
run: |
git config --global core.longpaths true
- uses: actions/checkout@v4
with:
+ persist-credentials: false
submodules: recursive
- name: Install Rust non-interactively if not already installed
if: ${{ matrix.container }}
@@ -181,6 +185,7 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
+ persist-credentials: false
submodules: recursive
- name: Install cached dist
uses: actions/download-artifact@v4
@@ -220,8 +225,8 @@ jobs:
- plan
- build-local-artifacts
- build-global-artifacts
- # Only run if we're "publishing", and only if local and global didn't fail (skipped is fine)
- if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
+ # Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine)
+ if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: "ubuntu-22.04"
@@ -230,6 +235,7 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
+ persist-credentials: false
submodules: recursive
- name: Install cached dist
uses: actions/download-artifact@v4
@@ -294,4 +300,5 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
+ persist-credentials: false
submodules: recursive
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index b65f9a81..4b8b2fa7 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -17,7 +17,7 @@ jobs:
build:
strategy:
matrix:
- os: [ubuntu-latest, macos-14]
+ os: [ubuntu-latest, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
steps:
@@ -26,7 +26,7 @@ jobs:
- name: Install rust
uses: dtolnay/rust-toolchain@master
with:
- toolchain: 1.90
+ toolchain: 1.91
- uses: actions/cache@v4
with:
@@ -88,7 +88,7 @@ jobs:
unit-test:
strategy:
matrix:
- os: [ubuntu-latest, macos-14]
+ os: [ubuntu-latest, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
steps:
@@ -97,7 +97,7 @@ jobs:
- name: Install rust
uses: dtolnay/rust-toolchain@master
with:
- toolchain: 1.90
+ toolchain: 1.91
- uses: taiki-e/install-action@v2
name: Install nextest
@@ -110,7 +110,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
target
- key: ${ runner.os }-cargo-debug-${{ hashFiles('**/Cargo.lock') }}
+ key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }}
- name: Run cargo test
run: cargo nextest run --lib --bins
@@ -118,7 +118,7 @@ jobs:
check:
strategy:
matrix:
- os: [ubuntu-latest, macos-14]
+ os: [ubuntu-latest, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
steps:
@@ -127,7 +127,7 @@ jobs:
- name: Install rust
uses: dtolnay/rust-toolchain@master
with:
- toolchain: 1.90
+ toolchain: 1.91
- uses: actions/cache@v4
with:
@@ -135,7 +135,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
target
- key: ${ runner.os }-cargo-debug-${{ hashFiles('**/Cargo.lock') }}
+ key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }}
- name: Run cargo check (all features)
run: cargo check --all-features --workspace
@@ -171,7 +171,7 @@ jobs:
- name: Install rust
uses: dtolnay/rust-toolchain@master
with:
- toolchain: 1.90
+ toolchain: 1.91
- uses: taiki-e/install-action@v2
name: Install nextest
@@ -184,7 +184,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
target
- key: ${ runner.os }-cargo-debug-${{ hashFiles('**/Cargo.lock') }}
+ key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }}
- name: Run cargo test
run: cargo nextest run --test '*'
@@ -200,7 +200,7 @@ jobs:
- name: Install latest rust
uses: dtolnay/rust-toolchain@master
with:
- toolchain: 1.90
+ toolchain: 1.91
components: clippy
- uses: actions/cache@v4
@@ -223,7 +223,7 @@ jobs:
- name: Install latest rust
uses: dtolnay/rust-toolchain@master
with:
- toolchain: 1.90
+ toolchain: 1.91
components: rustfmt
- name: Format
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/AGENTS.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5d88fde5..1945710f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,55 @@
All notable changes to this project will be documented in this file.
+## [18.11.0] - 2026-01-12
+
+### Bug Fixes
+
+- *(bash)* Fix issues with intermediate key sequences in the vi editing mode ([#2977](https://github.com/atuinsh/atuin/issues/2977))
+- *(bash)* Work around a keybinding bug of Bash 5.1 ([#2975](https://github.com/atuinsh/atuin/issues/2975))
+- *(bash/blesh)* Suppress error message for auto-complete source ([#2976](https://github.com/atuinsh/atuin/issues/2976))
+- *(powershell)* Run `atuin history end` in the background ([#3034](https://github.com/atuinsh/atuin/issues/3034))
+- *(powershell)* Add error safety and cleanup ([#3040](https://github.com/atuinsh/atuin/issues/3040))
+- Highlight the correct place when multibyte characters are involved ([#2965](https://github.com/atuinsh/atuin/issues/2965))
+- Prevent interactive search crash when update check fails ([#3016](https://github.com/atuinsh/atuin/issues/3016))
+- Move thorough search through search.filters w/ workspaces ([#2703](https://github.com/atuinsh/atuin/issues/2703))
+
+
+### Documentation
+
+- Migrate docs from separate repo to `docs` subfolder ([#3018](https://github.com/atuinsh/atuin/issues/3018))
+
+
+### Features
+
+- Support additional history filenames in replxx importer ([#3005](https://github.com/atuinsh/atuin/issues/3005))
+- Add colors to --help/-h ([#3000](https://github.com/atuinsh/atuin/issues/3000))
+- Add support for read replicas to postgres ([#3029](https://github.com/atuinsh/atuin/issues/3029))
+- Allow disabling sync v1 ([#3030](https://github.com/atuinsh/atuin/issues/3030))
+- Consider atuin dotfile aliases when calculating atuin wrapped ([#3048](https://github.com/atuinsh/atuin/issues/3048))
+- Add session and uuid column support to history list ([#3049](https://github.com/atuinsh/atuin/issues/3049))
+
+
+### Miscellaneous Tasks
+
+- *(nix)* Prevent deprecation warning on evaluation ([#3006](https://github.com/atuinsh/atuin/issues/3006))
+- Update changelog
+- Adjust update wording ([#2974](https://github.com/atuinsh/atuin/issues/2974))
+- Add Windows builds, second try ([#2966](https://github.com/atuinsh/atuin/issues/2966))
+- Update to rust 1.91 ([#2981](https://github.com/atuinsh/atuin/issues/2981))
+- Add Atuin Desktop information to install script
+- Remove trailing whitespace ([#2985](https://github.com/atuinsh/atuin/issues/2985))
+- Fix typo ([#2994](https://github.com/atuinsh/atuin/issues/2994))
+- Clarify docstring of the enter_accept config key ([#3003](https://github.com/atuinsh/atuin/issues/3003))
+- Fix github action syntax for variables ([#2998](https://github.com/atuinsh/atuin/issues/2998))
+- Add AGENTS.md
+
+
+### Build
+
+- *(nix)* Update rust toolchain hash ([#2990](https://github.com/atuinsh/atuin/issues/2990))
+
+
## [18.10.0] - 2025-10-21
### Bug Fixes
diff --git a/Cargo.lock b/Cargo.lock
index 8e9108ec..578e4412 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,15 +3,6 @@
version = 4
[[package]]
-name = "addr2line"
-version = "0.24.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
-dependencies = [
- "gimli",
-]
-
-[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -41,9 +32,9 @@ dependencies = [
[[package]]
name = "aho-corasick"
-version = "1.1.3"
+version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
@@ -65,9 +56,9 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.6.20"
+version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -80,9 +71,9 @@ dependencies = [
[[package]]
name = "anstyle"
-version = "1.0.11"
+version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
@@ -95,22 +86,22 @@ dependencies = [
[[package]]
name = "anstyle-query"
-version = "1.1.4"
+version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
name = "anstyle-wincon"
-version = "3.0.10"
+version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -150,12 +141,6 @@ dependencies = [
]
[[package]]
-name = "arc-swap"
-version = "1.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
-
-[[package]]
name = "argon2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -217,7 +202,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "atuin"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"arboard",
"async-trait",
@@ -269,11 +254,11 @@ dependencies = [
[[package]]
name = "atuin-client"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"async-trait",
"atuin-common",
- "base64 0.22.1",
+ "base64",
"clap",
"config",
"crossterm",
@@ -296,7 +281,7 @@ dependencies = [
"pretty_assertions",
"rand 0.8.5",
"regex",
- "reqwest 0.11.27",
+ "reqwest 0.13.1",
"rmp",
"rusty_paserk",
"rusty_paseto",
@@ -324,12 +309,12 @@ dependencies = [
[[package]]
name = "atuin-common"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
- "base64 0.22.1",
+ "base64",
"directories",
"eyre",
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
"lazy_static",
"pretty_assertions",
"semver",
@@ -344,7 +329,7 @@ dependencies = [
[[package]]
name = "atuin-daemon"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"atuin-client",
"atuin-dotfiles",
@@ -363,7 +348,7 @@ dependencies = [
"tonic",
"tonic-build",
"tonic-types",
- "tower 0.5.2",
+ "tower 0.5.3",
"tracing",
"tracing-subscriber",
"uuid",
@@ -371,7 +356,7 @@ dependencies = [
[[package]]
name = "atuin-dotfiles"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"atuin-client",
"atuin-common",
@@ -385,7 +370,7 @@ dependencies = [
[[package]]
name = "atuin-history"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"atuin-client",
"crossterm",
@@ -398,7 +383,7 @@ dependencies = [
[[package]]
name = "atuin-kv"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"atuin-client",
"atuin-common",
@@ -414,7 +399,7 @@ dependencies = [
[[package]]
name = "atuin-scripts"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"atuin-client",
"atuin-common",
@@ -436,14 +421,13 @@ dependencies = [
[[package]]
name = "atuin-server"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"argon2",
"async-trait",
"atuin-common",
"atuin-server-database",
"axum",
- "axum-server",
"config",
"eyre",
"fs-err",
@@ -451,21 +435,20 @@ dependencies = [
"metrics-exporter-prometheus",
"postmark",
"rand 0.8.5",
- "reqwest 0.11.27",
- "rustls 0.23.32",
+ "reqwest 0.13.1",
"semver",
"serde",
"serde_json",
"time",
"tokio",
- "tower 0.5.2",
+ "tower 0.5.3",
"tower-http",
"tracing",
]
[[package]]
name = "atuin-server-database"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"async-trait",
"atuin-common",
@@ -478,7 +461,7 @@ dependencies = [
[[package]]
name = "atuin-server-postgres"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"async-trait",
"atuin-common",
@@ -496,7 +479,7 @@ dependencies = [
[[package]]
name = "atuin-server-sqlite"
-version = "18.10.0"
+version = "18.11.0"
dependencies = [
"async-trait",
"atuin-common",
@@ -518,6 +501,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
+name = "aws-lc-rs"
+version = "1.15.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e84ce723ab67259cfeb9877c6a639ee9eb7a27b28123abd71db7f0d5d0cc9d86"
+dependencies = [
+ "aws-lc-sys",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-lc-sys"
+version = "0.36.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a442ece363113bd4bd4c8b18977a7798dd4d3c3383f34fb61936960e8f4ad8"
+dependencies = [
+ "cc",
+ "cmake",
+ "dunce",
+ "fs_extra",
+]
+
+[[package]]
name = "axum"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -527,10 +532,10 @@ dependencies = [
"axum-core",
"bytes",
"futures-util",
- "http 1.3.1",
- "http-body 1.0.1",
+ "http",
+ "http-body",
"http-body-util",
- "hyper 1.7.0",
+ "hyper",
"hyper-util",
"itoa",
"matchit",
@@ -543,9 +548,9 @@ dependencies = [
"serde_json",
"serde_path_to_error",
"serde_urlencoded",
- "sync_wrapper 1.0.2",
+ "sync_wrapper",
"tokio",
- "tower 0.5.2",
+ "tower 0.5.3",
"tower-layer",
"tower-service",
"tracing",
@@ -560,62 +565,19 @@ dependencies = [
"async-trait",
"bytes",
"futures-util",
- "http 1.3.1",
- "http-body 1.0.1",
+ "http",
+ "http-body",
"http-body-util",
"mime",
"pin-project-lite",
"rustversion",
- "sync_wrapper 1.0.2",
+ "sync_wrapper",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
-name = "axum-server"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "495c05f60d6df0093e8fb6e74aa5846a0ad06abaf96d76166283720bf740f8ab"
-dependencies = [
- "arc-swap",
- "bytes",
- "fs-err",
- "http 1.3.1",
- "http-body 1.0.1",
- "hyper 1.7.0",
- "hyper-util",
- "pin-project-lite",
- "rustls 0.23.32",
- "rustls-pemfile 2.2.0",
- "rustls-pki-types",
- "tokio",
- "tokio-rustls 0.26.3",
- "tower-service",
-]
-
-[[package]]
-name = "backtrace"
-version = "0.3.75"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
-dependencies = [
- "addr2line",
- "cfg-if",
- "libc",
- "miniz_oxide",
- "object",
- "rustc-demangle",
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "base64"
-version = "0.21.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
-
-[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -623,9 +585,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
-version = "1.8.0"
+version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
+checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]]
name = "beef"
@@ -635,17 +597,11 @@ checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
[[package]]
name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "bitflags"
-version = "2.9.4"
+version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
+checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
dependencies = [
- "serde",
+ "serde_core",
]
[[package]]
@@ -668,9 +624,9 @@ dependencies = [
[[package]]
name = "bumpalo"
-version = "3.19.0"
+version = "3.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
[[package]]
name = "by_address"
@@ -680,9 +636,9 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
[[package]]
name = "bytemuck"
-version = "1.23.2"
+version = "1.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677"
+checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
[[package]]
name = "byteorder"
@@ -698,9 +654,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "bytes"
-version = "1.10.1"
+version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
[[package]]
name = "cassowary"
@@ -719,19 +675,27 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.38"
+version = "1.2.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9"
+checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932"
dependencies = [
"find-msvc-tools",
+ "jobserver",
+ "libc",
"shlex",
]
[[package]]
+name = "cesu8"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
+
+[[package]]
name = "cfg-if"
-version = "1.0.3"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cfg_aliases"
@@ -752,14 +716,14 @@ dependencies = [
[[package]]
name = "chrono"
-version = "0.4.42"
+version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
+checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
dependencies = [
"iana-time-zone",
"num-traits",
"serde",
- "windows-link 0.2.0",
+ "windows-link",
]
[[package]]
@@ -775,9 +739,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.48"
+version = "4.5.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae"
+checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
dependencies = [
"clap_builder",
"clap_derive",
@@ -785,9 +749,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.48"
+version = "4.5.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9"
+checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
dependencies = [
"anstream",
"anstyle",
@@ -798,18 +762,18 @@ dependencies = [
[[package]]
name = "clap_complete"
-version = "4.5.58"
+version = "4.5.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75bf0b32ad2e152de789bb635ea4d3078f6b838ad7974143e99b99f45a04af4a"
+checksum = "430b4dc2b5e3861848de79627b2bedc9f3342c7da5173a14eaa5d0f8dc18ae5d"
dependencies = [
"clap",
]
[[package]]
name = "clap_complete_nushell"
-version = "4.5.8"
+version = "4.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a0c951694691e65bf9d421d597d68416c22de9632e884c28412cb8cd8b73dce"
+checksum = "685bc86fd34b7467e0532a4f8435ab107960d69a243785ef0275e571b35b641a"
dependencies = [
"clap",
"clap_complete",
@@ -817,9 +781,9 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.5.47"
+version = "4.5.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
+checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
dependencies = [
"heck",
"proc-macro2",
@@ -829,9 +793,9 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.7.5"
+version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
+checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
[[package]]
name = "clipboard-win"
@@ -843,6 +807,15 @@ dependencies = [
]
[[package]]
+name = "cmake"
+version = "0.1.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
+dependencies = [
+ "cc",
+]
+
+[[package]]
name = "colorchoice"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -859,6 +832,16 @@ dependencies = [
]
[[package]]
+name = "combine"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
name = "compact_str"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -889,9 +872,9 @@ checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af"
[[package]]
name = "config"
-version = "0.15.16"
+version = "0.15.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cef036f0ecf99baef11555578630e2cca559909b4c50822dbba828c252d21c49"
+checksum = "b30fa8254caad766fc03cb0ccae691e14bf3bd72bfff27f72802ce729551b3d6"
dependencies = [
"pathdiff",
"serde_core",
@@ -901,15 +884,15 @@ dependencies = [
[[package]]
name = "console"
-version = "0.16.1"
+version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4"
+checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4"
dependencies = [
"encode_unicode",
"libc",
"once_cell",
"unicode-width 0.2.0",
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -920,9 +903,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "core-foundation"
-version = "0.9.4"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
dependencies = [
"core-foundation-sys",
"libc",
@@ -945,9 +928,9 @@ dependencies = [
[[package]]
name = "crc"
-version = "3.3.0"
+version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675"
+checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
dependencies = [
"crc-catalog",
]
@@ -1007,7 +990,7 @@ version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"crossterm_winapi",
"filedescriptor",
"mio",
@@ -1036,9 +1019,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]]
name = "crypto-common"
-version = "0.1.6"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"rand_core 0.6.4",
@@ -1089,29 +1072,29 @@ dependencies = [
[[package]]
name = "darling"
-version = "0.20.11"
+version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
+checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
dependencies = [
- "darling_core 0.20.11",
- "darling_macro 0.20.11",
+ "darling_core 0.21.3",
+ "darling_macro 0.21.3",
]
[[package]]
name = "darling"
-version = "0.21.3"
+version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
+checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
dependencies = [
- "darling_core 0.21.3",
- "darling_macro 0.21.3",
+ "darling_core 0.23.0",
+ "darling_macro 0.23.0",
]
[[package]]
name = "darling_core"
-version = "0.20.11"
+version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
+checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
dependencies = [
"fnv",
"ident_case",
@@ -1123,11 +1106,10 @@ dependencies = [
[[package]]
name = "darling_core"
-version = "0.21.3"
+version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
+checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
dependencies = [
- "fnv",
"ident_case",
"proc-macro2",
"quote",
@@ -1137,22 +1119,22 @@ dependencies = [
[[package]]
name = "darling_macro"
-version = "0.20.11"
+version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
+checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
dependencies = [
- "darling_core 0.20.11",
+ "darling_core 0.21.3",
"quote",
"syn",
]
[[package]]
name = "darling_macro"
-version = "0.21.3"
+version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
+checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
dependencies = [
- "darling_core 0.21.3",
+ "darling_core 0.23.0",
"quote",
"syn",
]
@@ -1183,12 +1165,12 @@ dependencies = [
[[package]]
name = "deranged"
-version = "0.5.3"
+version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc"
+checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
dependencies = [
"powerfmt",
- "serde",
+ "serde_core",
]
[[package]]
@@ -1211,11 +1193,11 @@ dependencies = [
[[package]]
name = "directories"
-version = "5.0.1"
+version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
+checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
dependencies = [
- "dirs-sys 0.4.1",
+ "dirs-sys",
]
[[package]]
@@ -1224,19 +1206,7 @@ version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
dependencies = [
- "dirs-sys 0.5.0",
-]
-
-[[package]]
-name = "dirs-sys"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
-dependencies = [
- "libc",
- "option-ext",
- "redox_users 0.4.6",
- "windows-sys 0.48.0",
+ "dirs-sys",
]
[[package]]
@@ -1247,8 +1217,8 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
dependencies = [
"libc",
"option-ext",
- "redox_users 0.5.2",
- "windows-sys 0.61.0",
+ "redox_users",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -1257,7 +1227,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"objc2",
]
@@ -1310,6 +1280,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
+[[package]]
name = "dyn-clone"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1355,15 +1331,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
-name = "encoding_rs"
-version = "0.8.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1376,7 +1343,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -1477,15 +1444,9 @@ dependencies = [
[[package]]
name = "find-msvc-tools"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959"
-
-[[package]]
-name = "fixedbitset"
-version = "0.4.2"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
+checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
[[package]]
name = "fixedbitset"
@@ -1495,9 +1456,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "flate2"
-version = "1.1.2"
+version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
+checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -1527,6 +1488,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
+name = "foldhash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
+
+[[package]]
name = "form_urlencoded"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1537,15 +1504,20 @@ dependencies = [
[[package]]
name = "fs-err"
-version = "3.1.2"
+version = "3.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44f150ffc8782f35521cec2b23727707cb4045706ba3c854e86bef66b3a8cdbd"
+checksum = "baf68cef89750956493a66a10f512b9e58d9db21f2a573c079c0bdf1207a54a7"
dependencies = [
"autocfg",
- "tokio",
]
[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
+[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1668,79 +1640,54 @@ dependencies = [
[[package]]
name = "gethostname"
-version = "1.0.2"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55"
+checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
dependencies = [
- "rustix 1.1.2",
- "windows-targets 0.52.6",
+ "rustix 1.1.3",
+ "windows-link",
]
[[package]]
name = "getrandom"
-version = "0.2.16"
+version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"js-sys",
"libc",
- "wasi 0.11.1+wasi-snapshot-preview1",
+ "wasi",
"wasm-bindgen",
]
[[package]]
name = "getrandom"
-version = "0.3.3"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"r-efi",
- "wasi 0.14.7+wasi-0.2.4",
+ "wasip2",
"wasm-bindgen",
]
[[package]]
-name = "gimli"
-version = "0.31.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
-
-[[package]]
-name = "h2"
-version = "0.3.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d"
-dependencies = [
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "futures-util",
- "http 0.2.12",
- "indexmap 2.11.4",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
name = "h2"
-version = "0.4.12"
+version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
+checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
dependencies = [
"atomic-waker",
"bytes",
"fnv",
"futures-core",
"futures-sink",
- "http 1.3.1",
- "indexmap 2.11.4",
+ "http",
+ "indexmap 2.13.0",
"slab",
"tokio",
"tokio-util",
@@ -1749,12 +1696,13 @@ dependencies = [
[[package]]
name = "half"
-version = "2.6.0"
+version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
dependencies = [
"cfg-if",
"crunchy",
+ "zerocopy",
]
[[package]]
@@ -1765,15 +1713,6 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038"
-dependencies = [
- "ahash",
-]
-
-[[package]]
-name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
@@ -1786,14 +1725,17 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"allocator-api2",
"equivalent",
- "foldhash",
+ "foldhash 0.1.5",
]
[[package]]
name = "hashbrown"
-version = "0.16.0"
+version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+dependencies = [
+ "foldhash 0.2.0",
+]
[[package]]
name = "hashlink"
@@ -1811,12 +1753,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
-name = "hermit-abi"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
-
-[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1842,54 +1778,31 @@ dependencies = [
[[package]]
name = "home"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "http"
-version = "0.2.12"
+version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
+checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
dependencies = [
- "bytes",
- "fnv",
- "itoa",
+ "windows-sys 0.61.2",
]
[[package]]
name = "http"
-version = "1.3.1"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
+checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
dependencies = [
"bytes",
- "fnv",
"itoa",
]
[[package]]
name = "http-body"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
-dependencies = [
- "bytes",
- "http 0.2.12",
- "pin-project-lite",
-]
-
-[[package]]
-name = "http-body"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
- "http 1.3.1",
+ "http",
]
[[package]]
@@ -1900,8 +1813,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
"futures-core",
- "http 1.3.1",
- "http-body 1.0.1",
+ "http",
+ "http-body",
"pin-project-lite",
]
@@ -1925,41 +1838,17 @@ checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
[[package]]
name = "hyper"
-version = "0.14.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "h2 0.3.27",
- "http 0.2.12",
- "http-body 0.4.6",
- "httparse",
- "httpdate",
- "itoa",
- "pin-project-lite",
- "socket2 0.5.10",
- "tokio",
- "tower-service",
- "tracing",
- "want",
-]
-
-[[package]]
-name = "hyper"
-version = "1.7.0"
+version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
+checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
dependencies = [
"atomic-waker",
"bytes",
"futures-channel",
"futures-core",
- "h2 0.4.12",
- "http 1.3.1",
- "http-body 1.0.1",
+ "h2",
+ "http",
+ "http-body",
"httparse",
"httpdate",
"itoa",
@@ -1972,33 +1861,20 @@ dependencies = [
[[package]]
name = "hyper-rustls"
-version = "0.24.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
-dependencies = [
- "futures-util",
- "http 0.2.12",
- "hyper 0.14.32",
- "rustls 0.21.12",
- "tokio",
- "tokio-rustls 0.24.1",
-]
-
-[[package]]
-name = "hyper-rustls"
version = "0.27.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
dependencies = [
- "http 1.3.1",
- "hyper 1.7.0",
+ "http",
+ "hyper",
"hyper-util",
- "rustls 0.23.32",
+ "rustls",
+ "rustls-native-certs",
"rustls-pki-types",
"tokio",
- "tokio-rustls 0.26.3",
+ "tokio-rustls",
"tower-service",
- "webpki-roots 1.0.2",
+ "webpki-roots 1.0.5",
]
[[package]]
@@ -2007,7 +1883,7 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
dependencies = [
- "hyper 1.7.0",
+ "hyper",
"hyper-util",
"pin-project-lite",
"tokio",
@@ -2016,23 +1892,23 @@ dependencies = [
[[package]]
name = "hyper-util"
-version = "0.1.17"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8"
+checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
dependencies = [
- "base64 0.22.1",
+ "base64",
"bytes",
"futures-channel",
"futures-core",
"futures-util",
- "http 1.3.1",
- "http-body 1.0.1",
- "hyper 1.7.0",
+ "http",
+ "http-body",
+ "hyper",
"ipnet",
"libc",
"percent-encoding",
"pin-project-lite",
- "socket2 0.6.0",
+ "socket2 0.6.1",
"tokio",
"tower-service",
"tracing",
@@ -2050,7 +1926,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.62.0",
+ "windows-core 0.62.2",
]
[[package]]
@@ -2064,9 +1940,9 @@ dependencies = [
[[package]]
name = "icu_collections"
-version = "2.0.0"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
+checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
dependencies = [
"displaydoc",
"potential_utf",
@@ -2077,9 +1953,9 @@ dependencies = [
[[package]]
name = "icu_locale_core"
-version = "2.0.0"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
+checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
dependencies = [
"displaydoc",
"litemap",
@@ -2090,11 +1966,10 @@ dependencies = [
[[package]]
name = "icu_normalizer"
-version = "2.0.0"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
+checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
dependencies = [
- "displaydoc",
"icu_collections",
"icu_normalizer_data",
"icu_properties",
@@ -2105,42 +1980,38 @@ dependencies = [
[[package]]
name = "icu_normalizer_data"
-version = "2.0.0"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
+checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
[[package]]
name = "icu_properties"
-version = "2.0.1"
+version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
+checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
dependencies = [
- "displaydoc",
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
- "potential_utf",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
-version = "2.0.1"
+version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
+checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
[[package]]
name = "icu_provider"
-version = "2.0.0"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
+checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
dependencies = [
"displaydoc",
"icu_locale_core",
- "stable_deref_trait",
- "tinystr",
"writeable",
"yoke",
"zerofrom",
@@ -2177,9 +2048,9 @@ dependencies = [
[[package]]
name = "image"
-version = "0.25.8"
+version = "0.25.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7"
+checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a"
dependencies = [
"bytemuck",
"byteorder-lite",
@@ -2208,21 +2079,21 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.11.4"
+version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
+checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
dependencies = [
"equivalent",
- "hashbrown 0.16.0",
+ "hashbrown 0.16.1",
"serde",
"serde_core",
]
[[package]]
name = "indicatif"
-version = "0.18.0"
+version = "0.18.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70a646d946d06bedbbc4cac4c218acf4bbf2d87757a784857025f4d447e4e1cd"
+checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88"
dependencies = [
"console",
"portable-atomic",
@@ -2233,9 +2104,12 @@ dependencies = [
[[package]]
name = "indoc"
-version = "2.0.6"
+version = "2.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
+checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
+dependencies = [
+ "rustversion",
+]
[[package]]
name = "inout"
@@ -2248,11 +2122,11 @@ dependencies = [
[[package]]
name = "instability"
-version = "0.3.9"
+version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a"
+checksum = "357b7205c6cd18dd2c86ed312d1e70add149aea98e7ef72b9fdf0270e555c11d"
dependencies = [
- "darling 0.20.11",
+ "darling 0.23.0",
"indoc",
"proc-macro2",
"quote",
@@ -2270,17 +2144,6 @@ dependencies = [
]
[[package]]
-name = "io-uring"
-version = "0.7.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b"
-dependencies = [
- "bitflags 2.9.4",
- "cfg-if",
- "libc",
-]
-
-[[package]]
name = "ipnet"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2288,9 +2151,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
[[package]]
name = "iri-string"
-version = "0.7.8"
+version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
+checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
dependencies = [
"memchr",
"serde",
@@ -2298,9 +2161,9 @@ dependencies = [
[[package]]
name = "is_terminal_polyfill"
-version = "1.70.1"
+version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "iso8601"
@@ -2308,7 +2171,7 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1082f0c48f143442a1ac6122f67e360ceee130b967af4d50996e5154a45df46"
dependencies = [
- "nom 8.0.0",
+ "nom",
]
[[package]]
@@ -2331,15 +2194,47 @@ dependencies = [
[[package]]
name = "itoa"
-version = "1.0.15"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
+
+[[package]]
+name = "jni"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
+dependencies = [
+ "cesu8",
+ "cfg-if",
+ "combine",
+ "jni-sys",
+ "log",
+ "thiserror 1.0.69",
+ "walkdir",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
+
+[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom 0.3.4",
+ "libc",
+]
[[package]]
name = "js-sys"
-version = "0.3.80"
+version = "0.3.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e"
+checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -2356,9 +2251,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.176"
+version = "0.2.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174"
+checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
[[package]]
name = "libm"
@@ -2368,13 +2263,13 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libredox"
-version = "0.1.10"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
+checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"libc",
- "redox_syscall",
+ "redox_syscall 0.7.0",
]
[[package]]
@@ -2413,25 +2308,24 @@ dependencies = [
[[package]]
name = "litemap"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
+checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
[[package]]
name = "lock_api"
-version = "0.4.13"
+version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
- "autocfg",
"scopeguard",
]
[[package]]
name = "log"
-version = "0.4.28"
+version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "logos"
@@ -2483,15 +2377,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
[[package]]
-name = "mach2"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
-dependencies = [
- "libc",
-]
-
-[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2518,62 +2403,55 @@ dependencies = [
[[package]]
name = "memchr"
-version = "2.7.5"
+version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "metrics"
-version = "0.21.1"
+version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fde3af1a009ed76a778cb84fdef9e7dbbdf5775ae3e4cc1f434a6a307f6f76c5"
+checksum = "5d5312e9ba3771cfa961b585728215e3d972c950a3eed9252aa093d6301277e8"
dependencies = [
"ahash",
- "metrics-macros",
"portable-atomic",
]
[[package]]
name = "metrics-exporter-prometheus"
-version = "0.12.2"
+version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d4fa7ce7c4862db464a37b0b31d89bca874562f034bd7993895572783d02950"
+checksum = "3589659543c04c7dc5526ec858591015b87cd8746583b51b48ef4353f99dbcda"
dependencies = [
- "base64 0.21.7",
- "hyper 0.14.32",
- "indexmap 1.9.3",
+ "base64",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
+ "indexmap 2.13.0",
"ipnet",
"metrics",
"metrics-util",
"quanta",
- "thiserror 1.0.69",
+ "rustls",
+ "thiserror 2.0.18",
"tokio",
"tracing",
]
[[package]]
-name = "metrics-macros"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38b4faf00617defe497754acde3024865bc143d44a86799b24e191ecff91354f"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "metrics-util"
-version = "0.15.1"
+version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4de2ed6e491ed114b40b732e4d1659a9d53992ebd87490c44a6ffe23739d973e"
+checksum = "cdfb1365fea27e6dd9dc1dbc19f570198bc86914533ad639dae939635f096be4"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
- "hashbrown 0.13.1",
+ "hashbrown 0.16.1",
"metrics",
- "num_cpus",
"quanta",
+ "rand 0.9.2",
+ "rand_xoshiro",
"sketches-ddsketch",
]
@@ -2607,20 +2485,14 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minijinja"
-version = "2.12.0"
+version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9f264d75233323f4b7d2f03aefe8a990690cdebfbfe26ea86bcbaec5e9ac990"
+checksum = "12ea9ac0a51fb5112607099560fdf0f90366ab088a2a9e6e8ae176794e9806aa"
dependencies = [
"serde",
]
[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
-[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2638,21 +2510,21 @@ checksum = "20219d20b3b77f743358539a182e339a6f682e09bb5675f870f320c4a1058c44"
[[package]]
name = "mio"
-version = "1.0.4"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
+checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
dependencies = [
"libc",
"log",
- "wasi 0.11.1+wasi-snapshot-preview1",
- "windows-sys 0.59.0",
+ "wasi",
+ "windows-sys 0.61.2",
]
[[package]]
name = "moxcms"
-version = "0.7.5"
+version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08"
+checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
dependencies = [
"num-traits",
"pxfm",
@@ -2666,16 +2538,6 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
[[package]]
name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
-[[package]]
-name = "nom"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
@@ -2694,29 +2556,28 @@ dependencies = [
[[package]]
name = "ntapi"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
+checksum = "c70f219e21142367c70c0b30c6a9e3a14d55b4d12a204d897fbec83a0363f081"
dependencies = [
"winapi",
]
[[package]]
name = "nu-ansi-term"
-version = "0.50.1"
+version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.61.2",
]
[[package]]
name = "num-bigint-dig"
-version = "0.8.4"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
+checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7"
dependencies = [
- "byteorder",
"lazy_static",
"libm",
"num-integer",
@@ -2764,16 +2625,6 @@ dependencies = [
]
[[package]]
-name = "num_cpus"
-version = "1.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
-dependencies = [
- "hermit-abi",
- "libc",
-]
-
-[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2784,20 +2635,20 @@ dependencies = [
[[package]]
name = "objc2"
-version = "0.6.2"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc"
+checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05"
dependencies = [
"objc2-encode",
]
[[package]]
name = "objc2-app-kit"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc"
+checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"objc2",
"objc2-core-graphics",
"objc2-foundation",
@@ -2805,22 +2656,22 @@ dependencies = [
[[package]]
name = "objc2-core-foundation"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
+checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"dispatch2",
"objc2",
]
[[package]]
name = "objc2-core-graphics"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4"
+checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"dispatch2",
"objc2",
"objc2-core-foundation",
@@ -2835,36 +2686,27 @@ checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
[[package]]
name = "objc2-foundation"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
+checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"objc2",
"objc2-core-foundation",
]
[[package]]
name = "objc2-io-surface"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c"
+checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"objc2",
"objc2-core-foundation",
]
[[package]]
-name = "object"
-version = "0.36.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
-dependencies = [
- "memchr",
-]
-
-[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2872,9 +2714,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "once_cell_polyfill"
-version = "1.70.1"
+version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "opaque-debug"
@@ -2884,9 +2726,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl-probe"
-version = "0.1.6"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
+checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
[[package]]
name = "option-ext"
@@ -2896,12 +2738,12 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "os_pipe"
-version = "1.2.2"
+version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224"
+checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
dependencies = [
"libc",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -2937,9 +2779,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
[[package]]
name = "parking_lot"
-version = "0.12.4"
+version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
@@ -2947,15 +2789,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.11"
+version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall",
+ "redox_syscall 0.5.18",
"smallvec",
- "windows-targets 0.52.6",
+ "windows-link",
]
[[package]]
@@ -3007,22 +2849,23 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "petgraph"
-version = "0.6.5"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
+checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
dependencies = [
- "fixedbitset 0.4.2",
- "indexmap 2.11.4",
+ "fixedbitset",
+ "indexmap 2.13.0",
]
[[package]]
name = "petgraph"
-version = "0.7.1"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
+checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
dependencies = [
- "fixedbitset 0.5.7",
- "indexmap 2.11.4",
+ "fixedbitset",
+ "hashbrown 0.15.5",
+ "indexmap 2.13.0",
]
[[package]]
@@ -3132,7 +2975,7 @@ version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"crc32fast",
"fdeflate",
"flate2",
@@ -3152,9 +2995,9 @@ dependencies = [
[[package]]
name = "portable-atomic"
-version = "1.11.1"
+version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
+checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
[[package]]
name = "postmark"
@@ -3164,11 +3007,11 @@ checksum = "846751b682939565add1f69358a595fa6f3f7d4f1eb15d920b16478e0f981fe2"
dependencies = [
"async-trait",
"bytes",
- "http 1.3.1",
- "reqwest 0.12.23",
+ "http",
+ "reqwest 0.12.28",
"serde",
"serde_json",
- "thiserror 2.0.16",
+ "thiserror 2.0.18",
"time",
"typed-builder 0.21.2",
"url",
@@ -3176,9 +3019,9 @@ dependencies = [
[[package]]
name = "potential_utf"
-version = "0.1.3"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
+checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
dependencies = [
"zerovec",
]
@@ -3220,9 +3063,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.101"
+version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
@@ -3303,7 +3146,7 @@ dependencies = [
"prost-reflect",
"prost-types",
"protox-parse",
- "thiserror 2.0.16",
+ "thiserror 2.0.18",
]
[[package]]
@@ -3315,30 +3158,29 @@ dependencies = [
"logos",
"miette",
"prost-types",
- "thiserror 2.0.16",
+ "thiserror 2.0.18",
]
[[package]]
name = "pxfm"
-version = "0.1.24"
+version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83f9b339b02259ada5c0f4a389b7fb472f933aa17ce176fd2ad98f28bb401fde"
+checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8"
dependencies = [
"num-traits",
]
[[package]]
name = "quanta"
-version = "0.11.1"
+version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab"
+checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7"
dependencies = [
"crossbeam-utils",
"libc",
- "mach2",
"once_cell",
"raw-cpuid",
- "wasi 0.11.1+wasi-snapshot-preview1",
+ "wasi",
"web-sys",
"winapi",
]
@@ -3351,9 +3193,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quick-xml"
-version = "0.37.5"
+version = "0.38.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
+checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
dependencies = [
"memchr",
]
@@ -3370,9 +3212,9 @@ dependencies = [
"quinn-proto",
"quinn-udp",
"rustc-hash 2.1.1",
- "rustls 0.23.32",
- "socket2 0.6.0",
- "thiserror 2.0.16",
+ "rustls",
+ "socket2 0.6.1",
+ "thiserror 2.0.18",
"tokio",
"tracing",
"web-time",
@@ -3384,16 +3226,17 @@ version = "0.11.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
dependencies = [
+ "aws-lc-rs",
"bytes",
- "getrandom 0.3.3",
+ "getrandom 0.3.4",
"lru-slab",
"rand 0.9.2",
"ring",
"rustc-hash 2.1.1",
- "rustls 0.23.32",
+ "rustls",
"rustls-pki-types",
"slab",
- "thiserror 2.0.16",
+ "thiserror 2.0.18",
"tinyvec",
"tracing",
"web-time",
@@ -3408,16 +3251,16 @@ dependencies = [
"cfg_aliases",
"libc",
"once_cell",
- "socket2 0.6.0",
+ "socket2 0.6.1",
"tracing",
"windows-sys 0.60.2",
]
[[package]]
name = "quote"
-version = "1.0.40"
+version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
dependencies = [
"proc-macro2",
]
@@ -3446,7 +3289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha 0.9.0",
- "rand_core 0.9.3",
+ "rand_core 0.9.5",
]
[[package]]
@@ -3466,7 +3309,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
- "rand_core 0.9.3",
+ "rand_core 0.9.5",
]
[[package]]
@@ -3475,16 +3318,25 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
]
[[package]]
name = "rand_core"
-version = "0.9.3"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom 0.3.4",
+]
+
+[[package]]
+name = "rand_xoshiro"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41"
dependencies = [
- "getrandom 0.3.3",
+ "rand_core 0.9.5",
]
[[package]]
@@ -3493,7 +3345,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"cassowary",
"compact_str",
"crossterm",
@@ -3510,11 +3362,11 @@ dependencies = [
[[package]]
name = "raw-cpuid"
-version = "10.7.0"
+version = "11.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
+checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags",
]
[[package]]
@@ -3539,22 +3391,20 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.5.17"
+version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
]
[[package]]
-name = "redox_users"
-version = "0.4.6"
+name = "redox_syscall"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
dependencies = [
- "getrandom 0.2.16",
- "libredox",
- "thiserror 1.0.69",
+ "bitflags",
]
[[package]]
@@ -3563,25 +3413,25 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
"libredox",
- "thiserror 2.0.16",
+ "thiserror 2.0.18",
]
[[package]]
name = "ref-cast"
-version = "1.0.24"
+version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
+checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
-version = "1.0.24"
+version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
+checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
dependencies = [
"proc-macro2",
"quote",
@@ -3590,9 +3440,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.11.2"
+version = "1.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
+checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
dependencies = [
"aho-corasick",
"memchr",
@@ -3602,9 +3452,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.10"
+version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
dependencies = [
"aho-corasick",
"memchr",
@@ -3613,93 +3463,89 @@ dependencies = [
[[package]]
name = "regex-lite"
-version = "0.1.7"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30"
+checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da"
[[package]]
name = "regex-syntax"
-version = "0.8.6"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
name = "reqwest"
-version = "0.11.27"
+version = "0.12.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
+checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
dependencies = [
- "base64 0.21.7",
+ "base64",
"bytes",
- "encoding_rs",
"futures-core",
- "futures-util",
- "h2 0.3.27",
- "http 0.2.12",
- "http-body 0.4.6",
- "hyper 0.14.32",
- "hyper-rustls 0.24.2",
- "ipnet",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
"js-sys",
"log",
- "mime",
- "once_cell",
"percent-encoding",
"pin-project-lite",
- "rustls 0.21.12",
- "rustls-native-certs",
- "rustls-pemfile 1.0.4",
+ "quinn",
+ "rustls",
+ "rustls-pki-types",
"serde",
"serde_json",
"serde_urlencoded",
- "sync_wrapper 0.1.2",
- "system-configuration",
+ "sync_wrapper",
"tokio",
- "tokio-rustls 0.24.1",
+ "tokio-rustls",
+ "tower 0.5.3",
+ "tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "winreg",
+ "webpki-roots 1.0.5",
]
[[package]]
name = "reqwest"
-version = "0.12.23"
+version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb"
+checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62"
dependencies = [
- "base64 0.22.1",
+ "base64",
"bytes",
"futures-core",
- "http 1.3.1",
- "http-body 1.0.1",
+ "http",
+ "http-body",
"http-body-util",
- "hyper 1.7.0",
- "hyper-rustls 0.27.7",
+ "hyper",
+ "hyper-rustls",
"hyper-util",
"js-sys",
"log",
"percent-encoding",
"pin-project-lite",
"quinn",
- "rustls 0.23.32",
+ "rustls",
"rustls-pki-types",
+ "rustls-platform-verifier",
"serde",
"serde_json",
- "serde_urlencoded",
- "sync_wrapper 1.0.2",
+ "sync_wrapper",
"tokio",
- "tokio-rustls 0.26.3",
- "tower 0.5.2",
+ "tokio-rustls",
+ "tower 0.5.3",
"tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "webpki-roots 1.0.2",
]
[[package]]
@@ -3710,7 +3556,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
dependencies = [
"cc",
"cfg-if",
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
"libc",
"untrusted",
"windows-sys 0.52.0",
@@ -3718,13 +3564,11 @@ dependencies = [
[[package]]
name = "rmp"
-version = "0.8.14"
+version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4"
+checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c"
dependencies = [
- "byteorder",
"num-traits",
- "paste",
]
[[package]]
@@ -3740,9 +3584,9 @@ dependencies = [
[[package]]
name = "rsa"
-version = "0.9.8"
+version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b"
+checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d"
dependencies = [
"const-oid",
"digest",
@@ -3778,12 +3622,6 @@ dependencies = [
]
[[package]]
-name = "rustc-demangle"
-version = "0.1.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
-
-[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3810,7 +3648,7 @@ version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"errno",
"libc",
"linux-raw-sys 0.4.15",
@@ -3819,99 +3657,88 @@ dependencies = [
[[package]]
name = "rustix"
-version = "1.1.2"
+version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
+checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"errno",
"libc",
"linux-raw-sys 0.11.0",
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
name = "rustls"
-version = "0.21.12"
+version = "0.23.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
-dependencies = [
- "log",
- "ring",
- "rustls-webpki 0.101.7",
- "sct",
-]
-
-[[package]]
-name = "rustls"
-version = "0.23.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40"
+checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b"
dependencies = [
+ "aws-lc-rs",
"once_cell",
"ring",
"rustls-pki-types",
- "rustls-webpki 0.103.6",
+ "rustls-webpki",
"subtle",
"zeroize",
]
[[package]]
name = "rustls-native-certs"
-version = "0.6.3"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
+checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
dependencies = [
"openssl-probe",
- "rustls-pemfile 1.0.4",
+ "rustls-pki-types",
"schannel",
"security-framework",
]
[[package]]
-name = "rustls-pemfile"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
-dependencies = [
- "base64 0.21.7",
-]
-
-[[package]]
-name = "rustls-pemfile"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
-dependencies = [
- "rustls-pki-types",
-]
-
-[[package]]
name = "rustls-pki-types"
-version = "1.12.0"
+version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
+checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
dependencies = [
"web-time",
"zeroize",
]
[[package]]
-name = "rustls-webpki"
-version = "0.101.7"
+name = "rustls-platform-verifier"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
+checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784"
dependencies = [
- "ring",
- "untrusted",
+ "core-foundation",
+ "core-foundation-sys",
+ "jni",
+ "log",
+ "once_cell",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-platform-verifier-android",
+ "rustls-webpki",
+ "security-framework",
+ "security-framework-sys",
+ "webpki-root-certs",
+ "windows-sys 0.61.2",
]
[[package]]
+name = "rustls-platform-verifier-android"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
+
+[[package]]
name = "rustls-webpki"
-version = "0.103.6"
+version = "0.103.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb"
+checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
dependencies = [
+ "aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
@@ -3930,7 +3757,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b99c867582a6d5d0eb6dd394ce32b7d8e75e79a76cf532fba7b52c94b0ca4ae0"
dependencies = [
"argon2",
- "base64 0.22.1",
+ "base64",
"base64ct",
"blake2",
"chacha20",
@@ -3952,26 +3779,26 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a61ebc4c4e058565285d54a1134a4f9f5d951ef901194c79437f3ee4f2538e49"
dependencies = [
- "base64 0.22.1",
+ "base64",
"blake2",
"chacha20",
"digest",
"ed25519-dalek",
"hex",
"iso8601",
- "rand_core 0.9.3",
+ "rand_core 0.9.5",
"ring",
"subtle",
- "thiserror 2.0.16",
+ "thiserror 2.0.18",
"time",
"zeroize",
]
[[package]]
name = "ryu"
-version = "1.0.20"
+version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
[[package]]
name = "salsa20"
@@ -3983,12 +3810,21 @@ dependencies = [
]
[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
name = "schannel"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
dependencies = [
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -4005,9 +3841,9 @@ dependencies = [
[[package]]
name = "schemars"
-version = "1.0.4"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
+checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2"
dependencies = [
"dyn-clone",
"ref-cast",
@@ -4022,22 +3858,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
-name = "sct"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
-dependencies = [
- "ring",
- "untrusted",
-]
-
-[[package]]
name = "security-framework"
-version = "2.11.1"
+version = "3.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
+checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
@@ -4062,9 +3888,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
-version = "1.0.226"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
@@ -4072,18 +3898,18 @@ dependencies = [
[[package]]
name = "serde_core"
-version = "1.0.226"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.226"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
@@ -4092,15 +3918,15 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.145"
+version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
- "ryu",
"serde",
"serde_core",
+ "zmij",
]
[[package]]
@@ -4126,9 +3952,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
-version = "1.0.2"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee"
+checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
dependencies = [
"serde_core",
]
@@ -4147,19 +3973,18 @@ dependencies = [
[[package]]
name = "serde_with"
-version = "3.14.1"
+version = "3.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e"
+checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7"
dependencies = [
- "base64 0.22.1",
+ "base64",
"chrono",
"hex",
"indexmap 1.9.3",
- "indexmap 2.11.4",
+ "indexmap 2.13.0",
"schemars 0.9.0",
- "schemars 1.0.4",
- "serde",
- "serde_derive",
+ "schemars 1.2.0",
+ "serde_core",
"serde_json",
"serde_with_macros",
"time",
@@ -4167,9 +3992,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
-version = "3.14.1"
+version = "3.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e"
+checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c"
dependencies = [
"darling 0.21.3",
"proc-macro2",
@@ -4235,9 +4060,9 @@ dependencies = [
[[package]]
name = "signal-hook-mio"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
+checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc"
dependencies = [
"libc",
"mio",
@@ -4246,10 +4071,11 @@ dependencies = [
[[package]]
name = "signal-hook-registry"
-version = "1.4.6"
+version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
+checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
+ "errno",
"libc",
]
@@ -4265,9 +4091,9 @@ dependencies = [
[[package]]
name = "simd-adler32"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
[[package]]
name = "siphasher"
@@ -4277,9 +4103,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
[[package]]
name = "sketches-ddsketch"
-version = "0.2.2"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c"
+checksum = "c1e9a774a6c28142ac54bb25d25562e6bcf957493a184f15ad4eebccb23e410a"
[[package]]
name = "slab"
@@ -4308,12 +4134,12 @@ dependencies = [
[[package]]
name = "socket2"
-version = "0.6.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
+checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
dependencies = [
"libc",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -4364,7 +4190,7 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
dependencies = [
- "base64 0.22.1",
+ "base64",
"bytes",
"crc",
"crossbeam-queue",
@@ -4376,17 +4202,17 @@ dependencies = [
"futures-util",
"hashbrown 0.15.5",
"hashlink",
- "indexmap 2.11.4",
+ "indexmap 2.13.0",
"log",
"memchr",
"once_cell",
"percent-encoding",
- "rustls 0.23.32",
+ "rustls",
"serde",
"serde_json",
"sha2",
"smallvec",
- "thiserror 2.0.16",
+ "thiserror 2.0.18",
"time",
"tokio",
"tokio-stream",
@@ -4441,8 +4267,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
dependencies = [
"atoi",
- "base64 0.22.1",
- "bitflags 2.9.4",
+ "base64",
+ "bitflags",
"byteorder",
"bytes",
"crc",
@@ -4471,7 +4297,7 @@ dependencies = [
"smallvec",
"sqlx-core",
"stringprep",
- "thiserror 2.0.16",
+ "thiserror 2.0.18",
"time",
"tracing",
"uuid",
@@ -4485,8 +4311,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
dependencies = [
"atoi",
- "base64 0.22.1",
- "bitflags 2.9.4",
+ "base64",
+ "bitflags",
"byteorder",
"crc",
"dotenvy",
@@ -4510,7 +4336,7 @@ dependencies = [
"smallvec",
"sqlx-core",
"stringprep",
- "thiserror 2.0.16",
+ "thiserror 2.0.18",
"time",
"tracing",
"uuid",
@@ -4537,7 +4363,7 @@ dependencies = [
"serde",
"serde_urlencoded",
"sqlx-core",
- "thiserror 2.0.16",
+ "thiserror 2.0.18",
"time",
"tracing",
"url",
@@ -4546,9 +4372,9 @@ dependencies = [
[[package]]
name = "stable_deref_trait"
-version = "1.2.0"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "static_assertions"
@@ -4603,9 +4429,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
-version = "2.0.106"
+version = "2.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
+checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
dependencies = [
"proc-macro2",
"quote",
@@ -4614,12 +4440,6 @@ dependencies = [
[[package]]
name = "sync_wrapper"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
-
-[[package]]
-name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
@@ -4654,37 +4474,16 @@ dependencies = [
]
[[package]]
-name = "system-configuration"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
-dependencies = [
- "bitflags 1.3.2",
- "core-foundation",
- "system-configuration-sys",
-]
-
-[[package]]
-name = "system-configuration-sys"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
name = "tempfile"
-version = "3.23.0"
+version = "3.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
+checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
dependencies = [
"fastrand",
- "getrandom 0.3.3",
+ "getrandom 0.3.4",
"once_cell",
- "rustix 1.1.2",
- "windows-sys 0.61.0",
+ "rustix 1.1.3",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -4693,7 +4492,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0"
dependencies = [
- "rustix 1.1.2",
+ "rustix 1.1.3",
"windows-sys 0.60.2",
]
@@ -4717,11 +4516,11 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "2.0.16"
+version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
- "thiserror-impl 2.0.16",
+ "thiserror-impl 2.0.18",
]
[[package]]
@@ -4737,9 +4536,9 @@ dependencies = [
[[package]]
name = "thiserror-impl"
-version = "2.0.16"
+version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
@@ -4771,9 +4570,9 @@ dependencies = [
[[package]]
name = "time"
-version = "0.3.44"
+version = "0.3.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
+checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd"
dependencies = [
"deranged",
"itoa",
@@ -4781,22 +4580,22 @@ dependencies = [
"num-conv",
"num_threads",
"powerfmt",
- "serde",
+ "serde_core",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
-version = "0.1.6"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
+checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca"
[[package]]
name = "time-macros"
-version = "0.2.24"
+version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
+checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd"
dependencies = [
"num-conv",
"time-core",
@@ -4823,9 +4622,9 @@ dependencies = [
[[package]]
name = "tinystr"
-version = "0.8.1"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
+checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
dependencies = [
"displaydoc",
"zerovec",
@@ -4848,29 +4647,26 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.47.1"
+version = "1.49.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
+checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
dependencies = [
- "backtrace",
"bytes",
- "io-uring",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
- "slab",
- "socket2 0.6.0",
+ "socket2 0.6.1",
"tokio-macros",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
-version = "2.5.0"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
+checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
@@ -4879,29 +4675,19 @@ dependencies = [
[[package]]
name = "tokio-rustls"
-version = "0.24.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
-dependencies = [
- "rustls 0.21.12",
- "tokio",
-]
-
-[[package]]
-name = "tokio-rustls"
-version = "0.26.3"
+version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd"
+checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
dependencies = [
- "rustls 0.23.32",
+ "rustls",
"tokio",
]
[[package]]
name = "tokio-stream"
-version = "0.1.17"
+version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
+checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70"
dependencies = [
"futures-core",
"pin-project-lite",
@@ -4910,9 +4696,9 @@ dependencies = [
[[package]]
name = "tokio-util"
-version = "0.7.16"
+version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
+checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
dependencies = [
"bytes",
"futures-core",
@@ -4923,9 +4709,9 @@ dependencies = [
[[package]]
name = "toml"
-version = "0.9.7"
+version = "0.9.11+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0"
+checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46"
dependencies = [
"serde_core",
"serde_spanned",
@@ -4936,18 +4722,18 @@ dependencies = [
[[package]]
name = "toml_datetime"
-version = "0.7.2"
+version = "0.7.5+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1"
+checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_parser"
-version = "1.0.3"
+version = "1.0.6+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627"
+checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
dependencies = [
"winnow",
]
@@ -4961,13 +4747,13 @@ dependencies = [
"async-stream",
"async-trait",
"axum",
- "base64 0.22.1",
+ "base64",
"bytes",
- "h2 0.4.12",
- "http 1.3.1",
- "http-body 1.0.1",
+ "h2",
+ "http",
+ "http-body",
"http-body-util",
- "hyper 1.7.0",
+ "hyper",
"hyper-timeout",
"hyper-util",
"percent-encoding",
@@ -5029,14 +4815,14 @@ dependencies = [
[[package]]
name = "tower"
-version = "0.5.2"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
+checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
- "sync_wrapper 1.0.2",
+ "sync_wrapper",
"tokio",
"tower-layer",
"tower-service",
@@ -5045,18 +4831,18 @@ dependencies = [
[[package]]
name = "tower-http"
-version = "0.6.6"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
+checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"bytes",
"futures-util",
- "http 1.3.1",
- "http-body 1.0.1",
+ "http",
+ "http-body",
"iri-string",
"pin-project-lite",
- "tower 0.5.2",
+ "tower 0.5.3",
"tower-layer",
"tower-service",
"tracing",
@@ -5076,9 +4862,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
-version = "0.1.41"
+version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"log",
"pin-project-lite",
@@ -5088,9 +4874,9 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.30"
+version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
@@ -5099,9 +4885,9 @@ dependencies = [
[[package]]
name = "tracing-core"
-version = "0.1.34"
+version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
"valuable",
@@ -5120,9 +4906,9 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
-version = "0.3.20"
+version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
+checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
dependencies = [
"matchers",
"nu-ansi-term",
@@ -5150,14 +4936,13 @@ dependencies = [
[[package]]
name = "tree_magic_mini"
-version = "3.2.0"
+version = "3.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f943391d896cdfe8eec03a04d7110332d445be7df856db382dd96a730667562c"
+checksum = "b8765b90061cba6c22b5831f675da109ae5561588290f9fa2317adab2714d5a6"
dependencies = [
"memchr",
- "nom 7.1.3",
- "once_cell",
- "petgraph 0.6.5",
+ "nom",
+ "petgraph 0.8.3",
]
[[package]]
@@ -5208,9 +4993,9 @@ dependencies = [
[[package]]
name = "typenum"
-version = "1.18.0"
+version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
+checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]]
name = "unicode-bidi"
@@ -5220,24 +5005,24 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]]
name = "unicode-ident"
-version = "1.0.19"
+version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unicode-normalization"
-version = "0.1.24"
+version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
+checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-properties"
-version = "0.1.3"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
+checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
[[package]]
name = "unicode-segmentation"
@@ -5270,9 +5055,9 @@ checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
[[package]]
name = "unit-prefix"
-version = "0.5.1"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "323402cff2dd658f39ca17c789b502021b3f18707c91cdf22e3838e1b4023817"
+checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3"
[[package]]
name = "universal-hash"
@@ -5292,9 +5077,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
-version = "2.5.7"
+version = "2.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
dependencies = [
"form_urlencoded",
"idna",
@@ -5322,13 +5107,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
-version = "1.18.1"
+version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
+checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
dependencies = [
- "getrandom 0.3.3",
+ "getrandom 0.3.4",
"js-sys",
- "serde",
+ "serde_core",
"wasm-bindgen",
]
@@ -5351,6 +5136,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5366,19 +5161,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
-name = "wasi"
-version = "0.14.7+wasi-0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c"
-dependencies = [
- "wasip2",
-]
-
-[[package]]
name = "wasip2"
-version = "1.0.1+wasi-0.2.4"
+version = "1.0.2+wasi-0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
dependencies = [
"wit-bindgen",
]
@@ -5391,9 +5177,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
[[package]]
name = "wasm-bindgen"
-version = "0.2.103"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819"
+checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
dependencies = [
"cfg-if",
"once_cell",
@@ -5403,26 +5189,13 @@ dependencies = [
]
[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.103"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c"
-dependencies = [
- "bumpalo",
- "log",
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-shared",
-]
-
-[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.53"
+version = "0.4.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67"
+checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f"
dependencies = [
"cfg-if",
+ "futures-util",
"js-sys",
"once_cell",
"wasm-bindgen",
@@ -5431,9 +5204,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.103"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0"
+checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -5441,58 +5214,58 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.103"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32"
+checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
dependencies = [
+ "bumpalo",
"proc-macro2",
"quote",
"syn",
- "wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.103"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf"
+checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
dependencies = [
"unicode-ident",
]
[[package]]
name = "wayland-backend"
-version = "0.3.11"
+version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
+checksum = "fee64194ccd96bf648f42a65a7e589547096dfa702f7cadef84347b66ad164f9"
dependencies = [
"cc",
"downcast-rs",
- "rustix 1.1.2",
+ "rustix 1.1.3",
"smallvec",
"wayland-sys",
]
[[package]]
name = "wayland-client"
-version = "0.31.11"
+version = "0.31.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
+checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec"
dependencies = [
- "bitflags 2.9.4",
- "rustix 1.1.2",
+ "bitflags",
+ "rustix 1.1.3",
"wayland-backend",
"wayland-scanner",
]
[[package]]
name = "wayland-protocols"
-version = "0.32.9"
+version = "0.32.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901"
+checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"wayland-backend",
"wayland-client",
"wayland-scanner",
@@ -5500,11 +5273,11 @@ dependencies = [
[[package]]
name = "wayland-protocols-wlr"
-version = "0.3.9"
+version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec"
+checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags",
"wayland-backend",
"wayland-client",
"wayland-protocols",
@@ -5513,9 +5286,9 @@ dependencies = [
[[package]]
name = "wayland-scanner"
-version = "0.31.7"
+version = "0.31.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3"
+checksum = "5423e94b6a63e68e439803a3e153a9252d5ead12fd853334e2ad33997e3889e3"
dependencies = [
"proc-macro2",
"quick-xml",
@@ -5524,18 +5297,18 @@ dependencies = [
[[package]]
name = "wayland-sys"
-version = "0.31.7"
+version = "0.31.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142"
+checksum = "1e6dbfc3ac5ef974c92a2235805cc0114033018ae1290a72e474aa8b28cbbdfd"
dependencies = [
"pkg-config",
]
[[package]]
name = "web-sys"
-version = "0.3.80"
+version = "0.3.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc"
+checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -5552,28 +5325,37 @@ dependencies = [
]
[[package]]
+name = "webpki-root-certs"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
name = "webpki-roots"
version = "0.26.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
dependencies = [
- "webpki-roots 1.0.2",
+ "webpki-roots 1.0.5",
]
[[package]]
name = "webpki-roots"
-version = "1.0.2"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2"
+checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "weezl"
-version = "0.1.10"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3"
+checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
[[package]]
name = "whoami"
@@ -5603,6 +5385,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5629,22 +5420,22 @@ dependencies = [
[[package]]
name = "windows-core"
-version = "0.62.0"
+version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
- "windows-link 0.2.0",
+ "windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
-version = "0.60.0"
+version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
@@ -5653,9 +5444,9 @@ dependencies = [
[[package]]
name = "windows-interface"
-version = "0.59.1"
+version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
@@ -5664,32 +5455,35 @@ dependencies = [
[[package]]
name = "windows-link"
-version = "0.1.3"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
-name = "windows-link"
-version = "0.2.0"
+name = "windows-result"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link",
+]
[[package]]
-name = "windows-result"
-version = "0.4.0"
+name = "windows-strings"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
- "windows-link 0.2.0",
+ "windows-link",
]
[[package]]
-name = "windows-strings"
-version = "0.5.0"
+name = "windows-sys"
+version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
- "windows-link 0.2.0",
+ "windows-targets 0.42.2",
]
[[package]]
@@ -5725,16 +5519,31 @@ version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
- "windows-targets 0.53.3",
+ "windows-targets 0.53.5",
]
[[package]]
name = "windows-sys"
-version = "0.61.0"
+version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
- "windows-link 0.2.0",
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
]
[[package]]
@@ -5770,23 +5579,29 @@ dependencies = [
[[package]]
name = "windows-targets"
-version = "0.53.3"
+version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
+checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
- "windows-link 0.1.3",
- "windows_aarch64_gnullvm 0.53.0",
- "windows_aarch64_msvc 0.53.0",
- "windows_i686_gnu 0.53.0",
- "windows_i686_gnullvm 0.53.0",
- "windows_i686_msvc 0.53.0",
- "windows_x86_64_gnu 0.53.0",
- "windows_x86_64_gnullvm 0.53.0",
- "windows_x86_64_msvc 0.53.0",
+ "windows-link",
+ "windows_aarch64_gnullvm 0.53.1",
+ "windows_aarch64_msvc 0.53.1",
+ "windows_i686_gnu 0.53.1",
+ "windows_i686_gnullvm 0.53.1",
+ "windows_i686_msvc 0.53.1",
+ "windows_x86_64_gnu 0.53.1",
+ "windows_x86_64_gnullvm 0.53.1",
+ "windows_x86_64_msvc 0.53.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
@@ -5799,9 +5614,15 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.53.0"
+version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
@@ -5817,9 +5638,15 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.53.0"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
@@ -5835,9 +5662,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
-version = "0.53.0"
+version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
@@ -5847,9 +5674,15 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
-version = "0.53.0"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
@@ -5865,9 +5698,15 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
-version = "0.53.0"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
@@ -5883,9 +5722,15 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.53.0"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
@@ -5901,9 +5746,15 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.53.0"
+version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
@@ -5919,47 +5770,36 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.53.0"
+version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winnow"
-version = "0.7.13"
+version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
+checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
dependencies = [
"memchr",
]
[[package]]
-name = "winreg"
-version = "0.50.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
-dependencies = [
- "cfg-if",
- "windows-sys 0.48.0",
-]
-
-[[package]]
name = "wit-bindgen"
-version = "0.46.0"
+version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
[[package]]
name = "wl-clipboard-rs"
-version = "0.9.2"
+version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5ff8d0e60065f549fafd9d6cb626203ea64a798186c80d8e7df4f8af56baeb"
+checksum = "e9651471a32e87d96ef3a127715382b2d11cc7c8bb9822ded8a7cc94072eb0a3"
dependencies = [
"libc",
"log",
"os_pipe",
- "rustix 0.38.44",
- "tempfile",
- "thiserror 2.0.16",
+ "rustix 1.1.3",
+ "thiserror 2.0.18",
"tree_magic_mini",
"wayland-backend",
"wayland-client",
@@ -5969,9 +5809,9 @@ dependencies = [
[[package]]
name = "writeable"
-version = "0.6.1"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
+checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
[[package]]
name = "x11rb"
@@ -5980,7 +5820,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
dependencies = [
"gethostname",
- "rustix 1.1.2",
+ "rustix 1.1.3",
"x11rb-protocol",
]
@@ -5998,11 +5838,10 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "yoke"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
+checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
dependencies = [
- "serde",
"stable_deref_trait",
"yoke-derive",
"zerofrom",
@@ -6010,9 +5849,9 @@ dependencies = [
[[package]]
name = "yoke-derive"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
+checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [
"proc-macro2",
"quote",
@@ -6022,18 +5861,18 @@ dependencies = [
[[package]]
name = "zerocopy"
-version = "0.8.27"
+version = "0.8.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
+checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.27"
+version = "0.8.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
+checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1"
dependencies = [
"proc-macro2",
"quote",
@@ -6063,18 +5902,18 @@ dependencies = [
[[package]]
name = "zeroize"
-version = "1.8.1"
+version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
-version = "1.4.2"
+version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
+checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
dependencies = [
"proc-macro2",
"quote",
@@ -6083,9 +5922,9 @@ dependencies = [
[[package]]
name = "zerotrie"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
dependencies = [
"displaydoc",
"yoke",
@@ -6094,9 +5933,9 @@ dependencies = [
[[package]]
name = "zerovec"
-version = "0.11.4"
+version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
+checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
dependencies = [
"yoke",
"zerofrom",
@@ -6105,9 +5944,9 @@ dependencies = [
[[package]]
name = "zerovec-derive"
-version = "0.11.1"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
+checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [
"proc-macro2",
"quote",
@@ -6115,6 +5954,12 @@ dependencies = [
]
[[package]]
+name = "zmij"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65"
+
+[[package]]
name = "zune-core"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 81aa08c8..ba706344 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,9 +5,9 @@ resolver = "2"
exclude = ["ui/backend"]
[workspace.package]
-version = "18.10.0"
+version = "18.11.0"
authors = ["Ellie Huxtable <ellie@atuin.sh>"]
-rust-version = "1.90"
+rust-version = "1.91"
license = "MIT"
homepage = "https://atuin.sh"
repository = "https://github.com/atuinsh/atuin"
@@ -24,7 +24,7 @@ time = { version = "0.3.36", features = [
] }
clap = { version = "4.5.7", features = ["derive"] }
config = { version = "0.15.8", default-features = false, features = ["toml"] }
-directories = "5.0.1"
+directories = "6.0.0"
eyre = "0.6"
fs-err = "3.1"
interim = { version = "0.2.0", features = ["time_0_3"] }
@@ -51,8 +51,8 @@ version = "0.3"
features = ["ansi", "fmt", "registry", "env-filter"]
[workspace.dependencies.reqwest]
-version = "0.11"
-features = ["json", "rustls-tls-native-roots"]
+version = "0.13"
+features = ["json", "rustls"]
default-features = false
[workspace.dependencies.sqlx]
diff --git a/Dockerfile b/Dockerfile
index 9a161a55..8d50e53b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM lukemathwalker/cargo-chef:latest-rust-1.90.0-slim-bookworm AS chef
+FROM lukemathwalker/cargo-chef:latest-rust-1.92.0-slim-bookworm AS chef
WORKDIR app
FROM chef AS planner
@@ -16,7 +16,7 @@ RUN cargo chef cook --release --recipe-path recipe.json
COPY . .
RUN cargo build --release --bin atuin
-FROM debian:bookworm-20250929-slim AS runtime
+FROM debian:bookworm-20251208-slim AS runtime
RUN useradd -c 'atuin user' atuin && mkdir /config && chown atuin:atuin /config
# Install ca-certificates for webhooks to work
diff --git a/README.md b/README.md
index 787e5c3e..60eaa000 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,7 @@ I wanted to. And I **really** don't want to.
- fish
- nushell
- xonsh
+- powershell (tier 2 support)
## Community
diff --git a/crates/atuin-client/Cargo.toml b/crates/atuin-client/Cargo.toml
index 407ff491..2e65409f 100644
--- a/crates/atuin-client/Cargo.toml
+++ b/crates/atuin-client/Cargo.toml
@@ -19,7 +19,7 @@ daemon = []
check-update = []
[dependencies]
-atuin-common = { path = "../atuin-common", version = "18.10.0" }
+atuin-common = { path = "../atuin-common", version = "18.11.0" }
log = { workspace = true }
base64 = { workspace = true }
diff --git a/crates/atuin-client/config.toml b/crates/atuin-client/config.toml
index c40461ab..117ea066 100644
--- a/crates/atuin-client/config.toml
+++ b/crates/atuin-client/config.toml
@@ -49,7 +49,7 @@
## in any directory within a git repository tree (default: false).
##
## To use workspace mode by default when available, set this to true and
-## set filter_mode to "workspace" or leave it unspecified and
+## set filter_mode to "workspace" or leave it unspecified and
## set search.filters to include "workspace" before other filter modes.
# workspaces = false
@@ -154,8 +154,10 @@
## 5. Stripe live/test keys
# secrets_filter = true
-## Defaults to true. If enabled, upon hitting enter Atuin will immediately execute the command. Press tab to return to the shell and edit.
-# This applies for new installs. Old installs will keep the old behaviour unless configured otherwise.
+## Defaults to true. If enabled, upon hitting enter Atuin will immediately execute the command,
+## whereas tab will put the command in the prompt for editing.
+## If set to false, both enter and tab will place the command in the prompt for editing.
+## This applies for new installs. Old installs will keep the old behaviour unless configured otherwise.
enter_accept = true
## Defaults to false. If enabled, when triggered after &&, || or |, Atuin will complete commands to chain rather than replace the current line.
@@ -287,3 +289,44 @@ records = true
## The "workspace" mode is skipped when not in a workspace or workspaces = false.
## Default filter mode can be overridden with the filter_mode setting.
# filters = [ "global", "host", "session", "session-preload", "workspace", "directory" ]
+
+[ui]
+## Columns to display in the interactive search, from left to right.
+## The selection indicator (" > ") is always shown first implicitly.
+##
+## Each column can be specified as a simple string (uses default width)
+## or as an object with type, width, and expand:
+## { type = "directory", width = 30, expand = true }
+##
+## Available column types (with default widths):
+## duration (5) - Command execution duration (e.g., "123ms")
+## time (8) - Relative time since execution (e.g., "59m ago")
+## datetime (16) - Absolute timestamp (e.g., "2025-01-22 14:35")
+## directory (20) - Working directory (truncated if too long)
+## host (15) - Hostname where command was run
+## user (10) - Username
+## exit (3) - Exit code (colored by success/failure)
+## command (*) - The command itself (expands by default)
+##
+## The "expand" option (default: true for command, false for others) makes a
+## column fill remaining space. Only one column should have expand = true.
+##
+## Default:
+# columns = ["duration", "time", "command"]
+##
+## Examples:
+##
+## Minimal - more space for commands:
+# columns = ["duration", "command"]
+##
+## With wider directory column:
+# columns = ["duration", { type = "directory", width = 30 }, "command"]
+##
+## Show host for multi-machine sync users:
+# columns = ["duration", "time", "host", "command"]
+##
+## Show exit codes prominently:
+# columns = ["exit", "duration", "command"]
+##
+## Make directory expand instead of command:
+# columns = ["duration", "time", { type = "directory", expand = true }, { type = "command", expand = false }]
diff --git a/crates/atuin-client/src/import/replxx.rs b/crates/atuin-client/src/import/replxx.rs
index dd7030ad..47d566cf 100644
--- a/crates/atuin-client/src/import/replxx.rs
+++ b/crates/atuin-client/src/import/replxx.rs
@@ -19,8 +19,23 @@ fn default_histpath() -> Result<PathBuf> {
let home_dir = user_dirs.home_dir();
// There is no default histfile for replxx.
- // For simplicity let's use the most common one.
- Ok(home_dir.join(".histfile"))
+ // Here we try a couple of common names.
+ let mut candidates = ["replxx_history.txt", ".histfile"].iter();
+ loop {
+ match candidates.next() {
+ Some(candidate) => {
+ let histpath = home_dir.join(candidate);
+ if histpath.exists() {
+ break Ok(histpath);
+ }
+ }
+ None => {
+ break Err(eyre!(
+ "Could not find history file. Try setting and exporting $HISTFILE"
+ ));
+ }
+ }
+ }
}
#[async_trait]
diff --git a/crates/atuin-client/src/import/zsh.rs b/crates/atuin-client/src/import/zsh.rs
index b65e2608..11e2f371 100644
--- a/crates/atuin-client/src/import/zsh.rs
+++ b/crates/atuin-client/src/import/zsh.rs
@@ -70,7 +70,7 @@ impl Importer for Zsh {
if let Some(s) = s.strip_suffix('\\') {
line.push_str(s);
- line.push_str("\\\n");
+ line.push('\n');
} else {
line.push_str(&s);
let command = std::mem::take(&mut line);
@@ -188,7 +188,7 @@ mod test {
#[tokio::test]
async fn test_parse_file() {
let bytes = r": 1613322469:0;cargo install atuin
-: 1613322469:10;cargo install atuin; \
+: 1613322469:10;cargo install atuin; \\
cargo update
: 1613322469:10;cargo :b̷i̶t̴r̵o̴t̴ ̵i̷s̴ ̷r̶e̵a̸l̷
"
diff --git a/crates/atuin-client/src/secrets.rs b/crates/atuin-client/src/secrets.rs
index 25e8db9a..459e6238 100644
--- a/crates/atuin-client/src/secrets.rs
+++ b/crates/atuin-client/src/secrets.rs
@@ -12,7 +12,7 @@ pub enum TestValue<'a> {
pub static SECRET_PATTERNS: &[(&str, &str, TestValue)] = &[
(
"AWS Access Key ID",
- "AKIA[0-9A-Z]{16}",
+ "A[KS]IA[0-9A-Z]{16}",
TestValue::Single("AKIAIOSFODNN7EXAMPLE"),
),
(
diff --git a/crates/atuin-client/src/settings.rs b/crates/atuin-client/src/settings.rs
index 489c1a83..916172ba 100644
--- a/crates/atuin-client/src/settings.rs
+++ b/crates/atuin-client/src/settings.rs
@@ -451,6 +451,184 @@ pub enum PreviewStrategy {
Fixed,
}
+/// Column types available for the interactive search UI.
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
+#[serde(rename_all = "lowercase")]
+pub enum UiColumnType {
+ /// Command execution duration (e.g., "123ms")
+ Duration,
+ /// Relative time since execution (e.g., "59s ago")
+ Time,
+ /// Absolute timestamp (e.g., "2025-01-22 14:35")
+ Datetime,
+ /// Working directory
+ Directory,
+ /// Hostname
+ Host,
+ /// Username
+ User,
+ /// Exit code
+ Exit,
+ /// The command itself (should be last, expands to fill)
+ Command,
+}
+
+impl UiColumnType {
+ /// Returns the default width for this column type (in characters).
+ /// The Command column returns 0 as it expands to fill remaining space.
+ pub fn default_width(&self) -> u16 {
+ match self {
+ UiColumnType::Duration => 5,
+ UiColumnType::Time => 9, // "459ms ago" with padding
+ UiColumnType::Datetime => 16, // "2025-01-22 14:35"
+ UiColumnType::Directory => 20,
+ UiColumnType::Host => 15,
+ UiColumnType::User => 10,
+ UiColumnType::Exit => 3,
+ UiColumnType::Command => 0, // Expands to fill
+ }
+ }
+}
+
+/// A column configuration with type and optional custom width.
+/// Can be specified as just a string (uses default width) or as an object with type and width.
+#[derive(Clone, Debug, Serialize)]
+pub struct UiColumn {
+ pub column_type: UiColumnType,
+ pub width: u16,
+ /// If true, this column expands to fill remaining space. Only one column should expand.
+ pub expand: bool,
+}
+
+impl UiColumn {
+ pub fn new(column_type: UiColumnType) -> Self {
+ Self {
+ width: column_type.default_width(),
+ expand: column_type == UiColumnType::Command,
+ column_type,
+ }
+ }
+
+ pub fn with_width(column_type: UiColumnType, width: u16) -> Self {
+ Self {
+ column_type,
+ width,
+ expand: column_type == UiColumnType::Command,
+ }
+ }
+}
+
+// Custom deserialize to handle both string and object formats:
+// "duration" or { type = "duration", width = 8, expand = true }
+impl<'de> serde::Deserialize<'de> for UiColumn {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ use serde::de::{self, MapAccess, Visitor};
+
+ struct UiColumnVisitor;
+
+ impl<'de> Visitor<'de> for UiColumnVisitor {
+ type Value = UiColumn;
+
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ formatter.write_str(
+ "a column type string or an object with 'type' and optional 'width'/'expand'",
+ )
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<UiColumn, E>
+ where
+ E: de::Error,
+ {
+ let column_type: UiColumnType =
+ serde::Deserialize::deserialize(serde::de::value::StrDeserializer::new(value))?;
+ Ok(UiColumn::new(column_type))
+ }
+
+ fn visit_map<M>(self, mut map: M) -> Result<UiColumn, M::Error>
+ where
+ M: MapAccess<'de>,
+ {
+ let mut column_type: Option<UiColumnType> = None;
+ let mut width: Option<u16> = None;
+ let mut expand: Option<bool> = None;
+
+ while let Some(key) = map.next_key::<String>()? {
+ match key.as_str() {
+ "type" => {
+ column_type = Some(map.next_value()?);
+ }
+ "width" => {
+ width = Some(map.next_value()?);
+ }
+ "expand" => {
+ expand = Some(map.next_value()?);
+ }
+ _ => {
+ let _: serde::de::IgnoredAny = map.next_value()?;
+ }
+ }
+ }
+
+ let column_type = column_type.ok_or_else(|| de::Error::missing_field("type"))?;
+ let width = width.unwrap_or_else(|| column_type.default_width());
+ let expand = expand.unwrap_or(column_type == UiColumnType::Command);
+ Ok(UiColumn {
+ column_type,
+ width,
+ expand,
+ })
+ }
+ }
+
+ deserializer.deserialize_any(UiColumnVisitor)
+ }
+}
+
+/// UI-specific settings for the interactive search.
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Ui {
+ /// Columns to display in interactive search, from left to right.
+ /// The indicator column (" > ") is always shown first implicitly.
+ /// The "command" column should be last as it expands to fill remaining space.
+ /// Can be simple strings or objects with type and width.
+ #[serde(default = "Ui::default_columns")]
+ pub columns: Vec<UiColumn>,
+}
+
+impl Ui {
+ fn default_columns() -> Vec<UiColumn> {
+ vec![
+ UiColumn::new(UiColumnType::Duration),
+ UiColumn::new(UiColumnType::Time),
+ UiColumn::new(UiColumnType::Command),
+ ]
+ }
+
+ /// Validate the UI configuration.
+ /// Returns an error if more than one column has expand = true.
+ pub fn validate(&self) -> Result<()> {
+ let expand_count = self.columns.iter().filter(|c| c.expand).count();
+ if expand_count > 1 {
+ bail!(
+ "Only one column can have expand = true, but {} columns are set to expand",
+ expand_count
+ );
+ }
+ Ok(())
+ }
+}
+
+impl Default for Ui {
+ fn default() -> Self {
+ Self {
+ columns: Self::default_columns(),
+ }
+ }
+}
+
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Settings {
pub dialect: Dialect,
@@ -531,6 +709,9 @@ pub struct Settings {
pub theme: Theme,
#[serde(default)]
+ pub ui: Ui,
+
+ #[serde(default)]
pub scripts: scripts::Settings,
#[serde(default)]
@@ -735,10 +916,20 @@ impl Settings {
None
}
- pub fn default_filter_mode(&self) -> FilterMode {
+ pub fn default_filter_mode(&self, git_root: bool) -> FilterMode {
self.filter_mode
.filter(|x| self.search.filters.contains(x))
- .or(self.search.filters.first().copied())
+ .or_else(|| {
+ self.search
+ .filters
+ .iter()
+ .find(|x| match (x, git_root, self.workspaces) {
+ (FilterMode::Workspace, true, true) => true,
+ (FilterMode::Workspace, _, _) => false,
+ (_, _, _) => true,
+ })
+ .copied()
+ })
.unwrap_or(FilterMode::Global)
}
@@ -895,6 +1086,9 @@ impl Settings {
settings.session_path = Self::expand_path(settings.session_path)?;
settings.daemon.socket_path = Self::expand_path(settings.daemon.socket_path)?;
+ // Validate UI settings
+ settings.ui.validate()?;
+
Ok(settings)
}
@@ -979,4 +1173,58 @@ mod tests {
Ok(())
}
+
+ #[test]
+ fn can_choose_workspace_filters_when_in_git_context() -> Result<()> {
+ let mut settings = super::Settings::default();
+ settings.search.filters = vec![
+ super::FilterMode::Workspace,
+ super::FilterMode::Host,
+ super::FilterMode::Directory,
+ super::FilterMode::Session,
+ super::FilterMode::Global,
+ ];
+ settings.workspaces = true;
+
+ assert_eq!(
+ settings.default_filter_mode(true),
+ super::FilterMode::Workspace,
+ );
+
+ Ok(())
+ }
+
+ #[test]
+ fn wont_choose_workspace_filters_when_not_in_git_context() -> Result<()> {
+ let mut settings = super::Settings::default();
+ settings.search.filters = vec![
+ super::FilterMode::Workspace,
+ super::FilterMode::Host,
+ super::FilterMode::Directory,
+ super::FilterMode::Session,
+ super::FilterMode::Global,
+ ];
+ settings.workspaces = true;
+
+ assert_eq!(settings.default_filter_mode(false), super::FilterMode::Host,);
+
+ Ok(())
+ }
+
+ #[test]
+ fn wont_choose_workspace_filters_when_workspaces_disabled() -> Result<()> {
+ let mut settings = super::Settings::default();
+ settings.search.filters = vec![
+ super::FilterMode::Workspace,
+ super::FilterMode::Host,
+ super::FilterMode::Directory,
+ super::FilterMode::Session,
+ super::FilterMode::Global,
+ ];
+ settings.workspaces = false;
+
+ assert_eq!(settings.default_filter_mode(true), super::FilterMode::Host,);
+
+ Ok(())
+ }
}
diff --git a/crates/atuin-common/src/api.rs b/crates/atuin-common/src/api.rs
index 4e897811..1aaf9859 100644
--- a/crates/atuin-common/src/api.rs
+++ b/crates/atuin-common/src/api.rs
@@ -106,7 +106,6 @@ pub struct ErrorResponse<'a> {
pub struct IndexResponse {
pub homage: String,
pub version: String,
- pub total_history: i64,
}
#[derive(Debug, Serialize, Deserialize)]
diff --git a/crates/atuin-daemon/Cargo.toml b/crates/atuin-daemon/Cargo.toml
index 3a791a47..3c828205 100644
--- a/crates/atuin-daemon/Cargo.toml
+++ b/crates/atuin-daemon/Cargo.toml
@@ -14,9 +14,9 @@ readme.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-atuin-client = { path = "../atuin-client", version = "18.10.0" }
-atuin-dotfiles = { path = "../atuin-dotfiles", version = "18.10.0" }
-atuin-history = { path = "../atuin-history", version = "18.10.0" }
+atuin-client = { path = "../atuin-client", version = "18.11.0" }
+atuin-dotfiles = { path = "../atuin-dotfiles", version = "18.11.0" }
+atuin-history = { path = "../atuin-history", version = "18.11.0" }
time = { workspace = true }
uuid = { workspace = true }
diff --git a/crates/atuin-dotfiles/Cargo.toml b/crates/atuin-dotfiles/Cargo.toml
index 84b2d823..1f5d990e 100644
--- a/crates/atuin-dotfiles/Cargo.toml
+++ b/crates/atuin-dotfiles/Cargo.toml
@@ -14,8 +14,8 @@ readme.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-atuin-common = { path = "../atuin-common", version = "18.10.0" }
-atuin-client = { path = "../atuin-client", version = "18.10.0" }
+atuin-common = { path = "../atuin-common", version = "18.11.0" }
+atuin-client = { path = "../atuin-client", version = "18.11.0" }
eyre = { workspace = true }
tokio = { workspace = true }
diff --git a/crates/atuin-history/Cargo.toml b/crates/atuin-history/Cargo.toml
index 7153ed83..fe597303 100644
--- a/crates/atuin-history/Cargo.toml
+++ b/crates/atuin-history/Cargo.toml
@@ -14,7 +14,7 @@ readme.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-atuin-client = { path = "../atuin-client", version = "18.10.0" }
+atuin-client = { path = "../atuin-client", version = "18.11.0" }
time = { workspace = true }
serde = { workspace = true }
diff --git a/crates/atuin-kv/Cargo.toml b/crates/atuin-kv/Cargo.toml
index aeedfa59..e41c7b47 100644
--- a/crates/atuin-kv/Cargo.toml
+++ b/crates/atuin-kv/Cargo.toml
@@ -14,8 +14,8 @@ readme.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-atuin-client = { path = "../atuin-client", version = "18.10.0" }
-atuin-common = { path = "../atuin-common", version = "18.10.0" }
+atuin-client = { path = "../atuin-client", version = "18.11.0" }
+atuin-common = { path = "../atuin-common", version = "18.11.0" }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
diff --git a/crates/atuin-scripts/Cargo.toml b/crates/atuin-scripts/Cargo.toml
index 007ff860..aed696ba 100644
--- a/crates/atuin-scripts/Cargo.toml
+++ b/crates/atuin-scripts/Cargo.toml
@@ -14,8 +14,8 @@ readme.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-atuin-client = { path = "../atuin-client", version = "18.10.0" }
-atuin-common = { path = "../atuin-common", version = "18.10.0" }
+atuin-client = { path = "../atuin-client", version = "18.11.0" }
+atuin-common = { path = "../atuin-common", version = "18.11.0" }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
diff --git a/crates/atuin-server-database/Cargo.toml b/crates/atuin-server-database/Cargo.toml
index 9766cc71..537e34a2 100644
--- a/crates/atuin-server-database/Cargo.toml
+++ b/crates/atuin-server-database/Cargo.toml
@@ -10,7 +10,7 @@ homepage = { workspace = true }
repository = { workspace = true }
[dependencies]
-atuin-common = { path = "../atuin-common", version = "18.10.0" }
+atuin-common = { path = "../atuin-common", version = "18.11.0" }
tracing = { workspace = true }
time = { workspace = true }
diff --git a/crates/atuin-server-database/src/lib.rs b/crates/atuin-server-database/src/lib.rs
index e70c755c..a4ddf23c 100644
--- a/crates/atuin-server-database/src/lib.rs
+++ b/crates/atuin-server-database/src/lib.rs
@@ -51,6 +51,8 @@ pub enum DbType {
#[derive(Clone, Deserialize, Serialize)]
pub struct DbSettings {
pub db_uri: String,
+ /// Optional URI for read replicas. If set, read-only queries will use this connection.
+ pub read_db_uri: Option<String>,
}
impl DbSettings {
@@ -65,22 +67,29 @@ impl DbSettings {
}
}
+fn redact_db_uri(uri: &str) -> String {
+ url::Url::parse(uri)
+ .map(|mut url| {
+ let _ = url.set_password(Some("****"));
+ url.to_string()
+ })
+ .unwrap_or_else(|_| uri.to_string())
+}
+
// Do our best to redact passwords so they're not logged in the event of an error.
impl Debug for DbSettings {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.db_type() == DbType::Postgres {
- let redacted_uri = url::Url::parse(&self.db_uri)
- .map(|mut url| {
- let _ = url.set_password(Some("****"));
- url.to_string()
- })
- .unwrap_or(self.db_uri.clone());
+ let redacted_uri = redact_db_uri(&self.db_uri);
+ let redacted_read_uri = self.read_db_uri.as_ref().map(|uri| redact_db_uri(uri));
f.debug_struct("DbSettings")
.field("db_uri", &redacted_uri)
+ .field("read_db_uri", &redacted_read_uri)
.finish()
} else {
f.debug_struct("DbSettings")
.field("db_uri", &self.db_uri)
+ .field("read_db_uri", &self.read_db_uri)
.finish()
}
}
@@ -104,7 +113,6 @@ pub trait Database: Sized + Clone + Send + Sync + 'static {
async fn update_user_password(&self, u: &User) -> DbResult<()>;
- async fn total_history(&self) -> DbResult<i64>;
async fn count_history(&self, user: &User) -> DbResult<i64>;
async fn count_history_cached(&self, user: &User) -> DbResult<i64>;
diff --git a/crates/atuin-server-postgres/Cargo.toml b/crates/atuin-server-postgres/Cargo.toml
index 5abcd931..c73e4a52 100644
--- a/crates/atuin-server-postgres/Cargo.toml
+++ b/crates/atuin-server-postgres/Cargo.toml
@@ -10,8 +10,8 @@ homepage = { workspace = true }
repository = { workspace = true }
[dependencies]
-atuin-common = { path = "../atuin-common", version = "18.10.0" }
-atuin-server-database = { path = "../atuin-server-database", version = "18.10.0" }
+atuin-common = { path = "../atuin-common", version = "18.11.0" }
+atuin-server-database = { path = "../atuin-server-database", version = "18.11.0" }
eyre = { workspace = true }
tracing = { workspace = true }
@@ -20,6 +20,6 @@ serde = { workspace = true }
sqlx = { workspace = true }
async-trait = { workspace = true }
uuid = { workspace = true }
-metrics = "0.21.1"
+metrics = "0.24"
futures-util = "0.3"
rand.workspace = true \ No newline at end of file
diff --git a/crates/atuin-server-postgres/src/lib.rs b/crates/atuin-server-postgres/src/lib.rs
index 39c25256..54ba2ee8 100644
--- a/crates/atuin-server-postgres/src/lib.rs
+++ b/crates/atuin-server-postgres/src/lib.rs
@@ -24,6 +24,16 @@ const MIN_PG_VERSION: u32 = 14;
#[derive(Clone)]
pub struct Postgres {
pool: sqlx::Pool<sqlx::postgres::Postgres>,
+ /// Optional read replica pool for read-only queries
+ read_pool: Option<sqlx::Pool<sqlx::postgres::Postgres>>,
+}
+
+impl Postgres {
+ /// Returns the appropriate pool for read operations.
+ /// Uses read_pool if available, otherwise falls back to the primary pool.
+ fn read_pool(&self) -> &sqlx::Pool<sqlx::postgres::Postgres> {
+ self.read_pool.as_ref().unwrap_or(&self.pool)
+ }
}
fn fix_error(error: sqlx::Error) -> DbError {
@@ -65,14 +75,45 @@ impl Database for Postgres {
.await
.map_err(|error| DbError::Other(error.into()))?;
- Ok(Self { pool })
+ // Create read replica pool if configured
+ let read_pool = if let Some(read_db_uri) = &settings.read_db_uri {
+ tracing::info!("Connecting to read replica database");
+ let read_pool = PgPoolOptions::new()
+ .max_connections(100)
+ .connect(read_db_uri.as_str())
+ .await
+ .map_err(fix_error)?;
+
+ // Verify the read replica is also a supported PostgreSQL version
+ let read_pg_major_version: u32 = read_pool
+ .acquire()
+ .await
+ .map_err(fix_error)?
+ .server_version_num()
+ .ok_or(DbError::Other(eyre::Report::msg(
+ "could not get PostgreSQL version from read replica",
+ )))?
+ / 10000;
+
+ if read_pg_major_version < MIN_PG_VERSION {
+ return Err(DbError::Other(eyre::Report::msg(format!(
+ "unsupported PostgreSQL version {read_pg_major_version} on read replica, minimum required is {MIN_PG_VERSION}"
+ ))));
+ }
+
+ Some(read_pool)
+ } else {
+ None
+ };
+
+ Ok(Self { pool, read_pool })
}
#[instrument(skip_all)]
async fn get_session(&self, token: &str) -> DbResult<Session> {
sqlx::query_as("select id, user_id, token from sessions where token = $1")
.bind(token)
- .fetch_one(&self.pool)
+ .fetch_one(self.read_pool())
.await
.map_err(fix_error)
.map(|DbSession(session)| session)
@@ -84,7 +125,7 @@ impl Database for Postgres {
"select id, username, email, password, verified_at from users where username = $1",
)
.bind(username)
- .fetch_one(&self.pool)
+ .fetch_one(self.read_pool())
.await
.map_err(fix_error)
.map(|DbUser(user)| user)
@@ -95,7 +136,7 @@ impl Database for Postgres {
let res: (bool,) =
sqlx::query_as("select verified_at is not null from users where id = $1")
.bind(id)
- .fetch_one(&self.pool)
+ .fetch_one(self.read_pool())
.await
.map_err(fix_error)?;
@@ -173,13 +214,13 @@ impl Database for Postgres {
#[instrument(skip_all)]
async fn get_session_user(&self, token: &str) -> DbResult<User> {
sqlx::query_as(
- "select users.id, users.username, users.email, users.password, users.verified_at from users
- inner join sessions
- on users.id = sessions.user_id
+ "select users.id, users.username, users.email, users.password, users.verified_at from users
+ inner join sessions
+ on users.id = sessions.user_id
and sessions.token = $1",
)
.bind(token)
- .fetch_one(&self.pool)
+ .fetch_one(self.read_pool())
.await
.map_err(fix_error)
.map(|DbUser(user)| user)
@@ -196,7 +237,7 @@ impl Database for Postgres {
where user_id = $1",
)
.bind(user.id)
- .fetch_one(&self.pool)
+ .fetch_one(self.read_pool())
.await
.map_err(fix_error)?;
@@ -204,28 +245,13 @@ impl Database for Postgres {
}
#[instrument(skip_all)]
- async fn total_history(&self) -> DbResult<i64> {
- // The cache is new, and the user might not yet have a cache value.
- // They will have one as soon as they post up some new history, but handle that
- // edge case.
-
- let res: (i64,) = sqlx::query_as("select sum(total) from total_history_count_user")
- .fetch_optional(&self.pool)
- .await
- .map_err(fix_error)?
- .unwrap_or((0,));
-
- Ok(res.0)
- }
-
- #[instrument(skip_all)]
async fn count_history_cached(&self, user: &User) -> DbResult<i64> {
let res: (i32,) = sqlx::query_as(
"select total from total_history_count_user
where user_id = $1",
)
.bind(user.id)
- .fetch_one(&self.pool)
+ .fetch_one(self.read_pool())
.await
.map_err(fix_error)?;
@@ -283,12 +309,12 @@ impl Database for Postgres {
// edge case.
let res = sqlx::query(
- "select client_id from history
+ "select client_id from history
where user_id = $1
and deleted_at is not null",
)
.bind(user.id)
- .fetch_all(&self.pool)
+ .fetch_all(self.read_pool())
.await
.map_err(fix_error)?;
@@ -315,7 +341,7 @@ impl Database for Postgres {
.bind(user.id)
.bind(into_utc(range.start))
.bind(into_utc(range.end))
- .fetch_one(&self.pool)
+ .fetch_one(self.read_pool())
.await
.map_err(fix_error)?;
@@ -332,7 +358,7 @@ impl Database for Postgres {
page_size: i64,
) -> DbResult<Vec<History>> {
let res = sqlx::query_as(
- "select id, client_id, user_id, hostname, timestamp, data, created_at from history
+ "select id, client_id, user_id, hostname, timestamp, data, created_at from history
where user_id = $1
and hostname != $2
and created_at >= $3
@@ -345,7 +371,7 @@ impl Database for Postgres {
.bind(into_utc(created_after))
.bind(into_utc(since))
.bind(page_size)
- .fetch(&self.pool)
+ .fetch(self.read_pool())
.map_ok(|DbHistory(h)| h)
.try_collect()
.await
@@ -486,7 +512,7 @@ impl Database for Postgres {
async fn get_user_session(&self, u: &User) -> DbResult<Session> {
sqlx::query_as("select id, user_id, token from sessions where user_id = $1")
.bind(u.id)
- .fetch_one(&self.pool)
+ .fetch_one(self.read_pool())
.await
.map_err(fix_error)
.map(|DbSession(session)| session)
@@ -495,13 +521,13 @@ impl Database for Postgres {
#[instrument(skip_all)]
async fn oldest_history(&self, user: &User) -> DbResult<History> {
sqlx::query_as(
- "select id, client_id, user_id, hostname, timestamp, data, created_at from history
+ "select id, client_id, user_id, hostname, timestamp, data, created_at from history
where user_id = $1
order by timestamp asc
limit 1",
)
.bind(user.id)
- .fetch_one(&self.pool)
+ .fetch_one(self.read_pool())
.await
.map_err(fix_error)
.map(|DbHistory(h)| h)
@@ -606,7 +632,7 @@ impl Database for Postgres {
.bind(host)
.bind(start as i64)
.bind(count as i64)
- .fetch_all(&self.pool)
+ .fetch_all(self.read_pool())
.await
.map_err(fix_error);
@@ -650,14 +676,14 @@ impl Database for Postgres {
tracing::debug!("using idx cache for user {}", user.id);
sqlx::query_as("select host, tag, idx from store_idx_cache where user_id = $1")
.bind(user.id)
- .fetch_all(&self.pool)
+ .fetch_all(self.read_pool())
.await
.map_err(fix_error)?
} else {
tracing::debug!("using aggregate query for user {}", user.id);
sqlx::query_as(STATUS_SQL)
.bind(user.id)
- .fetch_all(&self.pool)
+ .fetch_all(self.read_pool())
.await
.map_err(fix_error)?
};
diff --git a/crates/atuin-server-sqlite/Cargo.toml b/crates/atuin-server-sqlite/Cargo.toml
index 5d22b6db..d9acf39a 100644
--- a/crates/atuin-server-sqlite/Cargo.toml
+++ b/crates/atuin-server-sqlite/Cargo.toml
@@ -10,8 +10,8 @@ homepage = { workspace = true }
repository = { workspace = true }
[dependencies]
-atuin-common = { path = "../atuin-common", version = "18.10.0" }
-atuin-server-database = { path = "../atuin-server-database", version = "18.10.0" }
+atuin-common = { path = "../atuin-common", version = "18.11.0" }
+atuin-server-database = { path = "../atuin-server-database", version = "18.11.0" }
eyre = { workspace = true }
tracing = { workspace = true }
@@ -20,5 +20,5 @@ serde = { workspace = true }
sqlx = { workspace = true, features = ["sqlite", "regexp"] }
async-trait = { workspace = true }
uuid = { workspace = true }
-metrics = "0.21.1"
+metrics = "0.24"
futures-util = "0.3"
diff --git a/crates/atuin-server-sqlite/src/lib.rs b/crates/atuin-server-sqlite/src/lib.rs
index 9cc1e8a7..83d05ea5 100644
--- a/crates/atuin-server-sqlite/src/lib.rs
+++ b/crates/atuin-server-sqlite/src/lib.rs
@@ -232,17 +232,6 @@ impl Database for Sqlite {
}
#[instrument(skip_all)]
- async fn total_history(&self) -> DbResult<i64> {
- let res: (i64,) = sqlx::query_as("select count(1) from history")
- .fetch_optional(&self.pool)
- .await
- .map_err(fix_error)?
- .unwrap_or((0,));
-
- Ok(res.0)
- }
-
- #[instrument(skip_all)]
async fn count_history(&self, user: &User) -> DbResult<i64> {
// The cache is new, and the user might not yet have a cache value.
// They will have one as soon as they post up some new history, but handle that
diff --git a/crates/atuin-server/Cargo.toml b/crates/atuin-server/Cargo.toml
index ad94c379..915ceb14 100644
--- a/crates/atuin-server/Cargo.toml
+++ b/crates/atuin-server/Cargo.toml
@@ -11,8 +11,8 @@ homepage = { workspace = true }
repository = { workspace = true }
[dependencies]
-atuin-common = { path = "../atuin-common", version = "18.10.0" }
-atuin-server-database = { path = "../atuin-server-database", version = "18.10.0" }
+atuin-common = { path = "../atuin-common", version = "18.11.0" }
+atuin-server-database = { path = "../atuin-server-database", version = "18.11.0" }
tracing = { workspace = true }
time = { workspace = true }
@@ -24,14 +24,12 @@ rand = { workspace = true }
tokio = { workspace = true }
async-trait = { workspace = true }
axum = "0.7"
-axum-server = { version = "0.7", features = ["tls-rustls-no-provider"] }
fs-err = { workspace = true }
tower = { workspace = true }
tower-http = { version = "0.6", features = ["trace"] }
reqwest = { workspace = true }
-rustls = { version = "0.23", features = ["ring"], default-features = false }
argon2 = "0.5"
semver = { workspace = true }
-metrics-exporter-prometheus = "0.12.1"
-metrics = "0.21.1"
+metrics-exporter-prometheus = "0.18"
+metrics = "0.24"
postmark = {version= "0.11", features=["reqwest", "reqwest-rustls-tls"]}
diff --git a/crates/atuin-server/server.toml b/crates/atuin-server/server.toml
index 1eff5b72..9ff95890 100644
--- a/crates/atuin-server/server.toml
+++ b/crates/atuin-server/server.toml
@@ -11,6 +11,10 @@
# db_uri="postgres://username:password@localhost/atuin"
# db_uri="sqlite:///config/atuin-server.db"
+## Optional: URI for read replica database
+## If set, read-only queries will be routed to this database
+# read_db_uri="postgres://username:password@localhost-replica/atuin"
+
## Maximum size for one history entry
# max_history_length = 8192
@@ -29,7 +33,6 @@
# host = 127.0.0.1
# port = 9001
-# [tls]
-# enable = false
-# cert_path = ""
-# pkey_path = ""
+## Enable legacy sync v1 routes (history-based sync)
+## Set to false to disable and use only the newer record-based sync
+# sync_v1_enabled = true
diff --git a/crates/atuin-server/src/handlers/history.rs b/crates/atuin-server/src/handlers/history.rs
index 5547a180..bdafcc60 100644
--- a/crates/atuin-server/src/handlers/history.rs
+++ b/crates/atuin-server/src/handlers/history.rs
@@ -65,7 +65,7 @@ pub async fn list<DB: Database>(
if req.sync_ts.unix_timestamp_nanos() < 0 || req.history_ts.unix_timestamp_nanos() < 0 {
error!("client asked for history from < epoch 0");
- counter!("atuin_history_epoch_before_zero", 1);
+ counter!("atuin_history_epoch_before_zero").increment(1);
return Err(
ErrorResponse::reply("asked for history from before epoch 0")
@@ -95,7 +95,7 @@ pub async fn list<DB: Database>(
user.id
);
- counter!("atuin_history_returned", history.len() as u64);
+ counter!("atuin_history_returned").increment(history.len() as u64);
Ok(Json(SyncHistoryResponse { history }))
}
@@ -131,7 +131,7 @@ pub async fn add<DB: Database>(
let State(AppState { database, settings }) = state;
debug!("request to add {} history items", req.len());
- counter!("atuin_history_uploaded", req.len() as u64);
+ counter!("atuin_history_uploaded").increment(req.len() as u64);
let mut history: Vec<NewHistory> = req
.into_iter()
@@ -151,7 +151,7 @@ pub async fn add<DB: Database>(
// Don't return an error here. We want to insert as much of the
// history list as we can, so log the error and continue going.
if !keep {
- counter!("atuin_history_too_long", 1);
+ counter!("atuin_history_too_long").increment(1);
tracing::warn!(
"history too long, got length {}, max {}",
diff --git a/crates/atuin-server/src/handlers/mod.rs b/crates/atuin-server/src/handlers/mod.rs
index 1b9fd162..2176ac5e 100644
--- a/crates/atuin-server/src/handlers/mod.rs
+++ b/crates/atuin-server/src/handlers/mod.rs
@@ -16,10 +16,6 @@ const VERSION: &str = env!("CARGO_PKG_VERSION");
pub async fn index<DB: Database>(state: State<AppState<DB>>) -> Json<IndexResponse> {
let homage = r#""Through the fathomless deeps of space swims the star turtle Great A'Tuin, bearing on its back the four giant elephants who carry on their shoulders the mass of the Discworld." -- Sir Terry Pratchett"#;
- // Error with a -1 response
- // It's super unlikely this will happen
- let count = state.database.total_history().await.unwrap_or(-1);
-
let version = state
.settings
.fake_version
@@ -28,7 +24,6 @@ pub async fn index<DB: Database>(state: State<AppState<DB>>) -> Json<IndexRespon
Json(IndexResponse {
homage: homage.to_string(),
- total_history: count,
version,
})
}
diff --git a/crates/atuin-server/src/handlers/user.rs b/crates/atuin-server/src/handlers/user.rs
index e493e714..4edd1787 100644
--- a/crates/atuin-server/src/handlers/user.rs
+++ b/crates/atuin-server/src/handlers/user.rs
@@ -146,7 +146,7 @@ pub async fn register<DB: Database>(
.await;
}
- counter!("atuin_users_registered", 1);
+ counter!("atuin_users_registered").increment(1);
match db.add_session(&new_session).await {
Ok(_) => Ok(Json(RegisterResponse { session: token })),
@@ -173,7 +173,7 @@ pub async fn delete<DB: Database>(
.with_status(StatusCode::INTERNAL_SERVER_ERROR));
};
- counter!("atuin_users_deleted", 1);
+ counter!("atuin_users_deleted").increment(1);
Ok(Json(DeleteUserResponse {}))
}
diff --git a/crates/atuin-server/src/handlers/v0/record.rs b/crates/atuin-server/src/handlers/v0/record.rs
index 01b91599..5c57910b 100644
--- a/crates/atuin-server/src/handlers/v0/record.rs
+++ b/crates/atuin-server/src/handlers/v0/record.rs
@@ -25,14 +25,14 @@ pub async fn post<DB: Database>(
"request to add records"
);
- counter!("atuin_record_uploaded", records.len() as u64);
+ counter!("atuin_record_uploaded").increment(records.len() as u64);
let keep = records
.iter()
.all(|r| r.data.data.len() <= settings.max_record_size || settings.max_record_size == 0);
if !keep {
- counter!("atuin_record_too_large", 1);
+ counter!("atuin_record_too_large").increment(1);
return Err(
ErrorResponse::reply("could not add records; record too large")
@@ -108,7 +108,7 @@ pub async fn next<DB: Database>(
}
};
- counter!("atuin_record_downloaded", records.len() as u64);
+ counter!("atuin_record_downloaded").increment(records.len() as u64);
Ok(Json(records))
}
diff --git a/crates/atuin-server/src/handlers/v0/store.rs b/crates/atuin-server/src/handlers/v0/store.rs
index 941f2487..6ca455d7 100644
--- a/crates/atuin-server/src/handlers/v0/store.rs
+++ b/crates/atuin-server/src/handlers/v0/store.rs
@@ -24,14 +24,14 @@ pub async fn delete<DB: Database>(
}) = state;
if let Err(e) = database.delete_store(&user).await {
- counter!("atuin_store_delete_failed", 1);
+ counter!("atuin_store_delete_failed").increment(1);
error!("failed to delete store {e:?}");
return Err(ErrorResponse::reply("failed to delete store")
.with_status(StatusCode::INTERNAL_SERVER_ERROR));
}
- counter!("atuin_store_deleted", 1);
+ counter!("atuin_store_deleted").increment(1);
Ok(())
}
diff --git a/crates/atuin-server/src/lib.rs b/crates/atuin-server/src/lib.rs
index f1d616f2..fcf5dde6 100644
--- a/crates/atuin-server/src/lib.rs
+++ b/crates/atuin-server/src/lib.rs
@@ -5,9 +5,7 @@ use std::net::SocketAddr;
use atuin_server_database::Database;
use axum::{Router, serve};
-use axum_server::Handle;
-use axum_server::tls_rustls::RustlsConfig;
-use eyre::{Context, Result, eyre};
+use eyre::{Context, Result};
mod handlers;
mod metrics;
@@ -46,18 +44,14 @@ async fn shutdown_signal() {
}
pub async fn launch<Db: Database>(settings: Settings, addr: SocketAddr) -> Result<()> {
- if settings.tls.enable {
- launch_with_tls::<Db>(settings, addr, shutdown_signal()).await
- } else {
- launch_with_tcp_listener::<Db>(
- settings,
- TcpListener::bind(addr)
- .await
- .context("could not connect to socket")?,
- shutdown_signal(),
- )
- .await
- }
+ launch_with_tcp_listener::<Db>(
+ settings,
+ TcpListener::bind(addr)
+ .await
+ .context("could not connect to socket")?,
+ shutdown_signal(),
+ )
+ .await
}
pub async fn launch_with_tcp_listener<Db: Database>(
@@ -74,43 +68,6 @@ pub async fn launch_with_tcp_listener<Db: Database>(
Ok(())
}
-async fn launch_with_tls<Db: Database>(
- settings: Settings,
- addr: SocketAddr,
- shutdown: impl Future<Output = ()>,
-) -> Result<()> {
- let crypto_provider = rustls::crypto::ring::default_provider().install_default();
- if crypto_provider.is_err() {
- return Err(eyre!("Failed to install default crypto provider"));
- }
- let rustls_config = RustlsConfig::from_pem_file(
- settings.tls.cert_path.clone(),
- settings.tls.pkey_path.clone(),
- )
- .await;
- if rustls_config.is_err() {
- return Err(eyre!("Failed to load TLS key and/or certificate"));
- }
- let rustls_config = rustls_config.unwrap();
-
- let r = make_router::<Db>(settings).await?;
-
- let handle = Handle::new();
-
- let server = axum_server::bind_rustls(addr, rustls_config)
- .handle(handle.clone())
- .serve(r.into_make_service());
-
- tokio::select! {
- _ = server => {}
- _ = shutdown => {
- handle.graceful_shutdown(None);
- }
- }
-
- Ok(())
-}
-
// The separate listener means it's much easier to ensure metrics are not accidentally exposed to
// the public.
pub async fn launch_metrics_server(host: String, port: u16) -> Result<()> {
diff --git a/crates/atuin-server/src/metrics.rs b/crates/atuin-server/src/metrics.rs
index ff0fe925..ebd0dd2d 100644
--- a/crates/atuin-server/src/metrics.rs
+++ b/crates/atuin-server/src/metrics.rs
@@ -48,8 +48,8 @@ pub async fn track_metrics(req: Request, next: Next) -> impl IntoResponse {
("status", status),
];
- metrics::increment_counter!("http_requests_total", &labels);
- metrics::histogram!("http_requests_duration_seconds", latency, &labels);
+ metrics::counter!("http_requests_total", &labels).increment(1);
+ metrics::histogram!("http_requests_duration_seconds", &labels).record(latency);
response
}
diff --git a/crates/atuin-server/src/router.rs b/crates/atuin-server/src/router.rs
index 1118ab29..9d4f7d44 100644
--- a/crates/atuin-server/src/router.rs
+++ b/crates/atuin-server/src/router.rs
@@ -109,15 +109,22 @@ pub struct AppState<DB: Database> {
}
pub fn router<DB: Database>(database: DB, settings: Settings) -> Router {
- let routes = Router::new()
+ let mut routes = Router::new()
.route("/", get(handlers::index))
- .route("/healthz", get(handlers::health::health_check))
- .route("/sync/count", get(handlers::history::count))
- .route("/sync/history", get(handlers::history::list))
- .route("/sync/calendar/:focus", get(handlers::history::calendar))
- .route("/sync/status", get(handlers::status::status))
- .route("/history", post(handlers::history::add))
- .route("/history", delete(handlers::history::delete))
+ .route("/healthz", get(handlers::health::health_check));
+
+ // Sync v1 routes - can be disabled in favor of record-based sync
+ if settings.sync_v1_enabled {
+ routes = routes
+ .route("/sync/count", get(handlers::history::count))
+ .route("/sync/history", get(handlers::history::list))
+ .route("/sync/calendar/:focus", get(handlers::history::calendar))
+ .route("/sync/status", get(handlers::status::status))
+ .route("/history", post(handlers::history::add))
+ .route("/history", delete(handlers::history::delete));
+ }
+
+ let routes = routes
.route("/user/:username", get(handlers::user::get))
.route("/account", delete(handlers::user::delete))
.route("/account/password", patch(handlers::user::change_password))
diff --git a/crates/atuin-server/src/settings.rs b/crates/atuin-server/src/settings.rs
index 7221d4dd..98d1d69f 100644
--- a/crates/atuin-server/src/settings.rs
+++ b/crates/atuin-server/src/settings.rs
@@ -65,9 +65,12 @@ pub struct Settings {
pub register_webhook_url: Option<String>,
pub register_webhook_username: String,
pub metrics: Metrics,
- pub tls: Tls,
pub mail: Mail,
+ /// Enable legacy sync v1 routes (history-based sync)
+ /// Set to false to use only the newer record-based sync
+ pub sync_v1_enabled: bool,
+
/// Advertise a version that is not what we are _actually_ running
/// Many clients compare their version with api.atuin.sh, and if they differ, notify the user
/// that an update is available.
@@ -106,9 +109,7 @@ impl Settings {
.set_default("metrics.host", "127.0.0.1")?
.set_default("metrics.port", 9001)?
.set_default("mail.enable", false)?
- .set_default("tls.enable", false)?
- .set_default("tls.cert_path", "")?
- .set_default("tls.pkey_path", "")?
+ .set_default("sync_v1_enabled", true)?
.add_source(
Environment::with_prefix("atuin")
.prefix_separator("_")
@@ -139,12 +140,3 @@ impl Settings {
pub fn example_config() -> &'static str {
EXAMPLE_CONFIG
}
-
-#[derive(Clone, Debug, Default, Deserialize, Serialize)]
-pub struct Tls {
- #[serde(alias = "enabled")]
- pub enable: bool,
-
- pub cert_path: PathBuf,
- pub pkey_path: PathBuf,
-}
diff --git a/crates/atuin/Cargo.toml b/crates/atuin/Cargo.toml
index 52f245ac..9c4e3de8 100644
--- a/crates/atuin/Cargo.toml
+++ b/crates/atuin/Cargo.toml
@@ -47,17 +47,17 @@ clipboard = ["arboard"]
check-update = ["atuin-client/check-update"]
[dependencies]
-atuin-server-database = { path = "../atuin-server-database", version = "18.10.0", optional = true }
-atuin-server-postgres = { path = "../atuin-server-postgres", version = "18.10.0", optional = true }
-atuin-server-sqlite = { path = "../atuin-server-sqlite", version = "18.10.0", optional = true }
-atuin-server = { path = "../atuin-server", version = "18.10.0", optional = true }
-atuin-client = { path = "../atuin-client", version = "18.10.0", optional = true, default-features = false }
-atuin-common = { path = "../atuin-common", version = "18.10.0" }
-atuin-dotfiles = { path = "../atuin-dotfiles", version = "18.10.0" }
-atuin-history = { path = "../atuin-history", version = "18.10.0" }
-atuin-daemon = { path = "../atuin-daemon", version = "18.10.0", optional = true, default-features = false }
-atuin-scripts = { path = "../atuin-scripts", version = "18.10.0" }
-atuin-kv = { path = "../atuin-kv", version = "18.10.0" }
+atuin-server-database = { path = "../atuin-server-database", version = "18.11.0", optional = true }
+atuin-server-postgres = { path = "../atuin-server-postgres", version = "18.11.0", optional = true }
+atuin-server-sqlite = { path = "../atuin-server-sqlite", version = "18.11.0", optional = true }
+atuin-server = { path = "../atuin-server", version = "18.11.0", optional = true }
+atuin-client = { path = "../atuin-client", version = "18.11.0", optional = true, default-features = false }
+atuin-common = { path = "../atuin-common", version = "18.11.0" }
+atuin-dotfiles = { path = "../atuin-dotfiles", version = "18.11.0" }
+atuin-history = { path = "../atuin-history", version = "18.11.0" }
+atuin-daemon = { path = "../atuin-daemon", version = "18.11.0", optional = true, default-features = false }
+atuin-scripts = { path = "../atuin-scripts", version = "18.11.0" }
+atuin-kv = { path = "../atuin-kv", version = "18.11.0" }
log = { workspace = true }
time = { workspace = true }
diff --git a/crates/atuin/src/command/client.rs b/crates/atuin/src/command/client.rs
index 330fef0c..a0d4373f 100644
--- a/crates/atuin/src/command/client.rs
+++ b/crates/atuin/src/command/client.rs
@@ -176,7 +176,7 @@ impl Cmd {
Ok(())
}
- Self::Wrapped { year } => wrapped::run(year, &db, &settings, theme).await,
+ Self::Wrapped { year } => wrapped::run(year, &db, &settings, sqlite_store, theme).await,
#[cfg(feature = "daemon")]
Self::Daemon => daemon::run(settings, sqlite_store, db).await,
diff --git a/crates/atuin/src/command/client/account/verify.rs b/crates/atuin/src/command/client/account/verify.rs
index 7c707117..1533c283 100644
--- a/crates/atuin/src/command/client/account/verify.rs
+++ b/crates/atuin/src/command/client/account/verify.rs
@@ -36,7 +36,7 @@ pub async fn run(settings: &Settings, token: Option<String>) -> Result<()> {
(false, false) => {
println!(
- "Your Atuin server does not have mail setup. This is not required, though your account cannot be verified. Speak to your admin."
+ "Your Atuin server does not have mail set up. This is not required, though your account cannot be verified. Speak to your admin."
);
}
diff --git a/crates/atuin/src/command/client/history.rs b/crates/atuin/src/command/client/history.rs
index 028db5f1..c85f6c49 100644
--- a/crates/atuin/src/command/client/history.rs
+++ b/crates/atuin/src/command/client/history.rs
@@ -85,7 +85,7 @@ pub enum Cmd {
#[arg(long, visible_alias = "tz")]
timezone: Option<Timezone>,
- /// Available variables: {command}, {directory}, {duration}, {user}, {host}, {exit} and {time}.
+ /// Available variables: {command}, {directory}, {duration}, {user}, {host}, {exit}, {time}, {session}, and {uuid}
/// Example: --format "{time} - [{duration}] - {directory}$\t{command}"
#[arg(long, short)]
format: Option<String>,
@@ -108,7 +108,7 @@ pub enum Cmd {
#[arg(long, visible_alias = "tz")]
timezone: Option<Timezone>,
- /// Available variables: {command}, {directory}, {duration}, {user}, {host} and {time}.
+ /// Available variables: {command}, {directory}, {duration}, {user}, {host}, {time}, {session}, {uuid} and {relativetime}.
/// Example: --format "{time} - [{duration}] - {directory}$\t{command}"
#[arg(long, short)]
format: Option<String>,
@@ -320,6 +320,8 @@ impl FormatKey for FmtHistory<'_> {
.split_once(':')
.map_or("", |(_, user)| user),
)?,
+ "session" => f.write_str(&self.history.session)?,
+ "uuid" => f.write_str(&self.history.id.0)?,
_ => return Err(FormatKeyError::UnknownKey),
}
Ok(())
@@ -514,7 +516,10 @@ impl Cmd {
(true, true) => [Session, Directory],
(true, false) => [Session, Global],
(false, true) => [Global, Directory],
- (false, false) => [settings.default_filter_mode(), Global],
+ (false, false) => [
+ settings.default_filter_mode(context.git_root.is_some()),
+ Global,
+ ],
};
let history = db
diff --git a/crates/atuin/src/command/client/scripts.rs b/crates/atuin/src/command/client/scripts.rs
index 65ceabde..851755af 100644
--- a/crates/atuin/src/command/client/scripts.rs
+++ b/crates/atuin/src/command/client/scripts.rs
@@ -230,7 +230,7 @@ impl Cmd {
let context = atuin_client::database::current_context();
// Get the last N+1 commands, filtering by the default mode
- let filters = [settings.default_filter_mode()];
+ let filters = [settings.default_filter_mode(context.git_root.is_some())];
let mut history = history_db
.list(&filters, &context, Some(count), false, false)
diff --git a/crates/atuin/src/command/client/search.rs b/crates/atuin/src/command/client/search.rs
index 4103901a..be00ee99 100644
--- a/crates/atuin/src/command/client/search.rs
+++ b/crates/atuin/src/command/client/search.rs
@@ -314,7 +314,7 @@ async fn run_non_interactive(
..filter_options
};
- let filter_mode = settings.default_filter_mode();
+ let filter_mode = settings.default_filter_mode(context.git_root.is_some());
let results = db
.search(
diff --git a/crates/atuin/src/command/client/search/engines/skim.rs b/crates/atuin/src/command/client/search/engines/skim.rs
index 1af49574..cb7ce24f 100644
--- a/crates/atuin/src/command/client/search/engines/skim.rs
+++ b/crates/atuin/src/command/client/search/engines/skim.rs
@@ -203,7 +203,7 @@ fn path_dist(a: &Path, b: &Path) -> usize {
let mut dist = 0;
- // pop a until there's a common anscestor
+ // pop a until there's a common ancestor
while !b.starts_with(&a) {
dist += 1;
a.pop();
diff --git a/crates/atuin/src/command/client/search/history_list.rs b/crates/atuin/src/command/client/search/history_list.rs
index 899308db..565a7972 100644
--- a/crates/atuin/src/command/client/search/history_list.rs
+++ b/crates/atuin/src/command/client/search/history_list.rs
@@ -4,6 +4,7 @@ use super::duration::format_duration;
use super::engines::SearchEngine;
use atuin_client::{
history::History,
+ settings::{UiColumn, UiColumnType},
theme::{Meaning, Theme},
};
use atuin_common::utils::Escapable as _;
@@ -40,6 +41,8 @@ pub struct HistoryList<'a> {
theme: &'a Theme,
history_highlighter: HistoryHighlighter<'a>,
show_numeric_shortcuts: bool,
+ /// Columns to display (in order, after the indicator)
+ columns: &'a [UiColumn],
}
#[derive(Default)]
@@ -58,6 +61,10 @@ impl ListState {
self.max_entries
}
+ pub fn offset(&self) -> usize {
+ self.offset
+ }
+
pub fn select(&mut self, index: usize) {
self.selected = index;
}
@@ -95,13 +102,11 @@ impl StatefulWidget for HistoryList<'_> {
theme: self.theme,
history_highlighter: self.history_highlighter,
show_numeric_shortcuts: self.show_numeric_shortcuts,
+ columns: self.columns,
};
for item in self.history.iter().skip(state.offset).take(end - start) {
- s.index();
- s.duration(item);
- s.time(item);
- s.command(item);
+ s.render_row(item);
// reset line
s.y += 1;
@@ -121,6 +126,7 @@ impl<'a> HistoryList<'a> {
theme: &'a Theme,
history_highlighter: HistoryHighlighter<'a>,
show_numeric_shortcuts: bool,
+ columns: &'a [UiColumn],
) -> Self {
Self {
history,
@@ -132,6 +138,7 @@ impl<'a> HistoryList<'a> {
theme,
history_highlighter,
show_numeric_shortcuts,
+ columns,
}
}
@@ -168,19 +175,53 @@ struct DrawState<'a> {
theme: &'a Theme,
history_highlighter: HistoryHighlighter<'a>,
show_numeric_shortcuts: bool,
+ columns: &'a [UiColumn],
}
-// longest line prefix I could come up with
-#[allow(clippy::cast_possible_truncation)] // we know that this is <65536 length
-pub const PREFIX_LENGTH: u16 = " > 123ms 59s ago".len() as u16;
-static SPACES: &str = " ";
-static _ASSERT: () = assert!(SPACES.len() == PREFIX_LENGTH as usize);
-
// these encode the slices of `" > "`, `" {n} "`, or `" "` in a compact form.
// Yes, this is a hack, but it makes me feel happy
static SLICES: &str = " > 1 2 3 4 5 6 7 8 9 ";
impl DrawState<'_> {
+ /// Render a complete row for a history item based on configured columns.
+ fn render_row(&mut self, h: &History) {
+ // Always render the indicator first (width 3)
+ self.index();
+
+ // Calculate the width for the expanding column
+ // Fixed columns use their configured width + 1 (trailing space)
+ let indicator_width: u16 = 3;
+ let fixed_width: u16 = self
+ .columns
+ .iter()
+ .filter(|c| !c.expand)
+ .map(|c| c.width + 1)
+ .sum();
+ let expand_width = self
+ .list_area
+ .width
+ .saturating_sub(indicator_width + fixed_width);
+
+ // Render each configured column
+ for column in self.columns {
+ let width = if column.expand {
+ expand_width
+ } else {
+ column.width
+ };
+ match column.column_type {
+ UiColumnType::Duration => self.duration(h, width),
+ UiColumnType::Time => self.time(h, width),
+ UiColumnType::Datetime => self.datetime(h, width),
+ UiColumnType::Directory => self.directory(h, width),
+ UiColumnType::Host => self.host(h, width),
+ UiColumnType::User => self.user(h, width),
+ UiColumnType::Exit => self.exit_code(h, width),
+ UiColumnType::Command => self.command(h),
+ }
+ }
+ }
+
fn index(&mut self) {
if !self.show_numeric_shortcuts {
let i = self.y as usize + self.state.offset;
@@ -204,18 +245,21 @@ impl DrawState<'_> {
self.draw(prompt, Style::default());
}
- fn duration(&mut self, h: &History) {
- let status = self.theme.as_style(if h.success() {
+ fn duration(&mut self, h: &History, width: u16) {
+ let style = self.theme.as_style(if h.success() {
Meaning::AlertInfo
} else {
Meaning::AlertError
});
let duration = Duration::from_nanos(u64::try_from(h.duration).unwrap_or(0));
- self.draw(&format_duration(duration), status.into());
+ let formatted = format_duration(duration);
+ let w = width as usize;
+ // Right-align duration within its column width, plus trailing space
+ let display = format!("{formatted:>w$} ");
+ self.draw(&display, style.into());
}
- #[allow(clippy::cast_possible_truncation)] // we know that time.len() will be <6
- fn time(&mut self, h: &History) {
+ fn time(&mut self, h: &History, width: u16) {
let style = self.theme.as_style(Meaning::Guidance);
// Account for the chance that h.timestamp is "in the future"
@@ -226,14 +270,11 @@ impl DrawState<'_> {
let since = (self.now)() - h.timestamp;
let time = format_duration(since.try_into().unwrap_or_default());
- // pad the time a little bit before we write. this aligns things nicely
- // skip padding if for some reason it is already too long to align nicely
- let padding =
- usize::from(PREFIX_LENGTH).saturating_sub(usize::from(self.x) + 4 + time.len());
- self.draw(&SPACES[..padding], Style::default());
-
- self.draw(&time, style.into());
- self.draw(" ago", style.into());
+ // Format as "Xs ago" right-aligned within column width, plus trailing space
+ let w = width as usize;
+ let time_str = format!("{time} ago");
+ let display = format!("{time_str:>w$} ");
+ self.draw(&display, style.into());
}
fn command(&mut self, h: &History) {
@@ -257,7 +298,9 @@ impl DrawState<'_> {
let mut pos = 0;
for section in h.command.escape_control().split_ascii_whitespace() {
- self.draw(" ", style.into());
+ if pos != 0 {
+ self.draw(" ", style.into());
+ }
for ch in section.chars() {
if self.x > self.list_area.width {
// Avoid attempting to draw a command section beyond the width
@@ -273,13 +316,93 @@ impl DrawState<'_> {
}
style.attributes.set(style::Attribute::Bold);
}
- self.draw(&ch.to_string(), style.into());
- pos += 1;
+ let s = ch.to_string();
+ self.draw(&s, style.into());
+ pos += s.len();
}
pos += 1;
}
}
+ /// Render the absolute datetime column (e.g., "2025-01-22 14:35")
+ fn datetime(&mut self, h: &History, width: u16) {
+ let style = self.theme.as_style(Meaning::Annotation);
+ // Format: YYYY-MM-DD HH:MM
+ let formatted = h
+ .timestamp
+ .format(
+ &time::format_description::parse("[year]-[month]-[day] [hour]:[minute]")
+ .expect("valid format"),
+ )
+ .unwrap_or_else(|_| "????-??-?? ??:??".to_string());
+ let w = width as usize;
+ let display = format!("{formatted:w$} ");
+ self.draw(&display, style.into());
+ }
+
+ /// Render the directory column (working directory, truncated)
+ fn directory(&mut self, h: &History, width: u16) {
+ let style = self.theme.as_style(Meaning::Annotation);
+ let w = width as usize;
+ let cwd = &h.cwd;
+ let char_count = cwd.chars().count();
+ // Truncate from the left with "..." if too long, plus trailing space
+ // Use character count for comparison and skip for UTF-8 safety
+ let display = if char_count > w && w >= 4 {
+ let truncated: String = cwd.chars().skip(char_count - (w - 3)).collect();
+ format!("...{truncated} ")
+ } else {
+ format!("{cwd:w$} ")
+ };
+ self.draw(&display, style.into());
+ }
+
+ /// Render the host column (just the hostname)
+ fn host(&mut self, h: &History, width: u16) {
+ let style = self.theme.as_style(Meaning::Annotation);
+ let w = width as usize - 1;
+ // Database stores hostname as "hostname:username"
+ let host = h.hostname.split(':').next().unwrap_or(&h.hostname);
+ let char_count = host.chars().count();
+ // Use character count for comparison and take for UTF-8 safety
+ let display = if char_count > w && w >= 4 {
+ let truncated: String = host.chars().take(w.saturating_sub(4)).collect();
+ format!("{truncated}... ")
+ } else {
+ format!("{host:w$} ")
+ };
+ self.draw(&display, style.into());
+ }
+
+ /// Render the user column
+ fn user(&mut self, h: &History, width: u16) {
+ let style = self.theme.as_style(Meaning::Annotation);
+ let w = width as usize;
+ // Database stores hostname as "hostname:username"
+ let user = h.hostname.split(':').nth(1).unwrap_or("");
+ let char_count = user.chars().count();
+ // Use character count for comparison and take for UTF-8 safety
+ let display = if char_count > w && w >= 4 {
+ let truncated: String = user.chars().take(w.saturating_sub(4)).collect();
+ format!("{truncated}... ")
+ } else {
+ format!("{user:w$} ")
+ };
+ self.draw(&display, style.into());
+ }
+
+ /// Render the exit code column
+ fn exit_code(&mut self, h: &History, width: u16) {
+ let style = if h.success() {
+ self.theme.as_style(Meaning::AlertInfo)
+ } else {
+ self.theme.as_style(Meaning::AlertError)
+ };
+ let w = width as usize;
+ let display = format!("{:>w$} ", h.exit);
+ self.draw(&display, style.into());
+ }
+
fn draw(&mut self, s: &str, mut style: Style) {
let cx = self.list_area.left() + self.x;
diff --git a/crates/atuin/src/command/client/search/inspector.rs b/crates/atuin/src/command/client/search/inspector.rs
index 34d22eba..890f7ff7 100644
--- a/crates/atuin/src/command/client/search/inspector.rs
+++ b/crates/atuin/src/command/client/search/inspector.rs
@@ -138,8 +138,8 @@ pub fn draw_stats_table(
format_duration(avg_duration),
]),
Row::new(vec!["Exit".to_string(), history.exit.to_string()]),
- Row::new(vec!["Directory".to_string(), history.cwd.to_string()]),
- Row::new(vec!["Session".to_string(), history.session.to_string()]),
+ Row::new(vec!["Directory".to_string(), history.cwd.clone()]),
+ Row::new(vec!["Session".to_string(), history.session.clone()]),
Row::new(vec!["Total runs".to_string(), stats.total.to_string()]),
];
diff --git a/crates/atuin/src/command/client/search/interactive.rs b/crates/atuin/src/command/client/search/interactive.rs
index 930f634c..bda4873d 100644
--- a/crates/atuin/src/command/client/search/interactive.rs
+++ b/crates/atuin/src/command/client/search/interactive.rs
@@ -13,13 +13,13 @@ use unicode_width::UnicodeWidthStr;
use super::{
cursor::Cursor,
engines::{SearchEngine, SearchState},
- history_list::{HistoryList, ListState, PREFIX_LENGTH},
+ history_list::{HistoryList, ListState},
};
use atuin_client::{
database::{Database, current_context},
history::{History, HistoryId, HistoryStats, store::HistoryStore},
settings::{
- CursorStyle, ExitMode, FilterMode, KeymapMode, PreviewStrategy, SearchMode, Settings,
+ CursorStyle, ExitMode, KeymapMode, PreviewStrategy, SearchMode, Settings, UiColumn,
},
};
@@ -119,6 +119,7 @@ pub struct State {
prefix: bool,
current_cursor: Option<CursorStyle>,
tab_index: usize,
+ pending_vim_key: Option<char>,
pub inspecting_state: InspectingState,
@@ -306,6 +307,9 @@ impl State {
{
Some(InputAction::Accept(self.results_state.selected()))
}
+ KeyCode::Left | KeyCode::Backspace if self.search.input.as_str().is_empty() => {
+ Some(InputAction::Accept(self.results_state.selected()))
+ }
KeyCode::Char('o') if ctrl => {
self.tab_index = (self.tab_index + 1) % TAB_TITLES.len();
Some(InputAction::Continue)
@@ -398,60 +402,175 @@ impl State {
// handle keymap specific keybindings.
match self.keymap_mode {
- KeymapMode::VimNormal => match input.code {
- KeyCode::Char('?' | '/') if !ctrl => {
- self.search.input.clear();
- self.set_keymap_cursor(settings, "vim_insert");
- self.keymap_mode = KeymapMode::VimInsert;
- return InputAction::Continue;
- }
- KeyCode::Char('j') if !ctrl => {
- return self.handle_search_down(settings, true);
- }
- KeyCode::Char('k') if !ctrl => {
- return self.handle_search_up(settings, true);
- }
- KeyCode::Char('h') if !ctrl => {
- self.search.input.left();
- return InputAction::Continue;
- }
- KeyCode::Char('l') if !ctrl => {
- self.search.input.right();
- return InputAction::Continue;
- }
- KeyCode::Char('a') if !ctrl => {
- self.search.input.right();
- self.set_keymap_cursor(settings, "vim_insert");
- self.keymap_mode = KeymapMode::VimInsert;
- return InputAction::Continue;
- }
- KeyCode::Char('A') if !ctrl => {
- self.search.input.end();
- self.set_keymap_cursor(settings, "vim_insert");
- self.keymap_mode = KeymapMode::VimInsert;
- return InputAction::Continue;
- }
- KeyCode::Char('i') if !ctrl => {
- self.set_keymap_cursor(settings, "vim_insert");
- self.keymap_mode = KeymapMode::VimInsert;
- return InputAction::Continue;
- }
- KeyCode::Char('I') if !ctrl => {
- self.search.input.start();
- self.set_keymap_cursor(settings, "vim_insert");
- self.keymap_mode = KeymapMode::VimInsert;
- return InputAction::Continue;
- }
- KeyCode::Char(c @ '1'..='9') => {
- return c.to_digit(10).map_or(InputAction::Continue, |c| {
- InputAction::Accept(self.results_state.selected() + c as usize)
- });
+ KeymapMode::VimNormal => {
+ // Reset pending key unless this is 'g' (for gg sequence)
+ if !matches!(input.code, KeyCode::Char('g')) || ctrl {
+ self.pending_vim_key = None;
}
- KeyCode::Char(_) if !ctrl => {
- return InputAction::Continue;
+
+ match input.code {
+ KeyCode::Char('?' | '/') if !ctrl => {
+ self.search.input.clear();
+ self.set_keymap_cursor(settings, "vim_insert");
+ self.keymap_mode = KeymapMode::VimInsert;
+ return InputAction::Continue;
+ }
+ KeyCode::Char('j') if !ctrl => {
+ return self.handle_search_down(settings, true);
+ }
+ KeyCode::Char('k') if !ctrl => {
+ return self.handle_search_up(settings, true);
+ }
+ KeyCode::Char('h') if !ctrl => {
+ self.search.input.left();
+ return InputAction::Continue;
+ }
+ KeyCode::Char('l') if !ctrl => {
+ self.search.input.right();
+ return InputAction::Continue;
+ }
+ KeyCode::Char('a') if !ctrl => {
+ self.search.input.right();
+ self.set_keymap_cursor(settings, "vim_insert");
+ self.keymap_mode = KeymapMode::VimInsert;
+ return InputAction::Continue;
+ }
+ KeyCode::Char('A') if !ctrl => {
+ self.search.input.end();
+ self.set_keymap_cursor(settings, "vim_insert");
+ self.keymap_mode = KeymapMode::VimInsert;
+ return InputAction::Continue;
+ }
+ KeyCode::Char('i') if !ctrl => {
+ self.set_keymap_cursor(settings, "vim_insert");
+ self.keymap_mode = KeymapMode::VimInsert;
+ return InputAction::Continue;
+ }
+ KeyCode::Char('I') if !ctrl => {
+ self.search.input.start();
+ self.set_keymap_cursor(settings, "vim_insert");
+ self.keymap_mode = KeymapMode::VimInsert;
+ return InputAction::Continue;
+ }
+ KeyCode::Char(c @ '1'..='9') => {
+ return c.to_digit(10).map_or(InputAction::Continue, |c| {
+ InputAction::Accept(self.results_state.selected() + c as usize)
+ });
+ }
+ KeyCode::Char('u') if ctrl => {
+ // Half-page up (toward visual top)
+ let scroll_len = self
+ .results_state
+ .max_entries()
+ .saturating_sub(settings.scroll_context_lines)
+ / 2;
+ if settings.invert {
+ self.scroll_down(scroll_len);
+ } else {
+ self.scroll_up(scroll_len);
+ }
+ return InputAction::Continue;
+ }
+ KeyCode::Char('d') if ctrl => {
+ // Half-page down (toward visual bottom)
+ let scroll_len = self
+ .results_state
+ .max_entries()
+ .saturating_sub(settings.scroll_context_lines)
+ / 2;
+ if settings.invert {
+ self.scroll_up(scroll_len);
+ } else {
+ self.scroll_down(scroll_len);
+ }
+ return InputAction::Continue;
+ }
+ KeyCode::Char('b') if ctrl => {
+ // Full-page up (toward visual top)
+ let scroll_len = self
+ .results_state
+ .max_entries()
+ .saturating_sub(settings.scroll_context_lines);
+ if settings.invert {
+ self.scroll_down(scroll_len);
+ } else {
+ self.scroll_up(scroll_len);
+ }
+ return InputAction::Continue;
+ }
+ KeyCode::Char('f') if ctrl => {
+ // Full-page down (toward visual bottom)
+ let scroll_len = self
+ .results_state
+ .max_entries()
+ .saturating_sub(settings.scroll_context_lines);
+ if settings.invert {
+ self.scroll_up(scroll_len);
+ } else {
+ self.scroll_down(scroll_len);
+ }
+ return InputAction::Continue;
+ }
+ KeyCode::Char('G') if !ctrl => {
+ // Jump to visual bottom of history
+ if settings.invert {
+ let last_idx = self.results_len.saturating_sub(1);
+ self.results_state.select(last_idx);
+ } else {
+ self.results_state.select(0);
+ }
+ self.inspecting_state.reset();
+ return InputAction::Continue;
+ }
+ KeyCode::Char('g') if !ctrl => {
+ if self.pending_vim_key == Some('g') {
+ // gg - jump to visual top of history
+ if settings.invert {
+ self.results_state.select(0);
+ } else {
+ let last_idx = self.results_len.saturating_sub(1);
+ self.results_state.select(last_idx);
+ }
+ self.inspecting_state.reset();
+ self.pending_vim_key = None;
+ } else {
+ self.pending_vim_key = Some('g');
+ }
+ return InputAction::Continue;
+ }
+ KeyCode::Char('H') if !ctrl => {
+ // Jump to top of visible screen
+ let top = self.results_state.offset();
+ let visible = self.results_state.max_entries().min(self.results_len);
+ let bottom = top + visible.saturating_sub(1);
+ self.results_state
+ .select(bottom.min(self.results_len.saturating_sub(1)));
+ self.inspecting_state.reset();
+ return InputAction::Continue;
+ }
+ KeyCode::Char('M') if !ctrl => {
+ // Jump to middle of visible screen
+ let top = self.results_state.offset();
+ let visible = self.results_state.max_entries().min(self.results_len);
+ let middle = top + visible / 2;
+ self.results_state
+ .select(middle.min(self.results_len.saturating_sub(1)));
+ self.inspecting_state.reset();
+ return InputAction::Continue;
+ }
+ KeyCode::Char('L') if !ctrl => {
+ // Jump to bottom of visible screen
+ let top_visible = self.results_state.offset();
+ self.results_state.select(top_visible);
+ self.inspecting_state.reset();
+ return InputAction::Continue;
+ }
+ KeyCode::Char(_) if !ctrl => {
+ return InputAction::Continue;
+ }
+ _ => {}
}
- _ => {}
- },
+ }
KeymapMode::VimInsert => {
if input.code == KeyCode::Esc || (ctrl && input.code == KeyCode::Char('[')) {
self.set_keymap_cursor(settings, "vim_normal");
@@ -825,6 +944,7 @@ impl State {
theme,
history_highlighter,
settings.show_numeric_shortcuts,
+ &settings.ui.columns,
);
f.render_stateful_widget(results_list, results_list_chunk, &mut self.results_state);
}
@@ -884,11 +1004,27 @@ impl State {
preview_chunk.width.into(),
theme,
);
- self.draw_preview(f, style, input_chunk, compactness, preview_chunk, preview);
+ #[allow(clippy::cast_possible_truncation)]
+ let prefix_width = settings
+ .ui
+ .columns
+ .iter()
+ .filter_map(|col| if col.expand { None } else { Some(col.width) })
+ .sum::<u16>()
+ + " > ".len() as u16;
+ self.draw_preview(
+ f,
+ style,
+ input_chunk,
+ compactness,
+ preview_chunk,
+ preview,
+ prefix_width,
+ );
}
}
- #[allow(clippy::cast_possible_truncation)]
+ #[allow(clippy::cast_possible_truncation, clippy::too_many_arguments)]
fn draw_preview(
&self,
f: &mut Frame,
@@ -897,8 +1033,9 @@ impl State {
compactness: Compactness,
preview_chunk: Rect,
preview: Paragraph,
+ prefix_width: u16,
) {
- let input = self.build_input(style);
+ let input = self.build_input(style, prefix_width - 2);
f.render_widget(input, input_chunk);
f.render_widget(preview, preview_chunk);
@@ -911,7 +1048,7 @@ impl State {
};
f.set_cursor_position((
// Put cursor past the end of the input text
- input_chunk.x + extra_width as u16 + PREFIX_LENGTH + 1 + cursor_offset,
+ input_chunk.x + extra_width as u16 + prefix_width + 1 + cursor_offset,
input_chunk.y + cursor_offset,
));
}
@@ -920,7 +1057,7 @@ impl State {
let title = if self.update_needed.is_some() {
let error_style: Style = theme.get_error().into();
Paragraph::new(Text::from(Span::styled(
- format!("Atuin v{VERSION} - UPGRADE"),
+ format!("Atuin v{VERSION} - UPDATE"),
error_style.add_modifier(Modifier::BOLD),
)))
} else {
@@ -991,6 +1128,7 @@ impl State {
theme: &'a Theme,
history_highlighter: HistoryHighlighter<'a>,
show_numeric_shortcuts: bool,
+ columns: &'a [UiColumn],
) -> HistoryList<'a> {
let results_list = HistoryList::new(
results,
@@ -1001,6 +1139,7 @@ impl State {
theme,
history_highlighter,
show_numeric_shortcuts,
+ columns,
);
match style.compactness {
@@ -1024,15 +1163,13 @@ impl State {
}
}
- fn build_input(&self, style: StyleState) -> Paragraph<'_> {
- /// Max width of the UI box showing current mode
- const MAX_WIDTH: usize = 14;
+ fn build_input(&self, style: StyleState, max_width: u16) -> Paragraph<'_> {
let (pref, mode) = if self.switched_search_mode {
(" SRCH:", self.search_mode.as_str())
} else {
("", self.search.filter_mode.as_str())
};
- let mode_width = MAX_WIDTH - pref.len();
+ let mode_width = usize::from(max_width) - pref.len();
// sanity check to ensure we don't exceed the layout limits
debug_assert!(mode_width >= mode.len(), "mode name '{mode}' is too long!");
let input = format!("[{pref}{mode:^mode_width$}] {}", self.search.input.as_str(),);
@@ -1260,9 +1397,7 @@ pub async fn history(
filter_mode: settings
.filter_mode_shell_up_key_binding
.filter(|_| settings.shell_up_key_binding)
- .or_else(|| Some(settings.default_filter_mode()))
- .filter(|&x| x != FilterMode::Workspace || context.git_root.is_some())
- .unwrap_or(FilterMode::Global),
+ .unwrap_or_else(|| settings.default_filter_mode(context.git_root.is_some())),
context,
},
engine: engines::engine(search_mode),
@@ -1280,6 +1415,7 @@ pub async fn history(
Box::new(OffsetDateTime::now_utc)
},
prefix: false,
+ pending_vim_key: None,
};
app.initialize_keymap_cursor(settings);
@@ -1355,7 +1491,9 @@ pub async fn history(
}
}
update_needed = &mut update_needed => {
- app.update_needed = update_needed?;
+ // Don't fail interactive search if update check fails
+ // The update check is a nice-to-have feature, not critical
+ app.update_needed = update_needed.ok().flatten();
}
}
@@ -1666,6 +1804,7 @@ mod tests {
prefix: false,
current_cursor: None,
tab_index: 0,
+ pending_vim_key: None,
inspecting_state: InspectingState {
current: None,
next: None,
@@ -1717,6 +1856,7 @@ mod tests {
prefix: false,
current_cursor: None,
tab_index: 0,
+ pending_vim_key: None,
inspecting_state: InspectingState {
current: None,
next: None,
@@ -1744,42 +1884,62 @@ mod tests {
"Tab should always accept"
);
- // Test left arrow with accept_past_line_start disabled (should continue)
+ // Test left arrow with empty search should accept (new default behavior)
let left_event = KeyEvent::new(KeyCode::Left, KeyModifiers::NONE);
let result = state.handle_key_input(&settings, &left_event);
assert!(
- matches!(result, super::InputAction::Continue),
- "Left arrow should continue when disabled"
+ matches!(result, super::InputAction::Accept(_)),
+ "Left arrow should accept when search is empty"
);
- // Test left arrow with accept_past_line_start enabled (should accept at start of line)
- settings.keys.accept_past_line_start = true;
- let result = state.handle_key_input(&settings, &left_event);
+ // Test backspace with empty search should accept (new default behavior)
+ let backspace_event = KeyEvent::new(KeyCode::Backspace, KeyModifiers::NONE);
+ let result = state.handle_key_input(&settings, &backspace_event);
assert!(
matches!(result, super::InputAction::Accept(_)),
- "Left arrow should accept at start of line when enabled"
+ "Backspace should accept when search is empty"
+ );
+
+ // Test left/backspace with non-empty search at cursor start should NOT accept
+ state.search.input.insert('t');
+ state.search.input.insert('e');
+ state.search.input.insert('s');
+ state.search.input.insert('t');
+ state.search.input.start(); // Move cursor to start of non-empty search
+
+ let left_event = KeyEvent::new(KeyCode::Left, KeyModifiers::NONE);
+ let result = state.handle_key_input(&settings, &left_event);
+ assert!(
+ matches!(result, super::InputAction::Continue),
+ "Left arrow should continue when search is not empty (even at cursor start)"
);
- settings.keys.accept_past_line_start = false;
let backspace_event = KeyEvent::new(KeyCode::Backspace, KeyModifiers::NONE);
let result = state.handle_key_input(&settings, &backspace_event);
assert!(
matches!(result, super::InputAction::Continue),
- "Backspace should continue when disabled"
+ "Backspace should continue when search is not empty (even at cursor start)"
);
+ // Test that accept_past_line_start flag still works with non-empty search at start
+ settings.keys.accept_past_line_start = true;
+ let result = state.handle_key_input(&settings, &left_event);
+ assert!(
+ matches!(result, super::InputAction::Accept(_)),
+ "Left arrow should accept at cursor start when flag enabled (even with non-empty search)"
+ );
+ settings.keys.accept_past_line_start = false;
+
+ // Test that accept_with_backspace flag still works with non-empty search at start
settings.keys.accept_with_backspace = true;
let result = state.handle_key_input(&settings, &backspace_event);
assert!(
matches!(result, super::InputAction::Accept(_)),
- "Backspace should accept at start of line when enabled"
+ "Backspace should accept at cursor start when flag enabled (even with non-empty search)"
);
+ settings.keys.accept_with_backspace = false;
- state.search.input.insert('t');
- state.search.input.insert('e');
- state.search.input.insert('s');
- state.search.input.insert('t');
- state.search.input.end();
+ state.search.input.end(); // Move cursor back to end for remaining tests
let right_event = KeyEvent::new(KeyCode::Right, KeyModifiers::NONE);
let result = state.handle_key_input(&settings, &right_event);
@@ -1806,4 +1966,274 @@ mod tests {
);
settings.keys.accept_with_backspace = false;
}
+
+ #[test]
+ fn test_vim_gg_multikey_sequence() {
+ use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
+
+ let settings = Settings::utc();
+
+ let mut state = State {
+ history_count: 100,
+ update_needed: None,
+ results_state: ListState::default(),
+ switched_search_mode: false,
+ search_mode: SearchMode::Fuzzy,
+ results_len: 100,
+ accept: false,
+ keymap_mode: KeymapMode::VimNormal,
+ prefix: false,
+ current_cursor: None,
+ tab_index: 0,
+ pending_vim_key: None,
+ inspecting_state: InspectingState {
+ current: None,
+ next: None,
+ previous: None,
+ },
+ search: SearchState {
+ input: String::new().into(),
+ filter_mode: FilterMode::Global,
+ context: Context {
+ session: String::new(),
+ cwd: String::new(),
+ hostname: String::new(),
+ host_id: String::new(),
+ git_root: None,
+ },
+ },
+ engine: engines::engine(SearchMode::Fuzzy),
+ now: Box::new(OffsetDateTime::now_utc),
+ };
+
+ // Start in the middle of the list
+ state.results_state.select(50);
+
+ // First 'g' should set pending state
+ let g_event = KeyEvent::new(KeyCode::Char('g'), KeyModifiers::NONE);
+ let result = state.handle_key_input(&settings, &g_event);
+ assert!(matches!(result, super::InputAction::Continue));
+ assert_eq!(state.pending_vim_key, Some('g'));
+ assert_eq!(state.results_state.selected(), 50); // Position unchanged
+
+ // Second 'g' should jump to end (visual top in non-inverted mode)
+ let result = state.handle_key_input(&settings, &g_event);
+ assert!(matches!(result, super::InputAction::Continue));
+ assert_eq!(state.pending_vim_key, None);
+ assert_eq!(state.results_state.selected(), 99); // Jumped to last index (visual top)
+ }
+
+ #[test]
+ fn test_vim_g_key_clears_on_other_input() {
+ use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
+
+ let settings = Settings::utc();
+
+ let mut state = State {
+ history_count: 100,
+ update_needed: None,
+ results_state: ListState::default(),
+ switched_search_mode: false,
+ search_mode: SearchMode::Fuzzy,
+ results_len: 100,
+ accept: false,
+ keymap_mode: KeymapMode::VimNormal,
+ prefix: false,
+ current_cursor: None,
+ tab_index: 0,
+ pending_vim_key: None,
+ inspecting_state: InspectingState {
+ current: None,
+ next: None,
+ previous: None,
+ },
+ search: SearchState {
+ input: String::new().into(),
+ filter_mode: FilterMode::Global,
+ context: Context {
+ session: String::new(),
+ cwd: String::new(),
+ hostname: String::new(),
+ host_id: String::new(),
+ git_root: None,
+ },
+ },
+ engine: engines::engine(SearchMode::Fuzzy),
+ now: Box::new(OffsetDateTime::now_utc),
+ };
+
+ state.results_state.select(50);
+
+ // Press 'g' to set pending state
+ let g_event = KeyEvent::new(KeyCode::Char('g'), KeyModifiers::NONE);
+ state.handle_key_input(&settings, &g_event);
+ assert_eq!(state.pending_vim_key, Some('g'));
+
+ // Press 'j' - should clear pending state
+ let j_event = KeyEvent::new(KeyCode::Char('j'), KeyModifiers::NONE);
+ state.handle_key_input(&settings, &j_event);
+ assert_eq!(state.pending_vim_key, None);
+ }
+
+ #[test]
+ fn test_vim_big_g_jump_to_bottom() {
+ use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
+
+ let settings = Settings::utc();
+
+ let mut state = State {
+ history_count: 100,
+ update_needed: None,
+ results_state: ListState::default(),
+ switched_search_mode: false,
+ search_mode: SearchMode::Fuzzy,
+ results_len: 100,
+ accept: false,
+ keymap_mode: KeymapMode::VimNormal,
+ prefix: false,
+ current_cursor: None,
+ tab_index: 0,
+ pending_vim_key: None,
+ inspecting_state: InspectingState {
+ current: None,
+ next: None,
+ previous: None,
+ },
+ search: SearchState {
+ input: String::new().into(),
+ filter_mode: FilterMode::Global,
+ context: Context {
+ session: String::new(),
+ cwd: String::new(),
+ hostname: String::new(),
+ host_id: String::new(),
+ git_root: None,
+ },
+ },
+ engine: engines::engine(SearchMode::Fuzzy),
+ now: Box::new(OffsetDateTime::now_utc),
+ };
+
+ state.results_state.select(50);
+
+ // 'G' should jump to visual bottom (index 0 in non-inverted mode)
+ let big_g_event = KeyEvent::new(KeyCode::Char('G'), KeyModifiers::NONE);
+ let result = state.handle_key_input(&settings, &big_g_event);
+ assert!(matches!(result, super::InputAction::Continue));
+ assert_eq!(state.results_state.selected(), 0);
+ }
+
+ #[test]
+ fn test_vim_ctrl_u_d_half_page_scroll() {
+ use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
+
+ let settings = Settings::utc();
+
+ let mut state = State {
+ history_count: 100,
+ update_needed: None,
+ results_state: ListState::default(),
+ switched_search_mode: false,
+ search_mode: SearchMode::Fuzzy,
+ results_len: 100,
+ accept: false,
+ keymap_mode: KeymapMode::VimNormal,
+ prefix: false,
+ current_cursor: None,
+ tab_index: 0,
+ pending_vim_key: None,
+ inspecting_state: InspectingState {
+ current: None,
+ next: None,
+ previous: None,
+ },
+ search: SearchState {
+ input: String::new().into(),
+ filter_mode: FilterMode::Global,
+ context: Context {
+ session: String::new(),
+ cwd: String::new(),
+ hostname: String::new(),
+ host_id: String::new(),
+ git_root: None,
+ },
+ },
+ engine: engines::engine(SearchMode::Fuzzy),
+ now: Box::new(OffsetDateTime::now_utc),
+ };
+
+ state.results_state.select(50);
+
+ // Ctrl+d should return Continue and clear pending key
+ // (scroll amount depends on max_entries which is 0 in tests)
+ state.pending_vim_key = Some('g');
+ let ctrl_d_event = KeyEvent::new(KeyCode::Char('d'), KeyModifiers::CONTROL);
+ let result = state.handle_key_input(&settings, &ctrl_d_event);
+ assert!(matches!(result, super::InputAction::Continue));
+ assert_eq!(state.pending_vim_key, None);
+
+ // Ctrl+u should return Continue and clear pending key
+ state.pending_vim_key = Some('g');
+ let ctrl_u_event = KeyEvent::new(KeyCode::Char('u'), KeyModifiers::CONTROL);
+ let result = state.handle_key_input(&settings, &ctrl_u_event);
+ assert!(matches!(result, super::InputAction::Continue));
+ assert_eq!(state.pending_vim_key, None);
+ }
+
+ #[test]
+ fn test_vim_ctrl_f_b_full_page_scroll() {
+ use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
+
+ let settings = Settings::utc();
+
+ let mut state = State {
+ history_count: 100,
+ update_needed: None,
+ results_state: ListState::default(),
+ switched_search_mode: false,
+ search_mode: SearchMode::Fuzzy,
+ results_len: 100,
+ accept: false,
+ keymap_mode: KeymapMode::VimNormal,
+ prefix: false,
+ current_cursor: None,
+ tab_index: 0,
+ pending_vim_key: None,
+ inspecting_state: InspectingState {
+ current: None,
+ next: None,
+ previous: None,
+ },
+ search: SearchState {
+ input: String::new().into(),
+ filter_mode: FilterMode::Global,
+ context: Context {
+ session: String::new(),
+ cwd: String::new(),
+ hostname: String::new(),
+ host_id: String::new(),
+ git_root: None,
+ },
+ },
+ engine: engines::engine(SearchMode::Fuzzy),
+ now: Box::new(OffsetDateTime::now_utc),
+ };
+
+ state.results_state.select(50);
+
+ // Ctrl+f should return Continue and clear pending key
+ // (scroll amount depends on max_entries which is 0 in tests)
+ state.pending_vim_key = Some('g');
+ let ctrl_f_event = KeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL);
+ let result = state.handle_key_input(&settings, &ctrl_f_event);
+ assert!(matches!(result, super::InputAction::Continue));
+ assert_eq!(state.pending_vim_key, None);
+
+ // Ctrl+b should return Continue and clear pending key
+ state.pending_vim_key = Some('g');
+ let ctrl_b_event = KeyEvent::new(KeyCode::Char('b'), KeyModifiers::CONTROL);
+ let result = state.handle_key_input(&settings, &ctrl_b_event);
+ assert!(matches!(result, super::InputAction::Continue));
+ assert_eq!(state.pending_vim_key, None);
+ }
}
diff --git a/crates/atuin/src/command/client/wrapped.rs b/crates/atuin/src/command/client/wrapped.rs
index 12357ece..ad578f7b 100644
--- a/crates/atuin/src/command/client/wrapped.rs
+++ b/crates/atuin/src/command/client/wrapped.rs
@@ -3,7 +3,11 @@ use eyre::Result;
use std::collections::{HashMap, HashSet};
use time::{Date, Duration, Month, OffsetDateTime, Time};
-use atuin_client::{database::Database, settings::Settings, theme::Theme};
+use atuin_client::{
+ database::Database, encryption, record::sqlite_store::SqliteStore, settings::Settings,
+ theme::Theme,
+};
+use atuin_dotfiles::store::AliasStore;
use atuin_history::stats::{Stats, compute};
@@ -20,7 +24,26 @@ struct WrappedStats {
impl WrappedStats {
#[allow(clippy::too_many_lines, clippy::cast_precision_loss)]
- fn new(settings: &Settings, stats: &Stats, history: &[atuin_client::history::History]) -> Self {
+ fn new(
+ settings: &Settings,
+ stats: &Stats,
+ history: &[atuin_client::history::History],
+ alias_map: &HashMap<String, String>,
+ ) -> Self {
+ // Helper to expand alias to its first command word
+ let expand_alias = |cmd: &str| -> String {
+ alias_map.get(cmd).map_or_else(
+ || cmd.to_string(),
+ |expanded| {
+ expanded
+ .split_whitespace()
+ .next()
+ .unwrap_or(cmd)
+ .to_string()
+ },
+ )
+ };
+
let nav_commands = stats
.top
.iter()
@@ -96,12 +119,13 @@ impl WrappedStats {
let mut hours: HashMap<String, usize> = HashMap::new();
for entry in history {
- let cmd = entry
+ let raw_cmd = entry
.command
.split_whitespace()
.next()
.unwrap_or("")
.to_string();
+ let cmd = expand_alias(&raw_cmd);
let (total, errors) = command_errors.entry(cmd.clone()).or_insert((0, 0));
*total += 1;
if entry.exit != 0 {
@@ -266,6 +290,7 @@ pub async fn run(
year: Option<i32>,
db: &impl Database,
settings: &Settings,
+ store: SqliteStore,
theme: &Theme,
) -> Result<()> {
let now = OffsetDateTime::now_utc().to_offset(settings.timezone.0);
@@ -299,9 +324,30 @@ pub async fn run(
return Ok(());
}
+ // Load aliases for expansion
+ let alias_map: HashMap<String, String> = if settings.dotfiles.enabled {
+ if let Ok(encryption_key) = encryption::load_key(settings) {
+ let encryption_key: [u8; 32] = encryption_key.into();
+ let host_id = Settings::host_id().expect("failed to get host_id");
+ let alias_store = AliasStore::new(store, host_id, encryption_key);
+
+ alias_store
+ .aliases()
+ .await
+ .unwrap_or_default()
+ .into_iter()
+ .map(|a| (a.name, a.value))
+ .collect()
+ } else {
+ HashMap::new()
+ }
+ } else {
+ HashMap::new()
+ };
+
// Compute overall stats using existing functionality
let stats = compute(settings, &history, 10, 1).expect("Failed to compute stats");
- let wrapped_stats = WrappedStats::new(settings, &stats, &history);
+ let wrapped_stats = WrappedStats::new(settings, &stats, &history, &alias_map);
// Print wrapped format
print_wrapped_header(year);
diff --git a/crates/atuin/src/main.rs b/crates/atuin/src/main.rs
index 8b6947e3..1a45988a 100644
--- a/crates/atuin/src/main.rs
+++ b/crates/atuin/src/main.rs
@@ -2,6 +2,8 @@
#![allow(clippy::use_self, clippy::missing_const_for_fn)] // not 100% reliable
use clap::Parser;
+use clap::builder::Styles;
+use clap::builder::styling::{AnsiColor, Effects};
use eyre::Result;
use command::AtuinCmd;
@@ -26,6 +28,12 @@ static HELP_TEMPLATE: &str = "\
{all-args}{after-help}";
+const STYLES: Styles = Styles::styled()
+ .header(AnsiColor::Yellow.on_default().effects(Effects::BOLD))
+ .usage(AnsiColor::Green.on_default().effects(Effects::BOLD))
+ .literal(AnsiColor::Green.on_default().effects(Effects::BOLD))
+ .placeholder(AnsiColor::Green.on_default());
+
/// Magical shell history
#[derive(Parser)]
#[command(
@@ -33,6 +41,7 @@ static HELP_TEMPLATE: &str = "\
version = VERSION,
long_version = LONG_VERSION,
help_template(HELP_TEMPLATE),
+ styles = STYLES,
)]
struct Atuin {
#[command(subcommand)]
diff --git a/crates/atuin/src/shell/atuin.bash b/crates/atuin/src/shell/atuin.bash
index 26d63d85..88b6af3a 100644
--- a/crates/atuin/src/shell/atuin.bash
+++ b/crates/atuin/src/shell/atuin.bash
@@ -312,7 +312,7 @@ __atuin_initialize_blesh() {
#
function ble/complete/auto-complete/source:atuin-history {
local suggestion
- suggestion=$(ATUIN_QUERY="$_ble_edit_str" atuin search --cmd-only --limit 1 --search-mode prefix)
+ suggestion=$(ATUIN_QUERY="$_ble_edit_str" atuin search --cmd-only --limit 1 --search-mode prefix 2>/dev/null)
[[ $suggestion == "$_ble_edit_str"?* ]] || return 1
ble/complete/auto-complete/enter h 0 "${suggestion:${#_ble_edit_str}}" '' "$suggestion"
}
@@ -377,16 +377,16 @@ __atuin_widget_run() {
# of IKEYSEQ2 to no-op by running `bind '"IKEYSEQ2": ""'`.
#
# For the choice of the intermediate key sequences, we want to choose key
-# sequences that are unlikely to conflict with others. For this, we consider
-# the key sequences of the form \e[0;<m>A. This is a variant of the key
-# sequences for the [up] key. A single [up] keypress is usually transmitted as
-# \e[A in the input stream, but it switches to the form \e[<n>;<m>A in the
-# presence of modifier keys (such as Control or Shift), where <m> represents
-# the 1 + (modifier flags) and <n> represents the number of [up] keypresses.
-# The number <n> is fixed to be 1 in the input stream, so we may use <n> = 0
-# (which is unlikely be used) as our special key sequences.
+# sequences that are unlikely to conflict with others. In addition, we want to
+# avoid a key sequence containing \e because keymap "vi-insert" stops
+# processing key sequences containing \e in older versions of Bash. We have
+# used \e[0;<m>A (a variant of the [up] key with modifier <m>) in Atuin 3.10.0
+# for intermediate key sequences, but this contains \e and caused a problem.
+# Instead, we use \C-x\C-_A<n>\a, which starts with \C-x\C-_ (an unlikely
+# two-byte combination) and A (represents the initial letter of Atuin),
+# followed by the payload <n> and the terminator \a (BEL, \C-g).
-__atuin_macro_chain='\e[0;0A'
+__atuin_macro_chain='\C-x\C-_A0\a'
for __atuin_keymap in emacs vi-insert vi-command; do
bind -m "$__atuin_keymap" "\"$__atuin_macro_chain\": \"\""
done
@@ -394,6 +394,7 @@ unset -v __atuin_keymap
if ((BASH_VERSINFO[0] >= 5 || BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 3)); then
# In Bash >= 4.3
+
__atuin_macro_accept_line=accept-line
__atuin_bind_impl() {
@@ -408,9 +409,20 @@ if ((BASH_VERSINFO[0] >= 5 || BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 3));
local REPLY
__atuin_widget_save "$keymap:$command"
local widget=$REPLY
- local ikeyseq1='\e[0;'$((1 + widget))'A'
+ local ikeyseq1='\C-x\C-_A'$((1 + widget))'\a'
local ikeyseq2=$__atuin_macro_chain
+ if ((BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] == 1)); then
+ # Workaround for Bash 5.1: Bash 5.1 has a bug that overwriting an
+ # existing "bind -x" keybinding breaks other existing "bind -x"
+ # keybindings [1,2]. To work around the problem, we explicitly
+ # unbind an existing keybinding before overwriting it.
+ #
+ # [1] https://lists.gnu.org/archive/html/bug-bash/2021-04/msg00135.html
+ # [2] https://github.com/atuinsh/atuin/issues/962#issuecomment-3451132291
+ bind -m "$keymap" -r "$keyseq"
+ fi
+
bind -m "$keymap" "\"$keyseq\": \"$ikeyseq1$ikeyseq2\""
bind -m "$keymap" -x "\"$ikeyseq1\": __atuin_widget_run $widget"
}
@@ -489,21 +501,33 @@ else
# `shell-expand-line'.
#
# Note: Concerning the key sequences to invoke bindable functions
- # such as "\e[0;1A", another option is to use
+ # such as "\C-x\C-_A1\a", another option is to use
# "\exbegginning-of-line\r", etc. to make it consistent with bash
# >= 5.3. However, an older Bash configuration can still conflict
- # on [M-x]. The conflict is more likely than \e[0;1A.
+ # on [M-x]. The conflict is more likely than \C-x\C-_A1\a.
for __atuin_keymap in emacs vi-insert vi-command; do
- bind -m "$__atuin_keymap" '"\e[0;1A": beginning-of-line'
- bind -m "$__atuin_keymap" '"\e[0;2A": kill-line'
- bind -m "$__atuin_keymap" '"\e[0;3A": shell-expand-line'
- bind -m "$__atuin_keymap" '"\e[0;4A": accept-line'
+ bind -m "$__atuin_keymap" '"\C-x\C-_A1\a": beginning-of-line'
+ bind -m "$__atuin_keymap" '"\C-x\C-_A2\a": kill-line'
+ # shellcheck disable=SC2016
+ bind -m "$__atuin_keymap" '"\C-x\C-_A3\a": "$READLINE_LINE"'
+ bind -m "$__atuin_keymap" '"\C-x\C-_A4\a": shell-expand-line'
+ bind -m "$__atuin_keymap" '"\C-x\C-_A5\a": accept-line'
+ bind -m "$__atuin_keymap" '"\C-x\C-_A6\a": end-of-line'
done
unset -v __atuin_keymap
- # shellcheck disable=SC2016
- __atuin_macro_accept_line='"\e[0;1A\e[0;2A$READLINE_LINE\e[0;3A\e[0;4A"'
- # shellcheck disable=SC2016
- __atuin_macro_insert_line='"\e[0;1A\e[0;2A$READLINE_LINE\e[0;3A"'
+
+ bind -m vi-command '"\C-x\C-_A7\a": vi-insertion-mode'
+ bind -m vi-insert '"\C-x\C-_A7\a": vi-movement-mode'
+
+ # "\C-x\C-_A10\a": Replace the command line with READLINE_LINE. When we are
+ # in the vi-command keymap, we go to vi-insert, input
+ # "$READLINE_LINE", and come back to vi-command.
+ bind -m emacs '"\C-x\C-_A10\a": "\C-x\C-_A1\a\C-x\C-_A2\a\C-x\C-_A3\a\C-x\C-_A4\a"'
+ bind -m vi-insert '"\C-x\C-_A10\a": "\C-x\C-_A1\a\C-x\C-_A2\a\C-x\C-_A3\a\C-x\C-_A4\a"'
+ bind -m vi-command '"\C-x\C-_A10\a": "\C-x\C-_A1\a\C-x\C-_A2\a\C-x\C-_A7\a\C-x\C-_A3\a\C-x\C-_A7\a\C-x\C-_A4\a"'
+
+ __atuin_macro_accept_line='"\C-x\C-_A10\a\C-x\C-_A5\a"'
+ __atuin_macro_insert_line='"\C-x\C-_A10\a\C-x\C-_A6\a"'
fi
__atuin_bash42_dispatch_selector=
diff --git a/crates/atuin/src/shell/atuin.ps1 b/crates/atuin/src/shell/atuin.ps1
index f1caee86..37753f8a 100644
--- a/crates/atuin/src/shell/atuin.ps1
+++ b/crates/atuin/src/shell/atuin.ps1
@@ -10,8 +10,13 @@
# It is initialized from the current prompt line count if not set when the first Atuin search is performed.
if (Get-Module Atuin -ErrorAction Ignore) {
- Write-Warning "The Atuin module is already loaded."
- return
+ if ($PSVersionTable.PSVersion.Major -ge 7) {
+ Write-Warning "The Atuin module is already loaded, replacing it."
+ Remove-Module Atuin
+ } else {
+ Write-Warning "The Atuin module is already loaded, skipping."
+ return
+ }
}
if (!(Get-Command atuin -ErrorAction Ignore)) {
@@ -33,6 +38,19 @@ New-Module -Name Atuin -ScriptBlock {
# The ReadLine overloads changed with breaking changes over time, make sure the one we expect is available.
$script:hasExpectedReadLineOverload = ([Microsoft.PowerShell.PSConsoleReadLine]::ReadLine).OverloadDefinitions.Contains("static string ReadLine(runspace runspace, System.Management.Automation.EngineIntrinsics engineIntrinsics, System.Threading.CancellationToken cancellationToken, System.Nullable[bool] lastRunStatus)")
+ function Get-CommandLine {
+ $commandLine = ""
+ [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$commandLine, [ref]$null)
+ return $commandLine
+ }
+
+ function Set-CommandLine {
+ param([string]$Text)
+
+ $commandLine = Get-CommandLine
+ [Microsoft.PowerShell.PSConsoleReadLine]::Replace(0, $commandLine.Length, $Text)
+ }
+
# This function name is called by PSReadLine to read the next command line to execute.
# We replace it with a custom implementation which adds Atuin support.
function PSConsoleHostReadLine {
@@ -47,14 +65,32 @@ New-Module -Name Atuin -ScriptBlock {
## 2. Report the status of the previous command to Atuin (atuin history end).
if ($script:atuinHistoryId) {
- # The duration is not recorded in old PowerShell versions, let Atuin handle it. $null arguments are ignored.
- $duration = (Get-History -Count 1).Duration.Ticks * 100
- $durationArg = if ($duration) { "--duration=$duration" } else { $null }
+ try {
+ # The duration is not recorded in old PowerShell versions, let Atuin handle it. $null arguments are ignored.
+ $duration = (Get-History -Count 1).Duration.Ticks * 100
+ $durationArg = if ($duration) { "--duration=$duration" } else { $null }
- atuin history end --exit=$exitCode $durationArg -- $script:atuinHistoryId | Out-Null
-
- $global:LASTEXITCODE = $exitCode
- $script:atuinHistoryId = $null
+ # Fire and forget the atuin history end command to avoid blocking the shell during a potential sync.
+ $process = New-Object System.Diagnostics.Process
+ $process.StartInfo.FileName = "atuin"
+ $process.StartInfo.Arguments = "history end --exit=$exitCode $durationArg -- $script:atuinHistoryId"
+ $process.StartInfo.UseShellExecute = $false
+ $process.StartInfo.CreateNoWindow = $true
+ $process.StartInfo.RedirectStandardInput = $true
+ $process.StartInfo.RedirectStandardOutput = $true
+ $process.StartInfo.RedirectStandardError = $true
+ $process.Start() | Out-Null
+ $process.StandardInput.Close()
+ $process.BeginOutputReadLine()
+ $process.BeginErrorReadLine()
+ }
+ catch {
+ # Ignore errors to avoid breaking the shell.
+ # An error would occur if the user removes atuin from the PATH, for instance.
+ }
+ finally {
+ $script:atuinHistoryId = $null
+ }
}
## 3. Read the next command line to execute.
@@ -79,6 +115,9 @@ New-Module -Name Atuin -ScriptBlock {
$env:ATUIN_COMMAND_LINE = $line
$script:atuinHistoryId = atuin history start --command-from-env
}
+ catch {
+ # Ignore errors to avoid breaking the shell, see above.
+ }
finally {
$env:ATUIN_COMMAND_LINE = $null
}
@@ -95,12 +134,9 @@ New-Module -Name Atuin -ScriptBlock {
try {
[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8
- $query = $null
- [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$query, [ref]$null)
-
# Atuin is started through Start-Process to avoid interfering with the current shell.
$env:ATUIN_SHELL = "powershell"
- $env:ATUIN_QUERY = $query
+ $env:ATUIN_QUERY = Get-CommandLine
$argString = "search -i --result-file ""$resultFile"" $ExtraArgs"
Start-Process -PassThru -NoNewWindow -FilePath atuin -ArgumentList $argString | Wait-Process
$suggestion = (Get-Content -Raw $resultFile -Encoding UTF8 | Out-String).Trim()
@@ -130,12 +166,10 @@ New-Module -Name Atuin -ScriptBlock {
$acceptPrefix = "__atuin_accept__:"
if ( $suggestion.StartsWith($acceptPrefix)) {
- [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
- [Microsoft.PowerShell.PSConsoleReadLine]::Insert($suggestion.Substring($acceptPrefix.Length))
+ Set-CommandLine $suggestion.Substring($acceptPrefix.Length)
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
} else {
- [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
- [Microsoft.PowerShell.PSConsoleReadLine]::Insert($suggestion)
+ Set-CommandLine $suggestion
}
}
finally {
@@ -157,8 +191,7 @@ New-Module -Name Atuin -ScriptBlock {
if ($UpArrow) {
Set-PSReadLineKeyHandler -Chord "UpArrow" -BriefDescription "Runs Atuin search" -ScriptBlock {
- $line = $null
- [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$null)
+ $line = Get-CommandLine
if (!$line.Contains("`n")) {
Invoke-AtuinSearch -ExtraArgs "--shell-up-key-binding"
diff --git a/crates/atuin/tests/common/mod.rs b/crates/atuin/tests/common/mod.rs
index d79c13d6..6cc4e443 100644
--- a/crates/atuin/tests/common/mod.rs
+++ b/crates/atuin/tests/common/mod.rs
@@ -30,15 +30,18 @@ pub async fn start_server(path: &str) -> (String, oneshot::Sender<()>, JoinHandl
host: "127.0.0.1".to_owned(),
port: 0,
path: path.to_owned(),
+ sync_v1_enabled: true,
open_registration: true,
max_history_length: 8192,
max_record_size: 1024 * 1024 * 1024,
page_size: 1100,
register_webhook_url: None,
register_webhook_username: String::new(),
- db_settings: DbSettings { db_uri },
+ db_settings: DbSettings {
+ db_uri: db_uri,
+ read_db_uri: None,
+ },
metrics: atuin_server::settings::Metrics::default(),
- tls: atuin_server::settings::Tls::default(),
mail: atuin_server::settings::Mail::default(),
fake_version: None,
};
diff --git a/dist-workspace.toml b/dist-workspace.toml
index 619b325e..e9e1b156 100644
--- a/dist-workspace.toml
+++ b/dist-workspace.toml
@@ -6,13 +6,13 @@ members = ["cargo:."]
# Path that installers should place binaries in
install-path = "~/.atuin/bin"
# The preferred dist version to use in CI (Cargo.toml SemVer syntax)
-cargo-dist-version = "0.28.3"
+cargo-dist-version = "0.30.3"
# CI backends to support
ci = "github"
# The installers to generate for each app
-installers = ["shell"]
+installers = ["shell", "powershell"]
# Target platforms to build apps for (Rust target-triple syntax)
-targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl"]
+targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-pc-windows-msvc"]
# Which actions to run on pull requests
pr-run-mode = "plan"
# Whether to install an updater program
diff --git a/docs/.gitignore b/docs-i18n/.gitignore
index b2d6de30..b2d6de30 100644
--- a/docs/.gitignore
+++ b/docs-i18n/.gitignore
diff --git a/docs/ru/config_ru.md b/docs-i18n/ru/config_ru.md
index b1e64218..b1e64218 100644
--- a/docs/ru/config_ru.md
+++ b/docs-i18n/ru/config_ru.md
diff --git a/docs/ru/import_ru.md b/docs-i18n/ru/import_ru.md
index 993d89b8..993d89b8 100644
--- a/docs/ru/import_ru.md
+++ b/docs-i18n/ru/import_ru.md
diff --git a/docs/ru/key-binding_ru.md b/docs-i18n/ru/key-binding_ru.md
index d6917e4e..d6917e4e 100644
--- a/docs/ru/key-binding_ru.md
+++ b/docs-i18n/ru/key-binding_ru.md
diff --git a/docs/ru/list_ru.md b/docs-i18n/ru/list_ru.md
index e40d3045..e40d3045 100644
--- a/docs/ru/list_ru.md
+++ b/docs-i18n/ru/list_ru.md
diff --git a/docs/ru/search_ru.md b/docs-i18n/ru/search_ru.md
index 8302decc..8302decc 100644
--- a/docs/ru/search_ru.md
+++ b/docs-i18n/ru/search_ru.md
diff --git a/docs/ru/server_ru.md b/docs-i18n/ru/server_ru.md
index 25b45abf..25b45abf 100644
--- a/docs/ru/server_ru.md
+++ b/docs-i18n/ru/server_ru.md
diff --git a/docs/ru/shell-completions_ru.md b/docs-i18n/ru/shell-completions_ru.md
index 56fb1602..56fb1602 100644
--- a/docs/ru/shell-completions_ru.md
+++ b/docs-i18n/ru/shell-completions_ru.md
diff --git a/docs/ru/stats_ru.md b/docs-i18n/ru/stats_ru.md
index 842ad71b..842ad71b 100644
--- a/docs/ru/stats_ru.md
+++ b/docs-i18n/ru/stats_ru.md
diff --git a/docs/ru/sync_ru.md b/docs-i18n/ru/sync_ru.md
index 08831cbd..08831cbd 100644
--- a/docs/ru/sync_ru.md
+++ b/docs-i18n/ru/sync_ru.md
diff --git a/docs/zh-CN/README.md b/docs-i18n/zh-CN/README.md
index 065d1b4d..065d1b4d 100644
--- a/docs/zh-CN/README.md
+++ b/docs-i18n/zh-CN/README.md
diff --git a/docs/zh-CN/config.md b/docs-i18n/zh-CN/config.md
index 3aa63a9e..3aa63a9e 100644
--- a/docs/zh-CN/config.md
+++ b/docs-i18n/zh-CN/config.md
diff --git a/docs/zh-CN/docker.md b/docs-i18n/zh-CN/docker.md
index 64704679..64704679 100644
--- a/docs/zh-CN/docker.md
+++ b/docs-i18n/zh-CN/docker.md
diff --git a/docs/zh-CN/import.md b/docs-i18n/zh-CN/import.md
index c1f1d06d..c1f1d06d 100644
--- a/docs/zh-CN/import.md
+++ b/docs-i18n/zh-CN/import.md
diff --git a/docs/zh-CN/k8s.md b/docs-i18n/zh-CN/k8s.md
index ce63aab1..ce63aab1 100644
--- a/docs/zh-CN/k8s.md
+++ b/docs-i18n/zh-CN/k8s.md
diff --git a/docs/zh-CN/key-binding.md b/docs-i18n/zh-CN/key-binding.md
index 54c68b37..54c68b37 100644
--- a/docs/zh-CN/key-binding.md
+++ b/docs-i18n/zh-CN/key-binding.md
diff --git a/docs/zh-CN/list.md b/docs-i18n/zh-CN/list.md
index fe03529f..fe03529f 100644
--- a/docs/zh-CN/list.md
+++ b/docs-i18n/zh-CN/list.md
diff --git a/docs/zh-CN/search.md b/docs-i18n/zh-CN/search.md
index 24e320d5..24e320d5 100644
--- a/docs/zh-CN/search.md
+++ b/docs-i18n/zh-CN/search.md
diff --git a/docs/zh-CN/server.md b/docs-i18n/zh-CN/server.md
index 4cb39df9..4cb39df9 100644
--- a/docs/zh-CN/server.md
+++ b/docs-i18n/zh-CN/server.md
diff --git a/docs/zh-CN/shell-completions.md b/docs-i18n/zh-CN/shell-completions.md
index 0979dcb0..0979dcb0 100644
--- a/docs/zh-CN/shell-completions.md
+++ b/docs-i18n/zh-CN/shell-completions.md
diff --git a/docs/zh-CN/stats.md b/docs-i18n/zh-CN/stats.md
index 2bf557ba..2bf557ba 100644
--- a/docs/zh-CN/stats.md
+++ b/docs-i18n/zh-CN/stats.md
diff --git a/docs/zh-CN/sync.md b/docs-i18n/zh-CN/sync.md
index 2fd451d8..2fd451d8 100644
--- a/docs/zh-CN/sync.md
+++ b/docs-i18n/zh-CN/sync.md
diff --git a/docs/docs/configuration/config.md b/docs/docs/configuration/config.md
new file mode 100644
index 00000000..f62c6160
--- /dev/null
+++ b/docs/docs/configuration/config.md
@@ -0,0 +1,820 @@
+# Config
+
+Atuin maintains two configuration files, stored in `~/.config/atuin/`. We store
+data in `~/.local/share/atuin` (unless overridden by XDG\_\*).
+
+The full path to the config file would be `~/.config/atuin/config.toml`
+
+The config location can be overridden with ATUIN_CONFIG_DIR
+
+### `db_path`
+
+Default: `~/.local/share/atuin/history.db`
+
+The path to the Atuin SQLite database.
+
+```toml
+db_path = "~/.history.db"
+```
+
+### `key_path`
+
+Default: `~/.local/share/atuin/key`
+
+The path to the Atuin encryption key.
+
+```toml
+key_path = "~/.atuin-key"
+```
+
+### `session_path`
+
+Default: `~/.local/share/atuin/session`
+
+The path to the Atuin server session file.
+This is essentially just an API token
+
+```toml
+session_path = "~/.atuin-session"
+```
+
+### `dialect`
+
+Default: `us`
+
+This configures how the [stats](../reference/stats.md) command parses dates. It has two
+possible values
+
+```toml
+dialect = "uk"
+```
+
+or
+
+```toml
+dialect = "us"
+```
+
+### `auto_sync`
+
+Default: `true`
+
+Configures whether or not to automatically sync, when logged in.
+
+```toml
+auto_sync = true/false
+```
+
+### `update_check`
+
+Default: `true`
+
+Configures whether or not to automatically check for updates.
+
+```toml
+update_check = true/false
+```
+
+### `sync_address`
+
+Default: `https://api.atuin.sh`
+
+The address of the server to sync with!
+
+```toml
+sync_address = "https://api.atuin.sh"
+```
+
+### `sync_frequency`
+
+Default: `1h`
+
+How often to automatically sync with the server. This can be given in a
+"human-readable" format. For example, `10s`, `20m`, `1h`, etc.
+
+If set to `0`, Atuin will sync after every command. Some servers may potentially
+rate limit, which won't cause any issues.
+
+```toml
+sync_frequency = "1h"
+```
+
+### `search_mode`
+
+Default: `fuzzy`
+
+Which search mode to use. Atuin supports "prefix", "fulltext", "fuzzy", and
+"skim" search modes.
+
+Prefix mode searches for "query\*"; fulltext mode searches for "\*query\*";
+"fuzzy" applies the [fuzzy search syntax](#fuzzy-search-syntax);
+"skim" applies the [skim search syntax](https://github.com/lotabout/skim#search-syntax).
+
+#### `fuzzy` search syntax
+
+The "fuzzy" search syntax is based on the
+[fzf search syntax](https://github.com/junegunn/fzf#search-syntax).
+
+| Token | Match type | Description |
+| --------- | -------------------------- | ------------------------------------ |
+| `sbtrkt` | fuzzy-match | Items that match `sbtrkt` |
+| `'wild` | exact-match (quoted) | Items that include `wild` |
+| `^music` | prefix-exact-match | Items that start with `music` |
+| `.mp3$` | suffix-exact-match | Items that end with `.mp3` |
+| `!fire` | inverse-exact-match | Items that do not include `fire` |
+| `!^music` | inverse-prefix-exact-match | Items that do not start with `music` |
+| `!.mp3$` | inverse-suffix-exact-match | Items that do not end with `.mp3` |
+
+A single bar character term acts as an OR operator. For example, the following
+query matches entries that start with `core` and end with either `go`, `rb`,
+or `py`.
+
+```
+^core go$ | rb$ | py$
+```
+
+### `filter_mode`
+
+Default: `global`
+
+The default filter to use when searching
+
+| Mode | Description |
+| ---------------- | ------------------------------------------------------------ |
+| global (default) | Search history from all hosts, all sessions, all directories |
+| host | Search history just from this host |
+| session | Search history just from the current session |
+| directory | Search history just from the current directory (global) |
+| workspace | Search history just from the current git repository (>17.0) |
+
+Filter modes can still be toggled via ctrl-r
+
+```toml
+filter_mode = "host"
+```
+
+### `search_mode_shell_up_key_binding`
+
+Atuin version: >= 17.0
+
+Default: `fuzzy`
+
+The default searchmode to use when searching and being invoked from a shell up-key binding.
+
+Accepts exactly the same options as `search_mode` above
+
+```toml
+search_mode_shell_up_key_binding = "fuzzy"
+```
+
+Defaults to the value specified for `search_mode`.
+
+### `filter_mode_shell_up_key_binding`
+
+Default: `global`
+
+The default filter to use when searching and being invoked from a shell up-key binding.
+
+Accepts exactly the same options as `filter_mode` above
+
+```toml
+filter_mode_shell_up_key_binding = "session"
+```
+
+Defaults to the value specified for `filter_mode`.
+
+### `workspaces`
+
+Atuin version: >= 17.0
+
+Default: `false`
+
+This flag enables a pseudo filter-mode named "workspace": the filter is automatically
+activated when you are in a git repository.
+
+With workspace filtering enabled, Atuin will filter for commands executed in any directory
+within a git repository tree.
+
+Filter modes can still be toggled via ctrl-r.
+
+### `style`
+
+Default: `compact`
+
+Which style to use. Possible values: `auto`, `full` and `compact`.
+
+- `compact`:
+
+![compact](https://user-images.githubusercontent.com/1710904/161623659-4fec047f-ea4b-471c-9581-861d2eb701a9.png)
+
+- `full`:
+
+![full](https://user-images.githubusercontent.com/1710904/161623547-42afbfa7-a3ef-4820-bacd-fcaf1e324969.png)
+
+This means that Atuin will automatically switch to `compact` mode when the terminal window is too short for `full` to display properly.
+
+### `invert`
+
+Atuin version: >= 17.0
+
+Default: `false`
+
+Invert the UI - put the search bar at the top.
+
+```toml
+invert = true/false
+```
+
+### `inline_height`
+
+Default: `40`
+
+Set the maximum number of lines Atuin's interface should take up.
+
+If set to `0`, Atuin will always take up as many lines as available (full screen).
+
+### `show_preview`
+
+Default: `true`
+
+Configure whether or not to show a preview of the selected command.
+
+Useful when the command is longer than the terminal width and is cut off.
+
+### `max_preview_height`
+
+Atuin version: >= 17.0
+
+Default: `4`
+
+Configure the maximum height of the preview to show.
+
+Useful when you have long scripts in your history that you want to distinguish by more than the first few lines.
+
+### `show_help`
+
+Atuin version: >= 17.0
+
+Default: `true`
+
+Configure whether or not to show the help row, which includes the current Atuin version (and whether an update is available), a keymap hint, and the total amount of commands in your history.
+
+### `show_tabs`
+
+Atuin version: >= 18.0
+
+Default: `true`
+
+Configure whether or not to show tabs for search and inspect.
+
+### `auto_hide_height`
+
+Atuin version: >= 18.4
+
+Default: `8`
+
+Set Atuin to hide lines when a minimum number of rows is subceeded. This has no effect except
+when `compact` style is being used (see `style` above), and currently applies to only the
+interactive search and inspector. It can be turned off entirely by setting to `0`.
+
+### `exit_mode`
+
+Default: `return-original`
+
+What to do when the escape key is pressed when searching
+
+| Value | Behaviour |
+| ------------------------- | ---------------------------------------------------------------- |
+| return-original (default) | Set the command-line to the value it had before starting search |
+| return-query | Set the command-line to the search query you have entered so far |
+
+Pressing ctrl+c or ctrl+d will always return the original command-line value.
+
+```toml
+exit_mode = "return-query"
+```
+
+### `history_format`
+
+Default to `history list`
+
+The history format allows you to configure the default `history list` format - which can also be specified with the --format arg.
+
+The specified --format arg will prioritize the config when both are present
+
+More on [history list](../reference/list.md)
+
+### `history_filter`
+
+The history filter allows you to exclude commands from history tracking - maybe you want to keep ALL of your `curl` commands totally out of your shell history, or maybe just some matching a pattern.
+
+This supports regular expressions, so you can hide pretty much whatever you want!
+
+```toml
+## Note that these regular expressions are unanchored, i.e. if they don't start
+## with ^ or end with $, they'll match anywhere in the command.
+history_filter = [
+ "^secret-cmd",
+ "^innocuous-cmd .*--secret=.+"
+]
+```
+
+### `cwd_filter`
+
+The cwd filter allows you to exclude directories from history tracking.
+
+This supports regular expressions, so you can hide pretty much whatever you want!
+
+```toml
+## Note that these regular expressions are unanchored, i.e. if they don't start
+## with ^ or end with $, they'll match anywhere in the command.
+# cwd_filter = [
+# "^/very/secret/directory",
+# ]
+```
+
+After updating that parameter, you can run [the prune command](../reference/prune.md) to remove old history entries that match the new filters.
+
+### `store_failed`
+
+Atuin version: >= 18.3.0
+
+Default: `true`
+
+```toml
+store_failed = true
+```
+
+Configures whether to store commands that failed (those with non-zero exit status) or not.
+
+### `secrets_filter`
+
+Atuin version: >= 17.0
+
+Default: `true`
+
+```toml
+secrets_filter = true
+```
+
+This matches history against a set of default regex, and will not save it if we get a match. Defaults include
+
+1. AWS key id
+2. Github pat (old and new)
+3. Slack oauth tokens (bot, user)
+4. Slack webhooks
+5. Stripe live/test keys
+6. Atuin login command
+7. Cloud environment variable patterns (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AZURE_STORAGE_CLASS_KEY`, `GOOGLE_SERVICE_ACCOUNT_KEY`)
+8. Netlify authentication tokens
+9. Npm pat
+10. Pulumi pat
+
+### macOS Ctrl-n key shortcuts
+
+Default: `true`
+
+macOS does not have an ++alt++ key, although terminal emulators can often be configured to map the ++option++ key to be used as ++alt++. _However_, remapping ++option++ this way may prevent typing some characters, such as using ++option+3++ to type `#` on the British English layout. For such a scenario, set the `ctrl_n_shortcuts` option to `true` in your config file to replace ++alt+0++ to ++alt+9++ shortcuts with ++ctrl+0++ to ++ctrl+9++ instead:
+
+```toml
+# Use Ctrl-0 .. Ctrl-9 instead of Alt-0 .. Alt-9 UI shortcuts
+ctrl_n_shortcuts = true
+```
+
+### `network_timeout`
+
+Atuin version: >= 18.0
+
+Default: `30`
+
+The max amount of time (in seconds) to wait for a network request. If any
+operations with a sync server take longer than this, the code will fail -
+rather than wait indefinitely.
+
+### `network_connect_timeout`
+
+Atuin version: >= 18.0
+
+Default: `5`
+
+The max time (in seconds) we wait for a connection to become established with a
+remote sync server. Any longer than this and the request will fail.
+
+### `local_timeout`
+
+Atuin version: >= 18.0
+
+Default: `5`
+
+Timeout (in seconds) for acquiring a local database connection (sqlite).
+
+### `command_chaining`
+
+Atuin version: >= 18.8
+
+Default: `false`
+
+Allows building a command chain with the `&&` or `||` operator. When enabled, opening atuin will search for the next command in the chain, and append to the current buffer.
+
+### `enter_accept`
+
+Atuin version: >= 17.0
+
+Default: `false`
+
+Not supported by NuShell presently
+
+When set to true, Atuin will default to immediately executing a command rather
+than the user having to press enter twice. Pressing tab will return to the
+shell and give the user a chance to edit.
+
+This technically defaults to true for new users, but false for existing. We
+have set `enter_accept = true` in the default config file. This is likely to
+change to be the default for everyone in a later release.
+
+### `keymap_mode`
+
+Atuin version: >= 18.0
+
+Default: `emacs`
+
+The initial keymap mode of the interactive Atuin search (e.g. started by the
+keybindings in the shells). There are four supported values: `"emacs"`,
+`"vim-normal"`, `"vim-insert"`, and `"auto"`. The keymap mode `"emacs"` is the
+most basic one. In the keymap mode `"vim-normal"`, you may use ++k++
+and ++j++ to navigate the history list as in Vim, whilst pressing
+
+++i++ changes the keymap mode to `"vim-insert"`. In the keymap mode `"vim-insert"`,
+you can search for a string as in the keymap mode `"emacs"`, while pressing ++esc++
+switches the keymap mode to `"vim-normal"`. When set to `"auto"`, the initial
+keymap mode is automatically determined based on the shell's keymap that triggered
+the Atuin search. `"auto"` is not supported by NuShell at present, where it will
+always trigger the Atuin search with the keymap mode `"emacs"`.
+
+### `keymap_cursor`
+
+Atuin version: >= 18.0
+
+Default: `(empty dictionary)`
+
+The terminal's cursor style associated with each keymap mode in the Atuin
+search. This is specified by a dictionary whose keys and values being the
+keymap names and the cursor styles, respectively. A key specifies one of the
+keymaps from `emacs`, `vim_insert`, and `vim_normal`. A value is one of the
+cursor styles, `default` or `{blink,steady}-{block,underline,bar}`. The
+following is an example.
+
+```toml
+keymap_cursor = { emacs = "blink-block", vim_insert = "blink-block", vim_normal = "steady-block" }
+```
+
+If the cursor style is specified, the terminal's cursor style is changed to the
+specified one when the Atuin search starts with or switches to the
+corresponding keymap mode. Also, the terminal's cursor style is reset to the
+one associated with the keymap mode corresponding to the shell's keymap on the
+termination of the Atuin search.
+
+### `prefers_reduced_motion`
+
+Atuin version: >= 18.0
+
+Default: `false`
+
+Enable this, and Atuin will reduce motion in the TUI as much as possible. Users
+with motion sensitivity can find the live-updating timestamps distracting.
+
+Alternatively, set env var NO_MOTION
+
+## Stats
+
+This section of client config is specifically for configuring Atuin stats calculations
+
+```
+[stats]
+common_subcommands = [...]
+common_prefix = [...]
+```
+
+### `common_subcommands`
+
+Default:
+
+```toml
+common_subcommands = [
+ "apt",
+ "cargo",
+ "composer",
+ "dnf",
+ "docker",
+ "git",
+ "go",
+ "ip",
+ "jj",
+ "kubectl",
+ "nix",
+ "nmcli",
+ "npm",
+ "pecl",
+ "pnpm",
+ "podman",
+ "port",
+ "systemctl",
+ "tmux",
+ "yarn",
+]
+```
+
+Configures commands where we should consider the subcommand as part of the statistics. For example, consider `kubectl get` rather than just `kubectl`.
+
+### `common_prefix`
+
+Atuin version: >= 17.1
+
+Default:
+
+```toml
+common_prefix = [
+ "sudo",
+]
+```
+
+Configures commands that should be totally stripped from stats calculations. For example, 'sudo' should be ignored.
+
+## sync
+
+We have developed a new version of sync, that is both faster and more efficient than the original version.
+
+Presently, it is the default for fresh installs but not for existing users. This will change in a later release.
+
+To enable sync v2, add the following to your config
+
+```toml
+[sync]
+records = true
+```
+
+## `dotfiles`
+
+Atuin version: >= 18.1
+
+Default: `false`
+
+To enable sync of shell aliases between hosts. Requires `sync` enabled.
+
+Add the new section to the bottom of your config file, for every machine you use Atuin with
+
+```toml
+[dotfiles]
+enabled = true
+```
+
+Note: you will need to have sync v2 enabled. See the above section.
+
+Manage aliases using the command line options
+
+```
+# Alias 'k' to 'kubectl'
+atuin dotfiles alias set k kubectl
+
+# List all aliases
+atuin dotfiles alias list
+
+# Delete an alias
+atuin dotfiles alias delete k
+```
+
+After setting an alias, you will either need to restart your shell or source the init file for the change to take affect
+
+## keys
+
+This section of the client config is specifically for configuring key-related settings.
+
+```
+[keys]
+scroll_exits = [...]
+prefix = 'a'
+```
+
+### `scroll_exits`
+
+Atuin version: >= 18.1
+
+Default: `true`
+
+Configures whether the TUI exits, when scrolled past the last or first entry.
+
+### `prefix`
+
+Atuin version: > 18.3
+
+Default: `a`
+
+Which key to use as the prefix
+
+### `exit_past_line_start`
+
+Atuin version: >= 18.5
+
+Default: `true`
+
+Exits the TUI when scrolling left while the cursor is at the start of the line.
+
+### `exit_past_line_end`
+
+Atuin version: >= 18.5
+
+Default: `true`
+
+Exits the TUI when scrolling right while the cursor is at the end of the line.
+
+## preview
+
+This section of the client config is specifically for configuring preview-related settings.
+(In the future the other 2 preview settings will be moved here.)
+
+```
+[preview]
+strategy = [...]
+```
+
+### `strategy`
+
+Atuin version: >= 18.3
+
+Default: `auto`
+
+Which preview strategy is used to calculate the preview height. It respects `max_preview_height`.
+
+| Value | Preview height is calculated from the length of the |
+| -------------- | --------------------------------------------------- |
+| auto (default) | selected command |
+| static | longest command in the current result set |
+| fixed | use `max_preview_height` as fixed value |
+
+By using `auto` a preview is shown, if the command is longer than the width of the terminal.
+
+## Daemon
+
+Atuin version: >= 18.3
+
+Default: `false`
+
+Enable the background daemon
+
+Add the new section to the bottom of your config file
+
+```toml
+[daemon]
+enabled = true
+```
+
+### sync_frequency
+
+Default: `300`
+
+How often the daemon should sync, in seconds
+
+```toml
+sync_frequency = 300
+```
+
+### socket_path
+
+Default:
+
+```toml
+socket_path = "~/.local/share/atuin/atuin.sock"
+```
+
+Where to bind a unix socket for client -> daemon communication
+
+If XDG_RUNTIME_DIR is available, then we use this directory instead.
+
+### systemd_socket
+
+Default `false`
+
+Use a socket passed via systemd socket activation protocol instead of the path
+
+```toml
+systemd_socket = false
+```
+
+### tcp_port
+
+Default: `8889`
+
+The port to use for client -> daemon communication. Only used on non-unix systems.
+
+```toml
+tcp_port = 8889
+```
+
+## theme
+
+Atuin version: >= 18.4
+
+The theme to use for showing the terminal interface.
+
+```toml
+[theme]
+name = "default"
+debug = false
+max_depth = 10
+```
+
+### `name`
+
+Default: `"default"`
+
+A theme name that must be present as a built-in (unset or `default` for the default,
+else `autumn` or `marine`), or found in the themes directory, with the suffix `.toml`.
+By default this is `~/.config/atuin/themes/` but can be overridden with the
+`ATUIN_THEME_DIR` environment variable.
+
+```toml
+name = "my-theme"
+```
+
+### `debug`
+
+Default: `false`
+
+Output information about why a theme will not load. Independent from other log
+levels as it can cause data from the theme file to be printed unfiltered to the
+terminal.
+
+```toml
+debug = false
+```
+
+### `max_depth`
+
+Default: 10
+
+Number of levels of "parenthood" that will be traversed for a theme. This should not
+need to be added in or changed in normal usage.
+
+```toml
+max_depth = 10
+```
+
+## ui
+
+Atuin version: >= 18.5
+
+Configure the interactive search UI appearance.
+
+```toml
+[ui]
+columns = ["duration", "time", "command"]
+```
+
+### `columns`
+
+Default: `["duration", "time", "command"]`
+
+Columns to display in the interactive search, from left to right. The selection
+indicator (`" > "`) is always shown first implicitly.
+
+Each column can be specified as:
+- A simple string (uses default width): `"duration"`
+- An object with type and optional width/expand: `{ type = "directory", width = 30 }`
+
+#### Available column types
+
+| Column | Default Width | Description |
+| --------- | ------------- | ----------------------------------------------- |
+| duration | 5 | Command execution duration (e.g., "123ms") |
+| time | 8 | Relative time since execution (e.g., "59m ago") |
+| datetime | 16 | Absolute timestamp (e.g., "2025-01-22 14:35") |
+| directory | 20 | Working directory (truncated if too long) |
+| host | 15 | Hostname where command was run |
+| user | 10 | Username |
+| exit | 3 | Exit code (colored by success/failure) |
+| command | * | The command itself (expands by default) |
+
+#### Column options
+
+- **type**: The column type (required when using object format)
+- **width**: Custom width in characters (optional, uses default if not specified)
+- **expand**: If `true`, the column fills remaining space. Default is `true` for `command`, `false` for others. Only one column should have `expand = true`.
+
+#### Examples
+
+```toml
+# Minimal - more space for commands
+columns = ["duration", "command"]
+
+# With custom directory width
+columns = ["duration", { type = "directory", width = 30 }, "command"]
+
+# Show host for multi-machine sync users
+columns = ["duration", "time", "host", "command"]
+
+# Show exit codes prominently
+columns = ["exit", "duration", "command"]
+
+# Make directory expand instead of command
+columns = ["duration", "time", { type = "directory", expand = true }, { type = "command", expand = false }]
+```
diff --git a/docs/docs/configuration/key-binding.md b/docs/docs/configuration/key-binding.md
new file mode 100644
index 00000000..42940be2
--- /dev/null
+++ b/docs/docs/configuration/key-binding.md
@@ -0,0 +1,271 @@
+# Key Binding
+
+Atuin does not yet have full key binding customization, though we do allow some changes.
+
+## Custom up arrow filter mode
+
+It can be useful to use a different filter or search mode on the up arrow. For example, you could use ctrl-r for searching globally, but the up arrow for searching history from the current directory only.
+
+Set your config like this:
+
+```
+filter_mode_shell_up_key_binding = "directory" # or global, host, directory, etc
+```
+
+## Disable up arrow
+
+Our default up-arrow binding can be a bit contentious. Some people love it, some people hate it. Many people who found it a bit jarring at first have since come to love it, so give it a try!
+
+It becomes much more powerful if you consider binding a different filter mode to the up arrow. For example, on "up" Atuin can default to searching all history for the current directory only, while ctrl-r searches history globally. See the [config](config.md#filter_mode_shell_up_key_binding) for more.
+
+Otherwise, if you don't like it, it's easy to disable.
+
+You can also disable either the up-arrow or ++ctrl+r++ bindings individually, by passing
+`--disable-up-arrow` or `--disable-ctrl-r` to the call to `atuin init` in your shell config file:
+
+An example for zsh:
+```
+# Bind ctrl-r but not up arrow
+eval "$(atuin init zsh --disable-up-arrow)"
+
+# Bind up-arrow but not ctrl-r
+eval "$(atuin init zsh --disable-ctrl-r)"
+```
+
+If you do not want either key to be bound, either pass both `--disable` arguments, or set the
+environment variable `ATUIN_NOBIND` to any value before the call to `atuin init`:
+
+```
+## Do not bind any keys
+# Either:
+eval "$(atuin init zsh --disable-up-arrow --disable-ctrl-r)"
+
+# Or:
+export ATUIN_NOBIND="true"
+eval "$(atuin init zsh)"
+```
+
+You can then choose to bind Atuin if needed, do this after the call to init.
+
+## Enter key behavior
+
+By default, the `enter` key will directly execute the selected command instead of letting you edit it like the `tab` key. If you want to change this behavior, set `enter_accept = false` in your config. For more details: [enter_accept](config.md#enter_accept).
+
+## Ctrl-n key shortcuts
+
+macOS does not have an ++alt++ key, although terminal emulators can often be configured to map the ++option++ key to be used as ++alt++. *However*, remapping ++option++ this way may prevent typing some characters, such as using ++option+3++ to type `#` on the British English layout. For such a scenario, set the `ctrl_n_shortcuts` option to `true` in your config file to replace ++alt+0++ to ++alt+9++ shortcuts with ++ctrl+0++ to ++ctrl+9++ instead:
+
+```
+# Use Ctrl-0 .. Ctrl-9 instead of Alt-0 .. Alt-9 UI shortcuts
+ctrl_n_shortcuts = true
+```
+
+Ghostty on Linux maps ++alt+1++ .. ++alt+9++ for switching between tabs by number. To disable this behavior either add the following to ~/.config/ghostty/config:
+```
+keybind=alt+one=unbind
+keybind=alt+two=unbind
+keybind=alt+three=unbind
+keybind=alt+four=unbind
+keybind=alt+five=unbind
+keybind=alt+six=unbind
+keybind=alt+seven=unbind
+keybind=alt+eight=unbind
+keybind=alt+nine=unbind
+```
+(this will disable tab switching by ++alt+n++)
+or use the `ctrl_n_shortcuts` as outlined above.
+
+## zsh
+
+If you'd like to customize your bindings further, it's possible to do so with custom shell config:
+
+Atuin defines the ZLE widgets "atuin-search" and "atuin-up-search". The latter
+can be used for the keybindings to the ++up++ key and similar keys.
+
+Note: instead use the widget names "\_atuin\_search\_widget" and "\_atuin\_up\_search\_widget", respectively, in `atuin < 18.0`
+
+```
+export ATUIN_NOBIND="true"
+eval "$(atuin init zsh)"
+
+bindkey '^r' atuin-search
+
+# bind to the up key, which depends on terminal mode
+bindkey '^[[A' atuin-up-search
+bindkey '^[OA' atuin-up-search
+```
+
+For the keybindings in vi mode, "atuin-search-viins", "atuin-search-vicmd",
+"atuin-up-search-viins", and "atuin-up-search-vicmd" (`atuin >= 18.0`) can be
+used in combination with the config
+["keymap\_mode"](config.md#keymap_mode)
+(`atuin >= 18.0`) to start the Atuin search in respective keymap modes.
+
+## bash
+
+Atuin (`>= 18.10.0`) provides a shell function `atuin-bind` to set up
+keybindings easily:
+
+```
+atuin-bind [-m KEYMAP] KEYSEQ COMMAND
+```
+
+`KEYMAP` is one of `emacs`, `vi-insert`, and `vi-command` and specifies the
+target keymap where the keybinding is defined. `KEYSEQ` specifies a key
+sequence in the format used in `bind '"KEYSEQ": ...'`. `COMMAND` specifies a
+shell command to run with the keybindings. The following special commands can
+be used as well as an arbitrary shell command:
+
+| Command | Description |
+| ----------------------- | ----------------------------------------------------------------------------------- |
+| `atuin-search` | Standard search |
+| `atuin-search-emacs` | Standard search with the `emacs` keymap mode |
+| `atuin-search-viins` | Standard search with the `vim-insert` keymap mode |
+| `atuin-search-vicmd` | Standard search with the `vim-normal` keymap mode |
+| `atuin-up-search` | Search command for <kbd>up</kbd> or similar keys |
+| `atuin-up-search-emacs` | Search command for <kbd>up</kbd> or similar keys, with the `emacs` keymap mode |
+| `atuin-up-search-viins` | Search command for <kbd>up</kbd> or similar keys, with the `vim-insert` keymap mode |
+| `atuin-up-search-vicmd` | Search command for <kbd>up</kbd> or similar keys, with the `vim-nomarl` keymap mode |
+
+The keymap mode controls the initial keymap in the Atuin search and is
+determined in combination with the config
+["keymap\_mode"](config.md#keymap_mode)
+(`atuin >= 18.0`).
+
+
+```
+export ATUIN_NOBIND="true"
+eval "$(atuin init bash)"
+
+# bind to ctrl-r, add any other bindings you want here too
+atuin-bind '\C-r' atuin-search
+# example of CTRL-upkey
+# atuin-bind '\e[1;5A' atuin-search
+
+# bind to the up key, which depends on terminal mode
+atuin-bind '\e[A' atuin-up-search
+atuin-bind '\eOA' atuin-up-search
+```
+
+With older versions of Atuin, the user needs to bind a bindable shell function
+"`__atuin_history`" directly using Bash's `bind`. The flag
+`--shell-up-key-binding` can be optionally specified to the first argument for
+keybindings to the <kbd>up</kbd> key or similar keys. For the keybindings in
+the `vi` editing mode, the options `--keymap-mode=vim-insert` and the keymap
+mode `--keymap-mode=vim-normal` (`atuin >= 18.0`) can be additionally specified
+to the shell function `__atuin_history`.
+
+## fish
+Edit key bindings in FISH shell by adding the following to ~/.config/fish/config.fish
+
+```
+set -gx ATUIN_NOBIND "true"
+atuin init fish | source
+
+# bind to ctrl-r in normal and insert mode, add any other bindings you want here too
+bind \cr _atuin_search
+bind -M insert \cr _atuin_search
+```
+
+For the ++up++ keybinding, `_atuin_bind_up` can be used instead of `_atuin_search`.
+
+Adding the useful alternative key binding of ++ctrl+up++ is tricky and determined by the terminals adherence to terminfo(5).
+
+Conveniently FISH uses a command to capture keystrokes and advises you of the exact command to add for your specific terminal.
+In your terminal, run `fish_key_reader` then punch the desired keystroke/s.
+
+For example, in Gnome Terminal the output to ++ctrl+up++ is `bind \e\[1\;5A 'do something'`
+
+So, adding this to the above sample, `bind \e\[1\;5A _atuin_search` will provide the additional search keybinding.
+
+## nu
+
+```
+$env.ATUIN_NOBIND = true
+atuin init nu | save -f ~/.local/share/atuin/init.nu #make sure you created the directory beforehand with `mkdir ~/.local/share/atuin/init.nu`
+source ~/.local/share/atuin/init.nu
+
+#bind to ctrl-r in emacs, vi_normal and vi_insert modes, add any other bindings you want here too
+$env.config = (
+ $env.config | upsert keybindings (
+ $env.config.keybindings
+ | append {
+ name: atuin
+ modifier: control
+ keycode: char_r
+ mode: [emacs, vi_normal, vi_insert]
+ event: { send: executehostcommand cmd: (_atuin_search_cmd) }
+ }
+ )
+)
+```
+
+
+## Atuin UI shortcuts
+
+| Shortcut | Action |
+| ----------------------------------------- | ----------------------------------------------------------------------------- |
+| enter | Execute selected item |
+| tab | Select item and edit |
+| ctrl + r | Cycle through filter modes |
+| ctrl + s | Cycle through search modes |
+| alt + 1 to alt + 9 | Select item by the number located near it |
+| ctrl + c / ctrl + d / ctrl + g / esc | Return original |
+| ctrl + y | Copy selected item to clipboard |
+| ctrl + ← / alt + b | Move the cursor to the previous word |
+| ctrl + → / alt + f | Move the cursor to the next word |
+| ctrl + b / ← | Move the cursor to the left |
+| ctrl + f / → | Move the cursor to the right |
+| ctrl + a / home | Move the cursor to the start of the line |
+| ctrl + e / end | Move the cursor to the end of the line |
+| ctrl + backspace / ctrl + alt + backspace | Remove the previous word / remove the word just before the cursor |
+| ctrl + delete / ctrl + alt + delete | Remove the next word or the word just after the cursor |
+| ctrl + w | Remove the word before the cursor even if it spans across the word boundaries |
+| ctrl + u | Clear the current line |
+| ctrl + n / ctrl + j / ↑ | Select the next item on the list |
+| ctrl + p / ctrl + k / ↓ | Select the previous item on the list |
+| ctrl + o | Open the [inspector](#inspector) |
+| page down | Scroll search results one page down |
+| page up | Scroll search results one page up |
+| ↓ (with no entry selected) | Return original or return query depending on [settings](config.md#exit_mode) |
+| ↓ | Select the next item on the list |
+
+
+### Vim mode
+If [vim is enabled in the config](config.md#keymap_mode), the following keybindings are enabled:
+
+| Shortcut | Mode | Action |
+| -------- | ------ | ------------------------------------------ |
+| k | Normal | Selects the next item on the list |
+| j | Normal | Selects the previous item on the list |
+| h | Normal | Move cursor left |
+| l | Normal | Move cursor right |
+| i | Normal | Enters insert mode |
+| I | Normal | Move to start of line and enter insert |
+| a | Normal | Move right and enter insert mode |
+| A | Normal | Move to end of line and enter insert |
+| Ctrl+u | Normal | Half-page up (toward visual top) |
+| Ctrl+d | Normal | Half-page down (toward visual bottom) |
+| Ctrl+b | Normal | Full-page up (toward visual top) |
+| Ctrl+f | Normal | Full-page down (toward visual bottom) |
+| G | Normal | Jump to visual bottom of history |
+| gg | Normal | Jump to visual top of history |
+| H | Normal | Jump to top of visible screen |
+| M | Normal | Jump to middle of visible screen |
+| L | Normal | Jump to bottom of visible screen |
+| ? or / | Normal | Clear input and enter insert mode |
+| 1-9 | Normal | Select item by number |
+| Esc | Insert | Enters normal mode |
+
+
+### Inspector
+Open the inspector with ctrl + o
+
+| Shortcut | Action |
+| -------- | --------------------------------------------- |
+| Esc | Close the inspector, returning to the shell |
+| ctrl + o | Close the inspector, returning to search view |
+| ctrl + d | Delete the inspected item from the history |
+| ↑ | Inspect the previous item in the history |
+| ↓ | Inspect the next item in the history |
+| tab | Select current item and edit |
diff --git a/docs/docs/faq.md b/docs/docs/faq.md
new file mode 100644
index 00000000..d016ef29
--- /dev/null
+++ b/docs/docs/faq.md
@@ -0,0 +1,58 @@
+# FAQ
+
+## How do I remove the default up arrow binding?
+
+Open your shell config file, find the line containing `atuin init`.
+
+Add `--disable-up-arrow`
+
+EG:
+
+```
+eval "$(atuin init zsh --disable-up-arrow)"
+```
+
+See [key binding](../configuration/key-binding.md) for more
+
+## How do I edit a command instead of running it immediately?
+
+Press tab! By default, enter will execute a command, and tab will insert it ready for editing.
+
+You can make `enter` edit a command by putting `enter_accept = false` into your config file (~/.config/atuin/config.toml)
+
+## How do I delete my account?
+
+**Attention:** This command does not prompt for confirmation.
+
+```
+atuin account delete
+```
+
+This will delete your account, and all history from the remote server. It will not delete your local data.
+
+## I've forgotten my password! How can I reset it?
+
+We don't (yet) have a password reset system, as we don't verify emails. This
+may change soon, but in the meantime so long as you're still logged in on at
+least one account, it's safe to delete and re-create the account.
+
+We're aware this isn't optimal.
+
+## I did not set up sync, and now I have to reinstall my system!
+
+If you have a backup of `~/.local/share/atuin`, you can import it by:
+1. disabling atuin by commenting out the shell integration, e.g. for bash it's `eval "$(atuin init bash)"`
+2. copying the backup to `~/.local/share/atuin`
+3. reenabling atuin
+4. setting up sync!
+
+## Alternative projects
+
+If you dont like atuin, perhaps one of these works better for you:
+
+- https://github.com/ddworken/hishtory
+ - written in go
+ - also provides sync'ed history
+- https://github.com/cantino/mcfly
+ - uses a small local neural network for search
+ - only local history
diff --git a/docs/docs/guide/basic-usage.md b/docs/docs/guide/basic-usage.md
new file mode 100644
index 00000000..0b40a0aa
--- /dev/null
+++ b/docs/docs/guide/basic-usage.md
@@ -0,0 +1,63 @@
+# Basic Usage
+
+Now that you're all set up and running, here's a quick walkthrough of how you can use Atuin best.
+
+## What does Atuin record?
+
+While you work, Atuin records:
+
+1. The command you run
+2. The directory you ran it in
+3. The time you ran it, and how long it took to run
+4. The exit code of the command
+5. The hostname + user of the machine
+6. The shell session you ran it in
+
+## Opening and using the TUI
+
+At any time, you can open the TUI with the default keybindings of the up arrow, or ctrl-r.
+
+Once in the TUI, press enter to immediately execute a command, or press tab to insert it into your shell for editing.
+
+While searching in the TUI, you can adjust the "filter mode" by repeatedly pressing ctrl-r. Atuin can filter by:
+
+1. All hosts
+2. Just your local machine
+3. The current directory only
+4. The current shell session only
+
+## Common config adjustment
+
+For a full set of config values, please see the [config reference page](../configuration/config.md).
+
+The default configuration file is located at `~/.config/atuin/config.toml`.
+
+### Keybindings
+
+We have a [full page dedicated to keybinding adjustments](../configuration/key-binding.md).
+There are a whole bunch of options there, including disabling the up arrow behavior if you don't like it.
+
+### Enter to run
+
+You may prefer that Atuin always inserts the selected command for editing. To configure this, set
+
+```
+enter_accept = false
+```
+
+in your config file.
+
+### Inline window
+
+If you find the full screen TUI overwhelming or too large, you can adjust it like so:
+
+```
+# height of the search window
+inline_height = 40
+```
+
+You may also prefer the compact UI mode:
+
+```
+style = "compact"
+```
diff --git a/docs/docs/guide/dotfiles.md b/docs/docs/guide/dotfiles.md
new file mode 100644
index 00000000..d4157cb7
--- /dev/null
+++ b/docs/docs/guide/dotfiles.md
@@ -0,0 +1,141 @@
+# Syncing dotfiles
+
+While Atuin started as a tool for syncing and searching shell history, we are
+building tooling for syncing dotfiles across machines, and making them easier
+to work with.
+
+At the moment, we support managing and syncing of shell aliases and environment variables - with more
+coming soon.
+
+The following shells are supported:
+
+- zsh
+- bash
+- fish
+- xonsh
+- powershell
+
+Note: Atuin handles your configuration internally, so once it is installed you
+no longer need to edit your config files manually.
+
+## Required config
+
+Once Atuin is set up and installed, the following is required in your config file (`~/.config/atuin/config.toml`)
+
+```
+[dotfiles]
+enabled = true
+```
+
+In a later release, this will be enabled by default.
+
+Note: If you have not yet set up sync v2, please also add
+
+```
+[sync]
+records = true
+```
+
+to the same config file.
+
+## Usage
+
+### Aliases
+
+After creating or deleting an alias, remember to restart your shell!
+
+#### Creating an alias
+
+```
+atuin dotfiles alias set NAME 'COMMAND'
+```
+
+For example, to alias `k` to be `kubectl`
+
+
+```
+atuin dotfiles alias set k 'kubectl'
+```
+
+or to alias `ll` to be `ls -lah`
+
+```
+atuin dotfiles alias set ll 'ls -lah'
+```
+
+#### Deleting an alias
+
+Deleting an alias is as simple as:
+
+```
+atuin dotfiles alias delete NAME
+```
+
+For example, to delete the above alias `k`:
+
+```
+atuin dotfiles alias delete k
+```
+
+#### Listing aliases
+
+You can list all aliases with:
+
+```
+atuin dotfiles alias list
+```
+
+### Env vars
+
+After creating or deleting an env var, remember to restart your shell!
+
+#### Creating a var
+
+```
+atuin dotfiles var set NAME 'value'
+```
+
+For example, to set `FOO` to be `bar`
+
+
+```
+atuin dotfiles var set FOO 'bar'
+```
+
+Vars are exported by default, but you can create a shell var like so
+
+```
+atuin dotfiles var set -n foo 'bar'
+```
+
+
+#### Deleting a var
+
+Deleting a var is as simple as:
+
+```
+atuin dotfiles var delete NAME
+```
+
+For example, to delete the above var `FOO`:
+
+```
+atuin dotfiles var delete FOO
+```
+
+#### Listing vars
+
+You can list all vars with:
+
+```
+atuin dotfiles var list
+```
+
+### Syncing and backing up dotfiles
+If you have [set up sync](sync.md), then running
+
+```
+atuin sync
+```
+
+will back up your config to the server and sync it across machines.
diff --git a/docs/docs/guide/getting-started.md b/docs/docs/guide/getting-started.md
new file mode 100644
index 00000000..85140b25
--- /dev/null
+++ b/docs/docs/guide/getting-started.md
@@ -0,0 +1,54 @@
+# Getting Started
+
+Atuin replaces your existing shell history with a SQLite database, and records
+additional context for your commands. With this context, Atuin gives you faster
+and better search of your shell history.
+
+Additionally, Atuin (optionally) syncs your shell history between all of your
+machines. Fully end-to-end encrypted, of course.
+
+You may use either the server I host, or host your own! Or just don't use sync
+at all. As all history sync is encrypted, I couldn't access your data even if I
+wanted to. And I **really** don't want to.
+
+If you have any problems, please open an [issue](https://github.com/ellie/atuin/issues) or get in touch on our [Discord](https://discord.gg/Fq8bJSKPHh)!
+
+## Supported Shells
+
+- zsh
+- bash
+- fish
+- nushell
+- xonsh
+- powershell (tier 2 support)
+
+## Quickstart
+
+Please do try and read this guide, but if you're in a hurry and want to get
+started quickly:
+
+```
+bash <(curl --proto '=https' --tlsv1.2 -sSf https://setup.atuin.sh)
+
+atuin register -u <USERNAME> -e <EMAIL>
+atuin import auto
+atuin sync
+```
+
+Now restart your shell!
+
+Anytime you press ctrl-r or up, you will see the Atuin search UI. Type your
+query, enter to execute. If you'd like to select a command without executing
+it, press tab.
+
+You might like to configure an [inline window](../configuration/config.md#inline_height), or [disable up arrow bindings](../configuration/key-binding.md#disable-up-arrow)
+
+Note: The above sync and registration is fully optional. If you'd like to use Atuin offline, you can run
+
+```
+bash <(curl --proto '=https' --tlsv1.2 -sSf https://setup.atuin.sh)
+
+atuin import auto
+```
+
+Your shell history will be local only, not backed up, and not synchronized across devices.
diff --git a/docs/docs/guide/import.md b/docs/docs/guide/import.md
new file mode 100644
index 00000000..3e19b26c
--- /dev/null
+++ b/docs/docs/guide/import.md
@@ -0,0 +1,18 @@
+# Import existing history
+
+Atuin uses a shell plugin to ensure that we capture new shell history. But for
+older history, you will need to import it
+
+This will import the history for your current shell:
+```
+atuin import auto
+```
+
+Alternatively, you can specify the shell like so:
+
+```
+atuin import bash
+atuin import zsh # etc
+```
+
+Your old shell history file will continue to be updated, regardless of Atuin usage.
diff --git a/docs/docs/guide/installation.md b/docs/docs/guide/installation.md
new file mode 100644
index 00000000..aeb33518
--- /dev/null
+++ b/docs/docs/guide/installation.md
@@ -0,0 +1,276 @@
+# Installation
+
+## Recommended installation approach
+
+### On Unix
+
+Let's get started! First up, you will want to install Atuin. The recommended
+approach is to use the installation script, which automatically handles the
+installation of Atuin including the requirements for your environment.
+
+
+It will install a binary to `~/.atuin/bin`, and if you'd rather do something else
+then the manual steps below offer much more flexibility.
+
+```shell
+curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh
+```
+
+[**Set up sync** - Move on to the next step, or read on to manually install Atuin instead.](sync.md)
+
+### On Windows
+
+The recommended approach on Windows is to use WinGet to install Atuin. Then, if you use PowerShell,
+add the initialization command to your PowerShell profile, and restart your shell.
+
+```shell
+winget install -e Atuinsh.Atuin
+if (-not (Test-Path -Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force | Out-Null }
+Write-Output 'atuin init powershell | Out-String | Invoke-Expression' >> $PROFILE
+```
+
+Note that the `$PROFILE` path may depend on your PowerShell version.
+
+[**Set up sync** - Move on to the next step.](sync.md)
+
+## Manual installation
+
+### Installing the binary
+
+If you don't wish to use the installer, the manual installation steps are as follows.
+
+=== "Cargo"
+
+ It's best to use [rustup](https://rustup.rs/) to set up a Rust
+ toolchain, then you can run:
+
+ ```shell
+ cargo install atuin
+ ```
+
+=== "Homebrew"
+
+ ```shell
+ brew install atuin
+ ```
+
+=== "MacPorts"
+
+ Atuin is also available in [MacPorts](https://ports.macports.org/port/atuin/)
+
+ ```shell
+ sudo port install atuin
+ ```
+
+=== "mise"
+
+ Atuin is also installable using [mise](https://github.com/jdx/mise)
+
+ ```shell
+ mise use -g atuin@latest
+ ```
+
+=== "Nix"
+
+ This repository is a flake, and can be installed using `nix profile`:
+
+ ```shell
+ nix profile install "github:atuinsh/atuin"
+ ```
+
+ Atuin is also available in [nixpkgs](https://github.com/NixOS/nixpkgs):
+
+ ```shell
+ nix-env -f '<nixpkgs>' -iA atuin
+ ```
+
+=== "Pacman"
+
+ Atuin is available in the Arch Linux [extra repository](https://archlinux.org/packages/extra/x86_64/atuin/):
+
+ ```shell
+ pacman -S atuin
+ ```
+
+=== "XBPS"
+
+ Atuin is available in the Void Linux [repository](https://github.com/void-linux/void-packages/tree/master/srcpkgs/atuin):
+
+ ```shell
+ sudo xbps-install atuin
+ ```
+
+=== "Termux"
+
+ Atuin is available in the Termux package repository:
+
+ ```shell
+ pkg install atuin
+ ```
+
+=== "zinit"
+
+ Atuin is installable from github-releases directly:
+
+ ```shell
+ # line 1: `atuin` binary as command, from github release, only look at .tar.gz files, use the `atuin` file from the extracted archive
+ # line 2: setup at clone(create init.zsh, completion)
+ # line 3: pull behavior same as clone, source init.zsh
+ zinit ice as"command" from"gh-r" bpick"atuin-*.tar.gz" mv"atuin*/atuin -> atuin" \
+ atclone"./atuin init zsh > init.zsh; ./atuin gen-completions --shell zsh > _atuin" \
+ atpull"%atclone" src"init.zsh"
+ zinit light atuinsh/atuin
+ ```
+
+=== "WinGet"
+
+ Atuin is available on WinGet:
+
+ ```shell
+ winget install -e Atuinsh.Atuin
+ ```
+
+=== "Source"
+
+ Atuin builds on the latest stable version of Rust, and we make no
+ promises regarding older versions. We recommend using [rustup](https://rustup.rs/).
+
+ ```shell
+ git clone https://github.com/atuinsh/atuin.git
+ cd atuin/crates/atuin
+ cargo install --path .
+ ```
+
+!!! warning "Please be advised"
+
+ If you choose to manually install Atuin rather than using the recommended installation script,
+ merely installing the binary is not sufficient, you should also set up the shell plugin.
+
+---
+
+### Installing the shell plugin
+
+Once the binary is installed, the shell plugin requires installing.
+If you use the install script, this should all be done for you!
+After installing, remember to restart your shell.
+
+=== "zsh"
+
+ ```shell
+ echo 'eval "$(atuin init zsh)"' >> ~/.zshrc
+ ```
+
+ === "zinit"
+
+ ```shell
+ # if you _only_ want to install the shell-plugin, do this; otherwise look above for a "everything via zinit" solution
+ zinit load atuinsh/atuin
+ ```
+
+ === "Antigen"
+
+ ```shell
+ antigen bundle atuinsh/atuin@main
+ ```
+
+ === "Antidote"
+
+ ```shell
+ antidote install atuinsh/atuin
+ ```
+
+=== "bash"
+
+ === "ble.sh"
+
+ Atuin works best in bash when using [ble.sh](https://github.com/akinomyoga/ble.sh) >= 0.4.
+
+ With ble.sh (>= 0.4) installed and loaded in `~/.bashrc`, just add atuin to your `~/.bashrc`
+
+ ```shell
+ echo 'eval "$(atuin init bash)"' >> ~/.bashrc
+ ```
+
+ === "bash-preexec"
+
+ [Bash-preexec](https://github.com/rcaloras/bash-preexec) can also be used, but you may experience
+ some minor problems with the recorded duration and exit status of some commands.
+
+ !!! warning "Please note"
+
+ bash-preexec currently has an issue where it will stop honoring `ignorespace`.
+ While Atuin will ignore commands prefixed with whitespace, they may still end up in your bash history.
+ Please check your configuration! All other shells do not have this issue.
+
+ To use `atuin < 18.10.0` in `bash < 4` with bash-preexec, the option
+ `enter_accept` needs to be turned on (which is so by default). There is no
+ restriction in the latest version of Atuin (>= 18.10.0).
+
+ bash-preexec cannot properly invoke the `preexec` hook for subshell commands
+ `(...)`, function definitions `func() { ...; }`, empty for-in-statements `for
+ i in; do ...; done`, etc., so those commands and duration may not be recorded
+ in the Atuin's history correctly.
+
+ To use bash-preexec, download and initialize it
+
+ ```shell
+ curl https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~/.bash-preexec.sh
+ echo '[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh' >> ~/.bashrc
+ ```
+
+ Then set up Atuin
+
+ ```shell
+ echo 'eval "$(atuin init bash)"' >> ~/.bashrc
+ ```
+
+=== "fish"
+
+ Add
+
+ ```shell
+ atuin init fish | source
+ ```
+
+ to your `is-interactive` block in your `~/.config/fish/config.fish` file
+
+=== "Nushell"
+
+ Run in *Nushell*:
+
+ ```shell
+ mkdir ~/.local/share/atuin/
+ atuin init nu | save ~/.local/share/atuin/init.nu
+ ```
+
+ Add to `config.nu`:
+
+ ```shell
+ source ~/.local/share/atuin/init.nu
+ ```
+
+=== "xonsh"
+
+ Add
+ ```shell
+ execx($(atuin init xonsh))
+ ```
+ to the end of your `~/.xonshrc`
+
+=== "PowerShell"
+
+ Add the following to the end of your `$PROFILE` file:
+
+ ```shell
+ atuin init powershell | Out-String | Invoke-Expression
+ ```
+
+## Upgrade
+
+Run `atuin update`, and if that command is not available, run the install script again.
+
+If you used a package manager to install Atuin, then you should also use your package manager to update Atuin.
+
+## Uninstall
+
+If you'd like to uninstall Atuin, please check out [the uninstall page](../uninstall.md).
diff --git a/docs/docs/guide/sync.md b/docs/docs/guide/sync.md
new file mode 100644
index 00000000..070d8178
--- /dev/null
+++ b/docs/docs/guide/sync.md
@@ -0,0 +1,78 @@
+# Setting up Sync
+
+At this point, you have Atuin storing and searching your shell history! But it
+isn't syncing it just yet. To do so, you'll need to register with the sync
+server. All of your history is fully end-to-end encrypted, so there are no
+risks of the server snooping on you.
+
+If you don't have an account, please [register](#register). If you have already registered,
+proceed to [login](#login).
+
+**Note:** You first have to set up your `sync_address` if you want to use a [self hosted server](../self-hosting/server-setup.md).
+
+## Register
+
+```
+atuin register -u <YOUR_USERNAME> -e <YOUR EMAIL>
+```
+
+After registration, Atuin will generate an encryption key for you and store it
+locally. This is needed for logging in to other machines, and can be seen with
+
+```
+atuin key
+```
+
+Please **never** share this key with anyone! The Atuin developers will never
+ask you for your key, your password, or the contents of your Atuin directory.
+
+If you lose your key, we can do nothing to help you. We recommend you store
+this somewhere safe, such as in a password manager.
+
+## First sync
+By default, Atuin will sync your history once per hour. This can be
+[configured](../configuration/config.md#sync_frequency).
+
+To run a sync manually, please run
+
+```
+atuin sync
+```
+
+Atuin tries to be smart with a sync, and not waste data transfer. However, if
+you are seeing some missing data, please try running
+
+```
+atuin sync -f
+```
+
+This triggers a full sync, which may take longer as it works through historical data.
+
+## Login
+
+When only signed in on one machine, Atuin sync operates as a backup. This is
+pretty useful by itself, but syncing multiple machines is where the magic
+happens.
+
+First, ensure you are [registered with the sync server](#register) and make a
+note of your key. You can see this with `atuin key`.
+
+Then, install Atuin on a new machine. Once installed, login with
+
+```
+atuin login -u <USERNAME>
+```
+
+You will be prompted for your password, and for your key.
+
+Syncing will happen automatically in the background, but you may wish to run it manually with
+
+```
+atuin sync
+```
+
+Or, if you see missing data, force a full sync with:
+
+```
+atuin sync -f
+```
diff --git a/docs/docs/guide/theming.md b/docs/docs/guide/theming.md
new file mode 100644
index 00000000..2d71d41d
--- /dev/null
+++ b/docs/docs/guide/theming.md
@@ -0,0 +1,138 @@
+# Theming
+
+Available in Atuin >= 18.4
+
+For terminal interface customization, Atuin supports user and built-in color themes.
+
+Atuin ships with only a couple of built-in alternative themes, but more can be added via TOML files.
+
+## Required config
+
+The following is required in your config file (`~/.config/atuin/config.toml`)
+
+```
+[theme]
+name = "THEMENAME"
+```
+
+Where `THEMENAME` is a known theme. The following themes are available out-of-the-box:
+
+* `default` theme
+* `autumn` theme
+* `marine` theme
+* `(none)` theme (removes all styling)
+
+These are present to ensure users and developers can try out theming, but in general, you
+will need to download themes or make your own.
+
+If you are writing your own themes, you can add the following line to get additional output:
+
+```
+debug = true
+```
+
+to the same config block. This will print out any color names that cannot be parsed from
+the requested theme.
+
+A final optional setting is available:
+
+```
+max_depth: 10
+```
+
+which sets the maximum levels of theme parents to traverse. This should not need to be
+explicitly added in normal use.
+
+## Usage
+
+### Theme structure
+
+Themes are maps from *Meanings*, describing the developer's intentions,
+to (at present) colors. In future, this may be expanded to allow richer style support.
+
+*Meanings* are from an enum with the following values:
+
+* `AlertInfo`: alerting the user at an INFO level
+* `AlertWarn`: alerting the user at a WARN level
+* `AlertError`: alerting the user at an ERROR level
+* `Annotation`: less-critical, supporting text
+* `Base`: default foreground color
+* `Guidance`: instructing the user as help or context
+* `Important`: drawing the user's attention to information
+* `Title`: titling a section or view
+* `Muted`: anodyne, usually grey, foreground for contrast with other colors. Normally equivalent to the base color, but allows themes to change the base color, with less risk of breaking intentional color contrasts (e.g. stacked bar charts)
+
+These may expand over time as they are added to Atuin's codebase, but Atuin
+should have fallbacks added for any new *Meanings* so that, whether themes limit to
+the present list or take advantage of new *Meanings* in future, they should
+keep working sensibly.
+
+**Note for Atuin contributors**: please do identify and, where appropriate during your own
+PRs, extend the Meanings enum if needed (along with a fallback Meaning!).
+
+### Theme creation
+
+When a theme name is read but not yet loaded, Atuin will look for it in the folder
+`~/.config/atuin/themes/` unless overridden by the `ATUIN_THEME_DIR` environment
+variable. It will attempt to open a file of name `THEMENAME.toml` and read it as a
+map from *Meanings* to foreground colors.
+
+Note that, at present, it is not possible to specify the default terminal color explicitly
+in a theme file. However, the default theme Base color will always be unset and therefore
+will be the user's default terminal color. Hence, you should only override the Base color
+in your theme, or derive from a theme that does so, if your theme would not make sense
+otherwise (e.g. the `marine` theme is intended to make everything green/blue, so it does,
+but the `autumn` theme only seeks to make the custom colors warmer, so it does not).
+
+Colors may be specified either as names from the [palette](https://ogeon.github.io/docs/palette/master/palette/named/index.html)
+crate in lowercase, or as six-character hex codes, prefixed with `#`. To explicitly select ANSI colors by integer, or for greater flexibility in general, you can prefix with `@` and the rest of the string will be handled by crossterm's color parsing. For examples, see [crossterm's color deserialization tests](https://github.com/crossterm-rs/crossterm/blob/5d50d8da62c5e034ef8b2787a771a2c0f9b3b2f9/src/style/types/color.rs#L389), remembering the need to add a `@` prefix for atuin.
+
+For example, the following are valid color names:
+
+* `#ff0088`
+* `teal`
+* `powderblue`
+* `@ansi_(255)`
+* `@rgb_(255, 128, 0)`
+
+You can also express colors through Crossterm-supported strings, prefixed by `@`.
+For example,
+
+* `@ansi_(123)`
+* `@dark_yellow`
+
+While there is not currently an official reference, you can see examples in the
+[crossterm tests](https://docs.rs/crossterm/latest/src/crossterm/style/types/color.rs.html#376).
+As this is passed straight to Crossterm, using [ANSI codes](https://www.ditig.com/256-colors-cheat-sheet)
+can be helpful for ensuring your theme is compatible with 256-color terminals.
+
+A theme file, say `my-theme.toml` can then be built up, such as:
+
+```toml
+[theme]
+name = "my-theme"
+parent = "autumn"
+
+[colors]
+AlertInfo = "green"
+Guidance = "#888844"
+
+```
+
+where not all of the *Meanings* need to be explicitly defined. If they are absent,
+then the color will be chosen from the parent theme, if one is defined, or if that
+key is missing in the `theme` block, from the `default` theme.
+
+If the entire named theme is missing, which is inherently an error, then the theme
+will drop to `(none)` and leave Atuin unstyled, rather than trying to fallback to
+the any default, or other, theme.
+
+This theme file should be moved to `~/.config/atuin/themes/my-theme.toml` and the
+following added to `~/.config/atuin/config.toml`:
+
+```
+[theme]
+name = "my-theme"
+```
+
+When you next run Atuin, your theme should be applied.
diff --git a/docs/docs/index.md b/docs/docs/index.md
new file mode 100644
index 00000000..43ef2f9c
--- /dev/null
+++ b/docs/docs/index.md
@@ -0,0 +1,48 @@
+# Getting started
+
+Atuin replaces your existing shell history with a SQLite database, and records
+additional context for your commands. With this context, Atuin gives you faster
+and better search of your shell history.
+
+Additionally, Atuin (optionally) syncs your shell history between all of your
+machines. Fully end-to-end encrypted, of course.
+
+You may use either the server I host, or host your own! Or just don't use sync
+at all. As all history sync is encrypted, I couldn't access your data even if I
+wanted to. And I **really** don't want to.
+
+If you have any problems, please open a topic on the [forum](https://forum.atuin.sh)
+
+Alternatively, get in touch on our [Discord](https://discord.gg/Fq8bJSKPHh) or open an [issue](https://github.com/atuinsh/atuin/issues)
+
+#### Supported Shells
+
+- zsh
+- bash
+- fish
+- nushell
+- xonsh
+- powershell (tier 2 support)
+
+## Quickstart
+
+Please do try and read this guide, but if you're in a hurry and want to get
+started quickly:
+
+```bash
+bash <(curl --proto '=https' --tlsv1.2 -sSf https://setup.atuin.sh)
+
+atuin register -u <USERNAME> -e <EMAIL>
+atuin import auto
+atuin sync
+```
+
+Now restart your shell!
+
+Anytime you press ctrl-r or up, you will see the Atuin search UI. Type your
+query, enter to execute. If you'd like to select a command without executing
+it, press tab.
+
+You might like to configure an [inline window](configuration/config.md#inline_height), or [disable up arrow bindings](configuration/key-binding.md#disable-up-arrow)
+
+[**Installation** - Install and setup Atuin](guide/installation.md)
diff --git a/docs/docs/integrations.md b/docs/docs/integrations.md
new file mode 100644
index 00000000..8c031601
--- /dev/null
+++ b/docs/docs/integrations.md
@@ -0,0 +1,33 @@
+# Integrations
+
+## zsh-autosuggestions
+
+Atuin automatically adds itself as an [autosuggest strategy](https://github.com/zsh-users/zsh-autosuggestions#suggestion-strategy).
+
+If you'd like to override this, add your own config after `"$(atuin init zsh)"` in your `.zshrc`.
+
+## zsh-vi-mode
+
+If you are using [Zsh Vi Mode](https://github.com/jeffreytse/zsh-vi-mode), you may want to add the following to your `.zshrc` to prevent overriding the default atuin binds:
+
+```shell
+# Append a command directly (after sourcing zvm)
+zvm_after_init_commands+=(
+ 'eval "$(atuin init zsh)"'
+)
+```
+
+## ble.sh auto-complete (Bash)
+
+If ble.sh is available when Atuin's integration is loaded in Bash, Atuin automatically defines and registers an auto-complete source for the autosuggestion feature of ble.sh.
+
+If you'd like to change the behavior, please overwrite the shell function `ble/complete/auto-complete/source:atuin-history` after `eval "$(atuin init bash)"` in your `.bashrc`.
+
+If you would not like Atuin's auto-complete source, please add the following setting after `eval "$(atuin init bash)"` in your `.bashrc`:
+
+```shell
+# bashrc (after eval "$(atuin init bash)")
+
+ble/util/import/eval-after-load core-complete '
+ ble/array#remove _ble_complete_auto_source atuin-history'
+```
diff --git a/docs/docs/known-issues.md b/docs/docs/known-issues.md
new file mode 100644
index 00000000..21179fa9
--- /dev/null
+++ b/docs/docs/known-issues.md
@@ -0,0 +1,4 @@
+# Known Issues
+
+- SQLite has some issues with ZFS in certain configurations. As Atuin uses SQLite, this may cause your shell to become slow! We have an [issue](https://github.com/atuinsh/atuin/issues/952) to track, with some workarounds
+- SQLite also does not tend to like network filesystems (eg, NFS)
diff --git a/docs/docs/reference/daemon.md b/docs/docs/reference/daemon.md
new file mode 100644
index 00000000..22088254
--- /dev/null
+++ b/docs/docs/reference/daemon.md
@@ -0,0 +1,29 @@
+# daemon
+
+## `atuin daemon`
+_This is experimental!_
+
+The Atuin daemon is a background daemon designed to
+
+1. Speed up database writes
+2. Allow machines to sync when not in use, so they're ready to go right away
+3. Perform background maintenance
+
+It may also work around issues with ZFS/SQLite performance.
+
+It's currently experimental, but is safe to use with a little bit of setup
+
+## To enable
+
+Add the following to the bottom of your Atuin config file
+
+```toml
+[daemon]
+enabled = true
+```
+
+Then, run `atuin daemon`. This might make sense in a tmux session, systemd unit, etc. Once it's ready for wider use, we will handle this setup for you.
+
+## Extra config
+
+See the [config section](../configuration/config.md#daemon)
diff --git a/docs/docs/reference/doctor.md b/docs/docs/reference/doctor.md
new file mode 100644
index 00000000..bd091aeb
--- /dev/null
+++ b/docs/docs/reference/doctor.md
@@ -0,0 +1,38 @@
+# doctor
+
+## `atuin doctor`
+
+This command will attempt to diagnose common problems. It will also dump information about your system
+
+Please include its output with issues and support requests.
+
+Example output:
+
+```
+Atuin Doctor
+Checking for diagnostics
+
+
+Please include the output below with any bug reports or issues
+
+atuin:
+ version: 18.1.0
+ sync:
+ cloud: true
+ records: true
+ auto_sync: true
+ last_sync: 2024-03-05 14:54:48.447677 +00:00:00
+shell:
+ name: zsh
+ plugins:
+ - atuin
+system:
+ os: Darwin
+ arch: arm64
+ version: 14.4
+ disks:
+ - name: Macintosh HD
+ filesystem: apfs
+ - name: Macintosh HD
+ filesystem: apfs
+```
diff --git a/docs/docs/reference/gen-completions.md b/docs/docs/reference/gen-completions.md
new file mode 100644
index 00000000..3027d8a9
--- /dev/null
+++ b/docs/docs/reference/gen-completions.md
@@ -0,0 +1,20 @@
+# gen-completions
+
+[Shell completions](https://en.wikipedia.org/wiki/Command-line_completion) for Atuin can be generated by specifying the output directory and desired shell via `gen-completions` subcommand.
+
+```
+$ atuin gen-completions --shell bash --out-dir $HOME
+
+Shell completion for BASH is generated in "/home/user"
+```
+
+Possible values for the `--shell` argument are the following:
+
+- `bash`
+- `fish`
+- `zsh`
+- `nushell`
+- `powershell`
+- `elvish`
+
+Also, see the [supported shells](https://github.com/atuinsh/atuin#supported-shells).
diff --git a/docs/docs/reference/import.md b/docs/docs/reference/import.md
new file mode 100644
index 00000000..05a4e466
--- /dev/null
+++ b/docs/docs/reference/import.md
@@ -0,0 +1,109 @@
+# import
+
+## `atuin import`
+
+Atuin can import your history from your "old" history file
+
+`atuin import auto` will attempt to figure out your shell (via \$SHELL) and run
+the correct importer
+
+Unfortunately these older files do not store as much information as Atuin does,
+so not all features are available with imported data.
+
+Except as noted otherwise, you can set the `HISTFILE` environment variable to
+control which file is read, otherwise each importer will try some default filenames.
+
+```
+HISTFILE=/path/to/history/file atuin import zsh
+```
+
+Note that for shells such as Xonsh that store history in many files rather than a
+single file, `$HISTFILE` should be set to the directory in which those files reside.
+
+For formats that don't store timestamps, timestamps will be generated starting at
+the current time plus 1ms for each additional command in the history.
+
+Most importers will discard commands found that have invalid UTF-8.
+
+## bash
+
+This will read the history from `$HISTFILE` or `$HOME/.bash_history`.
+
+Warnings will be issued if timestamps are found to be out of order, which could also
+happen when a history file starts without timestamps but later entries include them.
+
+## fish
+
+fish supports multiple history sessions, so the importer will default to the `fish`
+session unless the `fish_history` environment variable is set. The file to be read
+will be `{session}_history` in `$XDG_DATA_HOME/fish/` (or `$HOME/.local/share/fish`).
+
+Not all of the data in the fish history is preserved, some data about filenames used
+for each command are not used by Atuin, so it is discarded.
+
+## nu
+
+This importer reads from Nushell's text history format, which is stored in
+`$XDG_CONFIG_HOME/nushell/history.txt` or `$HOME/.config/nushell/history.txt`.
+There is no way to set the filename otherwise.
+
+## nu-hist-db
+
+This importer reads from Nushell's SQLite history database, which is stored in
+`$XDG_CONFIG_HOME/nushell/history.sqlite3` or `$HOME/.config/nushell/history.sqlite3`.
+There is no way to set the filename otherwise.
+
+## powershell
+
+This importer reads from
+[PowerShell's history file](https://learn.microsoft.com/en-us/powershell/module/psreadline/about/about_psreadline#command-history).
+On Windows, the file is located at
+`$APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt`.
+On other systems, it is located at
+`$XDG_DATA_HOME/powershell/PSReadLine/ConsoleHost_history.txt`
+or `$HOME/.local/share/powershell/PSReadLine/ConsoleHost_history.txt`.
+
+## replxx
+
+The [replxx](https://github.com/AmokHuginnsson/replxx) importer will read from
+`$HISTFILE` or `$HOME/.histfile`.
+
+## resh
+
+The [RESH](https://github.com/curusarn/resh) importer will read from `$HISTFILE`
+or `$HOME/.resh_history.json`.
+
+## xonsh
+
+The Xonsh importer will read from all JSON files it finds in the Xonsh history
+directory. The location of the directory is determined as follows:
+* If `$HISTFILE` is set, its value is used as the history directory.
+* If `$XONSH_DATA_DIR` is set (as it typically will be if the importer is invoked
+from within Xonsh), `$XONSH_DATA_DIR/history_json` is used.
+* If `$XDG_DATA_HOME` is set, `$XDG_DATA_HOME/xonsh/history_json` is used.
+* Otherwise, `$HOME/.local/share/xonsh/history_json` is used.
+
+Not all data present in Xonsh history JSON files is used by Atuin. Xonsh stores the
+environment variables present when each session was initiated, but this data is
+discarded by Atuin. Xonsh optionally stores the output of each command; if present
+this data is also ignored by Atuin.
+
+## xonsh-sqlite
+
+The Xonsh SQLite importer will read from the Xonsh SQLite history file. The history
+file's location is determined by the same process as the regular Xonsh importer,
+but with `history_json` replaced by `xonsh-history.sqlite`.
+
+The Xonsh SQLite backend does not store environment variables, but like the JSON
+backend it can optionally store the output of each command. As with the JSON backend,
+if present this data will be ignored by Atuin.
+
+## zsh
+
+This will read the Zsh history from `$HISTFILE` or `$HOME/.zhistory`
+or `$HOME/.zsh_history` in either the simple or extended format.
+
+## zsh-hist-db
+
+This will read the Zsh histdb SQLite file from `$HISTDB_FILE` or
+`$HOME/.histdb/zsh-history.db`.
diff --git a/docs/docs/reference/info.md b/docs/docs/reference/info.md
new file mode 100644
index 00000000..a19d0b42
--- /dev/null
+++ b/docs/docs/reference/info.md
@@ -0,0 +1,22 @@
+# info
+
+## `atuin info`
+
+This command shows the location of config files on your system
+
+Example output:
+
+```
+Config files:
+client config: "/Users/ellie/.config/atuin/config.toml"
+server config: "/Users/ellie/.config/atuin/server.toml"
+client db path: "/Users/ellie/.local/share/atuin/history.db"
+key path: "/Users/ellie/.local/share/atuin/key"
+session path: "/Users/ellie/.local/share/atuin/session"
+
+Env Vars:
+ATUIN_CONFIG_DIR = "None"
+
+Version info:
+version: 18.1.0
+```
diff --git a/docs/docs/reference/list.md b/docs/docs/reference/list.md
new file mode 100644
index 00000000..a9920718
--- /dev/null
+++ b/docs/docs/reference/list.md
@@ -0,0 +1,31 @@
+# history list
+
+## `atuin history list`
+
+
+| Arg | Description |
+|------------------|-------------------------------------------------------------------------------|
+| `--cwd`/`-c` | List history for the current directory only (default: all dirs) |
+| `--session`/`-s` | List history for the current session only (default: false) |
+| `--human` | Use human-readable formatting for the timestamp and duration (default: false) |
+| `--cmd-only` | Show only the text of the command (default: false) |
+| `--reverse` | Reverse the order of the output (default: false) |
+| `--format` | Specify the formatting of a command (see below) |
+| `--print0` | Terminate the output with a null, for better multiline support |
+
+
+## Format
+
+Customize the output of `history list`
+
+Example
+
+```
+atuin history list --format "{time} - {duration} - {command}"
+```
+
+Supported variables
+
+```
+{command}, {directory}, {duration}, {user}, {host} and {time}
+```
diff --git a/docs/docs/reference/prune.md b/docs/docs/reference/prune.md
new file mode 100644
index 00000000..40a75d5c
--- /dev/null
+++ b/docs/docs/reference/prune.md
@@ -0,0 +1,15 @@
+# history prune
+
+## `atuin history prune`
+
+This command deletes history entries matching the [history_filter](../configuration/config.md#history_filter) configuration parameter.
+
+These may be commands that match the current `history_filter` configuration, but were saved to history before the filter was set up, and therefore were not excluded from history at the time of execution.
+
+It may be useful to run the prune command after updating `history_filter` to remove old history entries that match the new filters.
+
+It can be run with `--dry-run` first to list history entries that will be removed.
+
+| Argument | Description |
+|------------------|--------------------------------------------------------------------|
+| `--dry-run`/`-n` | List matching history lines without performing the actual deletion |
diff --git a/docs/docs/reference/search.md b/docs/docs/reference/search.md
new file mode 100644
index 00000000..7bce816b
--- /dev/null
+++ b/docs/docs/reference/search.md
@@ -0,0 +1,65 @@
+# search
+
+Atuin search supports wildcards, with either the `*` or `%` character. By
+default, a prefix search is performed (ie, all queries are automatically
+appended with a wildcard).
+
+| Arg &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| Description |
+| -------------------- | ----------------------------------------------------------------------------- |
+| `--cwd`/`-c` | The directory to list history for (default: all dirs) |
+| `--exclude-cwd` | Do not include commands that ran in this directory (default: none) |
+| `--exit`/`-e` | Filter by exit code (default: none) |
+| `--exclude-exit` | Do not include commands that exited with this value (default: none) |
+| `--before` | Only include commands ran before this time(default: none) |
+| `--after` | Only include commands ran after this time(default: none) |
+| `--interactive`/`-i` | Open the interactive search UI (default: false) |
+| `--human` | Use human-readable formatting for the timestamp and duration (default: false) |
+| `--limit` | Limit the number of results (default: none) |
+| `--offset` | Offset from the start of the results (default: none) |
+| `--delete` | Delete history matching this query |
+| `--delete-it-all` | Delete all shell history |
+| `--reverse` | Reverse order of search results, oldest first |
+| `--format`/`-f` | Available variables: {command}, {directory}, {duration}, {user}, {host}, {time}, {exit} and {relativetime}. Example: --format "{time} - [{duration}] - {directory}$\t{command}" |
+| `--inline-height` | Set the maximum number of lines Atuin's interface should take up |
+| `--help`/`-h` | Print help |
+
+## `atuin search -i`
+
+Atuin's interactive search TUI allows you to fuzzy search through your history.
+
+![compact](https://user-images.githubusercontent.com/1710904/161623659-4fec047f-ea4b-471c-9581-861d2eb701a9.png)
+
+You can replay the `nth` command with `alt + #` where `#` is the line number of the command you would like to replay.
+
+Note: This is not yet supported on macOS.
+
+## Examples
+
+```
+# Open the interactive search TUI
+atuin search -i
+
+# Open the interactive search TUI preloaded with a query
+atuin search -i atuin
+
+# Search for all commands, beginning with cargo, that exited successfully
+atuin search --exit 0 cargo
+
+# Search for all commands, that failed, from the current dir, and were ran before April 1st 2021
+atuin search --exclude-exit 0 --before 01/04/2021 --cwd .
+
+# Search for all commands, beginning with cargo, that exited successfully, and were ran after yesterday at 3pm
+atuin search --exit 0 --after "yesterday 3pm" cargo
+
+# Delete all commands, beginning with cargo, that exited successfully, and were ran after yesterday at 3pm
+atuin search --delete --exit 0 --after "yesterday 3pm" cargo
+
+# Search for a command beginning with cargo, return exactly one result.
+atuin search --limit 1 cargo
+
+# Search for a single result for a command beginning with cargo, skipping (offsetting) one result
+atuin search --offset 1 --limit 1 cargo
+
+# Find the oldest cargo command
+atuin search --limit 1 --reverse cargo
+```
diff --git a/docs/docs/reference/stats.md b/docs/docs/reference/stats.md
new file mode 100644
index 00000000..b1e4f0f9
--- /dev/null
+++ b/docs/docs/reference/stats.md
@@ -0,0 +1,50 @@
+# stats
+
+Atuin can also calculate stats based on your history - this is currently a
+little basic, but more features to come.
+
+## 1-day stats
+
+You provide the starting point, and Atuin computes the stats for 24h from that point.
+Date parsing is provided by `interim`, which supports different formats
+for full or relative dates. Certain formats rely on the dialect option in your
+[configuration](../configuration/config.md#dialect) to differentiate day from month.
+Refer to [the module's documentation](https://docs.rs/interim/0.1.0/interim/#supported-formats) for more details on the supported date formats.
+
+```
+$ atuin stats last friday
+
++---------------------+------------+
+| Statistic | Value |
++---------------------+------------+
+| Most used command | git status |
++---------------------+------------+
+| Commands ran | 450 |
++---------------------+------------+
+| Unique commands ran | 213 |
++---------------------+------------+
+
+# A few more examples:
+$ atuin stats 2018-04-01
+$ atuin stats April 1
+$ atuin stats 01/04/22
+$ atuin stats last thursday 3pm # between last thursday 3:00pm and the following friday 3:00pm
+```
+
+## Full history stats
+
+```
+$ atuin stats
+# or
+$ atuin stats all
+
++---------------------+-------+
+| Statistic | Value |
++---------------------+-------+
+| Most used command | ls |
++---------------------+-------+
+| Commands ran | 8190 |
++---------------------+-------+
+| Unique commands ran | 2996 |
++---------------------+-------+
+```
diff --git a/docs/docs/reference/sync.md b/docs/docs/reference/sync.md
new file mode 100644
index 00000000..cbdfae6a
--- /dev/null
+++ b/docs/docs/reference/sync.md
@@ -0,0 +1,77 @@
+# sync
+
+Atuin can back up your history to a server, and use this to ensure multiple
+machines have the same shell history. This is all encrypted end-to-end, so the
+server operator can _never_ see your data!
+
+Anyone can host a server (try `atuin server start`, more docs to follow), but I
+host one at https://api.atuin.sh. This is the default server address, which can
+be changed in the [config](../configuration/config.md#sync_address). Again, I _cannot_ see your data, and
+do not want to.
+
+## Sync frequency
+
+Syncing will happen automatically, unless configured otherwise. The sync
+frequency is configurable in [config](../configuration/config.md#sync_frequency)
+
+## Sync
+
+You can manually trigger a sync with `atuin sync`
+
+## Register
+
+Register for a sync account with
+
+```
+atuin register -u <USERNAME> -e <EMAIL> -p <PASSWORD>
+```
+
+If you don't want to have your password be included in shell history, you can omit
+the password flag and you will be prompted to provide it through stdin.
+
+Usernames must be unique and only contain alphanumerics or hyphens,
+and emails shall only be used for important notifications (security breaches, changes to service, etc).
+
+Upon success, you are also logged in :) Syncing should happen automatically from
+here!
+
+## Delete
+
+You can delete your sync account with
+
+```
+atuin account delete
+```
+
+This will remove your account and all synchronized history from the server. Local data will not be touched!
+
+## Key
+
+As all your data is encrypted, Atuin generates a key for you. It's stored in the
+Atuin data directory (`~/.local/share/atuin` on Linux).
+
+You can also get this with
+
+```
+atuin key
+```
+
+Never share this with anyone!
+
+## Login
+
+If you want to log in to a new machine, you will require your encryption key
+(`atuin key`).
+
+```
+atuin login -u <USERNAME> -p <PASSWORD> -k <KEY>
+```
+
+If you don't want to have your password or encryption key be included in shell history, you can omit
+the corresponding flag and you will be prompted to provide it through stdin.
+
+## Logout
+
+```
+atuin logout
+```
diff --git a/docs/docs/self-hosting/docker.md b/docs/docs/self-hosting/docker.md
new file mode 100644
index 00000000..57f5ca0c
--- /dev/null
+++ b/docs/docs/self-hosting/docker.md
@@ -0,0 +1,130 @@
+# Docker
+
+!!! warning
+ If you are self hosting, we strongly suggest you stick to [tagged releases](https://github.com/atuinsh/atuin/releases), and do not follow `main` or `latest`
+
+ Follow the GitHub releases, and please read the notes for each release. Most of the time, upgrades can occur without any manual intervention.
+
+ We cannot guarantee that all updates will apply cleanly, and some may require some extra steps.
+
+There is a supplied docker image to make deploying a server as a container easier. The "LATEST TAGGED RELEASE" can be found on the [releases page](https://github.com/atuinsh/atuin/releases).
+
+```sh
+CONFIG="$HOME/.config/atuin"
+mkdir "$CONFIG"
+chown 1000:1000 "$CONFIG"
+docker run -d -v "$CONFIG:/config" ghcr.io/atuinsh/atuin:<LATEST TAGGED RELEASE> server start
+```
+
+## Docker Compose
+
+Using the already build docker image hosting your own Atuin can be done using the supplied docker-compose file.
+
+Create a `.env` file next to [`docker-compose.yml`](https://github.com/atuinsh/atuin/raw/main/docker-compose.yml) with contents like this:
+
+```ini
+ATUIN_DB_NAME=atuin
+ATUIN_DB_USERNAME=atuin
+# Choose your own secure password. Stick to [A-Za-z0-9.~_-]
+ATUIN_DB_PASSWORD=really-insecure
+```
+
+Create a `docker-compose.yml`:
+
+```yaml
+services:
+ atuin:
+ restart: always
+ image: ghcr.io/atuinsh/atuin:<LATEST TAGGED RELEASE>
+ command: server start
+ volumes:
+ - "./config:/config"
+ ports:
+ - 8888:8888
+ environment:
+ ATUIN_HOST: "0.0.0.0"
+ ATUIN_OPEN_REGISTRATION: "true"
+ ATUIN_DB_URI: postgres://${ATUIN_DB_USERNAME}:${ATUIN_DB_PASSWORD}@db/${ATUIN_DB_NAME}
+ RUST_LOG: info,atuin_server=debug
+ depends_on:
+ - db
+ db:
+ image: postgres:14
+ restart: unless-stopped
+ volumes: # Don't remove permanent storage for index database files!
+ - "./database:/var/lib/postgresql/data/"
+ environment:
+ POSTGRES_USER: ${ATUIN_DB_USERNAME}
+ POSTGRES_PASSWORD: ${ATUIN_DB_PASSWORD}
+ POSTGRES_DB: ${ATUIN_DB_NAME}
+```
+
+Start the services using `docker compose`:
+
+```sh
+mkdir config
+chown 1000:1000 config
+docker compose up -d
+```
+
+## Using systemd to manage your atuin server
+
+The following `systemd` unit file to manage your `docker-compose` managed service:
+
+```ini
+[Unit]
+Description=Docker Compose Atuin Service
+Requires=docker.service
+After=docker.service
+
+[Service]
+# Where the docker-compose file is located
+WorkingDirectory=/srv/atuin-server
+ExecStart=/usr/bin/docker compose up
+ExecStop=/usr/bin/docker compose down
+TimeoutStartSec=0
+Restart=on-failure
+StartLimitBurst=3
+
+[Install]
+WantedBy=multi-user.target
+```
+
+Start and enable the service with:
+
+```sh
+systemctl enable --now atuin
+```
+
+Check if its running with:
+
+```sh
+systemctl status atuin
+```
+
+## Creating backups of the Postgres database
+
+You can add another service to your `docker-compose.yml` file to have it run daily backups. It should look like this:
+
+```yaml
+ backup:
+ container_name: atuin_db_dumper
+ image: prodrigestivill/postgres-backup-local
+ env_file:
+ - .env
+ environment:
+ POSTGRES_HOST: postgresql
+ POSTGRES_DB: ${ATUIN_DB_NAME}
+ POSTGRES_USER: ${ATUIN_DB_USERNAME}
+ POSTGRES_PASSWORD: ${ATUIN_DB_PASSWORD}
+ SCHEDULE: "@daily"
+ BACKUP_DIR: /db_dumps
+ volumes:
+ - ./db_dumps:/db_dumps
+ depends_on:
+ - postgresql
+```
+
+This will create daily backups of your database for that additional layer of comfort.
+
+PLEASE NOTE: The `./db_dumps` mount MUST be a POSIX-compliant filesystem to store the backups (mainly with support for hardlinks and softlinks). So filesystems like VFAT, EXFAT, SMB/CIFS, ... can't be used with this docker image. See https://github.com/prodrigestivill/docker-postgres-backup-local for more details on how this works. There are additional settings for the number of backups retained, etc., all explained on the linked page.
diff --git a/docs/docs/self-hosting/kubernetes.md b/docs/docs/self-hosting/kubernetes.md
new file mode 100644
index 00000000..73bb772d
--- /dev/null
+++ b/docs/docs/self-hosting/kubernetes.md
@@ -0,0 +1,290 @@
+# Kubernetes
+
+!!! warning
+ If you are self hosting, we strongly suggest you stick to tagged releases, and do not follow `main` or `latest`
+
+ Follow the GitHub releases, and please read the notes for each release. Most of the time, upgrades can occur without any manual intervention.
+
+ We cannot guarantee that all updates will apply cleanly, and some may require some extra steps.
+
+You could host your own Atuin server using the Kubernetes platform.
+
+Create a [`secrets.yaml`](https://github.com/atuinsh/atuin/blob/main/k8s/secrets.yaml) file for the database credentials:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: atuin-secrets
+type: Opaque
+stringData:
+ ATUIN_DB_USERNAME: atuin
+ ATUIN_DB_PASSWORD: seriously-insecure
+ ATUIN_HOST: "127.0.0.1"
+ ATUIN_PORT: "8888"
+ ATUIN_OPEN_REGISTRATION: "true"
+ ATUIN_DB_URI: "postgres://atuin:seriously-insecure@postgres/atuin"
+immutable: true
+```
+
+Create a [`atuin.yaml`](https://github.com/atuinsh/atuin/blob/main/k8s/atuin.yaml) file for the Atuin server:
+
+```yaml
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: postgres
+ namespace: atuin
+spec:
+ replicas: 1
+ strategy:
+ type: Recreate # This is important to ensure duplicate pods don't run and cause corruption
+ selector:
+ matchLabels:
+ io.kompose.service: postgres
+ template:
+ metadata:
+ labels:
+ io.kompose.service: postgres
+ spec:
+ containers:
+ - name: postgresql
+ image: postgres:14
+ ports:
+ - containerPort: 5432
+ env:
+ - name: POSTGRES_DB
+ value: atuin
+ - name: POSTGRES_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: atuin-secrets
+ key: ATUIN_DB_PASSWORD
+ optional: false
+ - name: POSTGRES_USER
+ valueFrom:
+ secretKeyRef:
+ name: atuin-secrets
+ key: ATUIN_DB_USERNAME
+ optional: false
+ lifecycle:
+ preStop:
+ exec:
+ # This ensures graceful shutdown see: https://stackoverflow.com/a/75829325/3437018
+ # Potentially consider using a `StatefulSet` instead of a `Deployment`
+ command: ["/usr/local/bin/pg_ctl stop -D /var/lib/postgresql/data -w -t 60 -m fast"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 100Mi
+ limits:
+ cpu: 250m
+ memory: 600Mi
+ volumeMounts:
+ - mountPath: /var/lib/postgresql/data/
+ name: database
+ volumes:
+ - name: database
+ persistentVolumeClaim:
+ claimName: database
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: atuin
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ io.kompose.service: atuin
+ template:
+ metadata:
+ labels:
+ io.kompose.service: atuin
+ spec:
+ containers:
+ - args:
+ - server
+ - start
+ env:
+ - name: ATUIN_DB_URI
+ valueFrom:
+ secretKeyRef:
+ name: atuin-secrets
+ key: ATUIN_DB_URI
+ optional: false
+ - name: ATUIN_HOST
+ value: 0.0.0.0
+ - name: ATUIN_PORT
+ value: "8888"
+ - name: ATUIN_OPEN_REGISTRATION
+ value: "true"
+ image: ghcr.io/atuinsh/atuin:latest
+ name: atuin
+ ports:
+ - containerPort: 8888
+ resources:
+ limits:
+ cpu: 250m
+ memory: 1Gi
+ requests:
+ cpu: 250m
+ memory: 1Gi
+ volumeMounts:
+ - mountPath: /config
+ name: atuin-claim0
+ volumes:
+ - name: atuin-claim0
+ persistentVolumeClaim:
+ claimName: atuin-claim0
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ io.kompose.service: atuin
+ name: atuin
+spec:
+ type: NodePort
+ ports:
+ - name: "8888"
+ port: 8888
+ nodePort: 30530
+ selector:
+ io.kompose.service: atuin
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ io.kompose.service: postgres
+ name: postgres
+spec:
+ type: ClusterIP
+ selector:
+ io.kompose.service: postgres
+ ports:
+ - protocol: TCP
+ port: 5432
+ targetPort: 5432
+---
+kind: PersistentVolume
+apiVersion: v1
+metadata:
+ name: database-pv
+ labels:
+ app: database
+ type: local
+spec:
+ storageClassName: manual
+ capacity:
+ storage: 300Mi
+ accessModes:
+ - ReadWriteOnce
+ hostPath:
+ path: "/Users/firstname.lastname/.kube/database"
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ labels:
+ io.kompose.service: database
+ name: database
+spec:
+ storageClassName: manual
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 300Mi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ labels:
+ io.kompose.service: atuin-claim0
+ name: atuin-claim0
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 10Mi
+```
+
+Finally, you may want to use a separate namespace for atuin, by creating a [`namespaces.yaml`](https://github.com/atuinsh/atuin/blob/main/k8s/namespaces.yaml) file:
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: atuin-namespace
+ labels:
+ name: atuin
+```
+
+Note that this configuration will store the database folder _outside_ the kubernetes cluster, in the folder `/Users/firstname.lastname/.kube/database` of the host system by configuring the `storageClassName` to be `manual`. In a real enterprise setup, you would probably want to store the database content permanently in the cluster, and not in the host system.
+
+You should also change the password string in `ATUIN_DB_PASSWORD` and `ATUIN_DB_URI` in the`secrets.yaml` file to a more secure one.
+
+The atuin service on the port `30530` of the host system. That is configured by the `nodePort` property. Kubernetes has a strict rule that you are not allowed to expose a port numbered lower than 30000. To make the clients work, you can simply set the port in in your `config.toml` file, e.g. `sync_address = "http://192.168.1.10:30530"`.
+
+Deploy the Atuin server using `kubectl`:
+
+```shell
+ kubectl apply -f ./namespaces.yaml
+ kubectl apply -n atuin-namespace \
+ -f ./secrets.yaml \
+ -f ./atuin.yaml
+```
+
+The sample files above are also in the [k8s folder](https://github.com/atuinsh/atuin/tree/main/k8s) of the atuin repository.
+
+## Creating backups of the Postgres database
+
+Now you're up and running it's a good time to think about backups.
+
+You can create a [`CronJob`](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/) which uses [`pg_dump`](https://www.postgresql.org/docs/current/app-pgdump.html) to create a backup of the database. This example runs weekly and dumps to the local disk on the node.
+
+```yaml
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: atuin-db-backup
+spec:
+ schedule: "0 0 * * 0" # Run every Sunday at midnight
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ containers:
+ - name: atuin-db-backup-pg-dump
+ image: postgres:14
+ command: [
+ "/bin/bash",
+ "-c",
+ "pg_dump --host=postgres --username=atuin --format=c --file=/backup/atuin-backup-$(date +'%Y-%m-%d').pg_dump",
+ ]
+ env:
+ - name: PGPASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: atuin-secrets
+ key: ATUIN_DB_PASSWORD
+ optional: false
+ volumeMounts:
+ - name: backup-volume
+ mountPath: /backup
+ restartPolicy: OnFailure
+ volumes:
+ - name: backup-volume
+ hostPath:
+ path: /somewhere/on/node/for/database-backups
+ type: Directory
+```
+
+Configure/update the example `yaml` with the following:
+- Set a more or less frequent schedule with the `schedule` property.
+- Replace `/somewhere/on/node/for/database-backups` with a path on your node or reconfigure to use a `PersistentVolume` instead of `hostPath`.
+- `--format=c` outputs a format that can be restored with `pg_restore`. Use [`plain`](https://www.postgresql.org/docs/current/app-pgdump.html) if you want `.sql` files outputted instead.
diff --git a/docs/docs/self-hosting/server-setup.md b/docs/docs/self-hosting/server-setup.md
new file mode 100644
index 00000000..e983fa0b
--- /dev/null
+++ b/docs/docs/self-hosting/server-setup.md
@@ -0,0 +1,61 @@
+# Server setup
+
+While we offer a public sync server, and cannot view your data (as it is encrypted), you may still wish to self host your own Atuin sync server.
+
+The requirements to do so are pretty minimal! You need to be able to run a binary or docker container, and have a PostgreSQL database setup. Atuin requires PostgreSQL 14 or above.
+
+Atuin also supports sqlite 3 and above.
+
+Any host with the `atuin` binary may also run a server, by running
+
+```shell
+atuin server start
+```
+
+## Configuration
+
+The config for the server is kept separate from the config for the client, even
+though they are the same binary. Server config can be found at
+`~/.config/atuin/server.toml`.
+
+It looks something like this for PostgreSQL:
+
+```toml
+host = "0.0.0.0"
+port = 8888
+open_registration = true
+db_uri="postgres://user:password@hostname/database"
+```
+
+Alternatively, configuration can also be provided with environment variables.
+
+```sh
+ATUIN_HOST="0.0.0.0"
+ATUIN_PORT=8888
+ATUIN_OPEN_REGISTRATION=true
+ATUIN_DB_URI="postgres://user:password@hostname/database"
+```
+
+| Parameter | Description |
+| ------------------- | -------------------------------------------------------------- |
+| `host` | The host to listen on (default: 127.0.0.1) |
+| `port` | The TCP port to listen on (default: 8888) |
+| `open_registration` | If `true`, accept new user registrations (default: false) |
+| `db_uri` | A valid PostgreSQL URI, for saving history (default: false) |
+| `path` | A path to prepend to all routes of the server (default: false) |
+
+For sqlite, substitute the following:
+
+db_uri="sqlite:///config/atuin.db"
+
+ATUIN_DB_URI="sqlite:///config/atuin.db"
+
+These will create the database in the /config directory.
+
+You will need to map some sort of persistent volume for the /config directory and it should be writable by the atuin server.
+
+### TLS
+
+For TLS/HTTPS support, we recommend using a reverse proxy such as nginx, caddy, or traefik in front of the Atuin server. This is the standard approach for containerized applications and provides better flexibility for certificate management.
+
+> **Note:** The built-in `[tls]` configuration option has been removed. If you were previously using it, please migrate to a reverse proxy setup. Any existing `[tls]` sections in your config will be ignored.
diff --git a/docs/docs/self-hosting/systemd.md b/docs/docs/self-hosting/systemd.md
new file mode 100644
index 00000000..d31d0ee7
--- /dev/null
+++ b/docs/docs/self-hosting/systemd.md
@@ -0,0 +1,65 @@
+# Systemd
+
+First, create the service unit file
+[`atuin-server.service`](https://github.com/atuinsh/atuin/raw/main/systemd/atuin-server.service) at
+`/etc/systemd/system/atuin-server.service` with contents like this:
+
+```ini
+[Unit]
+Description=Start the Atuin server syncing service
+After=network-online.target
+Wants=network-online.target systemd-networkd-wait-online.service
+
+[Service]
+ExecStart=atuin server start
+Restart=on-failure
+User=atuin
+Group=atuin
+
+Environment=ATUIN_CONFIG_DIR=/etc/atuin
+ReadWritePaths=/etc/atuin
+
+# Hardening options
+CapabilityBoundingSet=
+AmbientCapabilities=
+NoNewPrivileges=true
+ProtectHome=true
+ProtectSystem=strict
+ProtectKernelTunables=true
+ProtectKernelModules=true
+ProtectControlGroups=true
+PrivateTmp=true
+PrivateDevices=true
+LockPersonality=true
+
+[Install]
+WantedBy=multi-user.target
+```
+
+This is the official Atuin service unit file which includes a lot of hardening options to increase
+security.
+
+Next, create [`atuin-server.conf`](https://github.com/atuinsh/atuin/raw/main/systemd/atuin-server.sysusers) at
+`/etc/sysusers.d/atuin-server.conf` with contents like this:
+
+```
+u atuin - "Atuin synchronized shell history"
+```
+This file will ensure a system user is created in the proper manner.
+
+Afterwards, run
+```sh
+systemctl restart systemd-sysusers
+```
+to make sure the file is read. A new `atuin-server` user should then be available.
+
+Now, you can attempt to run the Atuin server:
+```sh
+systemctl enable --now atuin-server
+```
+
+```sh
+systemctl status atuin-server
+```
+
+If it started fine, it should have created the default config inside `/etc/atuin/`.
diff --git a/docs/docs/self-hosting/usage.md b/docs/docs/self-hosting/usage.md
new file mode 100644
index 00000000..c5f598e8
--- /dev/null
+++ b/docs/docs/self-hosting/usage.md
@@ -0,0 +1,14 @@
+# Using a self hosted server
+
+!!! warning
+ If you are self hosting, we strongly suggest you stick to tagged releases, and do not follow `main` or `latest`
+
+ Follow the GitHub releases, and please read the notes for each release. Most of the time, upgrades can occur without any manual intervention.
+
+ We cannot guarantee that all updates will apply cleanly, and some may require some extra steps.
+
+## Client setup
+
+In order use a self hosted server with Atuin, you'll have to set up the `sync_address` in the config file at `~/.config/atuin/config.toml`. See the [config](../configuration/config.md#sync_address) page for more details on how to set the `sync_address`.
+
+Alternatively you can set the environment variable `ATUIN_SYNC_ADDRESS` to the correct host ie.: `ATUIN_SYNC_ADDRESS=https://api.atuin.sh`.
diff --git a/docs/docs/sync-v2.md b/docs/docs/sync-v2.md
new file mode 100644
index 00000000..8821b2f5
--- /dev/null
+++ b/docs/docs/sync-v2.md
@@ -0,0 +1,27 @@
+# Sync v2
+
+Just installed Atuin? Don't worry about this page, everything should be set up
+for you.
+
+If you've been using Atuin for a while, you might not be using the best sync. A
+long time ago, we shipped sync v1. It was "good enough", but never intended for
+the wide use it ended up getting.
+
+After evaluating issues and feedback from users, we developed sync v2. It
+includes a whole bunch of changes that I'll save writing about for a future
+blog post or deep dive, but suffice to say it's
+
+1. Faster
+2. More reliable
+3. Uses less bandwidth
+4. Supports many more features
+5. Recovers from issues more effectively
+
+There's really no reason to not use it.
+
+You can opt in with the following configuration
+
+```toml
+[sync]
+records = true
+```
diff --git a/docs/docs/uninstall.md b/docs/docs/uninstall.md
new file mode 100644
index 00000000..a608a5c8
--- /dev/null
+++ b/docs/docs/uninstall.md
@@ -0,0 +1,20 @@
+# Uninstalling Atuin
+
+Sorry to see you go!
+
+If you used the Atuin installer, you can totally delete it by removing the following
+
+1. Delete the ~/.atuin directory
+2. Delete the ~/.config/atuin directory
+3. Delete the ~/.local/share/atuin directory
+4. Remove the line referencing "atuin init" from your shell config
+
+Otherwise, uninstalling Atuin depends on your system, and how you installed it.
+
+EG, on macOS, you'd want to run
+
+```
+brew uninstall atuin
+```
+
+and then remove the shell integration.
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
new file mode 100644
index 00000000..1d435de9
--- /dev/null
+++ b/docs/mkdocs.yml
@@ -0,0 +1,92 @@
+site_name: Atuin CLI Docs
+site_url: https://docs.atuin.sh/cli/
+
+repo_name: atuinsh/atuin
+repo_url: https://github.com/atuinsh/atuin
+edit_uri: edit/main/docs/docs/
+
+theme:
+ name: material
+ palette:
+ - scheme: default
+ primary: deep purple
+ accent: deep purple
+ toggle:
+ icon: material/brightness-7
+ name: Switch to dark mode
+ - scheme: slate
+ primary: deep purple
+ accent: deep purple
+ toggle:
+ icon: material/brightness-4
+ name: Switch to light mode
+ features:
+ - navigation.sections
+ - navigation.expand
+ - search.suggest
+ - search.highlight
+ - content.code.copy
+ - content.action.edit
+ - content.action.view
+
+plugins:
+ - search
+ - multirepo:
+ imported_repo: true
+ url: https://github.com/atuinsh/docs
+ section_name: CLI
+ paths: ["mkdocs.yml", "docs/index.md", "docs/stylesheets/*"]
+ yml_file: mkdocs.yml
+ branch: mkt/docs-migration
+
+markdown_extensions:
+ - pymdownx.highlight:
+ anchor_linenums: true
+ - pymdownx.superfences
+ - pymdownx.tabbed:
+ alternate_style: true
+ - admonition
+ - pymdownx.details
+ - attr_list
+ - md_in_html
+ - tables
+ - pymdownx.keys
+ - pymdownx.emoji:
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
+
+nav:
+ - Home: index.md
+ - Guide:
+ - Getting Started: guide/getting-started.md
+ - Installation: guide/installation.md
+ - Setting up sync: guide/sync.md
+ - Import existing history: guide/import.md
+ - Basic usage: guide/basic-usage.md
+ - Syncing dotfiles: guide/dotfiles.md
+ - Theming: guide/theming.md
+ - Configuration:
+ - Config: configuration/config.md
+ - Key Binding: configuration/key-binding.md
+ - Reference:
+ - doctor: reference/doctor.md
+ - daemon: reference/daemon.md
+ - gen-completions: reference/gen-completions.md
+ - import: reference/import.md
+ - info: reference/info.md
+ - history list: reference/list.md
+ - history prune: reference/prune.md
+ - search: reference/search.md
+ - stats: reference/stats.md
+ - sync: reference/sync.md
+ - Self Hosting:
+ - Server Setup: self-hosting/server-setup.md
+ - Usage: self-hosting/usage.md
+ - Docker: self-hosting/docker.md
+ - Kubernetes: self-hosting/kubernetes.md
+ - Systemd: self-hosting/systemd.md
+ - Known Issues: known-issues.md
+ - Integrations: integrations.md
+ - FAQ: faq.md
+ - Uninstall: uninstall.md
+ - Sync v2: sync-v2.md
diff --git a/docs/pyproject.toml b/docs/pyproject.toml
new file mode 100644
index 00000000..e3bef982
--- /dev/null
+++ b/docs/pyproject.toml
@@ -0,0 +1,15 @@
+[project]
+name = "atuin-cli-docs"
+version = "1.0.0"
+description = "Atuin CLI documentation"
+requires-python = ">=3.11"
+dependencies = [
+ "mkdocs-material>=9.5",
+ "mkdocs-multirepo-plugin @ git+https://github.com/atuinsh/mkdocs-multirepo-plugin@mkt/imported_repo",
+ "mkdocs-git-revision-date-localized-plugin>=1.2",
+ "mkdocs-glightbox>=0.4",
+ "mkdocs-redirects>=1.2.2",
+]
+
+[dependency-groups]
+dev = []
diff --git a/docs/uv.lock b/docs/uv.lock
new file mode 100644
index 00000000..9575e6ea
--- /dev/null
+++ b/docs/uv.lock
@@ -0,0 +1,750 @@
+version = 1
+revision = 3
+requires-python = ">=3.11"
+
+[[package]]
+name = "atuin-cli-docs"
+version = "1.0.0"
+source = { virtual = "." }
+dependencies = [
+ { name = "mkdocs-git-revision-date-localized-plugin" },
+ { name = "mkdocs-glightbox" },
+ { name = "mkdocs-material" },
+ { name = "mkdocs-multirepo-plugin" },
+ { name = "mkdocs-redirects" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "mkdocs-git-revision-date-localized-plugin", specifier = ">=1.2" },
+ { name = "mkdocs-glightbox", specifier = ">=0.4" },
+ { name = "mkdocs-material", specifier = ">=9.5" },
+ { name = "mkdocs-multirepo-plugin", git = "https://github.com/atuinsh/mkdocs-multirepo-plugin?rev=mkt%2Fimported_repo" },
+ { name = "mkdocs-redirects", specifier = ">=1.2.2" },
+]
+
+[package.metadata.requires-dev]
+dev = []
+
+[[package]]
+name = "babel"
+version = "2.17.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" },
+]
+
+[[package]]
+name = "backrefs"
+version = "6.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/86/e3/bb3a439d5cb255c4774724810ad8073830fac9c9dee123555820c1bcc806/backrefs-6.1.tar.gz", hash = "sha256:3bba1749aafe1db9b915f00e0dd166cba613b6f788ffd63060ac3485dc9be231", size = 7011962, upload-time = "2025-11-15T14:52:08.323Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3b/ee/c216d52f58ea75b5e1841022bbae24438b19834a29b163cb32aa3a2a7c6e/backrefs-6.1-py310-none-any.whl", hash = "sha256:2a2ccb96302337ce61ee4717ceacfbf26ba4efb1d55af86564b8bbaeda39cac1", size = 381059, upload-time = "2025-11-15T14:51:59.758Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/9a/8da246d988ded941da96c7ed945d63e94a445637eaad985a0ed88787cb89/backrefs-6.1-py311-none-any.whl", hash = "sha256:e82bba3875ee4430f4de4b6db19429a27275d95a5f3773c57e9e18abc23fd2b7", size = 392854, upload-time = "2025-11-15T14:52:01.194Z" },
+ { url = "https://files.pythonhosted.org/packages/37/c9/fd117a6f9300c62bbc33bc337fd2b3c6bfe28b6e9701de336b52d7a797ad/backrefs-6.1-py312-none-any.whl", hash = "sha256:c64698c8d2269343d88947c0735cb4b78745bd3ba590e10313fbf3f78c34da5a", size = 398770, upload-time = "2025-11-15T14:52:02.584Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/95/7118e935b0b0bd3f94dfec2d852fd4e4f4f9757bdb49850519acd245cd3a/backrefs-6.1-py313-none-any.whl", hash = "sha256:4c9d3dc1e2e558965202c012304f33d4e0e477e1c103663fd2c3cc9bb18b0d05", size = 400726, upload-time = "2025-11-15T14:52:04.093Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/72/6296bad135bfafd3254ae3648cd152980a424bd6fed64a101af00cc7ba31/backrefs-6.1-py314-none-any.whl", hash = "sha256:13eafbc9ccd5222e9c1f0bec563e6d2a6d21514962f11e7fc79872fd56cbc853", size = 412584, upload-time = "2025-11-15T14:52:05.233Z" },
+ { url = "https://files.pythonhosted.org/packages/02/e3/a4fa1946722c4c7b063cc25043a12d9ce9b4323777f89643be74cef2993c/backrefs-6.1-py39-none-any.whl", hash = "sha256:a9e99b8a4867852cad177a6430e31b0f6e495d65f8c6c134b68c14c3c95bf4b0", size = 381058, upload-time = "2025-11-15T14:52:06.698Z" },
+]
+
+[[package]]
+name = "certifi"
+version = "2025.11.12"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" },
+]
+
+[[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/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.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
+]
+
+[[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 = "dacite"
+version = "1.9.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420, upload-time = "2025-02-05T09:27:29.757Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" },
+]
+
+[[package]]
+name = "ghp-import"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "python-dateutil" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" },
+]
+
+[[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.45"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "gitdb" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9a/c8/dd58967d119baab745caec2f9d853297cec1989ec1d63f677d3880632b88/gitpython-3.1.45.tar.gz", hash = "sha256:85b0ee964ceddf211c41b9f27a49086010a190fd8132a24e21f362a4b36a791c", size = 215076, upload-time = "2025-07-24T03:45:54.871Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/01/61/d4b89fec821f72385526e1b9d9a3a0385dda4a72b206d28049e2c7cd39b8/gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77", size = 208168, upload-time = "2025-07-24T03:45:52.517Z" },
+]
+
+[[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 = "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 = "markdown"
+version = "3.10"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/7dd27d9d863b3376fcf23a5a13cb5d024aed1db46f963f1b5735ae43b3be/markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e", size = 364931, upload-time = "2025-11-03T19:51:15.007Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/70/81/54e3ce63502cd085a0c556652a4e1b919c45a446bd1e5300e10c44c8c521/markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c", size = 107678, upload-time = "2025-11-03T19:51:13.887Z" },
+]
+
+[[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/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 = "mergedeep"
+version = "1.3.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" },
+]
+
+[[package]]
+name = "mkdocs"
+version = "1.6.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "ghp-import" },
+ { name = "jinja2" },
+ { name = "markdown" },
+ { name = "markupsafe" },
+ { name = "mergedeep" },
+ { name = "mkdocs-get-deps" },
+ { name = "packaging" },
+ { name = "pathspec" },
+ { name = "pyyaml" },
+ { name = "pyyaml-env-tag" },
+ { name = "watchdog" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" },
+]
+
+[[package]]
+name = "mkdocs-get-deps"
+version = "0.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mergedeep" },
+ { name = "platformdirs" },
+ { name = "pyyaml" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" },
+]
+
+[[package]]
+name = "mkdocs-git-revision-date-localized-plugin"
+version = "1.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "babel" },
+ { name = "gitpython" },
+ { name = "mkdocs" },
+ { name = "tzdata", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0f/c5/1d3c4e6ddae6230b89d09105cb79de711655e3ebd6745f7a92efea0f5160/mkdocs_git_revision_date_localized_plugin-1.5.0.tar.gz", hash = "sha256:17345ccfdf69a1905dc96fb1070dce82d03a1eb6b0d48f958081a7589ce3c248", size = 460697, upload-time = "2025-10-31T16:11:34.44Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bc/51/fe0e3fdb16f6eed65c9459d12bae6a4e1f0bb4e2228cb037e7907b002678/mkdocs_git_revision_date_localized_plugin-1.5.0-py3-none-any.whl", hash = "sha256:933f9e35a8c135b113f21bb57610d82e9b7bcc71dd34fb06a029053c97e99656", size = 26153, upload-time = "2025-10-31T16:11:32.987Z" },
+]
+
+[[package]]
+name = "mkdocs-glightbox"
+version = "0.5.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "selectolax" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8d/26/c793459622da8e31f954c6f5fb51e8f098143fdfc147b1e3c25bf686f4aa/mkdocs_glightbox-0.5.2.tar.gz", hash = "sha256:c7622799347c32310878e01ccf14f70648445561010911c80590cec0353370ac", size = 510586, upload-time = "2025-10-23T14:55:18.909Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4e/ca/03624e017e5ee2d7ce8a08d89f81c1e535eb3c30d7b2dc4a435ea3fbbeae/mkdocs_glightbox-0.5.2-py3-none-any.whl", hash = "sha256:23a431ea802b60b1030c73323db2eed6ba859df1a0822ce575afa43e0ea3f47e", size = 26458, upload-time = "2025-10-23T14:55:17.43Z" },
+]
+
+[[package]]
+name = "mkdocs-material"
+version = "9.7.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "babel" },
+ { name = "backrefs" },
+ { name = "colorama" },
+ { name = "jinja2" },
+ { name = "markdown" },
+ { name = "mkdocs" },
+ { name = "mkdocs-material-extensions" },
+ { name = "paginate" },
+ { name = "pygments" },
+ { name = "pymdown-extensions" },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9c/3b/111b84cd6ff28d9e955b5f799ef217a17bc1684ac346af333e6100e413cb/mkdocs_material-9.7.0.tar.gz", hash = "sha256:602b359844e906ee402b7ed9640340cf8a474420d02d8891451733b6b02314ec", size = 4094546, upload-time = "2025-11-11T08:49:09.73Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/87/eefe8d5e764f4cf50ed91b943f8e8f96b5efd65489d8303b7a36e2e79834/mkdocs_material-9.7.0-py3-none-any.whl", hash = "sha256:da2866ea53601125ff5baa8aa06404c6e07af3c5ce3d5de95e3b52b80b442887", size = 9283770, upload-time = "2025-11-11T08:49:06.26Z" },
+]
+
+[[package]]
+name = "mkdocs-material-extensions"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" },
+]
+
+[[package]]
+name = "mkdocs-multirepo-plugin"
+version = "0.8.3"
+source = { git = "https://github.com/atuinsh/mkdocs-multirepo-plugin?rev=mkt%2Fimported_repo#e2aed29184af719cce2bc0dddb90ceec99af21b9" }
+dependencies = [
+ { name = "dacite" },
+ { name = "mkdocs" },
+ { name = "python-slugify" },
+ { name = "typing-inspect" },
+]
+
+[[package]]
+name = "mkdocs-redirects"
+version = "1.2.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mkdocs" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f1/a8/6d44a6cf07e969c7420cb36ab287b0669da636a2044de38a7d2208d5a758/mkdocs_redirects-1.2.2.tar.gz", hash = "sha256:3094981b42ffab29313c2c1b8ac3969861109f58b2dd58c45fc81cd44bfa0095", size = 7162, upload-time = "2024-11-07T14:57:21.109Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c4/ec/38443b1f2a3821bbcb24e46cd8ba979154417794d54baf949fefde1c2146/mkdocs_redirects-1.2.2-py3-none-any.whl", hash = "sha256:7dbfa5647b79a3589da4401403d69494bd1f4ad03b9c15136720367e1f340ed5", size = 6142, upload-time = "2024-11-07T14:57:19.143Z" },
+]
+
+[[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 = "packaging"
+version = "25.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
+]
+
+[[package]]
+name = "paginate"
+version = "0.5.7"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" },
+]
+
+[[package]]
+name = "pathspec"
+version = "0.12.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" },
+]
+
+[[package]]
+name = "platformdirs"
+version = "4.5.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" },
+]
+
+[[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 = "pymdown-extensions"
+version = "10.19"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown" },
+ { name = "pyyaml" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1f/4e/e73e88f4f2d0b26cbd2e100074107470984f0a6055869805fc181b847ac7/pymdown_extensions-10.19.tar.gz", hash = "sha256:01bb917ea231f9ce14456fa9092cdb95ac3e5bd32202a3ee61dbd5ad2dd9ef9b", size = 847701, upload-time = "2025-12-11T18:20:46.093Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d4/56/fa9edaceb3805e03ac9faf68ca1ddc660a75b49aee5accb493511005fef5/pymdown_extensions-10.19-py3-none-any.whl", hash = "sha256:dc5f249fc3a1b6d8a6de4634ba8336b88d0942cee75e92b18ac79eaf3503bf7c", size = 266670, upload-time = "2025-12-11T18:20:44.736Z" },
+]
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
+]
+
+[[package]]
+name = "python-slugify"
+version = "8.0.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "text-unidecode" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/87/c7/5e1547c44e31da50a460df93af11a535ace568ef89d7a811069ead340c4a/python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856", size = 10921, upload-time = "2024-02-08T18:32:45.488Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051, upload-time = "2024-02-08T18:32:43.911Z" },
+]
+
+[[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/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 = "pyyaml-env-tag"
+version = "1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyyaml" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" },
+]
+
+[[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 = "selectolax"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fb/c5/959b8661d200d9fd3cf52061ce6f1d7087ec94823bb324fe1ca76c80b250/selectolax-0.4.6.tar.gz", hash = "sha256:bd9326cfc9bbd5bfcda980b0452b9761b3cf134015154e95d83fa32cbfbb751b", size = 4793248, upload-time = "2025-12-06T12:35:48.513Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/76/9b5358d82353b68c5828cc8ceae4ff1073495462979d2035c1089f4421dd/selectolax-0.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:751f727c9963584fcfa101b2696e0dd31236142901bbe7866a8e39f2ec346cc4", size = 2052057, upload-time = "2025-12-06T12:34:24.448Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/d1/9f8c8841f414a1b72174acef916d4ed38cc0fa041d3e933013e2b3213f30/selectolax-0.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6f45737b638836b9fe2a4e7ccfbcd48a315ebb96da76a79a04b8227c1a967ee", size = 2050379, upload-time = "2025-12-06T12:34:26.383Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/c4/8e5ab9275a185a31d06b5ea58e3ba61d57e57700964cbd56fe074dbe458c/selectolax-0.4.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15a22c5cd9c23f09227b2b9c227d986396125a9b0eb21be655f22fe4ccc5679a", size = 2238005, upload-time = "2025-12-06T12:34:28.2Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/af/f4299d931a8e11ba1998cac70d407c5338436978325232eb252ac7f5aba2/selectolax-0.4.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e64f771807f1a7353f4d6878c303bfbd6c6fe58897e301aa6d0de7e5e60cef61", size = 2272927, upload-time = "2025-12-06T12:34:29.955Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/5e/9afbb0e8495846bf97fa7725a6f97622ad85efc654cb3cbf4c881bd345de/selectolax-0.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0144a37fbf01695ccf2d0d24caaa058a28449cecb2c754bb9e616f339468d74", size = 2250901, upload-time = "2025-12-06T12:34:31.442Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/6b/914cc9c977fd21949af5776d25b9c011b6e72fb38569161ab6ca83d6130a/selectolax-0.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c9bdd4a9b3f71f28a0ee558a105451debd33cbe1ed350ebba7ad6b68d62815c", size = 2279842, upload-time = "2025-12-06T12:34:32.739Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/30/b32d79d31c893cf5ccea5a5be4565db1eda9bbf458ddfe402559267f2d31/selectolax-0.4.6-cp311-cp311-win32.whl", hash = "sha256:b91c34b854fdd5d21c8353f130899f8413b7104a96078acbca59c8b2d57e9352", size = 1730462, upload-time = "2025-12-06T12:34:34.435Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/f1/c7ba048d4fcc4c8d5857233c59d07f18e60b21400a8ad8e8d7da670024c2/selectolax-0.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:901064121e706bc86ed13f6e0dbe478398ad05ab112f5efbc8d722320a087b93", size = 1831442, upload-time = "2025-12-06T12:34:35.846Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/55/b33853f66b1f875bbbbfc2294ce7a4065774621ab6ebf20e8abf19965846/selectolax-0.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:609c6c19f5b7cb669a6321a1d4133d2e2b443f23f7d454de76904118a91236a6", size = 1781850, upload-time = "2025-12-06T12:34:37.175Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/81/1fdf6633df840afd9d7054a3441f04cfb1fc9d098c6c9f3bd46a64fb632e/selectolax-0.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:20615062d6062b197b61fd646e667591e987be3a894e8a8408d2a482ccddc747", size = 2051021, upload-time = "2025-12-06T12:34:38.495Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/54/d59738d090cb4df3a3a6297b7ec216b86d3ba7f320013c4bc8d4841c9f5d/selectolax-0.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c436006e2af6ade80b96411cf46652c11ced4f230032e25e1f5210b7522a4fe3", size = 2047409, upload-time = "2025-12-06T12:34:39.875Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/67/3b163ec18a128df3a3b59ce676a2dacfb26e714da81ba8a98e184b4ef187/selectolax-0.4.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:705a70b6f4e553e8c5299881269d3735a7df8a23711927a33caa16b4eaef580f", size = 2237052, upload-time = "2025-12-06T12:34:41.24Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/04/c3ae4a77e8cfa647b9177e727a7e80f64b160b65ad0db0dcb3738a4ef4a0/selectolax-0.4.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c04fd180689ed9450ad2453a3cba74cff2475a4281f76db9e18a658b7823e594", size = 2275615, upload-time = "2025-12-06T12:34:43.114Z" },
+ { url = "https://files.pythonhosted.org/packages/12/de/aaa016c44e63a1efd5525f6da6eac807388a06c70671091c735d93f13b74/selectolax-0.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cb33eb0809e70ba4a475105d164c3f90a4bb711744ca69e20037298256b8e9d7", size = 2249186, upload-time = "2025-12-06T12:34:44.84Z" },
+ { url = "https://files.pythonhosted.org/packages/76/9a/a9cf9f0158b0804c7ea404d790af031830eb6452a4948853f7582eea6c51/selectolax-0.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:97f30b7c731f9f3328e9c6aef7ca3c17fbcbc4495e286a2cdad9a77bcadfadf1", size = 2282041, upload-time = "2025-12-06T12:34:46.19Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/ea/85de7ab8a9fc0301d1b428e69dc0bced9c1cd7379872d576a2b88eb91933/selectolax-0.4.6-cp312-cp312-win32.whl", hash = "sha256:f4375b352b609508e4a6980431dc6cc1812b97658ad1aa8caa61e01565de0d7d", size = 1727544, upload-time = "2025-12-06T12:34:47.541Z" },
+ { url = "https://files.pythonhosted.org/packages/50/70/4aac2df64920112672cda846941d85c90b8152b2eddc9cf2615181551957/selectolax-0.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:1d02637a6746bf1ba7de1dfc00a0344ffb30bedd1b5d4e61727c960225bf6ce0", size = 1827825, upload-time = "2025-12-06T12:34:49.283Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/b0/09648383afed1a10df97ce30527d30714edc4072086915b4bb1a0d81a728/selectolax-0.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:bb0b371c3e2a94e6658ba4b5af88fc35aaf44f57f5a066ecaf96b4875a47aec4", size = 1775233, upload-time = "2025-12-06T12:34:51.576Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/87/7ed053cce7de8b29746c602851c67654287e25ec404d575911c6f40b671f/selectolax-0.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8303af0eeef6ab2f06f2b18e3c825df4f6984405a862c8e9e654621c26558aca", size = 2050412, upload-time = "2025-12-06T12:34:53.086Z" },
+ { url = "https://files.pythonhosted.org/packages/44/74/e8cd9b9b53da0e849b27a2ef68580915321ee52a662f015275a1cf6cca85/selectolax-0.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d8b1fb5507d90e719de705d93eaa3bdd5f2d69facf012fb67b7da8a9cd20ea6b", size = 2046513, upload-time = "2025-12-06T12:34:54.583Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/ca/c1cc7f03b681d272dbb0dc47cf9d0df857ae156d7ea54d88cc25ec23c8e9/selectolax-0.4.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:30ac51bd5bfcd6bffe58720b1fc5f97666681f0793d79d292069b3a3f8599ef0", size = 2234404, upload-time = "2025-12-06T12:34:55.971Z" },
+ { url = "https://files.pythonhosted.org/packages/df/00/a6e5c4d65243147fbd8837951267f098d9bee66ada4dc0c99d97259e052c/selectolax-0.4.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfee4d1269fd462256641abdf6c2ee4dd799ba82c578acab0bcde07547637826", size = 2272678, upload-time = "2025-12-06T12:34:57.3Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/a2/05351e0f0da62d1bc01b7820a990f1e4dec688206e0278ee8faeeb878940/selectolax-0.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fce09eeb5dd19fba672a829f63e3c40238af4a929ce1e5fd16dcbc4fd253e300", size = 2247471, upload-time = "2025-12-06T12:34:59.048Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/95/1ab9e3ad2d53dbcd7141af149c7259c693dc2dc46e27d72b7a68f17f3364/selectolax-0.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4e97ca71d545cab9c57ba3b18358cbc96ef0dcd01920ea903a531386ca1f849", size = 2278271, upload-time = "2025-12-06T12:35:00.487Z" },
+ { url = "https://files.pythonhosted.org/packages/04/41/ca80ca68fb9990cb46d753363d8dc0771225bc9bb9a77247a1987e52d2d5/selectolax-0.4.6-cp313-cp313-win32.whl", hash = "sha256:98fce08839cb8fd5d8788cbed2724cd892c78182cd923e246ef586d552a29a94", size = 1727514, upload-time = "2025-12-06T12:35:02.081Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/47/f048994ab32773fda8eda57a874afb30d0b2bf30952c009006e81737e07e/selectolax-0.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:cdc8e7833d2456331e519fe901d1c8844d120a26b21b6429f47ae946e65b0c04", size = 1829070, upload-time = "2025-12-06T12:35:03.857Z" },
+ { url = "https://files.pythonhosted.org/packages/50/94/ab0d86b1a719c090e2bde9f7d9037439900e86fb50c258b5fd9f6530521b/selectolax-0.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:d6f8c976ad067a6607b2a052b141149ae23584819b73288c32f08a1ece23d60a", size = 1774935, upload-time = "2025-12-06T12:35:05.323Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/38/93b4907c596487e13f8261129b1663559c96fc37ea2c973c98a393307484/selectolax-0.4.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:961c037ac41a12bf9db35a95d6076461f9b127d361c9ef26a77f76c45b1056eb", size = 2069131, upload-time = "2025-12-06T12:35:06.737Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/04/d29769a8313ccb9db6278401840e79662f341b716d268f7468b6270d15e1/selectolax-0.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f2be076a69a12657a38933b99d31c604d95d63911e0799f89305da8e89918874", size = 2066134, upload-time = "2025-12-06T12:35:08.163Z" },
+ { url = "https://files.pythonhosted.org/packages/29/a2/1c26b4cc6a708d234e39199bd75acdc1cfdcf4f3138e16d25e3e7aa0295d/selectolax-0.4.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25ae5dd7c20035312211de43952934981e8ff4e1502467ce78665f57bc5eaf7f", size = 2240810, upload-time = "2025-12-06T12:35:09.556Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/de/b021342d306bd08c92d0d9e9072a3ed6a3038f78387187d37fb775196fa0/selectolax-0.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfe1274930affe2b986fd20cbf2916ddf4a760edf30a7eeb9151b31e8cbe6027", size = 2274401, upload-time = "2025-12-06T12:35:11.023Z" },
+ { url = "https://files.pythonhosted.org/packages/29/77/b2816be2f4878f4e86fabca5932610401dc88d956948d97a82947e27d8bc/selectolax-0.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e52174a75236c1321f0f0353b5d97ba575c61428f16c2d78159cb154fa407e97", size = 2271054, upload-time = "2025-12-06T12:35:12.878Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/3a/ae48b9febf2af21a0fdd4fba07861ae3e13bd7235df3fa39918d33004058/selectolax-0.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5032187ed8f8d77da6dee5467a87fe9b1553c10c63671fe830e87a2d347ef8ae", size = 2297773, upload-time = "2025-12-06T12:35:14.383Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/8c/4e120b2b6dc55543bf2ffc43e78589022e59c02fa93dea0b4d22dfe3fc27/selectolax-0.4.6-cp314-cp314-win32.whl", hash = "sha256:8a4f50eb37abffe118730c062827a204a732cc1b9cd28b5dbf40752c371e9339", size = 1838289, upload-time = "2025-12-06T12:35:16.278Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/2f/51f15b06f4fcf9d5845d6bba534f7f2ed531f148c77ed8fff105cd770aa5/selectolax-0.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:11527cd430cb6d1d1a422209d87aec5767befff424f2affaa3daa2789878cf9f", size = 1938201, upload-time = "2025-12-06T12:35:17.694Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/8d/c099dcbb385e7d2145c4f19da183639bf4e429e1524dcba31ea311c5d276/selectolax-0.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:254d7f59580631dac1fcb861bb01f45039e3ac53187f07d8ccc3519110bacad0", size = 1886188, upload-time = "2025-12-06T12:35:19.538Z" },
+ { url = "https://files.pythonhosted.org/packages/54/ce/f3fa904517745ecd289b6ce18845ae968cf7d0b17e65ab781259f2746254/selectolax-0.4.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:48a9bce389c281fec8bf3b5a36bd376f1ad1f36ff072dcedaa977188b3882be1", size = 2088107, upload-time = "2025-12-06T12:35:21.061Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/18/359da9723d3ec1235819cea0958bc417ce6a12699977920854b300ad4529/selectolax-0.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ff1632c1767f6005adc2dff7b72ea9d0b6493702e86e04ee5cf934ab630172aa", size = 2090836, upload-time = "2025-12-06T12:35:22.421Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/20/199f2a05ca8dfd9bc146af03fbfaa1e2050601d3141267070a2a023ea68f/selectolax-0.4.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64a56dd91c22e809305e127bbd4cd75ad1016dd329a4e945a176c6f3376d00e2", size = 2248608, upload-time = "2025-12-06T12:35:23.946Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/67/261c06cdae29fad287008d39f51a80431f3fce66c2865b880e61d04cdfd2/selectolax-0.4.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:223471d2c9095406d69faf461aa217782575d62362d36809e350f6d3c2f69f4e", size = 2275653, upload-time = "2025-12-06T12:35:25.423Z" },
+ { url = "https://files.pythonhosted.org/packages/10/80/f2519487a86b5366acadd9e07c212b38fb657bb62b9e01de9fb24c3ada27/selectolax-0.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8c1043e61df29f4f8ef49f9f623b3d710f0c545d9a7939eee52c49987b06aef7", size = 2283495, upload-time = "2025-12-06T12:35:26.843Z" },
+ { url = "https://files.pythonhosted.org/packages/66/cc/35a0fd896371e0b5a84365b03f88c7dbe8984862e34ce32baed81ee6f486/selectolax-0.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b323ad4ebcf2edad2488022402fbc73ee158ffe81607ec1ce5eb1039eab94086", size = 2300207, upload-time = "2025-12-06T12:35:28.23Z" },
+ { url = "https://files.pythonhosted.org/packages/51/b2/dc83cce2f38a3c72d6bf9268ef6c1708ab1b4d546074384e7e0d097bf4f6/selectolax-0.4.6-cp314-cp314t-win32.whl", hash = "sha256:f5017f6e2408160604c87fb21490d9af802d09dbc1b91ac89acd9922b7b04d31", size = 1890595, upload-time = "2025-12-06T12:35:29.625Z" },
+ { url = "https://files.pythonhosted.org/packages/87/f9/8da49637643b1dffbcadc8972f1fee519c126978acaf5df59405e48424f4/selectolax-0.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:56adb0f014ab55627f20f53888a7bf1ec53aac8189fe344aec3d5077a7ad9889", size = 2005252, upload-time = "2025-12-06T12:35:31.116Z" },
+ { url = "https://files.pythonhosted.org/packages/94/7f/f783e2254db082df4f6bc00fe3b32b9dd27c3b7302a44c8c37728bb67fb7/selectolax-0.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:66558cfb1c7402fed0f47b9a2692eed53e3e2f345526314b493b5093cb951e21", size = 1906079, upload-time = "2025-12-06T12:35:32.951Z" },
+]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
+]
+
+[[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 = "text-unidecode"
+version = "1.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885, upload-time = "2019-08-30T21:36:45.405Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154, upload-time = "2019-08-30T21:37:03.543Z" },
+]
+
+[[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-inspect"
+version = "0.8.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mypy-extensions" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/72/23/bed3ea644bcd77ffe9a7f591eb058c00739747e33ab94d80cc4319ddee8e/typing_inspect-0.8.0.tar.gz", hash = "sha256:8b1ff0c400943b6145df8119c41c244ca8207f1f10c9c057aeed1560e4806e3d", size = 13550, upload-time = "2022-08-17T14:00:05.915Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/be/01/59b743dca816c4b6ca891b9e0f84d20513cd61bdbbaa8615de8f5aab68c1/typing_inspect-0.8.0-py3-none-any.whl", hash = "sha256:5fbf9c1e65d4fa01e701fe12a5bca6c6e08a4ffd5bc60bfac028253a447c5188", size = 8710, upload-time = "2022-08-17T14:00:03.093Z" },
+]
+
+[[package]]
+name = "tzdata"
+version = "2025.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
+]
+
+[[package]]
+name = "urllib3"
+version = "2.6.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" },
+]
+
+[[package]]
+name = "watchdog"
+version = "6.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" },
+ { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" },
+ { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" },
+ { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" },
+ { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" },
+ { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" },
+ { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" },
+ { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" },
+ { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" },
+ { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" },
+]
diff --git a/flake.nix b/flake.nix
index 6d503017..45ec70f6 100644
--- a/flake.nix
+++ b/flake.nix
@@ -31,7 +31,7 @@
fenix.packages.${system}.fromToolchainFile
{
file = ./rust-toolchain.toml;
- sha256 = "sha256-SJwZ8g0zF2WrKDVmHrVG3pD2RGoQeo24MEXnNx5FyuI=";
+ sha256 = "sha256-SDu4snEWjuZU475PERvu+iO50Mi39KVjqCeJeNvpguU=";
};
in
pkgs.makeRustPlatform {
@@ -68,7 +68,7 @@
})
// {
overlays.default = final: prev: {
- inherit (self.packages.${final.system}) atuin;
+ inherit (self.packages.${final.stdenv.hostPlatform.system}) atuin;
};
};
}
diff --git a/install.sh b/install.sh
index 35032fd3..2372d23f 100755
--- a/install.sh
+++ b/install.sh
@@ -35,7 +35,7 @@ elif ! command -v sed > /dev/null; then
fi
-__atuin_install_binary
+__atuin_install_binary
# TODO: Check which shell is in use
# Use of single quotes around $() is intentional here
@@ -73,7 +73,7 @@ cat << EOF
- _______ __ __ _______ __ _ ___ _ __ __ _______ __ __
+ _______ __ __ _______ __ _ ___ _ __ __ _______ __ __
| || | | || _ || | | || | | | | | | || || | | |
|_ _|| |_| || |_| || |_| || |_| | | |_| || _ || | | |
| | | || || || _| | || | | || |_| |
@@ -89,7 +89,9 @@ If you have any issues, please open an issue on GitHub or visit our forum (https
If you love Atuin, please give us a star on GitHub! It really helps ⭐️ https://github.com/atuinsh/atuin
-Please run "atuin register" to get setup with sync, or "atuin login" if you already have an account
+Please run "atuin register" to set up sync, or "atuin login" if you already have an account
+
+Check out Atuin Desktop to build executable runbooks from your shell history - https://github.com/atuinsh/desktop
EOF
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 73328e05..1a35d664 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,2 +1,2 @@
[toolchain]
-channel = "1.90"
+channel = "1.91"