diff --git a/.github/workflows/g-fe-certification.yml b/.github/workflows/g-fe-certification.yml new file mode 100644 index 000000000..6a271c34e --- /dev/null +++ b/.github/workflows/g-fe-certification.yml @@ -0,0 +1,236 @@ +name: G-FE certification +on: + push: + branches: ['fix/2817-tauri-keyboard-deadlock'] +permissions: + contents: read +concurrency: + group: g-fe-certification-${{ github.ref }} + cancel-in-progress: false +jobs: + g-fe: + name: g-fe + runs-on: ubuntu-latest + timeout-minutes: 60 + defaults: + run: + shell: bash + env: + EV_SUBDIR: g-fe-evidence + steps: + - uses: actions/checkout@v5 + - name: Identity and pre-state, asserted + run: | + EV="$RUNNER_TEMP/$EV_SUBDIR"; mkdir -p "$EV" + { + echo "githubSha=$GITHUB_SHA" + echo "headSha=$(git rev-parse HEAD)" + echo "treeId=$(git rev-parse 'HEAD^{tree}')" + echo "branch=$(git rev-parse --abbrev-ref HEAD)" + echo "runId=$GITHUB_RUN_ID attempt=$GITHUB_RUN_ATTEMPT" + } | tee "$EV/0-identity.log" + sha256sum .github/workflows/g-fe-certification.yml | tee -a "$EV/0-identity.log" + git status --porcelain | tee "$EV/0-porcelain-before.log" + test "$(git rev-parse HEAD)" = "$GITHUB_SHA" + test ! -s "$EV/0-porcelain-before.log" + - uses: actions/setup-node@v5 + with: + node-version: 24.13.0 + - name: Pin npm and record the toolchain, asserted + timeout-minutes: 5 + run: | + EV="$RUNNER_TEMP/$EV_SUBDIR" + npm install -g npm@11.6.2 --ignore-scripts + { node --version; npm --version; } | tee "$EV/0-toolchain.log" + test "$(node --version)" = "v24.13.0" + test "$(npm --version)" = "11.6.2" + - name: 1 npm ci + timeout-minutes: 10 + run: | + EV="$RUNNER_TEMP/$EV_SUBDIR"; L="$EV/1-npm-ci.log"; set +e + npm ci --ignore-scripts 2>&1 | tee "$L" + st=("${PIPESTATUS[@]}") + if [ -s "$L" ]; then + last="$(tail -c 1 "$L")"; tl=$? + if [ "$tl" -ne 0 ]; then + echo "reportingFailure cmd=1 tailExit=$tl commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + if [ -n "$last" ]; then + printf '\n' >> "$L"; nl=$? + if [ "$nl" -ne 0 ]; then + echo "reportingFailure cmd=1 newlineExit=$nl commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + fi + fi + printf 'status cmd=1 commandExit=%s loggerExit=%s run=%s attempt=%s sha=%s\n' \ + "${st[0]}" "${st[1]}" "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" "$GITHUB_SHA" >> "$L" + ap=$? + if [ "$ap" -ne 0 ]; then + echo "reportingFailure cmd=1 appendExit=$ap commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + [ "${st[0]}" -eq 0 ] && [ "${st[1]}" -eq 0 ] + - name: 2 typecheck + timeout-minutes: 5 + run: | + EV="$RUNNER_TEMP/$EV_SUBDIR"; L="$EV/2-typecheck.log"; set +e + npm run typecheck 2>&1 | tee "$L" + st=("${PIPESTATUS[@]}") + if [ -s "$L" ]; then + last="$(tail -c 1 "$L")"; tl=$? + if [ "$tl" -ne 0 ]; then + echo "reportingFailure cmd=2 tailExit=$tl commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + if [ -n "$last" ]; then + printf '\n' >> "$L"; nl=$? + if [ "$nl" -ne 0 ]; then + echo "reportingFailure cmd=2 newlineExit=$nl commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + fi + fi + printf 'status cmd=2 commandExit=%s loggerExit=%s run=%s attempt=%s sha=%s\n' \ + "${st[0]}" "${st[1]}" "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" "$GITHUB_SHA" >> "$L" + ap=$? + if [ "$ap" -ne 0 ]; then + echo "reportingFailure cmd=2 appendExit=$ap commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + [ "${st[0]}" -eq 0 ] && [ "${st[1]}" -eq 0 ] + - name: 3 npm test, strict and serial + timeout-minutes: 20 + run: | + EV="$RUNNER_TEMP/$EV_SUBDIR"; L="$EV/3-npm-test.log"; set +e + npm test -- --maxWorkers=1 2>&1 | tee "$L" + st=("${PIPESTATUS[@]}") + if [ -s "$L" ]; then + last="$(tail -c 1 "$L")"; tl=$? + if [ "$tl" -ne 0 ]; then + echo "reportingFailure cmd=3 tailExit=$tl commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + if [ -n "$last" ]; then + printf '\n' >> "$L"; nl=$? + if [ "$nl" -ne 0 ]; then + echo "reportingFailure cmd=3 newlineExit=$nl commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + fi + fi + printf 'status cmd=3 commandExit=%s loggerExit=%s run=%s attempt=%s sha=%s\n' \ + "${st[0]}" "${st[1]}" "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" "$GITHUB_SHA" >> "$L" + ap=$? + if [ "$ap" -ne 0 ]; then + echo "reportingFailure cmd=3 appendExit=$ap commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + [ "${st[0]}" -eq 0 ] && [ "${st[1]}" -eq 0 ] + - name: 4 check frontend dependencies + timeout-minutes: 5 + run: | + EV="$RUNNER_TEMP/$EV_SUBDIR"; L="$EV/4-fe-deps.log"; set +e + npm run check:frontend-dependencies 2>&1 | tee "$L" + st=("${PIPESTATUS[@]}") + if [ -s "$L" ]; then + last="$(tail -c 1 "$L")"; tl=$? + if [ "$tl" -ne 0 ]; then + echo "reportingFailure cmd=4 tailExit=$tl commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + if [ -n "$last" ]; then + printf '\n' >> "$L"; nl=$? + if [ "$nl" -ne 0 ]; then + echo "reportingFailure cmd=4 newlineExit=$nl commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + fi + fi + printf 'status cmd=4 commandExit=%s loggerExit=%s run=%s attempt=%s sha=%s\n' \ + "${st[0]}" "${st[1]}" "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" "$GITHUB_SHA" >> "$L" + ap=$? + if [ "$ap" -ne 0 ]; then + echo "reportingFailure cmd=4 appendExit=$ap commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + [ "${st[0]}" -eq 0 ] && [ "${st[1]}" -eq 0 ] + - name: 5 installed API version, recorded and asserted + timeout-minutes: 2 + run: | + EV="$RUNNER_TEMP/$EV_SUBDIR"; L="$EV/5-api-version.log"; set +e + node -p "require('@tauri-apps/api/package.json').version" 2>&1 | tee "$L" + st=("${PIPESTATUS[@]}") + v="$(node -p "require('@tauri-apps/api/package.json').version" 2>>"$L")"; vr=$? + if [ -s "$L" ]; then + last="$(tail -c 1 "$L")"; tl=$? + if [ "$tl" -ne 0 ]; then + echo "reportingFailure cmd=5 tailExit=$tl commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + if [ -n "$last" ]; then + printf '\n' >> "$L"; nl=$? + if [ "$nl" -ne 0 ]; then + echo "reportingFailure cmd=5 newlineExit=$nl commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + fi + fi + printf 'status cmd=5 commandExit=%s loggerExit=%s consumedExit=%s stdoutVersion=%s run=%s attempt=%s sha=%s\n' \ + "${st[0]}" "${st[1]}" "$vr" "$v" "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" "$GITHUB_SHA" >> "$L" + ap=$? + if [ "$ap" -ne 0 ]; then + echo "reportingFailure cmd=5 appendExit=$ap commandExit=${st[0]} loggerExit=${st[1]}" >&2 + exit 1 + fi + [ "${st[0]}" -eq 0 ] && [ "${st[1]}" -eq 0 ] && [ "$vr" -eq 0 ] && [ "$v" = "2.12.1" ] + - name: Post-state, asserted + timeout-minutes: 2 + run: | + EV="$RUNNER_TEMP/$EV_SUBDIR" + git status --porcelain | tee "$EV/6-porcelain-after.log" + test ! -s "$EV/6-porcelain-after.log" + - name: Completion record, every write propagates its failure + if: always() + run: | + EV="$RUNNER_TEMP/$EV_SUBDIR"; I="$EV/0-identity.log"; set +e + mkdir -p "$EV"; mk=$? + if [ "$mk" -ne 0 ]; then echo "reportingFailure step=completion mkdirExit=$mk" >&2; exit 1; fi + rc=0 + emit() { printf '%s\n' "$1" >> "$I" || rc=1; } + names=(1-npm-ci 2-typecheck 3-npm-test 4-fe-deps 5-api-version) + emit "completion run=$GITHUB_RUN_ID attempt=$GITHUB_RUN_ATTEMPT sha=$GITHUB_SHA" + for i in 1 2 3 4 5; do + f="$EV/${names[$((i-1))]}.log" + if [ ! -f "$f" ]; then + emit "cmd=$i evidence=absent history=unknown" + continue + fi + grep -q "^status cmd=$i " "$f"; g=$? + if [ "$g" -eq 0 ]; then + emit "cmd=$i evidence=present status=recorded" + elif [ "$g" -eq 1 ]; then + emit "cmd=$i evidence=present status=absent history=unknown" + else + emit "cmd=$i evidence=present readError=true grepExit=$g history=unknown" + rc=1 + fi + done + if [ -f "$EV/6-porcelain-after.log" ]; then + emit "postState=evidencePresent" + else + emit "postState=evidenceAbsent history=unknown" + fi + if [ "$rc" -ne 0 ]; then echo "reportingFailure step=completion rc=$rc" >&2; exit 1; fi + - name: Digests of the owned evidence set + if: always() + run: | + cd "$RUNNER_TEMP/$EV_SUBDIR" && sha256sum ./*.log | tee ./digests.txt + - name: Upload the owned evidence set + if: always() + uses: actions/upload-artifact@v7 + with: + name: g-fe-evidence-${{ github.sha }} + path: ${{ runner.temp }}/g-fe-evidence/ + if-no-files-found: error diff --git a/Cargo.lock b/Cargo.lock index 8327572f1..22ce9ee35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,7 +17,7 @@ dependencies = [ "chrono", "clap", "croner", - "dirs", + "dirs 6.0.0", "env_logger", "futures", "futures-util", @@ -39,6 +39,7 @@ dependencies = [ "serde_yaml", "sha2", "syn 2.0.117", + "tao", "tauri", "tauri-build", "tauri-plugin-clipboard-manager", @@ -99,15 +100,15 @@ dependencies = [ [[package]] name = "alloc-no-stdlib" -version = "2.0.4" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" +checksum = "c2fb6cfd47bf496ff64095c20eaba0c201404ee38714d4142fcfa1dc334fcc7a" [[package]] name = "alloc-stdlib" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +checksum = "0b5c1865780388bfa186411ab5f247819487fc4864c6e9c3106611fa347586e1" dependencies = [ "alloc-no-stdlib", ] @@ -657,9 +658,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.2" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "f8b851b75c23ca7873623d612fe49bd1989aeb03d08fb9432187eb253d3d4c6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -668,9 +669,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "941cd9bd4ddab83cb46fa5a2d428f1c857b24ac78cb876cf7beb710840934bd7" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -788,12 +789,13 @@ dependencies = [ [[package]] name = "cargo_toml" -version = "0.22.3" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +checksum = "82f4b26e751e711a5302649417f2da046dce6391b2ea30a4820f37462314f0b9" dependencies = [ + "semver", "serde", - "toml 0.9.12+spec-1.1.0", + "toml 1.1.2+spec-1.1.0", ] [[package]] @@ -825,13 +827,13 @@ dependencies = [ [[package]] name = "cfb" -version = "0.7.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +checksum = "a347dcabdae9c31b0825fd6a8bed285ec9c2acb89c47827126d52fa4f59cece3" dependencies = [ - "byteorder", "fnv", "uuid", + "web-time", ] [[package]] @@ -877,7 +879,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -1137,7 +1139,7 @@ version = "0.29.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" dependencies = [ - "cssparser-macros", + "cssparser-macros 0.6.1", "dtoa-short", "itoa", "matches", @@ -1150,11 +1152,11 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98" dependencies = [ - "cssparser-macros", + "cssparser-macros 0.7.1", "dtoa-short", "itoa", "phf 0.13.1", @@ -1172,15 +1174,21 @@ dependencies = [ ] [[package]] -name = "ctor" -version = "0.2.9" +name = "cssparser-macros" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +checksum = "d045de693cb712d0b22c6a64be5b953f67b3ce00ab5ad3dd5d8b441886ab8e1a" dependencies = [ "quote", "syn 2.0.117", ] +[[package]] +name = "ctor" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914a755b7c2d4af2bdcff7ce1739e2db9a1b81a9b07123d8015786ae03c0980d" + [[package]] name = "darling" version = "0.20.11" @@ -1256,6 +1264,17 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +[[package]] +name = "dbus" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + [[package]] name = "deranged" version = "0.5.8" @@ -1350,6 +1369,15 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-sys" version = "0.5.0" @@ -1419,16 +1447,16 @@ dependencies = [ [[package]] name = "dom_query" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" +checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc" dependencies = [ "bit-set", - "cssparser 0.36.0", + "cssparser 0.37.0", "foldhash 0.2.0", - "html5ever 0.38.0", + "html5ever 0.39.0", "precomputed-hash", - "selectors 0.36.1", + "selectors 0.38.0", "tendril 0.5.0", ] @@ -2108,7 +2136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ "rustix 1.1.4", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -2280,7 +2308,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c386b0a4a70cb2d39fffd74480f985b6f0bfbcb934b6a6b6b7e630e448f242e" dependencies = [ "crossbeam-channel", - "keyboard-types", + "keyboard-types 0.7.0", "objc2", "objc2-app-kit", "once_cell", @@ -2461,12 +2489,12 @@ dependencies = [ [[package]] name = "html5ever" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" +checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" dependencies = [ "log", - "markup5ever 0.38.0", + "markup5ever 0.39.0", ] [[package]] @@ -2611,7 +2639,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -2823,9 +2851,9 @@ dependencies = [ [[package]] name = "infer" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +checksum = "f4200d433cbd5178df7797c9c2e75b348b728e39631cf14520d1e2fc424201f4" dependencies = [ "cfb", ] @@ -3030,21 +3058,21 @@ dependencies = [ [[package]] name = "json-patch" -version = "3.0.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" dependencies = [ "jsonptr", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] name = "jsonptr" -version = "0.6.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" dependencies = [ "serde", "serde_json", @@ -3061,6 +3089,16 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "keyboard-types" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d" +dependencies = [ + "bitflags 2.11.0", + "serde", +] + [[package]] name = "khronos-egl" version = "6.0.0" @@ -3137,6 +3175,15 @@ version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + [[package]] name = "libfuzzer-sys" version = "0.4.13" @@ -3164,7 +3211,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -3306,9 +3353,9 @@ dependencies = [ [[package]] name = "markup5ever" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" +checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" dependencies = [ "log", "tendril 0.5.0", @@ -3436,23 +3483,23 @@ dependencies = [ [[package]] name = "muda" -version = "0.17.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9fec5a4e89860383d778d10563a605838f8f0b2f9303868937e5ff32e86177" +checksum = "cca139e57da4383727f189e43e66e84fa372347027fc996f9f1a007ec0a37996" dependencies = [ "crossbeam-channel", "dpi", "gtk", - "keyboard-types", + "keyboard-types 0.8.3", "objc2", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation", "once_cell", - "png 0.17.16", + "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3798,6 +3845,16 @@ dependencies = [ "objc2-foundation", ] +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + [[package]] name = "objc2-core-media" version = "0.3.2" @@ -3933,8 +3990,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ "bitflags 2.11.0", + "block2", "objc2", + "objc2-cloud-kit", + "objc2-core-data", "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", "objc2-foundation", ] @@ -4096,7 +4172,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -4160,7 +4236,6 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_macros 0.11.3", "phf_shared 0.11.3", ] @@ -4259,19 +4334,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "phf_macros" version = "0.13.1" @@ -5326,12 +5388,12 @@ dependencies = [ [[package]] name = "selectors" -version = "0.36.1" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" +checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d" dependencies = [ "bitflags 2.11.0", - "cssparser 0.36.0", + "cssparser 0.37.0", "derive_more 2.1.1", "log", "new_debug_unreachable", @@ -5345,9 +5407,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" dependencies = [ "serde", "serde_core", @@ -5859,9 +5921,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "swift-rs" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +checksum = "e45c444e496845d3f2a351146bff59aae4975b2280238df1dfaa0c7d1846f38e" dependencies = [ "base64 0.21.7", "serde", @@ -5959,15 +6021,16 @@ dependencies = [ [[package]] name = "tao" -version = "0.34.8" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9103edf55f2da3c82aea4c7fab7c4241032bfeea0e71fa557d98e00e7ce7cc20" +checksum = "f37f381f4e048e6cdf038b5705f8cf14ad108279d46eb968140a7b291aba9400" dependencies = [ "bitflags 2.11.0", "block2", "core-foundation 0.10.1", "core-graphics", "crossbeam-channel", + "dbus", "dispatch2", "dlopen2", "dpi", @@ -5983,23 +6046,24 @@ dependencies = [ "objc2", "objc2-app-kit", "objc2-foundation", - "once_cell", + "objc2-ui-kit", "parking_lot", + "percent-encoding", "raw-window-handle", "tao-macros", "unicode-segmentation", "url", - "windows 0.61.3", - "windows-core 0.61.2", + "windows", + "windows-core", "windows-version", "x11-dl", ] [[package]] name = "tao-macros" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +checksum = "5f7eeb6d99155545da6150a1795945f16ac9c178deb2a5f2e74d776107bd5849" dependencies = [ "proc-macro2", "quote", @@ -6020,14 +6084,14 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] name = "tauri" -version = "2.10.3" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da77cc00fb9028caf5b5d4650f75e31f1ef3693459dfca7f7e506d1ecef0ba2d" +checksum = "ed99ee9694a2deb776d91cae48ac7411ddfc89ecae2f9b5041111d8c88f2ace9" dependencies = [ "anyhow", "bytes", "cookie", - "dirs", + "dirs 7.0.0", "dunce", "embed_plist", "getrandom 0.3.4", @@ -6067,18 +6131,18 @@ dependencies = [ "webkit2gtk", "webview2-com", "window-vibrancy", - "windows 0.61.3", + "windows", ] [[package]] name = "tauri-build" -version = "2.5.6" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bbc990d1dbf57a8e1c7fa2327f2a614d8b757805603c1b9ba5c81bade09fd4d" +checksum = "59563ca5b331fd97f27ee9672ec8d36d33bb3c9e2c9f6710a1a5687256052e45" dependencies = [ "anyhow", "cargo_toml", - "dirs", + "dirs 7.0.0", "glob", "heck 0.5.0", "json-patch", @@ -6088,22 +6152,21 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml 0.9.12+spec-1.1.0", "walkdir", ] [[package]] name = "tauri-codegen" -version = "2.5.5" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a24476afd977c5d5d169f72425868613d82747916dd29e0a357c84c4bd6d29" +checksum = "e50213e463086ecc283d7e9f51c30cc0fd304ad457425158018be26dbf0d0a80" dependencies = [ "base64 0.22.1", "brotli", "ico", "json-patch", "plist", - "png 0.17.16", + "png 0.18.1", "proc-macro2", "quote", "semver", @@ -6121,9 +6184,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.5.5" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39b349a98dadaffebb73f0a40dcd1f23c999211e5a2e744403db384d0c33de7" +checksum = "8129fb43bb6e0d6b73ad3315cd172beaab17cd28899c594b1b32c80edbbfd99c" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -6222,9 +6285,9 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.10.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2826d79a3297ed08cd6ea7f412644ef58e32969504bc4fbd8d7dbeabc4445ea2" +checksum = "c2a57a2a9b8c8b7fc00d35b510fe808ded7f9f1b44fc1cdda6aee38632ea5413" dependencies = [ "cookie", "dpi", @@ -6242,14 +6305,14 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows 0.61.3", + "windows", ] [[package]] name = "tauri-runtime-wry" -version = "2.10.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11ea2e6f801d275fdd890d6c9603736012742a1c33b96d0db788c9cdebf7f9e" +checksum = "7f9e7e0c9f80a5130773cfabb6df4dc924518fb1b2c923726966804634b57d22" dependencies = [ "gtk", "http", @@ -6267,20 +6330,21 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows 0.61.3", + "windows", "wry", ] [[package]] name = "tauri-utils" -version = "2.8.3" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219a1f983a2af3653f75b5747f76733b0da7ff03069c7a41901a5eb3ace4557d" +checksum = "2ff55a614843b9a3f010f211df637c94df2607175b8d0f6e0f4a7c19e18621ee" dependencies = [ "anyhow", "brotli", "cargo_metadata", "ctor", + "dom_query", "dunce", "glob", "html5ever 0.29.1", @@ -6290,7 +6354,8 @@ dependencies = [ "kuchikiki", "log", "memchr", - "phf 0.11.3", + "phf 0.13.1", + "plist", "proc-macro2", "quote", "regex", @@ -6302,7 +6367,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror 2.0.18", - "toml 0.9.12+spec-1.1.0", + "toml 1.1.2+spec-1.1.0", "url", "urlpattern", "uuid", @@ -6778,12 +6843,12 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.21.3" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c" +checksum = "b2b9c52859a94554803ccd4a24b98f74148ebc73b90676d783f3490b1bff9d72" dependencies = [ "crossbeam-channel", - "dirs", + "dirs 7.0.0", "libappindicator", "muda", "objc2", @@ -6792,10 +6857,10 @@ dependencies = [ "objc2-core-graphics", "objc2-foundation", "once_cell", - "png 0.17.16", + "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -6862,47 +6927,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-ucd-ident" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - [[package]] name = "unicase" version = "2.9.0" @@ -6972,13 +6996,13 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "urlpattern" -version = "0.3.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +checksum = "df16f50ef4cc145211879a3867ba757076b25dfee812040dcb0658bd9ae7904b" dependencies = [ + "icu_properties", "regex", "serde", - "unic-ucd-ident", "url", ] @@ -7343,6 +7367,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "web_atoms" version = "0.2.3" @@ -7401,16 +7435,14 @@ dependencies = [ [[package]] name = "webview2-com" -version = "0.38.2" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +checksum = "3f89fca7a704cee10dcb3654c1dbb8941d1783132f1917358af75bec37a7d7e6" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-implement", - "windows-interface", + "windows", + "windows-core", ] [[package]] @@ -7426,13 +7458,13 @@ dependencies = [ [[package]] name = "webview2-com-sys" -version = "0.38.2" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" +checksum = "b3a07132775117d6065853d9d1178157b8c90e228de47129d6bce2c7edebedfb" dependencies = [ "thiserror 2.0.18", - "windows 0.61.3", - "windows-core 0.61.2", + "windows", + "windows-core", ] [[package]] @@ -7492,51 +7524,30 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window-vibrancy" -version = "0.6.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +checksum = "111e51caca442cafd9bab396628ac4d814880eaea4e63dfd76a12e9f342b5580" dependencies = [ "objc2", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation", + "objc2-quartz-core", "raw-window-handle", - "windows-sys 0.59.0", + "windows-sys 0.61.2", "windows-version", ] -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections 0.2.0", - "windows-core 0.61.2", - "windows-future 0.2.1", - "windows-link 0.1.3", - "windows-numerics 0.2.0", -] - [[package]] name = "windows" version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ - "windows-collections 0.3.2", - "windows-core 0.62.2", - "windows-future 0.3.2", - "windows-numerics 0.3.1", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.2", + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", ] [[package]] @@ -7545,20 +7556,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-core 0.62.2", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", + "windows-core", ] [[package]] @@ -7569,20 +7567,9 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", - "windows-threading 0.1.0", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] @@ -7591,9 +7578,9 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core 0.62.2", - "windows-link 0.2.1", - "windows-threading 0.2.1", + "windows-core", + "windows-link", + "windows-threading", ] [[package]] @@ -7618,36 +7605,20 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", -] - [[package]] name = "windows-numerics" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core 0.62.2", - "windows-link 0.2.1", + "windows-core", + "windows-link", ] [[package]] @@ -7656,18 +7627,9 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] @@ -7676,16 +7638,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -7694,7 +7647,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -7739,7 +7692,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -7779,7 +7732,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.2.1", + "windows-link", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -7790,22 +7743,13 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - [[package]] name = "windows-threading" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -7814,7 +7758,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -8121,15 +8065,15 @@ checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "wry" -version = "0.54.4" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a8135d8676225e5744de000d4dff5a082501bf7db6a1c1495034f8c314edbc" +checksum = "a819957a01b3119af85e638a38d242af76dbc87d130dca67bfd0441072e21ff0" dependencies = [ "base64 0.22.1", "block2", "cookie", "crossbeam-channel", - "dirs", + "dirs 7.0.0", "dom_query", "dpi", "dunce", @@ -8157,8 +8101,8 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows 0.61.3", - "windows-core 0.61.2", + "windows", + "windows-core", "windows-version", "x11-dl", ] @@ -8227,7 +8171,7 @@ dependencies = [ "thiserror 2.0.18", "url", "widestring", - "windows 0.62.2", + "windows", "xcb", "zbus", ] diff --git a/crates/terminal-snapshot-renderer/tests/fixtures/diagnostic-failure-harness/Cargo.lock b/crates/terminal-snapshot-renderer/tests/fixtures/diagnostic-failure-harness/Cargo.lock index e6f1b360c..2c57b0c2f 100644 --- a/crates/terminal-snapshot-renderer/tests/fixtures/diagnostic-failure-harness/Cargo.lock +++ b/crates/terminal-snapshot-renderer/tests/fixtures/diagnostic-failure-harness/Cargo.lock @@ -382,9 +382,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" diff --git a/package-lock.json b/package-lock.json index 02b2b6246..fc8f1b0b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -879,9 +879,9 @@ "license": "MIT" }, "node_modules/@tauri-apps/api": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.10.1.tgz", - "integrity": "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.12.1.tgz", + "integrity": "sha512-DeyFHa3wynpyoqTDikDEDGTJIq4LQ5USfolQGRmGIWT6JMADyxZBTDa5cAdT3tDg73rUXufPaCwN7aXBos4OnQ==", "license": "Apache-2.0 OR MIT", "funding": { "type": "opencollective", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index a0a540658..92e754b46 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -6,7 +6,7 @@ authors = ["AgentsCommander Contributors"] description = "AgentsCommander: Run multiple teams of AI coding agents" [dependencies] -tauri = { version = "2", features = ["image-png"] } +tauri = { version = "2.12.1", features = ["image-png"] } serde = { version = "1", features = ["derive"] } serde_json = "1" serde_yaml = "0.9" @@ -90,10 +90,18 @@ tauri-plugin-clipboard-manager = "2.3.2" xcap = "0.9.6" image = "0.25.10" +# #2817 The reentrancy harness needs a real tao window on its own HWND. The +# default-features and the feature set are the same as what +# tauri-runtime-wry 2.12.1 requests (its Cargo.toml:78-81, which pins +# "0.37.0"), so Cargo unifies on one tao and this dev-dependency adds no +# feature to the normal build. +[target.'cfg(windows)'.dev-dependencies] +tao = { version = "0.37.1", default-features = false, features = ["rwh_06"] } + [dev-dependencies] syn = { version = "=2.0.117", features = ["full", "visit"] } tempfile = "3" -tauri = { version = "2", features = ["image-png", "test"] } +tauri = { version = "2.12.1", features = ["image-png", "test"] } [build-dependencies] tauri-build = { version = "2", features = [] } diff --git a/src-tauri/tests/tao_keyboard_reentrancy.rs b/src-tauri/tests/tao_keyboard_reentrancy.rs new file mode 100644 index 000000000..2801dd27d --- /dev/null +++ b/src-tauri/tests/tao_keyboard_reentrancy.rs @@ -0,0 +1,281 @@ +//! #2817 regression harness for the `tao` keyboard reentrancy deadlock. +//! +//! `tao 0.34.8` held a global, non-reentrant `KEY_EVENT_BUILDERS` mutex while +//! its `WM_KEYUP` branch called `PeekMessageW`. That peek delivers pending sent +//! messages, so a `WM_KILLFOCUS` arriving at that instant reentered the same +//! callback and the event-loop thread waited on itself forever. +//! +//! T1 pins the resolved `tao` floor and is portable. T2 drives the reentrancy +//! on a hidden window the test owns, and lives in `win_harness`. + +use std::path::Path; + +const TAO_FLOOR: (u64, u64, u64) = (0, 37, 1); + +fn parse_version(text: &str) -> Option<(u64, u64, u64)> { + let mut parts = text.split('.').map(|part| part.parse::().ok()); + Some((parts.next()??, parts.next()??, parts.next()??)) +} + +/// The `version` of every `[[package]]` block named `tao`. +fn tao_versions(lock: &str) -> Vec { + lock.split("[[package]]") + .filter(|block| block.lines().any(|line| line == "name = \"tao\"")) + .filter_map(|block| { + block + .lines() + .find_map(|line| line.strip_prefix("version = \"")) + .map(|rest| rest.trim_end_matches('"').to_string()) + }) + .collect() +} + +#[test] +fn resolved_tao_is_at_least_0_37_1() { + let lock_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../Cargo.lock"); + let lock = std::fs::read_to_string(&lock_path) + .unwrap_or_else(|err| panic!("#2817: cannot read {}: {err}", lock_path.display())); + let versions = tao_versions(&lock); + assert_eq!( + versions.len(), + 1, + "#2817: expected exactly one resolved tao package, found {versions:?}; \ + a second tao can hide the KEY_EVENT_BUILDERS reentrancy deadlock" + ); + let found = &versions[0]; + let parsed = parse_version(found) + .unwrap_or_else(|| panic!("#2817: unparseable tao version {found:?} in Cargo.lock")); + assert!( + parsed >= TAO_FLOOR, + "#2817: resolved tao is {found}, below 0.37.1; tao < 0.37.1 reintroduces \ + the KEY_EVENT_BUILDERS reentrancy deadlock" + ); +} + +#[cfg(windows)] +mod win_harness { + use std::io::Write; + use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; + use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; + use std::sync::Arc; + use std::thread::{self, JoinHandle}; + use std::time::{Duration, Instant}; + + use tao::event_loop::{EventLoop, EventLoopBuilder}; + use tao::platform::windows::{EventLoopBuilderExtWindows, WindowExtWindows}; + use tao::window::{Window, WindowBuilder}; + use windows_sys::Win32::Foundation::HWND; + use windows_sys::Win32::UI::WindowsAndMessaging::{ + GetQueueStatus, PeekMessageW, SendMessageW, MSG, PM_NOREMOVE, QS_SENDMESSAGE, WM_KEYUP, + WM_KILLFOCUS, + }; + + /// One deadline for setup, body and teardown. + const WATCHDOG_DEADLINE: Duration = Duration::from_secs(25); + /// Own bound of every inner wait; shorter than the watchdog so an inner + /// expiry fails as a named assertion or cleanup error, never as an abort. + const STEP_BOUND: Duration = Duration::from_secs(5); + const POLL: Duration = Duration::from_millis(5); + + // Stage reached, printed by the watchdog. 1 and 2 are written on entry to + // the step, so a hang inside setup names the step that hung. + const STAGE_EVENT_LOOP: usize = 1; + const STAGE_WINDOW: usize = 2; + const STAGE_PENDING_OBSERVED: usize = 3; + const STAGE_OUTER_SEND_ISSUED: usize = 4; + const STAGE_OUTER_SEND_RETURNED: usize = 5; + const STAGE_DRAIN: usize = 6; + const STAGE_SENDER_SETTLED: usize = 7; + const STAGE_RESOURCES_DROPPED: usize = 8; + + const VK_SHIFT: usize = 0x10; + /// The `lparam` of the incident's `WM_KEYUP`. + const INCIDENT_KEYUP_LPARAM: isize = 0x80b6_0001; + + /// Everything that can hang on drop. Owned above `catch_unwind` so that + /// unwinding drops none of it and `teardown` alone decides the order. + #[derive(Default)] + struct Owned { + event_loop: Option>, + window: Option, + sender: Option>, + } + + /// tao hands out `isize`; `windows-sys 0.59` wants a raw pointer. + fn raw_hwnd(hwnd: isize) -> HWND { + hwnd as HWND + } + + /// High word of `GetQueueStatus`: a sent message is in the queue right + /// now. The low word only reports arrivals since the previous call. + fn sent_message_pending() -> bool { + let status = unsafe { GetQueueStatus(QS_SENDMESSAGE) }; + (status >> 16) & QS_SENDMESSAGE != 0 + } + + fn wait_until(bound: Duration, mut condition: impl FnMut() -> bool) -> bool { + let deadline = Instant::now() + bound; + loop { + if condition() { + return true; + } + if Instant::now() >= deadline { + return false; + } + thread::sleep(POLL); + } + } + + /// Writes the stderr handle directly: a spawned thread inherits libtest's + /// capture, so `eprintln!` would be buffered and lost at `abort()`. + fn write_stderr(line: &str) { + let mut stderr = std::io::stderr(); + let _ = writeln!(stderr, "{line}"); + let _ = stderr.flush(); + } + + fn arm_watchdog(done: Arc, stage: Arc) -> JoinHandle<()> { + thread::spawn(move || { + if wait_until(WATCHDOG_DEADLINE, || done.load(Ordering::SeqCst)) { + return; + } + write_stderr(&format!( + "#2817 watchdog abort: the WM_KEYUP send with a pending WM_KILLFOCUS did not \ + finish; stage reached {}, deadline {} s. Stage 4 is the tao keyboard \ + reentrancy deadlock, 1-3 an environment failure, 6-8 a teardown hang.", + stage.load(Ordering::SeqCst), + WATCHDOG_DEADLINE.as_secs() + )); + std::process::abort(); + }) + } + + fn spawn_killfocus_sender(hwnd: isize, kf_returned: Arc) -> JoinHandle<()> { + thread::spawn(move || { + // Blocks until the window thread processes it, so the message + // stays pending-sent against that thread. + unsafe { SendMessageW(raw_hwnd(hwnd), WM_KILLFOCUS, 0, 0) }; + kf_returned.store(true, Ordering::SeqCst); + }) + } + + fn body(owned: &mut Owned, stage: &AtomicUsize, kf_returned: &Arc) { + stage.store(STAGE_EVENT_LOOP, Ordering::SeqCst); + let event_loop = owned + .event_loop + .insert(EventLoopBuilder::<()>::new().with_any_thread(true).build()); + stage.store(STAGE_WINDOW, Ordering::SeqCst); + let window = WindowBuilder::new() + .with_visible(false) + .build(event_loop) + .expect("#2817: cannot create the hidden harness window"); + let hwnd = owned.window.insert(window).hwnd(); + + owned.sender = Some(spawn_killfocus_sender(hwnd, Arc::clone(kf_returned))); + assert!( + wait_until(STEP_BOUND, sent_message_pending), + "PENDING_SENT_NEVER_OBSERVED: no sent message became pending within {} s", + STEP_BOUND.as_secs() + ); + stage.store(STAGE_PENDING_OBSERVED, Ordering::SeqCst); + assert!( + sent_message_pending(), + "PENDING_SENT_LOST_BEFORE_OUTER_SEND: the pending WM_KILLFOCUS was consumed early" + ); + + stage.store(STAGE_OUTER_SEND_ISSUED, Ordering::SeqCst); + // A same-thread send calls the window procedure directly, without + // pumping the queue. + unsafe { SendMessageW(raw_hwnd(hwnd), WM_KEYUP, VK_SHIFT, INCIDENT_KEYUP_LPARAM) }; + stage.store(STAGE_OUTER_SEND_RETURNED, Ordering::SeqCst); + assert!( + !sent_message_pending(), + "PENDING_SENT_STILL_SET_AFTER_OUTER_SEND: the reentrancy path is no longer \ + exercised; tao's WM_KEYUP branch did not dispatch the pending WM_KILLFOCUS" + ); + } + + /// `PeekMessageW` dispatches pending sent messages whatever its filter; + /// this is the only thing in teardown that releases the sender. + fn drain_sent_messages(hwnd: isize) -> bool { + wait_until(STEP_BOUND, || { + let mut msg: MSG = unsafe { std::mem::zeroed() }; + unsafe { PeekMessageW(&mut msg, raw_hwnd(hwnd), 0, 0, PM_NOREMOVE) }; + !sent_message_pending() + }) + } + + fn settle_sender(sender: JoinHandle<()>, kf_returned: &AtomicBool) -> Option<&'static str> { + if !wait_until(STEP_BOUND, || kf_returned.load(Ordering::SeqCst)) { + // Still blocked in its send: detach, never join. It dies with + // this test binary. + drop(sender); + return Some("SENDER_DETACHED"); + } + // The still-armed watchdog bounds this join. + sender.join().err().map(|_| "SENDER_JOIN_FAILED") + } + + /// Same on the success path and the caught-panic path. Every step runs + /// even after an earlier one fails; the watchdog is disarmed last. + fn teardown( + owned: &mut Owned, + stage: &AtomicUsize, + kf_returned: &AtomicBool, + done: &AtomicBool, + watchdog: JoinHandle<()>, + ) -> Vec { + let mut failures = Vec::new(); + let mut fail = |name: &str, at: usize| failures.push(format!("{name} (stage {at})")); + + stage.store(STAGE_DRAIN, Ordering::SeqCst); + let hwnd = owned.window.as_ref().map_or(0, |window| window.hwnd()); + if !drain_sent_messages(hwnd) { + fail("DRAIN_DEADLINE_EXPIRED", STAGE_DRAIN); + } + + stage.store(STAGE_SENDER_SETTLED, Ordering::SeqCst); + let settled = owned + .sender + .take() + .and_then(|sender| settle_sender(sender, kf_returned)); + if let Some(name) = settled { + fail(name, STAGE_SENDER_SETTLED); + } + + stage.store(STAGE_RESOURCES_DROPPED, Ordering::SeqCst); + drop(owned.window.take()); + drop(owned.event_loop.take()); + + done.store(true, Ordering::SeqCst); + if watchdog.join().is_err() { + fail("WATCHDOG_JOIN_FAILED", STAGE_RESOURCES_DROPPED); + } + failures + } + + #[test] + fn wm_keyup_peek_does_not_deadlock_on_reentrant_wm_killfocus() { + let done = Arc::new(AtomicBool::new(false)); + let stage = Arc::new(AtomicUsize::new(0)); + let kf_returned = Arc::new(AtomicBool::new(false)); + // Armed before any tao call: setup can hang too. + let watchdog = arm_watchdog(Arc::clone(&done), Arc::clone(&stage)); + let mut owned = Owned::default(); + + let outcome = catch_unwind(AssertUnwindSafe(|| body(&mut owned, &stage, &kf_returned))); + let failures = teardown(&mut owned, &stage, &kf_returned, &done, watchdog); + + for failure in &failures { + write_stderr(&format!("#2817 cleanup failure: {failure}")); + } + if let Err(original) = outcome { + resume_unwind(original); + } + assert!( + failures.is_empty(), + "CLEANUP_FAILED: {}", + failures.join(", ") + ); + } +} diff --git a/src-tauri/tests/tauri_npm_version_coupling.rs b/src-tauri/tests/tauri_npm_version_coupling.rs new file mode 100644 index 000000000..2d2446587 --- /dev/null +++ b/src-tauri/tests/tauri_npm_version_coupling.rs @@ -0,0 +1,84 @@ +//! #2817 coupling gate: the Rust `tauri` crate and the npm `@tauri-apps/api` +//! package must share a `major.minor`. +//! +//! The Tauri CLI compares the two and aborts the build when they differ, so a +//! bump of one side alone turns the production build red only after a full +//! Windows build. This test reads both lockfiles and fails first. + +use std::path::{Path, PathBuf}; + +const NPM_API_KEY: &str = "node_modules/@tauri-apps/api"; + +fn repo_root() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .expect("#2817: the src-tauri package directory has a parent") + .to_path_buf() +} + +fn read(path: &Path) -> String { + std::fs::read_to_string(path) + .unwrap_or_else(|err| panic!("#2817: cannot read {}: {err}", path.display())) +} + +/// The version of the single `tauri` package in `Cargo.lock`. +fn cargo_tauri_version(path: &Path) -> String { + let lock: toml::Table = toml::from_str(&read(path)) + .unwrap_or_else(|err| panic!("#2817: cannot parse {}: {err}", path.display())); + let versions: Vec<&str> = lock + .get("package") + .and_then(toml::Value::as_array) + .into_iter() + .flatten() + .filter(|package| package.get("name").and_then(toml::Value::as_str) == Some("tauri")) + .filter_map(|package| package.get("version").and_then(toml::Value::as_str)) + .collect(); + assert_eq!( + versions.len(), + 1, + "#2817: expected exactly one `tauri` package in {}, found {versions:?}", + path.display() + ); + versions[0].to_string() +} + +/// The version of `@tauri-apps/api` in `package-lock.json`. +fn npm_api_version(path: &Path) -> String { + let lock: serde_json::Value = serde_json::from_str(&read(path)) + .unwrap_or_else(|err| panic!("#2817: cannot parse {}: {err}", path.display())); + lock["packages"][NPM_API_KEY]["version"] + .as_str() + .unwrap_or_else(|| panic!("#2817: {} has no version for {NPM_API_KEY}", path.display())) + .to_string() +} + +/// `(major, minor)` of `version`, ignoring any prerelease or build tag. +fn major_minor(version: &str, source: &Path) -> (u64, u64) { + let core = version.split(['-', '+']).next().unwrap_or_default(); + let mut fields = core.split('.').map(|field| field.parse::().ok()); + match (fields.next().flatten(), fields.next().flatten()) { + (Some(major), Some(minor)) => (major, minor), + _ => panic!( + "#2817: `{version}` from {} has no numeric major.minor", + source.display() + ), + } +} + +#[test] +fn tauri_crate_and_npm_api_share_a_major_minor() { + let root = repo_root(); + let cargo_lock = root.join("Cargo.lock"); + let package_lock = root.join("package-lock.json"); + let crate_version = cargo_tauri_version(&cargo_lock); + let npm_version = npm_api_version(&package_lock); + assert_eq!( + major_minor(&crate_version, &cargo_lock), + major_minor(&npm_version, &package_lock), + "#2817: `tauri` {crate_version} in {} and `@tauri-apps/api` {npm_version} in {} differ \ + in major.minor. The Tauri CLI aborts `npm run build:prod` and \ + `npm run build:prod:no-bundle` with \"Found version mismatched Tauri packages\".", + cargo_lock.display(), + package_lock.display() + ); +}