diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml new file mode 100644 index 00000000..06b9ec70 --- /dev/null +++ b/.github/actionlint.yaml @@ -0,0 +1,25 @@ +# actionlint configuration. +# +# actionlint validates `runs-on:` against GitHub's list of hosted-runner labels +# and reports anything else as unknown, because a typo'd label is a job that +# queues forever rather than failing. Self-hosted labels therefore have to be +# declared here — that is the mechanism actionlint's own diagnostic points at. +# +# Without this file, `actionlint` reports an error on EVERY run in a repo that +# has the reviewer installed. That is not a harmless false positive: a linter +# that always reports something is a linter people stop reading, and the real +# findings go with it. +# +# Run it over the whole tree with: +# +# actionlint +# +# (no arguments — it discovers `.github/workflows/*.yml` and reads this file.) + +self-hosted-runner: + labels: + # The maintainer's self-hosted runner for the Antigravity PR reviewer + # (`.github/workflows/antigravity-review.yml`, `runs-on: [self-hosted, agy]`). + # It is a personal machine holding the `agy` CLI's Google AI Ultra OAuth + # session, which is why that workflow cannot run on a hosted runner. + - agy diff --git a/.github/workflows/antigravity-review.yml b/.github/workflows/antigravity-review.yml index 32ba8cf4..4a5abbbc 100644 --- a/.github/workflows/antigravity-review.yml +++ b/.github/workflows/antigravity-review.yml @@ -53,6 +53,10 @@ jobs: group: agy-review-${{ github.event.pull_request.number || github.event.issue.number }} cancel-in-progress: false runs-on: [self-hosted, agy] + # Bounded harder than the hosted jobs, not softer: this runs on the + # maintainer's own hardware, so a hung run holds a real machine rather than + # a disposable VM. Observed runtime is 1-3 minutes. + timeout-minutes: 30 steps: # Check out the DEFAULT BRANCH, never the PR head. This job runs the checked-out # `scripts/agy-review.sh` on a self-hosted runner with a token in the environment, @@ -63,6 +67,12 @@ jobs: # branch throughout. Consequence worth knowing: a PR that edits the reviewer or the # style guide is reviewed by the version already on the default branch until it merges. - name: Check out repo (for the style guide + scripts) + # SHA-pinned, not `@v7`: this job runs on a SELF-HOSTED runner -- the + # maintainer's own machine -- so a compromised tag would execute there + # rather than in a disposable VM. Verified to be exactly what `v7` + # resolves to (v7.0.1, 2026-07-17). The trailing `# v7` is the form + # Dependabot's github-actions ecosystem reads to keep the pin current. + # Adopted FROM RustySNES and SLAC, which had it while the template did not. uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: ref: ${{ github.event.repository.default_branch }} @@ -91,5 +101,21 @@ jobs: # MAX_PROMPT_BYTES: "125000" # inline/file threshold + hard backstop on the argv prompt # STYLE_GUIDE: .github/agy-review.md # style guide, loaded if present run: | + # The workflow and the scripts come from DIFFERENT REFS: for a `pull_request` + # event GitHub runs this YAML from the PR branch, while the checkout step + # above deliberately fetches the DEFAULT branch to get the scripts. So a + # change that adds a script file breaks its own PR -- the new workflow + # chmods a file the default branch does not have yet. Observed exactly + # once, on the PR that introduced `_agy_comment_body.sh`. + # + # The two required files are chmod'd unconditionally; anything added later + # is chmod'd only if present, so the workflow stays compatible with both + # the old and the new script set. A genuinely missing required file still + # fails loudly -- `agy-review.sh` sources it and dies -- rather than being + # papered over here. chmod +x scripts/agy-review.sh scripts/_agy_print.sh + for opt in scripts/_agy_comment_body.sh; do + [ -f "$opt" ] && chmod +x "$opt" + done + true scripts/agy-review.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 6903721e..81b05136 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Security + +- **`webbrowser` 1.2.1 → 1.2.4, closing RUSTSEC-2026-0257** (`BROWSER` argument + injection on Unix). Reached transitively through `egui-winit`: on Unix the + affected versions substituted the URL into the `BROWSER` template *before* + tokenizing with `split_ascii_whitespace()`, so a URL retaining spaces could + become extra browser arguments — reproduced upstream against Chromium with + `--remote-debugging-port` and `--proxy-server`. + + The advisory was failing `Cargo Deny Check` and `Dependency Audit` on `main`, + not only on a branch, so this had been shipping. + +### Changed + +- **Every dependency moved to its latest semver-compatible version** — 141 + packages, `cargo update`. Not a targeted patch of the one vulnerable crate: + the whole graph is now current, which is the state a security gate can + meaningfully assert against. + + Verified rather than assumed: `cargo deny check` reports **advisories ok, bans + ok, licenses ok, sources ok**, and the workspace is green at **66 suites / 897 + tests / 0 failures** with `fmt`, `clippy --workspace -D warnings` and a full + `build` all passing. + +- **Two `deny.toml` advisory ignores retired on their own stated condition.** The + `quick-xml 0.39.4` pair (RUSTSEC-2026-0194 / RUSTSEC-2026-0195) was ignored with + the note *"no upgrade path exists … revisit on the next wayland-scanner / + smithay-client-toolkit release"*. That release arrived: + `wayland-scanner 0.31.10 → 0.31.11` pulls `quick-xml 0.39.4 → 0.41.0`, past the + `>= 0.40` the fixes live in. `cargo deny` flagged both as matching no crate, and + it stays green with them removed. + + The `ttf-parser` ignore (RUSTSEC-2026-0192) still matches and is kept — it is an + informational *unmaintained* advisory on a transitive dep of `winit`'s + decoration stack, with no upgrade available. + ## [1.31.1] "Firewall" - 2026-08-04 ### Added diff --git a/Cargo.lock b/Cargo.lock index c1187973..b880685e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,9 +52,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -72,7 +72,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812947049edcd670a82cd5c73c3661d2e58468577ba8489de58e1a73c04cbd5d" dependencies = [ "alsa-sys", - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if", "libc", ] @@ -94,7 +94,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", - "bitflags 2.13.0", + "bitflags 2.13.1", "cc", "jni 0.22.4", "libc", @@ -103,7 +103,7 @@ dependencies = [ "ndk-context", "ndk-sys", "num_enum", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] @@ -196,9 +196,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "approx" @@ -225,7 +225,7 @@ dependencies = [ "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "x11rb", ] @@ -237,9 +237,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "as-raw-xcb-connection" @@ -280,10 +280,10 @@ dependencies = [ "memchr", "proc-macro2", "quote", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "serde", "serde_derive", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -325,6 +325,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "basic-toml" version = "0.1.10" @@ -394,9 +400,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" [[package]] name = "block-buffer" @@ -427,9 +433,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" +checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" dependencies = [ "memchr", "serde_core", @@ -449,22 +455,22 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.10.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +checksum = "fc0e56a716f1e132ff6bf4bdac1c944a3fcdc1cae65f70a4a2a1ac3b401d2d1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -475,9 +481,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "calloop" @@ -485,7 +491,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "log", "polling", "rustix 0.38.44", @@ -507,9 +513,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" +checksum = "bb1307f12aa967b5a58416e87b3653360e0fd614a016b6e970db08fecbb1b80d" dependencies = [ "serde_core", ] @@ -534,7 +540,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -554,9 +560,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.65" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" dependencies = [ "find-msvc-tools", "jobserver", @@ -587,9 +593,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "ciborium" @@ -620,9 +626,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.8.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" dependencies = [ "glob", "libc", @@ -631,9 +637,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.1" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" dependencies = [ "clap_builder", "clap_derive", @@ -641,9 +647,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" dependencies = [ "anstream", "anstyle", @@ -653,23 +659,23 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.6.5" +version = "4.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7a9bfdb35811f9e59832f0f05975114d2251b415fb534108e6f34060fd772" +checksum = "3be2ad0423bdbbb0e25bc89add796f3559706d4a95e1bc98e4d9662a957b6a19" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.6.1" +version = "4.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -748,9 +754,9 @@ dependencies = [ [[package]] name = "console" -version = "0.16.3" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" dependencies = [ "encode_unicode", "libc", @@ -792,16 +798,6 @@ dependencies = [ "libc", ] -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -815,7 +811,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.4", + "core-foundation", "core-graphics-types", "foreign-types", "libc", @@ -828,7 +824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.4", + "core-foundation", "libc", ] @@ -838,7 +834,7 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d5d7dca3ebcf65a035582c9ad4385371a9d9ee6537474d2a278f4e1e475bb58" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "objc2-audio-toolbox", "objc2-core-audio", @@ -848,9 +844,9 @@ dependencies = [ [[package]] name = "cpal" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f77b11176c37874be37e8d691c946e31b2b8c357abce9526f6a99eb469e1028" +checksum = "6f02e8d0327b42d3e2e4ab2119af397344eb9fc54a34bf0ddeaa1277af8681f1" dependencies = [ "alsa", "block2 0.6.2", @@ -954,9 +950,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crossterm" @@ -964,7 +960,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crossterm_winapi", "derive_more", "document-features", @@ -1019,9 +1015,9 @@ checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" [[package]] name = "darling" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec" dependencies = [ "darling_core", "darling_macro", @@ -1029,26 +1025,26 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff" dependencies = [ "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] name = "darling_macro" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" dependencies = [ "darling_core", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -1088,7 +1084,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -1134,7 +1130,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -1142,13 +1138,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -1199,7 +1195,7 @@ checksum = "2796c98d50b79631281d516343a6f6e93c0666462ca36e2c93b39f25d7793325" dependencies = [ "accesskit", "ahash", - "bitflags 2.13.0", + "bitflags 2.13.1", "emath", "epaint", "itertools 0.14.0", @@ -1222,7 +1218,7 @@ dependencies = [ "epaint", "log", "profiling", - "thiserror 2.0.18", + "thiserror 2.0.20", "type-map", "web-time", "wgpu", @@ -1249,9 +1245,9 @@ dependencies = [ [[package]] name = "either" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" [[package]] name = "emath" @@ -1327,9 +1323,9 @@ dependencies = [ [[package]] name = "error-code" -version = "3.3.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" +checksum = "0b5343afd4a8365a643ac588dab4cf234a190c7f6c88c9f6dd6ffe00837661b7" [[package]] name = "euclid" @@ -1350,17 +1346,11 @@ dependencies = [ "regex", ] -[[package]] -name = "fast-srgb8" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" - [[package]] name = "fastrand" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fax" @@ -1396,9 +1386,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" [[package]] name = "finl_unicode" @@ -1462,13 +1452,13 @@ dependencies = [ [[package]] name = "foreign-types-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -1497,21 +1487,21 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ "futures-core", "futures-task", @@ -1636,9 +1626,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" [[package]] name = "glow" @@ -1682,7 +1672,7 @@ dependencies = [ "hashbrown 0.16.1", "log", "presser", - "thiserror 2.0.18", + "thiserror 2.0.20", "windows", ] @@ -1692,7 +1682,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -1703,7 +1693,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -1733,7 +1723,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0431e8e389aa0f1e72bb9d1c2db8957a1a7a3580e8ed97db819c14837aac9b3e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "bytemuck", "read-fonts", "smallvec", @@ -1805,9 +1795,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -1821,9 +1811,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" dependencies = [ "displaydoc", "potential_utf", @@ -1835,9 +1825,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" dependencies = [ "displaydoc", "litemap", @@ -1848,9 +1838,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1862,16 +1852,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -1882,15 +1873,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "92a7ed671a6aad807a8651a2e1782a6598fda9ce5185dd8158549e95a91c6428" dependencies = [ "displaydoc", "icu_locale_core", @@ -1963,20 +1954,20 @@ dependencies = [ [[package]] name = "inotify" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533e68a5842e734946fe159fb03fc9bbbb254f590dd0d8ad321ae5ff7beca2c1" +checksum = "4cc00ea907cab49550b7da656f80ebb97be1b997d931fbcd28d39734e17ce592" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "inotify-sys", "libc", ] [[package]] name = "inotify-sys" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d" dependencies = [ "libc", ] @@ -1995,15 +1986,15 @@ dependencies = [ [[package]] name = "instability" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" +checksum = "2bf84e73fa6f27f299dec58e13223cf70db80da872eb921d4f6138342a0eabc8" dependencies = [ "darling", "indoc", "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -2064,7 +2055,7 @@ dependencies = [ "jni-sys 0.4.1", "log", "simd_cesu8", - "thiserror 2.0.18", + "thiserror 2.0.20", "walkdir", "windows-link", ] @@ -2079,7 +2070,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2107,24 +2098,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.103" +version = "0.3.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" dependencies = [ "cfg-if", "futures-util", @@ -2139,7 +2130,7 @@ checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899" dependencies = [ "hashbrown 0.16.1", "portable-atomic", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -2191,9 +2182,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.186" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libloading" @@ -2213,14 +2204,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +checksum = "28d0a00925a9f930d679b6789b721e3a7f9ed110f41b86d2497caa780c3a070a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "plain", - "redox_syscall 0.8.1", + "redox_syscall 0.9.2", ] [[package]] @@ -2235,11 +2226,11 @@ dependencies = [ [[package]] name = "line-clipping" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" +checksum = "e752191d037c44ad111a8caa762921926658402f01cc1253f7bef2020ece4f5e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -2262,9 +2253,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "litrs" @@ -2289,9 +2280,9 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lru" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9" +checksum = "5d2f2f9b4ba7e6b24d95e7e899329d35be83bcded72c8540cdd5368932d1d90a" dependencies = [ "hashbrown 0.17.1", ] @@ -2312,7 +2303,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "920cf654b23d217c550ceea57c32cd2a413ea27b6d47ed77b5ee0cf655adefa6" dependencies = [ "cc", - "which 8.0.4", + "which 8.0.5", ] [[package]] @@ -2333,9 +2324,9 @@ checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memmap2" @@ -2379,9 +2370,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "log", @@ -2401,7 +2392,7 @@ dependencies = [ "mlua-sys", "num-traits", "parking_lot", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", ] [[package]] @@ -2430,13 +2421,13 @@ dependencies = [ [[package]] name = "naga" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd91265cc2454558f659b3b4b9640f0ddb8cc6521277f166b8a8c181c898079" +checksum = "b2bf919621e7975acb27d881bae2fb993e0d45c8e0446e85e6272971e00dc8df" dependencies = [ "arrayvec", "bit-set 0.9.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -2451,7 +2442,7 @@ dependencies = [ "pp-rs", "rustc-hash 1.1.0", "spirv", - "thiserror 2.0.18", + "thiserror 2.0.20", "unicode-ident", ] @@ -2461,7 +2452,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "jni-sys 0.3.1", "log", "ndk-sys", @@ -2491,7 +2482,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if", "cfg_aliases", "libc", @@ -2504,7 +2495,7 @@ version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if", "cfg_aliases", "libc", @@ -2540,7 +2531,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2572,7 +2563,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2615,7 +2606,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -2631,7 +2622,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "objc2 0.6.4", "objc2-core-graphics", @@ -2644,7 +2635,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "objc2 0.6.4", "objc2-core-audio", @@ -2659,7 +2650,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13a380031deed8e99db00065c45937da434ca987c034e13b87e4441f9e4090be" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -2670,7 +2661,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", @@ -2707,7 +2698,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2 0.6.4", ] @@ -2717,7 +2708,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2729,7 +2720,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "dispatch2", "libc", @@ -2742,7 +2733,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "dispatch2", "objc2 0.6.4", "objc2-core-foundation", @@ -2785,7 +2776,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "dispatch", "libc", @@ -2798,7 +2789,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -2811,7 +2802,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "objc2-core-foundation", ] @@ -2822,7 +2813,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2 0.6.4", "objc2-core-foundation", ] @@ -2845,7 +2836,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2857,7 +2848,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "objc2 0.6.4", "objc2-foundation 0.3.2", @@ -2869,7 +2860,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2882,7 +2873,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -2905,7 +2896,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-cloud-kit", @@ -2926,7 +2917,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -2949,7 +2940,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", @@ -3019,26 +3010,35 @@ dependencies = [ [[package]] name = "palette" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +checksum = "ddeed8580d347d2abf3dcf06a5f0b3dc020258338526b277847cd4248a70fc64" dependencies = [ "approx", - "fast-srgb8", "libm", "palette_derive", + "palette_math", ] [[package]] name = "palette_derive" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +checksum = "88537020289b719d81be994ccf1bbf4990f477e2f69ee52fe3e45f43a02e56be" dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", +] + +[[package]] +name = "palette_math" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6eb142958d64335fb0e345c5b9ead2ecd6fc438c307e9d7d3c4fd428dbaf12" +dependencies = [ + "libm", ] [[package]] @@ -3091,9 +3091,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.6" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +checksum = "5a07a60cc7a4d00c91f95c685609d1d2f79050e6804b70ebedd7650f0b839bcf" dependencies = [ "memchr", "ucd-trie", @@ -3101,9 +3101,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.6" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +checksum = "b3a83744a5c8455b8b3e0dc5031362780a347c878bdd11584d1a8984228cc88d" dependencies = [ "pest", "pest_generator", @@ -3111,25 +3111,24 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.6" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +checksum = "e0cd3451aa3de60d4b9a1e736885e4dea6b31617598026f12256ad566d63304a" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "pest_meta" -version = "2.8.6" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +checksum = "e04d3a0849e241d7dfce834c83b1c5edc8622009e8dd51a12ba1927c32f05496" dependencies = [ "pest", - "sha2", ] [[package]] @@ -3172,7 +3171,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -3201,7 +3200,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -3212,9 +3211,9 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkg-config" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "plain" @@ -3256,7 +3255,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crc32fast", "fdeflate", "flate2", @@ -3294,9 +3293,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" [[package]] name = "portable-atomic-util" @@ -3309,9 +3308,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] @@ -3348,9 +3347,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] @@ -3375,18 +3374,18 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.39.4" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -3405,9 +3404,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ "rand_core", ] @@ -3446,7 +3445,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "compact_str", "critical-section", "hashbrown 0.17.1", @@ -3456,7 +3455,7 @@ dependencies = [ "palette", "serde", "strum", - "thiserror 2.0.18", + "thiserror 2.0.20", "unicode-segmentation", "unicode-truncate", "unicode-width", @@ -3511,7 +3510,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "hashbrown 0.17.1", "indoc", "instability", @@ -3588,16 +3587,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] name = "redox_syscall" -version = "0.8.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7" +checksum = "f1c93da5bb2c5d4e6c0ef7abeead62c89169a0a4882bfb83ac892f2423aea2fe" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -3608,14 +3607,14 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.17", "libredox", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] name = "regex" -version = "1.12.4" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -3625,9 +3624,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -3743,9 +3742,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -3762,7 +3761,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -3775,7 +3774,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.12.1", @@ -3784,9 +3783,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.41" +version = "0.23.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" dependencies = [ "log", "once_cell", @@ -3799,18 +3798,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "0527518605e68109d875e248ea259b6758801cf165e4b2c2733ae3b51f12535a" dependencies = [ "ring", "rustls-pki-types", @@ -3819,9 +3818,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "rustysnes-android" @@ -3843,7 +3842,7 @@ dependencies = [ name = "rustysnes-apu" version = "1.25.0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustysnes-savestate", ] @@ -3851,9 +3850,9 @@ dependencies = [ name = "rustysnes-cart" version = "1.25.0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustysnes-savestate", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -3875,7 +3874,7 @@ dependencies = [ "rustysnes-ppu", "rustysnes-savestate", "sha2", - "thiserror 2.0.18", + "thiserror 2.0.20", "zip", ] @@ -3883,7 +3882,7 @@ dependencies = [ name = "rustysnes-cpu" version = "1.25.0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustysnes-savestate", ] @@ -3918,8 +3917,8 @@ dependencies = [ "rustysnes-savestate", "rustysnes-script", "serde", - "thiserror 2.0.18", - "toml 1.1.2+spec-1.1.0", + "thiserror 2.0.20", + "toml 1.1.4+spec-1.1.0", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -3961,7 +3960,7 @@ version = "1.25.0" dependencies = [ "rustysnes-cart", "rustysnes-core", - "thiserror 2.0.18", + "thiserror 2.0.20", "uniffi", ] @@ -3972,7 +3971,7 @@ dependencies = [ "js-sys", "rustysnes-core", "rustysnes-savestate", - "thiserror 2.0.18", + "thiserror 2.0.20", "wasm-bindgen", "web-sys", ] @@ -3981,7 +3980,7 @@ dependencies = [ name = "rustysnes-ppu" version = "1.25.0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustysnes-cart", "rustysnes-savestate", "xxhash-rust", @@ -3991,7 +3990,7 @@ dependencies = [ name = "rustysnes-savestate" version = "1.25.0" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -4000,7 +3999,7 @@ version = "1.25.0" dependencies = [ "mlua", "rustysnes-core", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -4059,7 +4058,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4077,9 +4076,9 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" +checksum = "2ab42ca02749e120097e328d91d415325bdf43b1c72c4c8badf37375fe40a813" [[package]] name = "semver" @@ -4093,9 +4092,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -4103,29 +4102,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] name = "serde_json" -version = "1.0.150" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", @@ -4199,15 +4198,15 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "simd_cesu8" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" dependencies = [ "rustc_version", "simdutf8", @@ -4280,7 +4279,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "calloop", "calloop-wayland-source", "cursor-icon", @@ -4314,7 +4313,7 @@ version = "0.4.0+sdk-1.4.341.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9571ea910ebd84c86af4b3ed27f9dbdc6ad06f17c5f96146b2b671e2976744f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -4359,7 +4358,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4381,9 +4380,20 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.118" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -4398,7 +4408,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4429,7 +4439,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9048a889effe34a5cddee0af7f53285198b16dca3be510858d38dfdb3e62a04e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "parking_lot", "rustix 1.1.4", "signal-hook", @@ -4464,8 +4474,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", - "base64", - "bitflags 2.13.0", + "base64 0.22.1", + "bitflags 2.13.1", "fancy-regex", "filedescriptor", "finl_unicode", @@ -4519,11 +4529,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.20", ] [[package]] @@ -4534,18 +4544,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -4564,9 +4574,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.51" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", "libc", @@ -4610,9 +4620,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" dependencies = [ "displaydoc", "zerovec", @@ -4639,9 +4649,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.2+spec-1.1.0" +version = "1.1.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" dependencies = [ "indexmap", "serde_core", @@ -4649,7 +4659,7 @@ dependencies = [ "toml_datetime", "toml_parser", "toml_writer", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] @@ -4663,30 +4673,30 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.12+spec-1.1.0" +version = "0.25.13+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" dependencies = [ "indexmap", "toml_datetime", "toml_parser", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" [[package]] name = "tracing" @@ -4716,7 +4726,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" dependencies = [ - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", ] [[package]] @@ -4842,7 +4852,7 @@ dependencies = [ "indexmap", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4857,7 +4867,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.118", + "syn 2.0.119", "toml 0.5.11", "uniffi_meta", ] @@ -4907,11 +4917,11 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" +checksum = "972d7902c8735f2695410b8aed7df6ed12a47394aa1c8d7af49f0497b731a94d" dependencies = [ - "base64", + "base64 0.23.1", "log", "percent-encoding", "rustls", @@ -4923,11 +4933,11 @@ dependencies = [ [[package]] name = "ureq-proto" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" +checksum = "da5f78b09e6941e1a0f2e30e695e4b120377b54d5e0aec11b594bb57b3971613" dependencies = [ - "base64", + "base64 0.23.1", "http", "httparse", "log", @@ -4965,9 +4975,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.4" +version = "1.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" +checksum = "2cefc03fd367c0c6d4305de1b312cf00248c4114f4a0418ce6a6af769e3b0bd9" dependencies = [ "atomic", "getrandom 0.4.3", @@ -4994,7 +5004,7 @@ dependencies = [ "log", "peniko", "smallvec", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -5051,9 +5061,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" dependencies = [ "cfg-if", "once_cell", @@ -5064,9 +5074,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.76" +version = "0.4.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +checksum = "6b7777d5cc23d0e91404e53ce2d5e8ec7acae3026b16233dba62cd3246457950" dependencies = [ "js-sys", "wasm-bindgen", @@ -5074,9 +5084,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5084,31 +5094,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" dependencies = [ "unicode-ident", ] [[package]] name = "wayland-backend" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" +checksum = "38a91b4eaddff87b1cd1074985e3713da4af2c49742d1b356b2c01670a67a078" dependencies = [ "cc", "downcast-rs", @@ -5120,11 +5130,11 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.14" +version = "0.31.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" +checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustix 1.1.4", "wayland-backend", "wayland-scanner", @@ -5136,7 +5146,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cursor-icon", "wayland-backend", ] @@ -5158,7 +5168,7 @@ version = "0.32.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -5170,7 +5180,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -5183,7 +5193,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -5192,9 +5202,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.10" +version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" +checksum = "338e30461b3a2b67d70eb30a6d89f8e0c93a833e07d2ae89085cd070c4a00ac0" dependencies = [ "proc-macro2", "quick-xml", @@ -5215,9 +5225,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.103" +version = "0.3.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +checksum = "c435338968042f4f59a557f690a253676d47ce13ceb55d70100e7facf6620a30" dependencies = [ "js-sys", "wasm-bindgen", @@ -5235,15 +5245,15 @@ dependencies = [ [[package]] name = "webbrowser" -version = "1.2.1" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc95580916af1e68ff6a7be07446fc5db73ebf71cf092de939bbf5f7e189f72" +checksum = "62c35be770821a214dbc362fc26908c853e776c0004294d0b10b8a6bad582f94" dependencies = [ - "core-foundation 0.10.1", "jni 0.22.4", "log", "ndk-context", "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-foundation 0.3.2", "url", "web-sys", @@ -5251,9 +5261,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" dependencies = [ "rustls-pki-types", ] @@ -5347,12 +5357,12 @@ dependencies = [ [[package]] name = "wgpu" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb3feacc458f7bee8bc1737149b42b6c731aa461039a4264a67bb6681646b250" +checksum = "76e8840e1ba2881d4cbb18d2147627a56af426ff064c0401eb0c8410c6325d07" dependencies = [ "arrayvec", - "bitflags 2.13.0", + "bitflags 2.13.1", "bytemuck", "cfg-if", "cfg_aliases", @@ -5377,14 +5387,14 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02da3ad1b568337f25513b317870960ef87073ea0945502e44b864b67a8c77b7" +checksum = "2f519832254e56965a9940c4af57dcb75f702b6f6fa4a0b172f685395843a4d7" dependencies = [ "arrayvec", "bit-set 0.9.1", "bit-vec 0.9.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "bytemuck", "cfg_aliases", "document-features", @@ -5399,7 +5409,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror 2.0.18", + "thiserror 2.0.20", "wgpu-core-deps-apple", "wgpu-core-deps-emscripten", "wgpu-core-deps-wasm", @@ -5411,51 +5421,51 @@ dependencies = [ [[package]] name = "wgpu-core-deps-apple" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e51b5447e144b3dbba4feb01f80f4fa21696fa0cd99afb2c3df1affd6fdb28" +checksum = "f5e39e26c4c0e07589e67d18546cf79ff45383659fc72fca4dd293358a0347f3" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-emscripten" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3487cd6293a963bc5c0c0396f6a2192043c50003c07f4efdccbad3d90ec9d819" +checksum = "01e09be551dc939498bdd5f6b2c66e55ab275dad25825267a08605a80fc9f0af" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-wasm" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2f2fb042f36920771deb0b966543c5751b18f3d327760ffc90f74e20b2dcd4" +checksum = "af1fb1798be2a912497d4c224f72d39bb0cb34af50e8bcc29865bc339c943059" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-windows-linux-android" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb01076d0aa08b0ba9bd741e178b5cc440f5abe99d9581323a4c8b5d1a1916" +checksum = "4e592c1bbef6ad047647ae6e666ebd8cee7a32bb4544d9700ec96cbf73230257" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-hal" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8e1a9e7a8512f276f7c62e018c7fa8d60954303fed2e5750114332049193f" +checksum = "97ace1c17727311c22a46e4e3faf56ea6de81af99dcc839bdfb54857b94d448d" dependencies = [ "android_system_properties", "arrayvec", "ash", "bit-set 0.9.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "bytemuck", "cfg-if", @@ -5488,7 +5498,7 @@ dependencies = [ "raw-window-metal", "renderdoc-sys", "smallvec", - "thiserror 2.0.18", + "thiserror 2.0.20", "wasm-bindgen", "wayland-sys", "web-sys", @@ -5501,9 +5511,9 @@ dependencies = [ [[package]] name = "wgpu-naga-bridge" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c654c483f058800972c3645e95388a7eca31bf9fe1933bc20e036588a0be02" +checksum = "95226013f547544b223281cd16a4fb549aa9dcb562adbda0faae4c73ffbbc161" dependencies = [ "naga", "wgpu-types", @@ -5511,11 +5521,11 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9bcc31518a0e9735aefebedb5f7a9ef3ed1c42549c9f4c882fa9060ceaac639" +checksum = "84bf84cd9ca8ca45e2b223a3868f1adf9bfc0c66aeac212e76ee7e40fdadf8f5" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "bytemuck", "js-sys", "log", @@ -5537,9 +5547,9 @@ dependencies = [ [[package]] name = "which" -version = "8.0.4" +version = "8.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d7cd18d4acb58fb3cdfe9ea54e6cd96a4e7d4cc45c56338b236e82dad47248" +checksum = "8f3ef584124b911bcc3875c2f1472e80f24361ceb789bd1c62b3e9a3df9ff43c" dependencies = [ "libc", ] @@ -5628,7 +5638,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -5639,7 +5649,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -5703,6 +5713,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -5736,13 +5755,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "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-threading" version = "0.2.1" @@ -5764,6 +5800,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -5776,6 +5818,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +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" @@ -5788,12 +5836,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +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" @@ -5806,6 +5866,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +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" @@ -5818,6 +5884,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +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" @@ -5830,6 +5902,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -5842,6 +5920,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winit" version = "0.30.13" @@ -5851,13 +5935,13 @@ dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "bytemuck", "calloop", "cfg_aliases", "concurrent-queue", - "core-foundation 0.9.4", + "core-foundation", "core-graphics", "cursor-icon", "dpi", @@ -5905,9 +5989,9 @@ dependencies = [ [[package]] name = "winnow" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] @@ -5920,9 +6004,9 @@ checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "x11-dl" @@ -5958,9 +6042,9 @@ checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "xcursor" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" +checksum = "163b33ed8786455e2fa5d72f554057ce3f3182425434f756cd39c99839d88e23" [[package]] name = "xkbcommon-dl" @@ -5968,7 +6052,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "dlib", "log", "once_cell", @@ -5983,15 +6067,15 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.28" +version = "0.8.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" +checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7" [[package]] name = "xxhash-rust" -version = "0.8.16" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d93c89cdc2d3a63c3ec48ffe926931bdc069eafa8e4402fe6d8f790c9d1e576" +checksum = "aee1b19627c7c60102ab80d3a9cbe18de90bfe03bfa6c3715447681f0e8c8af6" [[package]] name = "yoke" @@ -6012,28 +6096,28 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -6053,7 +6137,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", "synstructure", ] @@ -6065,9 +6149,9 @@ checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -6076,9 +6160,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" dependencies = [ "yoke", "zerofrom", @@ -6087,13 +6171,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "9f212a141d820099d57ffafb9569be9617a6f27d3dc881fbee8fb56642f917a9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -6112,15 +6196,15 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5431d5661c32445236631278f27946e444ddafe4684cac70b185272d4f9c52d5" +checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12" [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zopfli" @@ -6136,9 +6220,9 @@ dependencies = [ [[package]] name = "zune-core" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" [[package]] name = "zune-jpeg" diff --git a/deny.toml b/deny.toml index 6528806c..cadec380 100644 --- a/deny.toml +++ b/deny.toml @@ -21,16 +21,6 @@ ignore = [ # sctk-adwaita -> ab_glyph -> owned_ttf_parser -> ttf-parser 0.25.1 (already the latest # release). No safe upgrade exists until winit's decoration stack moves off ab_glyph. "RUSTSEC-2026-0192", - # `quick-xml 0.39.4` -- two real advisories (quadratic duplicate-attribute scan; unbounded - # NsReader namespace allocation), BOTH requiring attacker-controlled XML input. The only - # consumer here is `wayland-scanner` 0.31.10, a PROC-MACRO that parses the vendored Wayland - # protocol XML files at COMPILE TIME -- no runtime code path in this project parses XML at - # all, and the inputs are trusted files shipped inside the wayland-protocols crates, never - # external data. No upgrade path exists: 0.39.4 is the max of its line, the fixes live in - # quick-xml >= 0.40, and wayland-scanner 0.31.10 (its own max version) pins ^0.39. Revisit on - # the next wayland-scanner / smithay-client-toolkit release. - "RUSTSEC-2026-0194", - "RUSTSEC-2026-0195", ] [licenses] diff --git a/scripts/_agy_comment_body.sh b/scripts/_agy_comment_body.sh new file mode 100755 index 00000000..5668f9ce --- /dev/null +++ b/scripts/_agy_comment_body.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# +# _agy_comment_body.sh -- the review comment's body format, as sourceable functions. +# +# Sourced by `agy-review.sh` (which uses them) and by `agy-review-selftest.sh` (which tests +# them). It exists as a separate file for one reason: `agy-review.sh` does its work at TOP +# LEVEL, so it cannot be sourced without running a review, and a test that cannot call the +# real implementation ends up reimplementing it. That failure is not hypothetical here -- the +# first version of the archive test inlined its own copy of the `awk` pipeline, so a mutation +# deleting the marker strip from the script came back NOT CAUGHT. A test that reimplements its +# subject agrees with itself forever. +# +# Defines no state and runs nothing on source. + +# The sentinels delimiting the archive of earlier review rounds inside the comment body. +# +# The reviewer used to POST a fresh comment each round and DELETE the previous one. That kept +# the PR tidy and destroyed the record: a round nobody read before the next push was gone, with +# nothing on the PR indicating it had existed -- and unlike a CodeRabbit or Copilot thread, an +# unaddressed finding left no trace. Observed on a real PR where two consecutive rounds each +# raised a blocking issue and only the second survived. +# +# Now there is ONE comment per PR, edited in place: newest round on top, earlier rounds folded +# into a collapsed `
` below. Same tidiness, no destruction. +AGY_ARCHIVE_START='' +AGY_ARCHIVE_END='' + +# The newest round of a comment body: everything after the marker, before the archive. +# +# `awk` matching WHOLE LINES rather than `sed` with a pattern, because a review body +# legitimately contains regex metacharacters, backslashes and HTML, and the sentinels must not +# match a line that merely mentions one. +agy_body_head() { + local marker="$1" + awk -v s="$AGY_ARCHIVE_START" '$0 == s { exit } { print }' \ + | grep -v -F -x "$marker" || true +} + +# The archived rounds of a comment body: everything strictly between the sentinels. +# +# The `$0 == e` test comes FIRST so a body whose archive is empty yields nothing rather than +# emitting its own end sentinel. +agy_body_archive() { + awk -v s="$AGY_ARCHIVE_START" -v e="$AGY_ARCHIVE_END" ' + $0 == e { inside = 0 } + inside { print } + $0 == s { inside = 1 }' || true +} + +# Delimits one archived round. Emitted by the caller ahead of each round's `
`. +# +# A dedicated sentinel, NOT the `
` tag itself. Matching `/^
$/` looked +# equivalent and was a data-corruption bug: a review body legitimately contains `
` +# blocks -- folded logs, collapsed code, another bot's summary, and the archived rounds are +# themselves nested `
` -- so the cut could land INSIDE a round and leave torn HTML +# plus half a review. The sentinel is an HTML comment, so it is invisible when rendered and +# cannot occur by accident in prose the way a tag can. Found in review. +AGY_ROUND_MARK='' + +# Drop the OLDEST archived round -- everything from the last round marker onward. +# +# Exits non-zero when there is no marker to cut at, so a caller trimming to a size limit +# terminates rather than spinning. That is also the fail-safe direction for an archive written +# by an older version of this script: with no markers present, nothing is dropped and the edit +# simply fails on size, rather than the archive being silently mangled. +agy_drop_oldest_round() { + awk -v m="$AGY_ROUND_MARK" ' + $0 == m { starts[++n] = NR } + { line[NR] = $0 } + END { + cut = (n > 0) ? starts[n] : 0 + if (cut == 0) exit 1 + for (i = 1; i < cut; i++) print line[i] + }' +} diff --git a/scripts/agy-review-selftest.sh b/scripts/agy-review-selftest.sh index db684954..491f8a5f 100755 --- a/scripts/agy-review-selftest.sh +++ b/scripts/agy-review-selftest.sh @@ -30,16 +30,56 @@ SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" extract_marker() { sed -n 's/^MARKER="\(.*\)"$/\1/p' "$SCRIPT_DIR/agy-review.sh" | head -n 1 } +# Extraction is delimited by explicit `SELFTEST-EXTRACT` markers rather than by matching the +# declaration's own syntax. Adopted FROM SLAC, and it is the better mechanism: the `sed` range +# it replaced ended at the first line closing with a quote, so a filter whose body ever ended a +# line that way would be silently TRUNCATED -- and a truncated jq program can still compile and +# still return ids, which is exactly the silent-wrong-answer this file exists to prevent. +# Markers also let a guard be several statements rather than one assignment, which is what makes +# the OAuth and service-error guards testable at all. +extract_block() { + sed -n "/^# >>> SELFTEST-EXTRACT: $1\$/,/^# <<< SELFTEST-EXTRACT\$/p" "$SCRIPT_DIR/agy-review.sh" +} extract_filter() { - sed -n "/^SELECT_STALE_JQ='/,/'\$/p" "$SCRIPT_DIR/agy-review.sh" \ - | sed "1s/^SELECT_STALE_JQ='//; \$s/'\$//" + extract_block "ours-comment filter" \ + | sed -n "/^SELECT_OURS_JQ='/,/'\$/p" \ + | sed "1s/^SELECT_OURS_JQ='//; \$s/'\$//" } +# Every marked block must exist and be sourceable. A renamed or unbalanced marker would +# otherwise extract EMPTY, and an empty guard sources fine and asserts nothing -- the same +# absence-reads-as-agreement failure the markers were adopted to prevent. +for guard in "service-error guard" "oauth guard" "ours-comment filter"; do + blk="$(extract_block "$guard")" + [ -n "$blk" ] || { echo "FAIL: SELFTEST-EXTRACT block '$guard' is missing or empty" >&2; exit 1; } + printf '%s\n' "$blk" | bash -n - 2>/dev/null \ + || { echo "FAIL: extracted block '$guard' is not valid shell (unbalanced markers?)" >&2; exit 1; } + eval "$blk" +done + MARKER="$(extract_marker)" FILTER="$(extract_filter)" [ -n "$MARKER" ] || { echo "FAIL: could not extract MARKER from agy-review.sh" >&2; exit 1; } -[ -n "$FILTER" ] || { echo "FAIL: could not extract SELECT_STALE_JQ from agy-review.sh" >&2; exit 1; } +[ -n "$FILTER" ] || { echo "FAIL: could not extract SELECT_OURS_JQ from agy-review.sh" >&2; exit 1; } + +# The REAL body-format implementation, sourced rather than reimplemented. The first version of +# these checks inlined its own copy of the `awk` pipeline, and a mutation deleting the marker +# strip from the script came back NOT CAUGHT -- a test that reimplements its subject agrees with +# itself forever. `agy-review.sh` cannot be sourced (it works at top level), which is exactly +# why the format lives in its own file. +# shellcheck source=scripts/_agy_comment_body.sh +. "$SCRIPT_DIR/_agy_comment_body.sh" +[ -n "${AGY_ARCHIVE_START:-}" ] || { echo "FAIL: _agy_comment_body.sh defined no AGY_ARCHIVE_START" >&2; exit 1; } +[ -n "${AGY_ARCHIVE_END:-}" ] || { echo "FAIL: _agy_comment_body.sh defined no AGY_ARCHIVE_END" >&2; exit 1; } + +# The script must actually USE the shared helper, or these checks test a file nothing runs. +grep -q '_agy_comment_body.sh' "$SCRIPT_DIR/agy-review.sh" \ + || { echo "FAIL: agy-review.sh does not source _agy_comment_body.sh" >&2; exit 1; } +for fn in agy_body_head agy_body_archive agy_drop_oldest_round; do + grep -q "$fn" "$SCRIPT_DIR/agy-review.sh" \ + || { echo "FAIL: agy-review.sh does not call $fn" >&2; exit 1; } +done # A non-empty extraction is not the same as a COMPLETE one. The `sed` range above ends at the # first line closing with a quote, so a filter whose body ever ends a line that way would be @@ -51,14 +91,14 @@ FILTER="$(extract_filter)" # prefix of one. # The named args must be supplied here too: the filter references `$marker`/`$new_id`, and jq # rejects an undefined variable at COMPILE time — so omitting them fails a perfectly good program. -if ! printf '[]' | jq --arg marker x --argjson new_id 0 "$FILTER" >/dev/null 2>&1; then - echo "FAIL: extracted SELECT_STALE_JQ is not a valid jq program (truncated?):" >&2 +if ! printf '[]' | jq --arg marker x "$FILTER" >/dev/null 2>&1; then + echo "FAIL: extracted SELECT_OURS_JQ is not a valid jq program (truncated?):" >&2 printf '%s\n' "$FILTER" >&2 exit 1 fi case "$(printf '%s' "$FILTER" | tr -d '[:space:]')" in - *'|.id') : ;; - *) echo "FAIL: extracted SELECT_STALE_JQ does not end in '| .id'; extraction truncated" >&2 + *'|.id//empty') : ;; + *) echo "FAIL: extracted SELECT_OURS_JQ does not end in '| .id // empty'; extraction truncated" >&2 printf '%s\n' "$FILTER" >&2 exit 1 ;; esac @@ -66,20 +106,19 @@ esac fixture() { cat <\nOLDER ROUND\n
')" "$archive_part" + +# A body with NO archive yet (the first round) must split to a head and an empty archive, not to +# an empty head -- the first re-review is exactly when this path runs for the first time. +first_body="$(printf '%s\nFIRST ROUND\n' "$MARKER")" +check "a body with no archive still yields its head" "FIRST ROUND" \ + "$(printf '%s\n' "$first_body" | agy_body_head "$MARKER")" +check "a body with no archive yields an empty archive" "" \ + "$(printf '%s\n' "$first_body" | agy_body_archive)" + +# The head must NOT carry the marker forward: an archived round that still contains it would +# make every future run's `contains($marker)` match inside the archive, and the split would +# then cut at the wrong place. A mutation removing the strip must fail here. +check "the head never carries the marker into the archive" "" \ + "$(printf '%s\nX\n' "$MARKER" | agy_body_head "$MARKER" | grep -F -x "$MARKER" || true)" + +# Trimming must terminate: with no `
` left, dropping fails rather than looping. +check "dropping from an empty archive fails rather than spinning" "1" \ + "$(printf 'no rounds here\n' | agy_drop_oldest_round >/dev/null 2>&1; echo $?)" + +# An archive written by an OLDER version has no round markers. Nothing must be dropped: +# the edit then fails on size, which is recoverable, rather than the archive being mangled. +check "an unmarked (legacy) archive drops nothing" "1" \ + "$(printf '
\nNEW\n
\n
\nOLD\n
\n' \ + | agy_drop_oldest_round >/dev/null 2>&1; echo $?)" + +marked_archive="$(printf '%s\n
\nNEW\n
\n%s\n
\nOLD\n
\n' \ + "$AGY_ROUND_MARK" "$AGY_ROUND_MARK")" +check "dropping removes the OLDEST round, keeping the newest" \ + "$(printf '%s\n
\nNEW\n
' "$AGY_ROUND_MARK")" \ + "$(printf '%s\n' "$marked_archive" | agy_drop_oldest_round)" -# Regression #1, pinned: an unknown id must not select everything. The caller now refuses to run -# the delete at all in this case, but the filter itself is checked so the two guards are -# independent rather than one relying on the other. -check "an id of 0 still excludes nothing real" "111 222 999" "$(select_ids 0)" +# THE BUG THIS SENTINEL EXISTS FOR. A review body legitimately contains `
` blocks +# -- folded logs, collapsed code, another bot's summary -- and matching the tag itself cut +# INSIDE a round, leaving torn HTML and half a review. The newest round below carries its own +# `
`; dropping the oldest must not touch it. +nested="$(printf '%s\n
\nRound\n
\nfolded log\n
\nfinding\n
\n%s\n
\nOLD\n
\n' \ + "$AGY_ROUND_MARK" "$AGY_ROUND_MARK")" +check "a
INSIDE a round is not mistaken for a round boundary" \ + "$(printf '%s\n
\nRound\n
\nfolded log\n
\nfinding\n
' "$AGY_ROUND_MARK")" \ + "$(printf '%s\n' "$nested" | agy_drop_oldest_round)" -# A different id in the set behaves the same way, so the exclusion is genuinely by value. -check "excludes whichever id it is given" "222 999" "$(select_ids 111)" +# The writer must actually EMIT the sentinel, or every archive is legacy-shaped and the trim +# silently never fires -- the comment would then grow until the edit fails. +if grep -q 'AGY_ROUND_MARK' "$SCRIPT_DIR/agy-review.sh"; then + echo " ok agy-review.sh emits the round sentinel" +else + echo " FAIL agy-review.sh never emits AGY_ROUND_MARK; the archive would never trim" + fails=$((fails + 1)) +fi + +# The script must not delete comments any more. A reintroduced DELETE is the regression that +# would silently restore the destructive behavior this design replaced. +if grep -qE 'gh api +-X +DELETE' "$SCRIPT_DIR/agy-review.sh"; then + echo " FAIL agy-review.sh deletes comments again; the archive design forbids it" + fails=$((fails + 1)) +else + echo " ok agy-review.sh never deletes a comment" +fi # Regression #2, pinned: `--arg`/`--argjson` belong to jq. If they are ever moved onto `gh api` # again, that command exits non-zero — assert the flags are not passed to `gh api` in the script. @@ -128,6 +242,54 @@ else echo " ok --arg/--argjson are not passed to \`gh api\`" fi +# --- the service-error guard --------------------------------------------------- +# When agy's upstream is down it prints an error, not a review. That text is non-empty, so +# `have_text` alone treats it as a valid review and POSTs it -- a green check for a review that +# never ran. Observed twice on SLAC PR #14, where the check passed in 7 seconds with the error +# string as its entire body. A control that cannot fail is worse than no control. +se() { printf '%s' "$1" > "$TMPD/cap"; service_error_present "$TMPD/cap" && echo MATCH || echo NOMATCH; } +TMPD="$(mktemp -d)" +trap 'rm -rf "$TMPD"' EXIT + +check "a bare backend 503 is caught" "MATCH" \ + "$(se 'Error: Eligibility check failed: UNAVAILABLE (code 503): The service is currently unavailable.')" +check "RESOURCE_EXHAUSTED is caught" "MATCH" "$(se 'Error: RESOURCE_EXHAUSTED')" + +# The false positives the anchoring exists to avoid. A genuine review may quote a 503 while +# reviewing retry logic, and aborting on that would be the very failure the OAuth guard's design +# notes warn about. +check "a review DISCUSSING a 503 is not caught" "NOMATCH" \ + "$(se "$(printf '## Review\n\nThe retry path should handle Error: UNAVAILABLE (code 503) here.\n')")" +check "an error on line 3 is not caught (only line 1 counts)" "NOMATCH" \ + "$(se "$(printf '## Review\n\nError: UNAVAILABLE (code 503)\n')")" +check "an empty capture is not caught" "NOMATCH" "$(se '')" + +# The ANCHOR, tested where it is the only thing that matters: the error text is on LINE ONE but +# not at its start. `head -n 1` cannot exclude this; only `^` can. Without this fixture the +# anchor could be deleted and every other check still passed. +check "a heading MENTIONING an error mid-line is not caught" "NOMATCH" \ + "$(se '## Review of the Error: UNAVAILABLE (code 503) retry path')" + +# ...and the anchored form still matches with leading whitespace, which the regex allows. +check "a leading-whitespace error is still caught" "MATCH" \ + "$(se ' Error: UNAVAILABLE (code 503)')" + +# The size cap is what separates "the error IS the whole capture" from "a review mentions one". +long="Error: UNAVAILABLE (code 503) $(head -c 3000 /dev/zero | tr '\0' 'x')" +check "a long capture opening with an error is not caught" "NOMATCH" "$(se "$long")" + +# The script must FAIL rather than post when the backend errored and nothing was produced. +# Called, not grepped for: `if false && [ "${service_errors:-0}" -gt 0 ]` still contains what a +# structural grep looks for, and that mutation came back NOT CAUGHT. +: > "$TMPD/empty" +printf 'a real review\n' > "$TMPD/review" +check "outage + no review -> fail the job" "0" \ + "$(backend_outage_should_fail 2 "$TMPD/empty"; echo $?)" +check "outage + a review -> do not fail" "1" \ + "$(backend_outage_should_fail 2 "$TMPD/review"; echo $?)" +check "no outage + no review -> not THIS guard's job" "1" \ + "$(backend_outage_should_fail 0 "$TMPD/empty"; echo $?)" + if [ "$fails" -ne 0 ]; then echo "$fails check(s) failed" >&2 exit 1 diff --git a/scripts/agy-review.sh b/scripts/agy-review.sh index 9b273dea..656e760a 100755 --- a/scripts/agy-review.sh +++ b/scripts/agy-review.sh @@ -17,7 +17,60 @@ set -euo pipefail # clamp, so log() must already exist. (Defined later, a clamp that fires would die with # `log: command not found` under set -e instead of warning — a latent misconfiguration trap.) log() { printf '[agy-review] %s\n' "$*" >&2; } + +# A capture that is only a BACKEND ERROR, not a review. When agy's upstream is down it prints +# something like: +# +# Error: Eligibility check failed: UNAVAILABLE (code 503): The service is currently unavailable. +# +# That text is non-empty, so have_text() alone treats it as a valid review, POSTs it as the +# review comment, and the job exits 0 -- a green check for a review that never happened. Observed +# on SLAC PR #14: the `review` check passed in 7 seconds with that string as its entire body, +# twice. A control that cannot fail is worse than no control. +# +# The match is deliberately ANCHORED to the start of the capture rather than being a substring +# search. A genuine review may legitimately quote a 503, an "UNAVAILABLE" constant, or an +# eligibility check while reviewing retry logic -- and aborting on that would be the +# false-positive the OAuth guard's design notes warn about. agy's backend failures occupy the +# WHOLE capture and begin with `Error:`, so requiring the error at the top, in a capture short +# enough to contain nothing else, separates the two without a content heuristic. +# +# Adopted FROM SLAC, which had it while the template and the other installs did not. +# >>> SELFTEST-EXTRACT: service-error guard +# `have_text` lives INSIDE this block, not above it: `backend_outage_should_fail` calls it, so +# an extracted block without it is not self-contained and the selftest cannot run it. It is a +# general helper used throughout the script -- the marker is a comment, so its position +# changes nothing about where the function is defined. have_text() { [ -s "$1" ] && grep -q '[^[:space:]]' "$1"; } +AGY_ERROR_RE='^[[:space:]]*Error:.*(Eligibility check failed|UNAVAILABLE|unavailable|RESOURCE_EXHAUSTED|INTERNAL|DEADLINE_EXCEEDED|code [45][0-9]{2})' +# Captures longer than this are assumed to be real reviews even if they open with an error line: +# a genuine review is thousands of bytes, a bare backend error is a couple of hundred. +AGY_ERROR_MAX_BYTES="${AGY_ERROR_MAX_BYTES:-2000}" +# `head -n 1`, not `head -n 5`. grep matches line-by-line, so scanning five lines +# means "any of the first five lines is an error line" -- which would discard a short, +# genuine review whose heading is on line 1 and which happens to discuss `Error: ... +# UNAVAILABLE` on line 3. That is the false positive the anchoring was supposed to +# prevent, reintroduced by the very check meant to enforce it. The invariant is that a +# backend failure IS the whole capture, so only the first line can carry it. +service_error_present() { + [ -s "$1" ] || return 1 + [ "$(wc -c < "$1")" -le "$AGY_ERROR_MAX_BYTES" ] || return 1 + head -n 1 "$1" | grep -qE "$AGY_ERROR_RE" +} + +# True when the run must FAIL rather than post: the backend errored at least once and no review +# survived. A separate named function rather than an inline condition, because a structural grep +# for the condition is too weak to notice it being disabled -- `if false && [ ... ]` still +# contains the text a grep looks for, and that mutation came back NOT CAUGHT. +# +# The `have_text` half is redundant today (the retry loop truncates the capture whenever it +# counts a backend error) and is kept deliberately: it makes the "post nothing" guarantee +# independent of that truncation surviving a future edit. +backend_outage_should_fail() { + [ "${1:-0}" -gt 0 ] || return 1 + ! have_text "$2" +} +# <<< SELFTEST-EXTRACT # Guarding against a leak of agy's interactive Google OAuth login flow. When agy's cached # session lapses on the runner, `--print` emits the login prompt (a live OAuth URL + "paste the # authorization code here") instead of a review; that text is non-empty, so have_text() alone @@ -44,6 +97,7 @@ have_text() { [ -s "$1" ] && grep -q '[^[:space:]]' "$1"; } # would miss a URL emitted as `.../o/oauth2?client_id=…` or bare `.../o/oauth2` (a leak). The # scheme is what keeps a review's bare-pattern quote from matching, so dropping the trailing # slash loses no safety. +# >>> SELFTEST-EXTRACT: oauth guard OAUTH_URL_RE='https?://accounts\.google\.com/o/oauth2' # The single guard, used at BOTH the retry-loop capture (Layer 1) and the assembled body before @@ -54,6 +108,7 @@ OAUTH_URL_RE='https?://accounts\.google\.com/o/oauth2' # URL is always present in a real login flow, so it alone is both necessary and sufficient; a # lapse is detected AND a leak is blocked by the same unconditional check. oauth_url_present() { [ -s "$1" ] && grep -qiE "$OAUTH_URL_RE" "$1"; } +# <<< SELFTEST-EXTRACT # --- configuration (all env-overridable from the workflow) --------------------- AGY_BIN="${AGY_BIN:-agy}" @@ -100,21 +155,33 @@ AGY_RETRIES="${AGY_RETRIES:-3}" # attempts to get a usable agy respon AGY_RETRY_DELAY="${AGY_RETRY_DELAY:-15}" # base backoff seconds between retries (grows per attempt) MARKER="" -# The jq program that picks which prior review comments to delete. Named, and exercised directly -# by `scripts/agy-review-selftest.sh`, because this filter has now been wrong TWICE in ways -# nothing observed: first the just-posted comment was not excluded (so it deleted itself), then -# jq's `--arg` was handed to `gh api`, which has no such flag (so the whole step died silently and -# stale comments accumulated). Both were invisible from the outside — the review still posted. +# The comment body's format -- sentinels plus the split/trim helpers -- lives in a sourceable +# file so `agy-review-selftest.sh` can test the REAL implementation rather than a copy of it. +# This script does its work at top level and so cannot itself be sourced. +# shellcheck source=scripts/_agy_comment_body.sh +. "$(dirname -- "${BASH_SOURCE[0]}")/_agy_comment_body.sh" + +MAX_BODY_BYTES="${MAX_BODY_BYTES:-60000}" + +# The jq program that finds THIS bot's existing review comment on the PR, so it can be edited +# rather than replaced. Named, and exercised directly by `scripts/agy-review-selftest.sh`, +# because its predecessor (which selected comments to DELETE) was wrong twice in ways nothing +# observed: first the just-posted comment was not excluded, so a run deleted its own review; +# then jq's `--arg` was handed to `gh api`, which has no such flag, so the step died silently. +# Both were invisible from the outside — the review still posted. # -# The two `select`s that matter: the AUTHOR filter (without it, any user could put the marker in a -# comment and have this bot delete arbitrary comments) and the ID exclusion (without it, the run -# deletes the comment it just published). -SELECT_STALE_JQ='.[] +# The AUTHOR filter is load-bearing, not cosmetic: without it, any user could put the marker +# (an HTML comment, invisible when rendered) in a PR comment and have this bot edit it. Only +# ever touch our own bot's comments. `first` picks the OLDEST match, so if duplicates exist +# from an older version of this script, the canonical thread is the one that keeps growing. +# >>> SELFTEST-EXTRACT: ours-comment filter +SELECT_OURS_JQ='[ .[] | select(.user.type == "Bot" and .user.login == "github-actions[bot]") - | select(.body | contains($marker)) - | select(.id != $new_id) - | .id' -readonly SELECT_STALE_JQ + | select(.body | contains($marker)) ] + | first + | .id // empty' +readonly SELECT_OURS_JQ +# <<< SELFTEST-EXTRACT REPO="${GITHUB_REPOSITORY:?GITHUB_REPOSITORY not set}" @@ -155,6 +222,9 @@ diff_file= diff_err= meta_file= prompt_file= out_file= raw= body_file= agy_diff_ # Set to 1 if agy printed its interactive OAuth login flow instead of a review (lapsed session); # gates the no-post abort below. Pre-declared so `${auth_failed:-0}` is set-u-safe on every path. auth_failed=0 +# Counts backend-error captures across attempts; see `service_error_present`. Pre-declared so +# `${service_errors:-0}` is set-u-safe even on paths that never enter the retry loop. +service_errors=0 # Set when the large-diff fallback below creates refs/agy/* so the trap can remove them. agy_refs_created= cleanup() { @@ -175,7 +245,7 @@ trap cleanup EXIT # but is NOT harmless now that isCrossRepository gates whether an untrusted diff # reaches agy: a lookup failure must never be indistinguishable from "same-repo". diff_file="$(mktemp)"; meta_file="$(mktemp)"; diff_err="$(mktemp)" -gh pr view "$PR" --repo "$REPO" --json title,isCrossRepository,baseRefName > "$meta_file" \ +gh pr view "$PR" --repo "$REPO" --json title,isCrossRepository,baseRefName,headRefOid > "$meta_file" \ || { log "gh pr view failed; refusing to review without knowing the PR's head repo"; exit 1; } # THE FORK GATE (see the trust model at the agy invocation below). The workflow `if:` @@ -221,13 +291,28 @@ esac # ($diff_err was allocated alongside $diff_file / $meta_file above, so the cleanup # trap never references it before it exists.) if ! gh pr diff "$PR" --repo "$REPO" > "$diff_file" 2>"$diff_err"; then - if grep -qi 'diff exceeded the maximum number of lines' "$diff_err"; then + # GitHub refuses an oversized diff TWO ways, with different wording: over + # 20,000 lines, and over 300 FILES. Both are HTTP 406 and both mean the same + # thing here -- the PR is too big for the API, not that anything went wrong -- + # so both must reach the local fallback. Matching only the `lines` variant made + # a wide-but-shallow PR -- hundreds of files, well under the line limit, as a + # bulk regeneration of test baselines produces -- fail the review outright + # instead of falling back. + if grep -qiE 'diff exceeded the maximum number of (lines|files)' "$diff_err"; then base_ref="$(jq -r '.baseRefName // empty' "$meta_file")" if [ -z "$base_ref" ] || [ "$base_ref" = "null" ]; then log "diff exceeds the API limit and the base branch is unknown; cannot fall back" exit 1 fi - log "diff exceeds GitHub's 20,000-line API limit; falling back to a local git diff" + # Name the limit that actually fired. Reporting "20,000-line" for a + # file-count refusal is the same class of misleading triage signal that + # made this bug look like a runner auth failure in the first place. + if grep -qi 'maximum number of files' "$diff_err"; then + hit="300-file" + else + hit="20,000-line" + fi + log "diff exceeds GitHub's ${hit} API limit; falling back to a local git diff" pr_ref="refs/agy/pr-${PR}" base_local="refs/agy/base-${PR}" agy_refs_created=1 @@ -245,8 +330,39 @@ if ! gh pr diff "$PR" --repo "$REPO" > "$diff_file" 2>"$diff_err"; then log "could not fetch PR #${PR} refs for the local diff fallback" exit 1 fi - merge_base="$(git merge-base "$base_local" "$pr_ref")" || { - log "could not compute the merge base for PR #${PR}"; exit 1; } + # The workflow clones with `fetch-depth: 1`, so the two refs above arrive as + # DISCONNECTED shallow histories -- there is no common ancestor for + # `git merge-base` to find, and it fails even though both refs fetched fine. + # (A full local clone hides this completely, which is how it got missed.) + # + # Ask the API for the merge base and fetch that one commit, rather than + # unshallowing: a repo with a large history would pay a full clone on a path + # that only exists because the PR is already unusually big. Diffing two + # commits needs both trees, not the history between them, so a shallow fetch + # of the merge base is enough. + merge_base="$(git merge-base "$base_local" "$pr_ref" 2>/dev/null || true)" + if [ -z "$merge_base" ]; then + head_sha="$(jq -r '.headRefOid // empty' "$meta_file")" + # Percent-encode the branch name for the URL path. NOT for the `/` in a + # `/` branch -- GitHub's compare endpoint accepts those + # raw, verified against a real slashed branch, returning the same SHA + # either way. It is for `%` and `#`, which git permits in a ref name and + # which a URL does not survive: `%` starts an escape and `#` truncates the + # path at the fragment. Both would fail silently into the `|| true`. + base_enc="$(jq -rn --arg v "$base_ref" '$v|@uri')" + api_base="$(gh api "repos/${REPO}/compare/${base_enc}...${head_sha}" \ + --jq '.merge_base_commit.sha' 2>/dev/null || true)" + if [ -n "$api_base" ] && [ "$api_base" != "null" ]; then + if git fetch --no-tags --quiet origin "$api_base" 2>/dev/null \ + || git fetch --no-tags --quiet --deepen=250 origin "${fetch_refspecs[@]}" 2>/dev/null; then + merge_base="$(git merge-base "$base_local" "$pr_ref" 2>/dev/null || echo "$api_base")" + log "shallow clone: merge base ${merge_base} resolved via the compare API" + fi + fi + fi + if [ -z "$merge_base" ]; then + log "could not compute the merge base for PR #${PR}"; exit 1 + fi git diff "$merge_base" "$pr_ref" > "$diff_file" || { log "local git diff failed for PR #${PR}"; exit 1; } log "local diff: $(wc -l < "$diff_file") lines, $(wc -c < "$diff_file") bytes" @@ -498,6 +614,21 @@ for (( attempt=1; attempt<=AGY_RETRIES; attempt++ )); do # reading it would post that session's output into a public PR comment (data # leak). The PTY path above plus the retry loop cover agy issue #76 without it. + # A backend error is TRANSIENT, so it retries like empty output rather than aborting the way a + # lapsed session does -- but it must never be mistaken for a review. Blank the capture so no + # later path can post it, and let the loop try again. + # + # A COUNTER, not a per-attempt flag. A boolean reset each attempt reflects only the last one, + # so a 503 on attempt 1 followed by empty output on attempt 3 would report the generic "no + # output" cause, and the reverse would claim the backend was down on every attempt when it was + # down on one. Both exit non-zero, so nothing unsafe -- but the log line is the only thing + # telling a human which outage they are looking at. + if service_error_present "$out_file"; then + log "agy returned a backend error rather than a review (attempt ${attempt}/${AGY_RETRIES}): $(head -n 1 "$out_file")" + : > "$out_file" + service_errors=$(( ${service_errors:-0} + 1 )) + fi + have_text "$out_file" && break if [ "$attempt" -lt "$AGY_RETRIES" ]; then delay=$(( AGY_RETRY_DELAY * attempt )) @@ -515,6 +646,17 @@ if [ "${auth_failed:-0}" = "1" ]; then exit 1 fi +# A persistent backend failure is reported as its own cause, and it FAILS THE JOB. Posting the +# error as a review comment (the previous behavior) produced a passing check for a review that +# never ran; posting nothing and exiting non-zero makes the outage visible where it matters. +# The `! have_text` is redundant today -- the loop truncates $out_file whenever it counts a +# backend error -- and is kept deliberately: it makes the "post nothing" guarantee independent +# of that truncation surviving a future edit. +if backend_outage_should_fail "${service_errors:-0}" "$out_file"; then + log "agy's backend returned an error on ${service_errors} of ${AGY_RETRIES} attempt(s) and no review was produced. Failing the check rather than posting the error as a review. Re-run with '/agy-review' once the service recovers." + exit 1 +fi + if ! have_text "$out_file"; then log "no review output after ${AGY_RETRIES} attempt(s). Check $LOG and confirm 'agy -p \"hi\"' works for this user." # Surface agy's stderr into the job log. RUNNER_TEMP is wiped between jobs, so a bare @@ -554,65 +696,102 @@ if oauth_url_present "$body_file"; then exit 1 fi -# --- post fresh, THEN replace any prior review comment -------------------------- -# Publish-before-delete, deliberately: if this ordering were reversed and posting failed -# afterward (a transient gh/API error), the PR would be left with NO review comment at all -# instead of the still-valid prior one. Posting first means a failure here can only ever -# leave a harmless duplicate, never a silent loss of the last review. -# The posted comment's id comes from the POST itself, not from a read-back. `gh pr comment` -# prints the new comment's URL, whose trailing `#issuecomment-` is authoritative the instant -# it returns. Re-querying the comment list to find "the newest one with our marker" raced with -# GitHub's own read replication: right after posting, the list can still omit it, and then the -# exclusion below matched nothing and the script deleted the comment it had just published -- -# turning publish-before-delete into publish-then-destroy, the exact failure the ordering exists -# to prevent. +# --- edit our existing comment, appending the previous round to its archive ------ +# One comment per PR, edited in place: newest round on top, earlier rounds folded into a +# collapsed `
` below. NOTHING IS DELETED. The previous design posted fresh and +# deleted the prior comment, which kept the PR tidy at the cost of destroying any round +# nobody had read yet — and left no evidence a round had happened at all. +# +# Fail-closed in the direction that matters: every step below falls back to a plain POST of +# the new review. A duplicate comment is noise; failing to publish a review, or losing one, is +# not. The lookup happens BEFORE the post so a PATCH is possible at all, but a failed lookup +# costs only the archive, never the review. +prior_id="" +prior_body_file="$(mktemp)" +if prior_json="$(gh api "repos/${REPO}/issues/${PR}/comments" --paginate 2>/dev/null)"; then + prior_id="$(printf '%s' "$prior_json" | jq -r --arg marker "$MARKER" "$SELECT_OURS_JQ" 2>/dev/null || true)" + if [ -n "$prior_id" ] && [ "$prior_id" != "null" ]; then + printf '%s' "$prior_json" \ + | jq -r --argjson id "$prior_id" '.[] | select(.id == $id) | .body' > "$prior_body_file" 2>/dev/null \ + || : > "$prior_body_file" + else + prior_id="" + fi +else + log "warning: could not list PR comments; posting a fresh review without the archive" +fi + +if [ -n "$prior_id" ] && [ -s "$prior_body_file" ]; then + # Split the prior body into its newest round (everything after the marker, before the + # archive) and the archive's existing inner rounds. `awk` rather than `sed`, because the + # sentinels must match whole lines and a review body legitimately contains regex + # metacharacters, backslashes and HTML. + prior_head="$(agy_body_head "$MARKER" < "$prior_body_file")" + prior_archive="$(agy_body_archive < "$prior_body_file")" + + archived_file="$(mktemp)" + { + printf '%s\n' "$AGY_ROUND_MARK" + printf '
\nRound reviewed at %s\n\n' \ + "$(date -u +'%Y-%m-%d %H:%M UTC')" + printf '%s\n' "$prior_head" + printf '\n
\n' + printf '%s\n' "$prior_archive" + } > "$archived_file" + + # Drop the oldest rounds until the whole comment fits, and SAY SO. A silent truncation + # here would look identical to "there were never any earlier rounds", which is the exact + # confusion this whole change exists to remove. + dropped=0 + while :; do + combined_size=$(( $(wc -c < "$body_file") + $(wc -c < "$archived_file") + 200 )) + [ "$combined_size" -le "$MAX_BODY_BYTES" ] && break + # Remove the LAST `
` block (the oldest round) from the archive. + trimmed="$(mktemp)" + agy_drop_oldest_round < "$archived_file" > "$trimmed" || { rm -f "$trimmed"; break; } + mv "$trimmed" "$archived_file" + dropped=$(( dropped + 1 )) + done + + { + printf '\n%s\n' "$AGY_ARCHIVE_START" + if [ "$dropped" -gt 0 ]; then + printf '%d earlier round(s) dropped to stay under GitHub'"'"'s comment size limit.\n\n' "$dropped" + fi + printf '
\nEarlier review rounds (newest first)\n\n' + cat "$archived_file" + printf '\n
\n' + printf '%s\n' "$AGY_ARCHIVE_END" + } >> "$body_file" + rm -f "$archived_file" + + # Re-run the OAuth guard on the ASSEMBLED body. The archive is text this script published + # earlier and so has already passed the guard once, but the body is what gets published now + # and the guard's contract is that it runs on exactly that. + if oauth_url_present "$body_file"; then + log "refusing to post: the assembled comment body contains a live OAuth authorization URL." + exit 1 + fi + + # The body goes through STDIN as JSON, never through argv. At `MAX_BODY_BYTES` + # the comment can approach 60 KB, and a single execve argument is capped at + # `MAX_ARG_STRLEN` (128 KB on Linux) -- close enough that a future raise of that + # bound would start failing with E2BIG, and the failure would look like a + # GitHub error rather than a local limit. `--rawfile` also makes the value a + # JSON string by construction, so no shell quoting or `-F` type-coercion can + # reinterpret a body that happens to look like a number or a boolean. + if jq -n --rawfile b "$body_file" '{body: $b}' \ + | gh api -X PATCH "repos/${REPO}/issues/comments/${prior_id}" --input - >/dev/null 2>&1; then + log "updated review comment ${prior_id} on ${REPO}#${PR} (earlier rounds archived in place)" + rm -f "$prior_body_file" + exit 0 + fi + log "warning: could not edit comment ${prior_id}; posting a fresh review instead" +fi +rm -f "$prior_body_file" + if ! post_output="$(gh pr comment "$PR" --repo "$REPO" --body-file "$body_file" 2>&1)"; then - # Nothing is deleted when the post fails: the prior review comment is still the best - # information the PR has, and removing it would leave no review at all. log "failed to post review to ${REPO}#${PR}: ${post_output}" exit 1 fi log "posted review to ${REPO}#${PR}" -new_comment_id="$(printf '%s\n' "$post_output" | sed -n 's/.*#issuecomment-\([0-9][0-9]*\).*/\1/p' | tail -n 1)" - -# A failed delete is logged, not swallowed: silently ignoring it would let a transient API/perms -# error leave the old comment in place alongside the new one, so runs accumulate duplicates. -# The author filter is load-bearing, not cosmetic: without it, ANY user could put the -# marker (an HTML comment) in a PR comment and have this bot delete arbitrary comments on -# the next run. Only ever delete OUR OWN bot's prior review comments -- and only ones from -# BEFORE this run (the just-posted comment's own id is excluded so it can never delete itself). -if [ -z "$new_comment_id" ]; then - # FAIL CLOSED. Without a known id there is no way to tell the new comment from the old ones, - # and the safe direction is unambiguous: a leftover duplicate is noise, deleting the review - # that was just posted is data loss. - log "warning: could not determine the posted comment id; leaving prior review comments in place" -else - # `--arg`/`--argjson` rather than shell interpolation into the filter: the marker is an HTML - # comment today, but a quote or a backslash in it would otherwise break the jq program itself - # rather than simply not matching. - # - # Those are JQ flags, so the JSON is fetched raw and piped into a real `jq` — `gh api` has no - # `--arg`/`--argjson` of its own and rejects them. Handing them to `gh api --jq` made it exit - # non-zero on every run; with the old `2>/dev/null` swallowing the message and `set -o pipefail` - # in force, the script then died *after* posting, so the stale comments were never deleted and - # the job went red for a reason nothing printed. stderr is kept this time for exactly that - # reason. (`--paginate` without `--jq` emits one JSON array per page; `jq` reads that stream - # fine, applying `.[]` to each.) - stale_ids="$( - gh api "repos/${REPO}/issues/${PR}/comments" --paginate \ - | jq -r --arg marker "$MARKER" --argjson new_id "$new_comment_id" "$SELECT_STALE_JQ" - )" || { - log "warning: could not list prior review comments; leaving them in place" - stale_ids="" - } - while read -r cid; do - [ -n "$cid" ] || continue - if ! gh api -X DELETE "repos/${REPO}/issues/comments/${cid}" >/dev/null 2>&1; then - log "warning: could not delete prior review comment ${cid}; a duplicate may result" - fi - done <<< "$stale_ids" -fi - -# The delete loop above is the last real work; end on a defined status so a stray non-zero from -# it can never be mistaken for "the review failed" once the comment is already published. -exit 0